Merge branch 'nvme-5.2-rc2' of git://git.infradead.org/nvme into for-linus
[linux-2.6-microblaze.git] / drivers / media / usb / as102 / as102_fw.c
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 }