Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
as102_fw.c
Go to the documentation of this file.
1 /*
2  * Abilis Systems Single DVB-T Receiver
3  * Copyright (C) 2008 Pierrick Hascoet <[email protected]>
4  * Copyright (C) 2010 Devin Heitmueller <[email protected]>
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 char as102_st_fw1[] = "as102_data1_st.hex";
30 char as102_st_fw2[] = "as102_data2_st.hex";
31 char as102_dt_fw1[] = "as102_data1_dt.hex";
32 char as102_dt_fw2[] = "as102_data2_dt.hex";
33 
34 static unsigned char atohx(unsigned char *dst, char *src)
35 {
36  unsigned char value = 0;
37 
38  char msb = tolower(*src) - '0';
39  char lsb = tolower(*(src + 1)) - '0';
40 
41  if (msb > 9)
42  msb -= 7;
43  if (lsb > 9)
44  lsb -= 7;
45 
46  *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
47  return value;
48 }
49 
50 /*
51  * Parse INTEL HEX firmware file to extract address and data.
52  */
53 static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
54  unsigned char *data, int *dataLength,
55  unsigned char *addr_has_changed) {
56 
57  int count = 0;
58  unsigned char *src, dst;
59 
60  if (*fw_data++ != ':') {
61  pr_err("invalid firmware file\n");
62  return -EFAULT;
63  }
64 
65  /* locate end of line */
66  for (src = fw_data; *src != '\n'; src += 2) {
67  atohx(&dst, src);
68  /* parse line to split addr / data */
69  switch (count) {
70  case 0:
71  *dataLength = dst;
72  break;
73  case 1:
74  addr[2] = dst;
75  break;
76  case 2:
77  addr[3] = dst;
78  break;
79  case 3:
80  /* check if data is an address */
81  if (dst == 0x04)
82  *addr_has_changed = 1;
83  else
84  *addr_has_changed = 0;
85  break;
86  case 4:
87  case 5:
88  if (*addr_has_changed)
89  addr[(count - 4)] = dst;
90  else
91  data[(count - 4)] = dst;
92  break;
93  default:
94  data[(count - 4)] = dst;
95  break;
96  }
97  count++;
98  }
99 
100  /* return read value + ':' + '\n' */
101  return (count * 2) + 2;
102 }
103 
104 static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
105  unsigned char *cmd,
106  const struct firmware *firmware) {
107 
108  struct as10x_fw_pkt_t fw_pkt;
109  int total_read_bytes = 0, errno = 0;
110  unsigned char addr_has_changed = 0;
111 
112  ENTER();
113 
114  for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
115  int read_bytes = 0, data_len = 0;
116 
117  /* parse intel hex line */
118  read_bytes = parse_hex_line(
119  (u8 *) (firmware->data + total_read_bytes),
120  fw_pkt.raw.address,
121  fw_pkt.raw.data,
122  &data_len,
123  &addr_has_changed);
124 
125  if (read_bytes <= 0)
126  goto error;
127 
128  /* detect the end of file */
129  total_read_bytes += read_bytes;
130  if (total_read_bytes == firmware->size) {
131  fw_pkt.u.request[0] = 0x00;
132  fw_pkt.u.request[1] = 0x03;
133 
134  /* send EOF command */
135  errno = bus_adap->ops->upload_fw_pkt(bus_adap,
136  (uint8_t *)
137  &fw_pkt, 2, 0);
138  if (errno < 0)
139  goto error;
140  } else {
141  if (!addr_has_changed) {
142  /* prepare command to send */
143  fw_pkt.u.request[0] = 0x00;
144  fw_pkt.u.request[1] = 0x01;
145 
146  data_len += sizeof(fw_pkt.u.request);
147  data_len += sizeof(fw_pkt.raw.address);
148 
149  /* send cmd to device */
150  errno = bus_adap->ops->upload_fw_pkt(bus_adap,
151  (uint8_t *)
152  &fw_pkt,
153  data_len,
154  0);
155  if (errno < 0)
156  goto error;
157  }
158  }
159  }
160 error:
161  LEAVE();
162  return (errno == 0) ? total_read_bytes : errno;
163 }
164 
166 {
167  int errno = -EFAULT;
168  const struct firmware *firmware = NULL;
169  unsigned char *cmd_buf = NULL;
170  char *fw1, *fw2;
171  struct usb_device *dev = bus_adap->usb_dev;
172 
173  ENTER();
174 
175  /* select fw file to upload */
176  if (dual_tuner) {
177  fw1 = as102_dt_fw1;
178  fw2 = as102_dt_fw2;
179  } else {
180  fw1 = as102_st_fw1;
181  fw2 = as102_st_fw2;
182  }
183 
184  /* allocate buffer to store firmware upload command and data */
185  cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
186  if (cmd_buf == NULL) {
187  errno = -ENOMEM;
188  goto error;
189  }
190 
191  /* request kernel to locate firmware file: part1 */
192  errno = request_firmware(&firmware, fw1, &dev->dev);
193  if (errno < 0) {
194  pr_err("%s: unable to locate firmware file: %s\n",
195  DRIVER_NAME, fw1);
196  goto error;
197  }
198 
199  /* initiate firmware upload */
200  errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
201  if (errno < 0) {
202  pr_err("%s: error during firmware upload part1\n",
203  DRIVER_NAME);
204  goto error;
205  }
206 
207  pr_info("%s: firmware: %s loaded with success\n",
208  DRIVER_NAME, fw1);
209  release_firmware(firmware);
210 
211  /* wait for boot to complete */
212  mdelay(100);
213 
214  /* request kernel to locate firmware file: part2 */
215  errno = request_firmware(&firmware, fw2, &dev->dev);
216  if (errno < 0) {
217  pr_err("%s: unable to locate firmware file: %s\n",
218  DRIVER_NAME, fw2);
219  goto error;
220  }
221 
222  /* initiate firmware upload */
223  errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
224  if (errno < 0) {
225  pr_err("%s: error during firmware upload part2\n",
226  DRIVER_NAME);
227  goto error;
228  }
229 
230  pr_info("%s: firmware: %s loaded with success\n",
231  DRIVER_NAME, fw2);
232 error:
233  kfree(cmd_buf);
234  release_firmware(firmware);
235 
236  LEAVE();
237  return errno;
238 }