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