Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/dvb/siano/smsusb.c
15111 views
1
/****************************************************************
2
3
Siano Mobile Silicon, Inc.
4
MDTV receiver kernel modules.
5
Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat
6
7
This program is free software: you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation, either version 2 of the License, or
10
(at your option) any later version.
11
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
16
17
You should have received a copy of the GNU General Public License
18
along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
****************************************************************/
21
22
#include <linux/kernel.h>
23
#include <linux/init.h>
24
#include <linux/usb.h>
25
#include <linux/firmware.h>
26
#include <linux/slab.h>
27
28
#include "smscoreapi.h"
29
#include "sms-cards.h"
30
#include "smsendian.h"
31
32
static int sms_dbg;
33
module_param_named(debug, sms_dbg, int, 0644);
34
MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
35
36
#define USB1_BUFFER_SIZE 0x1000
37
#define USB2_BUFFER_SIZE 0x4000
38
39
#define MAX_BUFFERS 50
40
#define MAX_URBS 10
41
42
struct smsusb_device_t;
43
44
struct smsusb_urb_t {
45
struct smscore_buffer_t *cb;
46
struct smsusb_device_t *dev;
47
48
struct urb urb;
49
};
50
51
struct smsusb_device_t {
52
struct usb_device *udev;
53
struct smscore_device_t *coredev;
54
55
struct smsusb_urb_t surbs[MAX_URBS];
56
57
int response_alignment;
58
int buffer_size;
59
};
60
61
static int smsusb_submit_urb(struct smsusb_device_t *dev,
62
struct smsusb_urb_t *surb);
63
64
static void smsusb_onresponse(struct urb *urb)
65
{
66
struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
67
struct smsusb_device_t *dev = surb->dev;
68
69
if (urb->status == -ESHUTDOWN) {
70
sms_err("error, urb status %d (-ESHUTDOWN), %d bytes",
71
urb->status, urb->actual_length);
72
return;
73
}
74
75
if ((urb->actual_length > 0) && (urb->status == 0)) {
76
struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p;
77
78
smsendian_handle_message_header(phdr);
79
if (urb->actual_length >= phdr->msgLength) {
80
surb->cb->size = phdr->msgLength;
81
82
if (dev->response_alignment &&
83
(phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) {
84
85
surb->cb->offset =
86
dev->response_alignment +
87
((phdr->msgFlags >> 8) & 3);
88
89
/* sanity check */
90
if (((int) phdr->msgLength +
91
surb->cb->offset) > urb->actual_length) {
92
sms_err("invalid response "
93
"msglen %d offset %d "
94
"size %d",
95
phdr->msgLength,
96
surb->cb->offset,
97
urb->actual_length);
98
goto exit_and_resubmit;
99
}
100
101
/* move buffer pointer and
102
* copy header to its new location */
103
memcpy((char *) phdr + surb->cb->offset,
104
phdr, sizeof(struct SmsMsgHdr_ST));
105
} else
106
surb->cb->offset = 0;
107
108
smscore_onresponse(dev->coredev, surb->cb);
109
surb->cb = NULL;
110
} else {
111
sms_err("invalid response "
112
"msglen %d actual %d",
113
phdr->msgLength, urb->actual_length);
114
}
115
} else
116
sms_err("error, urb status %d, %d bytes",
117
urb->status, urb->actual_length);
118
119
120
exit_and_resubmit:
121
smsusb_submit_urb(dev, surb);
122
}
123
124
static int smsusb_submit_urb(struct smsusb_device_t *dev,
125
struct smsusb_urb_t *surb)
126
{
127
if (!surb->cb) {
128
surb->cb = smscore_getbuffer(dev->coredev);
129
if (!surb->cb) {
130
sms_err("smscore_getbuffer(...) returned NULL");
131
return -ENOMEM;
132
}
133
}
134
135
usb_fill_bulk_urb(
136
&surb->urb,
137
dev->udev,
138
usb_rcvbulkpipe(dev->udev, 0x81),
139
surb->cb->p,
140
dev->buffer_size,
141
smsusb_onresponse,
142
surb
143
);
144
surb->urb.transfer_dma = surb->cb->phys;
145
surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
146
147
return usb_submit_urb(&surb->urb, GFP_ATOMIC);
148
}
149
150
static void smsusb_stop_streaming(struct smsusb_device_t *dev)
151
{
152
int i;
153
154
for (i = 0; i < MAX_URBS; i++) {
155
usb_kill_urb(&dev->surbs[i].urb);
156
157
if (dev->surbs[i].cb) {
158
smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
159
dev->surbs[i].cb = NULL;
160
}
161
}
162
}
163
164
static int smsusb_start_streaming(struct smsusb_device_t *dev)
165
{
166
int i, rc;
167
168
for (i = 0; i < MAX_URBS; i++) {
169
rc = smsusb_submit_urb(dev, &dev->surbs[i]);
170
if (rc < 0) {
171
sms_err("smsusb_submit_urb(...) failed");
172
smsusb_stop_streaming(dev);
173
break;
174
}
175
}
176
177
return rc;
178
}
179
180
static int smsusb_sendrequest(void *context, void *buffer, size_t size)
181
{
182
struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
183
int dummy;
184
185
smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer);
186
return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
187
buffer, size, &dummy, 1000);
188
}
189
190
static char *smsusb1_fw_lkup[] = {
191
"dvbt_stellar_usb.inp",
192
"dvbh_stellar_usb.inp",
193
"tdmb_stellar_usb.inp",
194
"none",
195
"dvbt_bda_stellar_usb.inp",
196
};
197
198
static inline char *sms_get_fw_name(int mode, int board_id)
199
{
200
char **fw = sms_get_board(board_id)->fw;
201
return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode];
202
}
203
204
static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
205
{
206
const struct firmware *fw;
207
u8 *fw_buffer;
208
int rc, dummy;
209
char *fw_filename;
210
211
if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
212
sms_err("invalid firmware id specified %d", id);
213
return -EINVAL;
214
}
215
216
fw_filename = sms_get_fw_name(id, board_id);
217
218
rc = request_firmware(&fw, fw_filename, &udev->dev);
219
if (rc < 0) {
220
sms_warn("failed to open \"%s\" mode %d, "
221
"trying again with default firmware", fw_filename, id);
222
223
fw_filename = smsusb1_fw_lkup[id];
224
rc = request_firmware(&fw, fw_filename, &udev->dev);
225
if (rc < 0) {
226
sms_warn("failed to open \"%s\" mode %d",
227
fw_filename, id);
228
229
return rc;
230
}
231
}
232
233
fw_buffer = kmalloc(fw->size, GFP_KERNEL);
234
if (fw_buffer) {
235
memcpy(fw_buffer, fw->data, fw->size);
236
237
rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
238
fw_buffer, fw->size, &dummy, 1000);
239
240
sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
241
242
kfree(fw_buffer);
243
} else {
244
sms_err("failed to allocate firmware buffer");
245
rc = -ENOMEM;
246
}
247
sms_info("read FW %s, size=%zd", fw_filename, fw->size);
248
249
release_firmware(fw);
250
251
return rc;
252
}
253
254
static void smsusb1_detectmode(void *context, int *mode)
255
{
256
char *product_string =
257
((struct smsusb_device_t *) context)->udev->product;
258
259
*mode = DEVICE_MODE_NONE;
260
261
if (!product_string) {
262
product_string = "none";
263
sms_err("product string not found");
264
} else if (strstr(product_string, "DVBH"))
265
*mode = 1;
266
else if (strstr(product_string, "BDA"))
267
*mode = 4;
268
else if (strstr(product_string, "DVBT"))
269
*mode = 0;
270
else if (strstr(product_string, "TDMB"))
271
*mode = 2;
272
273
sms_info("%d \"%s\"", *mode, product_string);
274
}
275
276
static int smsusb1_setmode(void *context, int mode)
277
{
278
struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
279
sizeof(struct SmsMsgHdr_ST), 0 };
280
281
if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
282
sms_err("invalid firmware id specified %d", mode);
283
return -EINVAL;
284
}
285
286
return smsusb_sendrequest(context, &Msg, sizeof(Msg));
287
}
288
289
static void smsusb_term_device(struct usb_interface *intf)
290
{
291
struct smsusb_device_t *dev = usb_get_intfdata(intf);
292
293
if (dev) {
294
smsusb_stop_streaming(dev);
295
296
/* unregister from smscore */
297
if (dev->coredev)
298
smscore_unregister_device(dev->coredev);
299
300
sms_info("device %p destroyed", dev);
301
kfree(dev);
302
}
303
304
usb_set_intfdata(intf, NULL);
305
}
306
307
static int smsusb_init_device(struct usb_interface *intf, int board_id)
308
{
309
struct smsdevice_params_t params;
310
struct smsusb_device_t *dev;
311
int i, rc;
312
313
/* create device object */
314
dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
315
if (!dev) {
316
sms_err("kzalloc(sizeof(struct smsusb_device_t) failed");
317
return -ENOMEM;
318
}
319
320
memset(&params, 0, sizeof(params));
321
usb_set_intfdata(intf, dev);
322
dev->udev = interface_to_usbdev(intf);
323
324
params.device_type = sms_get_board(board_id)->type;
325
326
switch (params.device_type) {
327
case SMS_STELLAR:
328
dev->buffer_size = USB1_BUFFER_SIZE;
329
330
params.setmode_handler = smsusb1_setmode;
331
params.detectmode_handler = smsusb1_detectmode;
332
break;
333
default:
334
sms_err("Unspecified sms device type!");
335
/* fall-thru */
336
case SMS_NOVA_A0:
337
case SMS_NOVA_B0:
338
case SMS_VEGA:
339
dev->buffer_size = USB2_BUFFER_SIZE;
340
dev->response_alignment =
341
le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) -
342
sizeof(struct SmsMsgHdr_ST);
343
344
params.flags |= SMS_DEVICE_FAMILY2;
345
break;
346
}
347
348
params.device = &dev->udev->dev;
349
params.buffer_size = dev->buffer_size;
350
params.num_buffers = MAX_BUFFERS;
351
params.sendrequest_handler = smsusb_sendrequest;
352
params.context = dev;
353
usb_make_path(dev->udev, params.devpath, sizeof(params.devpath));
354
355
/* register in smscore */
356
rc = smscore_register_device(&params, &dev->coredev);
357
if (rc < 0) {
358
sms_err("smscore_register_device(...) failed, rc %d", rc);
359
smsusb_term_device(intf);
360
return rc;
361
}
362
363
smscore_set_board_id(dev->coredev, board_id);
364
365
/* initialize urbs */
366
for (i = 0; i < MAX_URBS; i++) {
367
dev->surbs[i].dev = dev;
368
usb_init_urb(&dev->surbs[i].urb);
369
}
370
371
sms_info("smsusb_start_streaming(...).");
372
rc = smsusb_start_streaming(dev);
373
if (rc < 0) {
374
sms_err("smsusb_start_streaming(...) failed");
375
smsusb_term_device(intf);
376
return rc;
377
}
378
379
rc = smscore_start_device(dev->coredev);
380
if (rc < 0) {
381
sms_err("smscore_start_device(...) failed");
382
smsusb_term_device(intf);
383
return rc;
384
}
385
386
sms_info("device %p created", dev);
387
388
return rc;
389
}
390
391
static int __devinit smsusb_probe(struct usb_interface *intf,
392
const struct usb_device_id *id)
393
{
394
struct usb_device *udev = interface_to_usbdev(intf);
395
char devpath[32];
396
int i, rc;
397
398
rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
399
rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
400
401
if (intf->num_altsetting > 0) {
402
rc = usb_set_interface(
403
udev, intf->cur_altsetting->desc.bInterfaceNumber, 0);
404
if (rc < 0) {
405
sms_err("usb_set_interface failed, rc %d", rc);
406
return rc;
407
}
408
}
409
410
sms_info("smsusb_probe %d",
411
intf->cur_altsetting->desc.bInterfaceNumber);
412
for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
413
sms_info("endpoint %d %02x %02x %d", i,
414
intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
415
intf->cur_altsetting->endpoint[i].desc.bmAttributes,
416
intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
417
418
if ((udev->actconfig->desc.bNumInterfaces == 2) &&
419
(intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
420
sms_err("rom interface 0 is not used");
421
return -ENODEV;
422
}
423
424
if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
425
snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
426
udev->bus->busnum, udev->devpath);
427
sms_info("stellar device was found.");
428
return smsusb1_load_firmware(
429
udev, smscore_registry_getmode(devpath),
430
id->driver_info);
431
}
432
433
rc = smsusb_init_device(intf, id->driver_info);
434
sms_info("rc %d", rc);
435
sms_board_load_modules(id->driver_info);
436
return rc;
437
}
438
439
static void smsusb_disconnect(struct usb_interface *intf)
440
{
441
smsusb_term_device(intf);
442
}
443
444
static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
445
{
446
struct smsusb_device_t *dev = usb_get_intfdata(intf);
447
printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event);
448
smsusb_stop_streaming(dev);
449
return 0;
450
}
451
452
static int smsusb_resume(struct usb_interface *intf)
453
{
454
int rc, i;
455
struct smsusb_device_t *dev = usb_get_intfdata(intf);
456
struct usb_device *udev = interface_to_usbdev(intf);
457
458
printk(KERN_INFO "%s: Entering.\n", __func__);
459
usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
460
usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
461
462
for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
463
printk(KERN_INFO "endpoint %d %02x %02x %d\n", i,
464
intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
465
intf->cur_altsetting->endpoint[i].desc.bmAttributes,
466
intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
467
468
if (intf->num_altsetting > 0) {
469
rc = usb_set_interface(udev,
470
intf->cur_altsetting->desc.
471
bInterfaceNumber, 0);
472
if (rc < 0) {
473
printk(KERN_INFO "%s usb_set_interface failed, "
474
"rc %d\n", __func__, rc);
475
return rc;
476
}
477
}
478
479
smsusb_start_streaming(dev);
480
return 0;
481
}
482
483
static const struct usb_device_id smsusb_id_table[] __devinitconst = {
484
{ USB_DEVICE(0x187f, 0x0010),
485
.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
486
{ USB_DEVICE(0x187f, 0x0100),
487
.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
488
{ USB_DEVICE(0x187f, 0x0200),
489
.driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
490
{ USB_DEVICE(0x187f, 0x0201),
491
.driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
492
{ USB_DEVICE(0x187f, 0x0300),
493
.driver_info = SMS1XXX_BOARD_SIANO_VEGA },
494
{ USB_DEVICE(0x2040, 0x1700),
495
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
496
{ USB_DEVICE(0x2040, 0x1800),
497
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
498
{ USB_DEVICE(0x2040, 0x1801),
499
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
500
{ USB_DEVICE(0x2040, 0x2000),
501
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
502
{ USB_DEVICE(0x2040, 0x2009),
503
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
504
{ USB_DEVICE(0x2040, 0x200a),
505
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
506
{ USB_DEVICE(0x2040, 0x2010),
507
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
508
{ USB_DEVICE(0x2040, 0x2011),
509
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
510
{ USB_DEVICE(0x2040, 0x2019),
511
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
512
{ USB_DEVICE(0x2040, 0x5500),
513
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
514
{ USB_DEVICE(0x2040, 0x5510),
515
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
516
{ USB_DEVICE(0x2040, 0x5520),
517
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
518
{ USB_DEVICE(0x2040, 0x5530),
519
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
520
{ USB_DEVICE(0x2040, 0x5580),
521
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
522
{ USB_DEVICE(0x2040, 0x5590),
523
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
524
{ USB_DEVICE(0x187f, 0x0202),
525
.driver_info = SMS1XXX_BOARD_SIANO_NICE },
526
{ USB_DEVICE(0x187f, 0x0301),
527
.driver_info = SMS1XXX_BOARD_SIANO_VENICE },
528
{ USB_DEVICE(0x2040, 0xb900),
529
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
530
{ USB_DEVICE(0x2040, 0xb910),
531
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
532
{ USB_DEVICE(0x2040, 0xb980),
533
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
534
{ USB_DEVICE(0x2040, 0xb990),
535
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
536
{ USB_DEVICE(0x2040, 0xc000),
537
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
538
{ USB_DEVICE(0x2040, 0xc010),
539
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
540
{ USB_DEVICE(0x2040, 0xc080),
541
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
542
{ USB_DEVICE(0x2040, 0xc090),
543
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
544
{ } /* Terminating entry */
545
};
546
547
MODULE_DEVICE_TABLE(usb, smsusb_id_table);
548
549
static struct usb_driver smsusb_driver = {
550
.name = "smsusb",
551
.probe = smsusb_probe,
552
.disconnect = smsusb_disconnect,
553
.id_table = smsusb_id_table,
554
555
.suspend = smsusb_suspend,
556
.resume = smsusb_resume,
557
};
558
559
static int __init smsusb_module_init(void)
560
{
561
int rc = usb_register(&smsusb_driver);
562
if (rc)
563
sms_err("usb_register failed. Error number %d", rc);
564
565
sms_debug("");
566
567
return rc;
568
}
569
570
static void __exit smsusb_module_exit(void)
571
{
572
/* Regular USB Cleanup */
573
usb_deregister(&smsusb_driver);
574
sms_info("end");
575
}
576
577
module_init(smsusb_module_init);
578
module_exit(smsusb_module_exit);
579
580
MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle");
581
MODULE_AUTHOR("Siano Mobile Silicon, INC. ([email protected])");
582
MODULE_LICENSE("GPL");
583
584