CIFS: Rename *UCS* functions to *UTF16*
[sfrench/cifs-2.6.git] / drivers / staging / media / 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  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 #include <linux/kernel.h>
21 #include <linux/errno.h>
22 #include <linux/ctype.h>
23 #include <linux/delay.h>
24 #include <linux/firmware.h>
25
26 #include "as102_drv.h"
27 #include "as102_fw.h"
28
29 #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
30 char as102_st_fw1[] = "as102_data1_st.hex";
31 char as102_st_fw2[] = "as102_data2_st.hex";
32 char as102_dt_fw1[] = "as102_data1_dt.hex";
33 char as102_dt_fw2[] = "as102_data2_dt.hex";
34
35 static unsigned char atohx(unsigned char *dst, char *src)
36 {
37         unsigned char value = 0;
38
39         char msb = tolower(*src) - '0';
40         char lsb = tolower(*(src + 1)) - '0';
41
42         if (msb > 9)
43                 msb -= 7;
44         if (lsb > 9)
45                 lsb -= 7;
46
47         *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
48         return value;
49 }
50
51 /*
52  * Parse INTEL HEX firmware file to extract address and data.
53  */
54 static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
55                           unsigned char *data, int *dataLength,
56                           unsigned char *addr_has_changed) {
57
58         int count = 0;
59         unsigned char *src, dst;
60
61         if (*fw_data++ != ':') {
62                 printk(KERN_ERR "invalid firmware file\n");
63                 return -EFAULT;
64         }
65
66         /* locate end of line */
67         for (src = fw_data; *src != '\n'; src += 2) {
68                 atohx(&dst, src);
69                 /* parse line to split addr / data */
70                 switch (count) {
71                 case 0:
72                         *dataLength = dst;
73                         break;
74                 case 1:
75                         addr[2] = dst;
76                         break;
77                 case 2:
78                         addr[3] = dst;
79                         break;
80                 case 3:
81                         /* check if data is an address */
82                         if (dst == 0x04)
83                                 *addr_has_changed = 1;
84                         else
85                                 *addr_has_changed = 0;
86                         break;
87                 case  4:
88                 case  5:
89                         if (*addr_has_changed)
90                                 addr[(count - 4)] = dst;
91                         else
92                                 data[(count - 4)] = dst;
93                         break;
94                 default:
95                         data[(count - 4)] = dst;
96                         break;
97                 }
98                 count++;
99         }
100
101         /* return read value + ':' + '\n' */
102         return (count * 2) + 2;
103 }
104
105 static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap,
106                                  unsigned char *cmd,
107                                  const struct firmware *firmware) {
108
109         struct as10x_fw_pkt_t fw_pkt;
110         int total_read_bytes = 0, errno = 0;
111         unsigned char addr_has_changed = 0;
112
113         ENTER();
114
115         for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
116                 int read_bytes = 0, data_len = 0;
117
118                 /* parse intel hex line */
119                 read_bytes = parse_hex_line(
120                                 (u8 *) (firmware->data + total_read_bytes),
121                                 fw_pkt.raw.address,
122                                 fw_pkt.raw.data,
123                                 &data_len,
124                                 &addr_has_changed);
125
126                 if (read_bytes <= 0)
127                         goto error;
128
129                 /* detect the end of file */
130                 total_read_bytes += read_bytes;
131                 if (total_read_bytes == firmware->size) {
132                         fw_pkt.u.request[0] = 0x00;
133                         fw_pkt.u.request[1] = 0x03;
134
135                         /* send EOF command */
136                         errno = bus_adap->ops->upload_fw_pkt(bus_adap,
137                                                              (uint8_t *)
138                                                              &fw_pkt, 2, 0);
139                         if (errno < 0)
140                                 goto error;
141                 } else {
142                         if (!addr_has_changed) {
143                                 /* prepare command to send */
144                                 fw_pkt.u.request[0] = 0x00;
145                                 fw_pkt.u.request[1] = 0x01;
146
147                                 data_len += sizeof(fw_pkt.u.request);
148                                 data_len += sizeof(fw_pkt.raw.address);
149
150                                 /* send cmd to device */
151                                 errno = bus_adap->ops->upload_fw_pkt(bus_adap,
152                                                                      (uint8_t *)
153                                                                      &fw_pkt,
154                                                                      data_len,
155                                                                      0);
156                                 if (errno < 0)
157                                         goto error;
158                         }
159                 }
160         }
161 error:
162         LEAVE();
163         return (errno == 0) ? total_read_bytes : errno;
164 }
165
166 int as102_fw_upload(struct as102_bus_adapter_t *bus_adap)
167 {
168         int errno = -EFAULT;
169         const struct firmware *firmware;
170         unsigned char *cmd_buf = NULL;
171         char *fw1, *fw2;
172
173 #if defined(CONFIG_AS102_USB)
174         struct usb_device *dev = bus_adap->usb_dev;
175 #endif
176 #if defined(CONFIG_AS102_SPI)
177         struct spi_device *dev = bus_adap->spi_dev;
178 #endif
179         ENTER();
180
181         /* select fw file to upload */
182         if (dual_tuner) {
183                 fw1 = as102_dt_fw1;
184                 fw2 = as102_dt_fw2;
185         } else {
186                 fw1 = as102_st_fw1;
187                 fw2 = as102_st_fw2;
188         }
189
190 #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
191         /* allocate buffer to store firmware upload command and data */
192         cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
193         if (cmd_buf == NULL) {
194                 errno = -ENOMEM;
195                 goto error;
196         }
197
198         /* request kernel to locate firmware file: part1 */
199         errno = request_firmware(&firmware, fw1, &dev->dev);
200         if (errno < 0) {
201                 printk(KERN_ERR "%s: unable to locate firmware file: %s\n",
202                                  DRIVER_NAME, fw1);
203                 goto error;
204         }
205
206         /* initiate firmware upload */
207         errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
208         if (errno < 0) {
209                 printk(KERN_ERR "%s: error during firmware upload part1\n",
210                                  DRIVER_NAME);
211                 goto error;
212         }
213
214         printk(KERN_INFO "%s: fimrware: %s loaded with success\n",
215                          DRIVER_NAME, fw1);
216         release_firmware(firmware);
217
218         /* wait for boot to complete */
219         mdelay(100);
220
221         /* request kernel to locate firmware file: part2 */
222         errno = request_firmware(&firmware, fw2, &dev->dev);
223         if (errno < 0) {
224                 printk(KERN_ERR "%s: unable to locate firmware file: %s\n",
225                                  DRIVER_NAME, fw2);
226                 goto error;
227         }
228
229         /* initiate firmware upload */
230         errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
231         if (errno < 0) {
232                 printk(KERN_ERR "%s: error during firmware upload part2\n",
233                                  DRIVER_NAME);
234                 goto error;
235         }
236
237         printk(KERN_INFO "%s: fimrware: %s loaded with success\n",
238                         DRIVER_NAME, fw2);
239 error:
240         /* free data buffer */
241         kfree(cmd_buf);
242         /* release firmware if needed */
243         if (firmware != NULL)
244                 release_firmware(firmware);
245 #endif
246         LEAVE();
247         return errno;
248 }
249 #endif
250
251 /* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */