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
atohx(unsigned char * dst,char * src)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 */
parse_hex_line(unsigned char * fw_data,unsigned char * addr,unsigned char * data,int * dataLength,unsigned char * addr_has_changed)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
as102_firmware_upload(struct as10x_bus_adapter_t * bus_adap,unsigned char * cmd,const struct firmware * firmware)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 for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
109 int read_bytes = 0, data_len = 0;
110
111 /* parse intel hex line */
112 read_bytes = parse_hex_line(
113 (u8 *) (firmware->data + total_read_bytes),
114 fw_pkt.raw.address,
115 fw_pkt.raw.data,
116 &data_len,
117 &addr_has_changed);
118
119 if (read_bytes <= 0)
120 goto error;
121
122 /* detect the end of file */
123 total_read_bytes += read_bytes;
124 if (total_read_bytes == firmware->size) {
125 fw_pkt.u.request[0] = 0x00;
126 fw_pkt.u.request[1] = 0x03;
127
128 /* send EOF command */
129 errno = bus_adap->ops->upload_fw_pkt(bus_adap,
130 (uint8_t *)
131 &fw_pkt, 2, 0);
132 if (errno < 0)
133 goto error;
134 } else {
135 if (!addr_has_changed) {
136 /* prepare command to send */
137 fw_pkt.u.request[0] = 0x00;
138 fw_pkt.u.request[1] = 0x01;
139
140 data_len += sizeof(fw_pkt.u.request);
141 data_len += sizeof(fw_pkt.raw.address);
142
143 /* send cmd to device */
144 errno = bus_adap->ops->upload_fw_pkt(bus_adap,
145 (uint8_t *)
146 &fw_pkt,
147 data_len,
148 0);
149 if (errno < 0)
150 goto error;
151 }
152 }
153 }
154 error:
155 return (errno == 0) ? total_read_bytes : errno;
156 }
157
as102_fw_upload(struct as10x_bus_adapter_t * bus_adap)158 int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
159 {
160 int errno = -EFAULT;
161 const struct firmware *firmware = NULL;
162 unsigned char *cmd_buf = NULL;
163 const char *fw1, *fw2;
164 struct usb_device *dev = bus_adap->usb_dev;
165
166 /* select fw file to upload */
167 if (dual_tuner) {
168 fw1 = as102_dt_fw1;
169 fw2 = as102_dt_fw2;
170 } else {
171 fw1 = as102_st_fw1;
172 fw2 = as102_st_fw2;
173 }
174
175 /* allocate buffer to store firmware upload command and data */
176 cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
177 if (cmd_buf == NULL) {
178 errno = -ENOMEM;
179 goto error;
180 }
181
182 /* request kernel to locate firmware file: part1 */
183 errno = request_firmware(&firmware, fw1, &dev->dev);
184 if (errno < 0) {
185 pr_err("%s: unable to locate firmware file: %s\n",
186 DRIVER_NAME, fw1);
187 goto error;
188 }
189
190 /* initiate firmware upload */
191 errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
192 if (errno < 0) {
193 pr_err("%s: error during firmware upload part1\n",
194 DRIVER_NAME);
195 goto error;
196 }
197
198 pr_info("%s: firmware: %s loaded with success\n",
199 DRIVER_NAME, fw1);
200 release_firmware(firmware);
201
202 /* wait for boot to complete */
203 mdelay(100);
204
205 /* request kernel to locate firmware file: part2 */
206 errno = request_firmware(&firmware, fw2, &dev->dev);
207 if (errno < 0) {
208 pr_err("%s: unable to locate firmware file: %s\n",
209 DRIVER_NAME, fw2);
210 goto error;
211 }
212
213 /* initiate firmware upload */
214 errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
215 if (errno < 0) {
216 pr_err("%s: error during firmware upload part2\n",
217 DRIVER_NAME);
218 goto error;
219 }
220
221 pr_info("%s: firmware: %s loaded with success\n",
222 DRIVER_NAME, fw2);
223 error:
224 kfree(cmd_buf);
225 release_firmware(firmware);
226
227 return errno;
228 }
229