Linux-libre 5.4.39-gnu
[librecmc/linux-libre.git] / drivers / media / usb / as102 / as102_fw.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Abilis Systems Single DVB-T Receiver
4  * 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
16 static const char as102_st_fw1[] = "/*(DEBLOBBED)*/";
17 static const char as102_st_fw2[] = "/*(DEBLOBBED)*/";
18 static const char as102_dt_fw1[] = "/*(DEBLOBBED)*/";
19 static const char as102_dt_fw2[] = "/*(DEBLOBBED)*/";
20
21 static 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  */
40 static 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                         else
71                                 *addr_has_changed = 0;
72                         break;
73                 case  4:
74                 case  5:
75                         if (*addr_has_changed)
76                                 addr[(count - 4)] = dst;
77                         else
78                                 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
91 static 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         }
150 error:
151         kfree(fw_pkt);
152         return (errno == 0) ? total_read_bytes : errno;
153 }
154
155 int 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 = reject_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 = reject_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);
221 error:
222         kfree(cmd_buf);
223         release_firmware(firmware);
224
225         return errno;
226 }