File Index
Files and directories
Sign in
FILE

as102_fw.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/usb/as102/as102_fw.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Abilis Systems Single DVB-T Receiver
  4 * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
  5 * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
  6 */
  7#include <linux/kernel.h>
  8#include <linux/errno.h>
  9#include <linux/ctype.h>
 10#include <linux/delay.h>
 11#include <linux/firmware.h>
 12
 13#include "as102_drv.h"
 14#include "as102_fw.h"
 15
 16static const char as102_st_fw1[] = "as102_data1_st.hex";
 17static const char as102_st_fw2[] = "as102_data2_st.hex";
 18static const char as102_dt_fw1[] = "as102_data1_dt.hex";
 19static const char as102_dt_fw2[] = "as102_data2_dt.hex";
 20
 21static unsigned char atohx(unsigned char *dst, char *src)
 22{
 23	unsigned char value = 0;
 24
 25	char msb = tolower(*src) - '0';
 26	char lsb = tolower(*(src + 1)) - '0';
 27
 28	if (msb > 9)
 29		msb -= 7;
 30	if (lsb > 9)
 31		lsb -= 7;
 32
 33	*dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
 34	return value;
 35}
 36
 37/*
 38 * Parse INTEL HEX firmware file to extract address and data.
 39 */
 40static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
 41			  unsigned char *data, int *dataLength,
 42			  unsigned char *addr_has_changed) {
 43
 44	int count = 0;
 45	unsigned char *src, dst;
 46
 47	if (*fw_data++ != ':') {
 48		pr_err("invalid firmware file\n");
 49		return -EFAULT;
 50	}
 51
 52	/* locate end of line */
 53	for (src = fw_data; *src != '\n'; src += 2) {
 54		atohx(&dst, src);
 55		/* parse line to split addr / data */
 56		switch (count) {
 57		case 0:
 58			*dataLength = dst;
 59			break;
 60		case 1:
 61			addr[2] = dst;
 62			break;
 63		case 2:
 64			addr[3] = dst;
 65			break;
 66		case 3:
 67			/* check if data is an address */
 68			if (dst == 0x04)
 69				*addr_has_changed = 1;
 70			else
 71				*addr_has_changed = 0;
 72			break;
 73		case  4:
 74		case  5:
 75			if (*addr_has_changed)
 76				addr[(count - 4)] = dst;
 77			else
 78				data[(count - 4)] = dst;
 79			break;
 80		default:
 81			data[(count - 4)] = dst;
 82			break;
 83		}
 84		count++;
 85	}
 86
 87	/* return read value + ':' + '\n' */
 88	return (count * 2) + 2;
 89}
 90
 91static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
 92				 unsigned char *cmd,
 93				 const struct firmware *firmware) {
 94
 95	struct as10x_fw_pkt_t *fw_pkt;
 96	int total_read_bytes = 0, errno = 0;
 97	unsigned char addr_has_changed = 0;
 98
 99	fw_pkt = kmalloc(sizeof(*fw_pkt), GFP_KERNEL);
100	if (!fw_pkt)
101		return -ENOMEM;
102
103
104	for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
105		int read_bytes = 0, data_len = 0;
106
107		/* parse intel hex line */
108		read_bytes = parse_hex_line(
109				(u8 *) (firmware->data + total_read_bytes),
110				fw_pkt->raw.address,
111				fw_pkt->raw.data,
112				&data_len,
113				&addr_has_changed);
114
115		if (read_bytes <= 0)
116			goto error;
117
118		/* detect the end of file */
119		total_read_bytes += read_bytes;
120		if (total_read_bytes == firmware->size) {
121			fw_pkt->u.request[0] = 0x00;
122			fw_pkt->u.request[1] = 0x03;
123
124			/* send EOF command */
125			errno = bus_adap->ops->upload_fw_pkt(bus_adap,
126							     (uint8_t *)
127							     fw_pkt, 2, 0);
128			if (errno < 0)
129				goto error;
130		} else {
131			if (!addr_has_changed) {
132				/* prepare command to send */
133				fw_pkt->u.request[0] = 0x00;
134				fw_pkt->u.request[1] = 0x01;
135
136				data_len += sizeof(fw_pkt->u.request);
137				data_len += sizeof(fw_pkt->raw.address);
138
139				/* send cmd to device */
140				errno = bus_adap->ops->upload_fw_pkt(bus_adap,
141								     (uint8_t *)
142								     fw_pkt,
143								     data_len,
144								     0);
145				if (errno < 0)
146					goto error;
147			}
148		}
149	}
150error:
151	kfree(fw_pkt);
152	return (errno == 0) ? total_read_bytes : errno;
153}
154
155int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
156{
157	int errno = -EFAULT;
158	const struct firmware *firmware = NULL;
159	unsigned char *cmd_buf = NULL;
160	const char *fw1, *fw2;
161	struct usb_device *dev = bus_adap->usb_dev;
162
163	/* select fw file to upload */
164	if (dual_tuner) {
165		fw1 = as102_dt_fw1;
166		fw2 = as102_dt_fw2;
167	} else {
168		fw1 = as102_st_fw1;
169		fw2 = as102_st_fw2;
170	}
171
172	/* allocate buffer to store firmware upload command and data */
173	cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
174	if (cmd_buf == NULL) {
175		errno = -ENOMEM;
176		goto error;
177	}
178
179	/* request kernel to locate firmware file: part1 */
180	errno = request_firmware(&firmware, fw1, &dev->dev);
181	if (errno < 0) {
182		pr_err("%s: unable to locate firmware file: %s\n",
183		       DRIVER_NAME, fw1);
184		goto error;
185	}
186
187	/* initiate firmware upload */
188	errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
189	if (errno < 0) {
190		pr_err("%s: error during firmware upload part1\n",
191		       DRIVER_NAME);
192		goto error;
193	}
194
195	pr_info("%s: firmware: %s loaded with success\n",
196		DRIVER_NAME, fw1);
197	release_firmware(firmware);
198	firmware = NULL;
199
200	/* wait for boot to complete */
201	mdelay(100);
202
203	/* request kernel to locate firmware file: part2 */
204	errno = request_firmware(&firmware, fw2, &dev->dev);
205	if (errno < 0) {
206		pr_err("%s: unable to locate firmware file: %s\n",
207		       DRIVER_NAME, fw2);
208		goto error;
209	}
210
211	/* initiate firmware upload */
212	errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
213	if (errno < 0) {
214		pr_err("%s: error during firmware upload part2\n",
215		       DRIVER_NAME);
216		goto error;
217	}
218
219	pr_info("%s: firmware: %s loaded with success\n",
220		DRIVER_NAME, fw2);
221error:
222	kfree(cmd_buf);
223	release_firmware(firmware);
224
225	return errno;
226}
~/ Read-only file preview.