Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/usb/6fire/firmware.c
10817 views
1
/*
2
* Linux driver for TerraTec DMX 6Fire USB
3
*
4
* Firmware loader
5
*
6
* Author: Torsten Schenk <[email protected]>
7
* Created: Jan 01, 2011
8
* Version: 0.3.0
9
* Copyright: (C) Torsten Schenk
10
*
11
* This program is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation; either version 2 of the License, or
14
* (at your option) any later version.
15
*/
16
17
#include <linux/firmware.h>
18
#include <linux/bitrev.h>
19
20
#include "firmware.h"
21
#include "chip.h"
22
23
MODULE_FIRMWARE("6fire/dmx6firel2.ihx");
24
MODULE_FIRMWARE("6fire/dmx6fireap.ihx");
25
MODULE_FIRMWARE("6fire/dmx6firecf.bin");
26
27
enum {
28
FPGA_BUFSIZE = 512, FPGA_EP = 2
29
};
30
31
/*
32
* wMaxPacketSize of pcm endpoints.
33
* keep synced with rates_in_packet_size and rates_out_packet_size in pcm.c
34
* fpp: frames per isopacket
35
*
36
* CAUTION: keep sizeof <= buffer[] in usb6fire_fw_init
37
*/
38
static const u8 ep_w_max_packet_size[] = {
39
0xe4, 0x00, 0xe4, 0x00, /* alt 1: 228 EP2 and EP6 (7 fpp) */
40
0xa4, 0x01, 0xa4, 0x01, /* alt 2: 420 EP2 and EP6 (13 fpp)*/
41
0x94, 0x01, 0x5c, 0x02 /* alt 3: 404 EP2 and 604 EP6 (25 fpp) */
42
};
43
44
static const u8 known_fw_versions[][4] = {
45
{ 0x03, 0x01, 0x0b, 0x00 }
46
};
47
48
struct ihex_record {
49
u16 address;
50
u8 len;
51
u8 data[256];
52
char error; /* true if an error occurred parsing this record */
53
54
u8 max_len; /* maximum record length in whole ihex */
55
56
/* private */
57
const char *txt_data;
58
unsigned int txt_length;
59
unsigned int txt_offset; /* current position in txt_data */
60
};
61
62
static u8 usb6fire_fw_ihex_nibble(const u8 n)
63
{
64
if (n >= '0' && n <= '9')
65
return n - '0';
66
else if (n >= 'A' && n <= 'F')
67
return n - ('A' - 10);
68
else if (n >= 'a' && n <= 'f')
69
return n - ('a' - 10);
70
return 0;
71
}
72
73
static u8 usb6fire_fw_ihex_hex(const u8 *data, u8 *crc)
74
{
75
u8 val = (usb6fire_fw_ihex_nibble(data[0]) << 4) |
76
usb6fire_fw_ihex_nibble(data[1]);
77
*crc += val;
78
return val;
79
}
80
81
/*
82
* returns true if record is available, false otherwise.
83
* iff an error occurred, false will be returned and record->error will be true.
84
*/
85
static bool usb6fire_fw_ihex_next_record(struct ihex_record *record)
86
{
87
u8 crc = 0;
88
u8 type;
89
int i;
90
91
record->error = false;
92
93
/* find begin of record (marked by a colon) */
94
while (record->txt_offset < record->txt_length
95
&& record->txt_data[record->txt_offset] != ':')
96
record->txt_offset++;
97
if (record->txt_offset == record->txt_length)
98
return false;
99
100
/* number of characters needed for len, addr and type entries */
101
record->txt_offset++;
102
if (record->txt_offset + 8 > record->txt_length) {
103
record->error = true;
104
return false;
105
}
106
107
record->len = usb6fire_fw_ihex_hex(record->txt_data +
108
record->txt_offset, &crc);
109
record->txt_offset += 2;
110
record->address = usb6fire_fw_ihex_hex(record->txt_data +
111
record->txt_offset, &crc) << 8;
112
record->txt_offset += 2;
113
record->address |= usb6fire_fw_ihex_hex(record->txt_data +
114
record->txt_offset, &crc);
115
record->txt_offset += 2;
116
type = usb6fire_fw_ihex_hex(record->txt_data +
117
record->txt_offset, &crc);
118
record->txt_offset += 2;
119
120
/* number of characters needed for data and crc entries */
121
if (record->txt_offset + 2 * (record->len + 1) > record->txt_length) {
122
record->error = true;
123
return false;
124
}
125
for (i = 0; i < record->len; i++) {
126
record->data[i] = usb6fire_fw_ihex_hex(record->txt_data
127
+ record->txt_offset, &crc);
128
record->txt_offset += 2;
129
}
130
usb6fire_fw_ihex_hex(record->txt_data + record->txt_offset, &crc);
131
if (crc) {
132
record->error = true;
133
return false;
134
}
135
136
if (type == 1 || !record->len) /* eof */
137
return false;
138
else if (type == 0)
139
return true;
140
else {
141
record->error = true;
142
return false;
143
}
144
}
145
146
static int usb6fire_fw_ihex_init(const struct firmware *fw,
147
struct ihex_record *record)
148
{
149
record->txt_data = fw->data;
150
record->txt_length = fw->size;
151
record->txt_offset = 0;
152
record->max_len = 0;
153
/* read all records, if loop ends, record->error indicates,
154
* whether ihex is valid. */
155
while (usb6fire_fw_ihex_next_record(record))
156
record->max_len = max(record->len, record->max_len);
157
if (record->error)
158
return -EINVAL;
159
record->txt_offset = 0;
160
return 0;
161
}
162
163
static int usb6fire_fw_ezusb_write(struct usb_device *device,
164
int type, int value, char *data, int len)
165
{
166
int ret;
167
168
ret = usb_control_msg(device, usb_sndctrlpipe(device, 0), type,
169
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
170
value, 0, data, len, HZ);
171
if (ret < 0)
172
return ret;
173
else if (ret != len)
174
return -EIO;
175
return 0;
176
}
177
178
static int usb6fire_fw_ezusb_read(struct usb_device *device,
179
int type, int value, char *data, int len)
180
{
181
int ret = usb_control_msg(device, usb_rcvctrlpipe(device, 0), type,
182
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value,
183
0, data, len, HZ);
184
if (ret < 0)
185
return ret;
186
else if (ret != len)
187
return -EIO;
188
return 0;
189
}
190
191
static int usb6fire_fw_fpga_write(struct usb_device *device,
192
char *data, int len)
193
{
194
int actual_len;
195
int ret;
196
197
ret = usb_bulk_msg(device, usb_sndbulkpipe(device, FPGA_EP), data, len,
198
&actual_len, HZ);
199
if (ret < 0)
200
return ret;
201
else if (actual_len != len)
202
return -EIO;
203
return 0;
204
}
205
206
static int usb6fire_fw_ezusb_upload(
207
struct usb_interface *intf, const char *fwname,
208
unsigned int postaddr, u8 *postdata, unsigned int postlen)
209
{
210
int ret;
211
u8 data;
212
struct usb_device *device = interface_to_usbdev(intf);
213
const struct firmware *fw = 0;
214
struct ihex_record *rec = kmalloc(sizeof(struct ihex_record),
215
GFP_KERNEL);
216
217
if (!rec)
218
return -ENOMEM;
219
220
ret = request_firmware(&fw, fwname, &device->dev);
221
if (ret < 0) {
222
kfree(rec);
223
snd_printk(KERN_ERR PREFIX "error requesting ezusb "
224
"firmware %s.\n", fwname);
225
return ret;
226
}
227
ret = usb6fire_fw_ihex_init(fw, rec);
228
if (ret < 0) {
229
kfree(rec);
230
release_firmware(fw);
231
snd_printk(KERN_ERR PREFIX "error validating ezusb "
232
"firmware %s.\n", fwname);
233
return ret;
234
}
235
/* upload firmware image */
236
data = 0x01; /* stop ezusb cpu */
237
ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
238
if (ret < 0) {
239
kfree(rec);
240
release_firmware(fw);
241
snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
242
"firmware %s: begin message.\n", fwname);
243
return ret;
244
}
245
246
while (usb6fire_fw_ihex_next_record(rec)) { /* write firmware */
247
ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address,
248
rec->data, rec->len);
249
if (ret < 0) {
250
kfree(rec);
251
release_firmware(fw);
252
snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
253
"firmware %s: data urb.\n", fwname);
254
return ret;
255
}
256
}
257
258
release_firmware(fw);
259
kfree(rec);
260
if (postdata) { /* write data after firmware has been uploaded */
261
ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
262
postdata, postlen);
263
if (ret < 0) {
264
snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
265
"firmware %s: post urb.\n", fwname);
266
return ret;
267
}
268
}
269
270
data = 0x00; /* resume ezusb cpu */
271
ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
272
if (ret < 0) {
273
snd_printk(KERN_ERR PREFIX "unable to upload ezusb "
274
"firmware %s: end message.\n", fwname);
275
return ret;
276
}
277
return 0;
278
}
279
280
static int usb6fire_fw_fpga_upload(
281
struct usb_interface *intf, const char *fwname)
282
{
283
int ret;
284
int i;
285
struct usb_device *device = interface_to_usbdev(intf);
286
u8 *buffer = kmalloc(FPGA_BUFSIZE, GFP_KERNEL);
287
const char *c;
288
const char *end;
289
const struct firmware *fw;
290
291
if (!buffer)
292
return -ENOMEM;
293
294
ret = request_firmware(&fw, fwname, &device->dev);
295
if (ret < 0) {
296
snd_printk(KERN_ERR PREFIX "unable to get fpga firmware %s.\n",
297
fwname);
298
kfree(buffer);
299
return -EIO;
300
}
301
302
c = fw->data;
303
end = fw->data + fw->size;
304
305
ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0);
306
if (ret < 0) {
307
kfree(buffer);
308
release_firmware(fw);
309
snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: "
310
"begin urb.\n");
311
return ret;
312
}
313
314
while (c != end) {
315
for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++)
316
buffer[i] = byte_rev_table[(u8) *c];
317
318
ret = usb6fire_fw_fpga_write(device, buffer, i);
319
if (ret < 0) {
320
release_firmware(fw);
321
kfree(buffer);
322
snd_printk(KERN_ERR PREFIX "unable to upload fpga "
323
"firmware: fw urb.\n");
324
return ret;
325
}
326
}
327
release_firmware(fw);
328
kfree(buffer);
329
330
ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0);
331
if (ret < 0) {
332
snd_printk(KERN_ERR PREFIX "unable to upload fpga firmware: "
333
"end urb.\n");
334
return ret;
335
}
336
return 0;
337
}
338
339
/* check, if the firmware version the devices has currently loaded
340
* is known by this driver. 'version' needs to have 4 bytes version
341
* info data. */
342
static int usb6fire_fw_check(u8 *version)
343
{
344
int i;
345
346
for (i = 0; i < ARRAY_SIZE(known_fw_versions); i++)
347
if (!memcmp(version, known_fw_versions + i, 4))
348
return 0;
349
350
snd_printk(KERN_ERR PREFIX "invalid fimware version in device: "
351
"%02x %02x %02x %02x. "
352
"please reconnect to power. if this failure "
353
"still happens, check your firmware installation.",
354
version[0], version[1], version[2], version[3]);
355
return -EINVAL;
356
}
357
358
int usb6fire_fw_init(struct usb_interface *intf)
359
{
360
int i;
361
int ret;
362
struct usb_device *device = interface_to_usbdev(intf);
363
/* buffer: 8 receiving bytes from device and
364
* sizeof(EP_W_MAX_PACKET_SIZE) bytes for non-const copy */
365
u8 buffer[12];
366
367
ret = usb6fire_fw_ezusb_read(device, 1, 0, buffer, 8);
368
if (ret < 0) {
369
snd_printk(KERN_ERR PREFIX "unable to receive device "
370
"firmware state.\n");
371
return ret;
372
}
373
if (buffer[0] != 0xeb || buffer[1] != 0xaa || buffer[2] != 0x55) {
374
snd_printk(KERN_ERR PREFIX "unknown device firmware state "
375
"received from device: ");
376
for (i = 0; i < 8; i++)
377
snd_printk("%02x ", buffer[i]);
378
snd_printk("\n");
379
return -EIO;
380
}
381
/* do we need fpga loader ezusb firmware? */
382
if (buffer[3] == 0x01) {
383
ret = usb6fire_fw_ezusb_upload(intf,
384
"6fire/dmx6firel2.ihx", 0, NULL, 0);
385
if (ret < 0)
386
return ret;
387
return FW_NOT_READY;
388
}
389
/* do we need fpga firmware and application ezusb firmware? */
390
else if (buffer[3] == 0x02) {
391
ret = usb6fire_fw_check(buffer + 4);
392
if (ret < 0)
393
return ret;
394
ret = usb6fire_fw_fpga_upload(intf, "6fire/dmx6firecf.bin");
395
if (ret < 0)
396
return ret;
397
memcpy(buffer, ep_w_max_packet_size,
398
sizeof(ep_w_max_packet_size));
399
ret = usb6fire_fw_ezusb_upload(intf, "6fire/dmx6fireap.ihx",
400
0x0003, buffer, sizeof(ep_w_max_packet_size));
401
if (ret < 0)
402
return ret;
403
return FW_NOT_READY;
404
}
405
/* all fw loaded? */
406
else if (buffer[3] == 0x03)
407
return usb6fire_fw_check(buffer + 4);
408
/* unknown data? */
409
else {
410
snd_printk(KERN_ERR PREFIX "unknown device firmware state "
411
"received from device: ");
412
for (i = 0; i < 8; i++)
413
snd_printk("%02x ", buffer[i]);
414
snd_printk("\n");
415
return -EIO;
416
}
417
return 0;
418
}
419
420
421