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