brintos

brintos / linux-shallow public Read only

0
0
Text · 5.1 KiB · 5147642 Raw
227 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Abilis Systems Single DVB-T Receiver4 * 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			else71				*addr_has_changed = 0;72			break;73		case  4:74		case  5:75			if (*addr_has_changed)76				addr[(count - 4)] = dst;77			else78				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}227