as102_fw.c (5176B)
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}