xref: /openbmc/linux/drivers/media/usb/siano/smsusb.c (revision 12eb4683)
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 #include <linux/module.h>
28 
29 #include "smscoreapi.h"
30 #include "sms-cards.h"
31 #include "smsendian.h"
32 
33 static int sms_dbg;
34 module_param_named(debug, sms_dbg, int, 0644);
35 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
36 
37 #define USB1_BUFFER_SIZE		0x1000
38 #define USB2_BUFFER_SIZE		0x2000
39 
40 #define MAX_BUFFERS		50
41 #define MAX_URBS		10
42 
43 struct smsusb_device_t;
44 
45 enum smsusb_state {
46 	SMSUSB_DISCONNECTED,
47 	SMSUSB_SUSPENDED,
48 	SMSUSB_ACTIVE
49 };
50 
51 struct smsusb_urb_t {
52 	struct list_head entry;
53 	struct smscore_buffer_t *cb;
54 	struct smsusb_device_t *dev;
55 
56 	struct urb urb;
57 };
58 
59 struct smsusb_device_t {
60 	struct usb_device *udev;
61 	struct smscore_device_t *coredev;
62 
63 	struct smsusb_urb_t 	surbs[MAX_URBS];
64 
65 	int		response_alignment;
66 	int		buffer_size;
67 
68 	unsigned char in_ep;
69 	unsigned char out_ep;
70 	enum smsusb_state state;
71 };
72 
73 static int smsusb_submit_urb(struct smsusb_device_t *dev,
74 			     struct smsusb_urb_t *surb);
75 
76 /**
77  * Completing URB's callback handler - top half (interrupt context)
78  * adds completing sms urb to the global surbs list and activtes the worker
79  * thread the surb
80  * IMPORTANT - blocking functions must not be called from here !!!
81 
82  * @param urb pointer to a completing urb object
83  */
84 static void smsusb_onresponse(struct urb *urb)
85 {
86 	struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
87 	struct smsusb_device_t *dev = surb->dev;
88 
89 	if (urb->status == -ESHUTDOWN) {
90 		sms_err("error, urb status %d (-ESHUTDOWN), %d bytes",
91 			urb->status, urb->actual_length);
92 		return;
93 	}
94 
95 	if ((urb->actual_length > 0) && (urb->status == 0)) {
96 		struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)surb->cb->p;
97 
98 		smsendian_handle_message_header(phdr);
99 		if (urb->actual_length >= phdr->msg_length) {
100 			surb->cb->size = phdr->msg_length;
101 
102 			if (dev->response_alignment &&
103 			    (phdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG)) {
104 
105 				surb->cb->offset =
106 					dev->response_alignment +
107 					((phdr->msg_flags >> 8) & 3);
108 
109 				/* sanity check */
110 				if (((int) phdr->msg_length +
111 				     surb->cb->offset) > urb->actual_length) {
112 					sms_err("invalid response "
113 						"msglen %d offset %d "
114 						"size %d",
115 						phdr->msg_length,
116 						surb->cb->offset,
117 						urb->actual_length);
118 					goto exit_and_resubmit;
119 				}
120 
121 				/* move buffer pointer and
122 				 * copy header to its new location */
123 				memcpy((char *) phdr + surb->cb->offset,
124 				       phdr, sizeof(struct sms_msg_hdr));
125 			} else
126 				surb->cb->offset = 0;
127 
128 			sms_debug("received %s(%d) size: %d",
129 				  smscore_translate_msg(phdr->msg_type),
130 				  phdr->msg_type, phdr->msg_length);
131 
132 			smsendian_handle_rx_message((struct sms_msg_data *) phdr);
133 
134 			smscore_onresponse(dev->coredev, surb->cb);
135 			surb->cb = NULL;
136 		} else {
137 			sms_err("invalid response "
138 				"msglen %d actual %d",
139 				phdr->msg_length, urb->actual_length);
140 		}
141 	} else
142 		sms_err("error, urb status %d, %d bytes",
143 			urb->status, urb->actual_length);
144 
145 
146 exit_and_resubmit:
147 	smsusb_submit_urb(dev, surb);
148 }
149 
150 static int smsusb_submit_urb(struct smsusb_device_t *dev,
151 			     struct smsusb_urb_t *surb)
152 {
153 	if (!surb->cb) {
154 		surb->cb = smscore_getbuffer(dev->coredev);
155 		if (!surb->cb) {
156 			sms_err("smscore_getbuffer(...) returned NULL");
157 			return -ENOMEM;
158 		}
159 	}
160 
161 	usb_fill_bulk_urb(
162 		&surb->urb,
163 		dev->udev,
164 		usb_rcvbulkpipe(dev->udev, dev->in_ep),
165 		surb->cb->p,
166 		dev->buffer_size,
167 		smsusb_onresponse,
168 		surb
169 	);
170 	surb->urb.transfer_dma = surb->cb->phys;
171 	surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
172 
173 	return usb_submit_urb(&surb->urb, GFP_ATOMIC);
174 }
175 
176 static void smsusb_stop_streaming(struct smsusb_device_t *dev)
177 {
178 	int i;
179 
180 	for (i = 0; i < MAX_URBS; i++) {
181 		usb_kill_urb(&dev->surbs[i].urb);
182 
183 		if (dev->surbs[i].cb) {
184 			smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
185 			dev->surbs[i].cb = NULL;
186 		}
187 	}
188 }
189 
190 static int smsusb_start_streaming(struct smsusb_device_t *dev)
191 {
192 	int i, rc;
193 
194 	for (i = 0; i < MAX_URBS; i++) {
195 		rc = smsusb_submit_urb(dev, &dev->surbs[i]);
196 		if (rc < 0) {
197 			sms_err("smsusb_submit_urb(...) failed");
198 			smsusb_stop_streaming(dev);
199 			break;
200 		}
201 	}
202 
203 	return rc;
204 }
205 
206 static int smsusb_sendrequest(void *context, void *buffer, size_t size)
207 {
208 	struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
209 	struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer;
210 	int dummy;
211 
212 	if (dev->state != SMSUSB_ACTIVE) {
213 		sms_debug("Device not active yet");
214 		return -ENOENT;
215 	}
216 
217 	sms_debug("sending %s(%d) size: %d",
218 		  smscore_translate_msg(phdr->msg_type), phdr->msg_type,
219 		  phdr->msg_length);
220 
221 	smsendian_handle_tx_message((struct sms_msg_data *) phdr);
222 	smsendian_handle_message_header((struct sms_msg_hdr *)buffer);
223 	return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
224 			    buffer, size, &dummy, 1000);
225 }
226 
227 static char *smsusb1_fw_lkup[] = {
228 	"dvbt_stellar_usb.inp",
229 	"dvbh_stellar_usb.inp",
230 	"tdmb_stellar_usb.inp",
231 	"none",
232 	"dvbt_bda_stellar_usb.inp",
233 };
234 
235 static inline char *sms_get_fw_name(int mode, int board_id)
236 {
237 	char **fw = sms_get_board(board_id)->fw;
238 	return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode];
239 }
240 
241 static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
242 {
243 	const struct firmware *fw;
244 	u8 *fw_buffer;
245 	int rc, dummy;
246 	char *fw_filename;
247 
248 	if (id < 0)
249 		id = sms_get_board(board_id)->default_mode;
250 
251 	if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
252 		sms_err("invalid firmware id specified %d", id);
253 		return -EINVAL;
254 	}
255 
256 	fw_filename = sms_get_fw_name(id, board_id);
257 
258 	rc = request_firmware(&fw, fw_filename, &udev->dev);
259 	if (rc < 0) {
260 		sms_warn("failed to open \"%s\" mode %d, "
261 			 "trying again with default firmware", fw_filename, id);
262 
263 		fw_filename = smsusb1_fw_lkup[id];
264 		rc = request_firmware(&fw, fw_filename, &udev->dev);
265 		if (rc < 0) {
266 			sms_warn("failed to open \"%s\" mode %d",
267 				 fw_filename, id);
268 
269 			return rc;
270 		}
271 	}
272 
273 	fw_buffer = kmalloc(fw->size, GFP_KERNEL);
274 	if (fw_buffer) {
275 		memcpy(fw_buffer, fw->data, fw->size);
276 
277 		rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
278 				  fw_buffer, fw->size, &dummy, 1000);
279 
280 		sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
281 
282 		kfree(fw_buffer);
283 	} else {
284 		sms_err("failed to allocate firmware buffer");
285 		rc = -ENOMEM;
286 	}
287 	sms_info("read FW %s, size=%zd", fw_filename, fw->size);
288 
289 	release_firmware(fw);
290 
291 	return rc;
292 }
293 
294 static void smsusb1_detectmode(void *context, int *mode)
295 {
296 	char *product_string =
297 		((struct smsusb_device_t *) context)->udev->product;
298 
299 	*mode = DEVICE_MODE_NONE;
300 
301 	if (!product_string) {
302 		product_string = "none";
303 		sms_err("product string not found");
304 	} else if (strstr(product_string, "DVBH"))
305 		*mode = 1;
306 	else if (strstr(product_string, "BDA"))
307 		*mode = 4;
308 	else if (strstr(product_string, "DVBT"))
309 		*mode = 0;
310 	else if (strstr(product_string, "TDMB"))
311 		*mode = 2;
312 
313 	sms_info("%d \"%s\"", *mode, product_string);
314 }
315 
316 static int smsusb1_setmode(void *context, int mode)
317 {
318 	struct sms_msg_hdr msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
319 			     sizeof(struct sms_msg_hdr), 0 };
320 
321 	if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
322 		sms_err("invalid firmware id specified %d", mode);
323 		return -EINVAL;
324 	}
325 
326 	return smsusb_sendrequest(context, &msg, sizeof(msg));
327 }
328 
329 static void smsusb_term_device(struct usb_interface *intf)
330 {
331 	struct smsusb_device_t *dev = usb_get_intfdata(intf);
332 
333 	if (dev) {
334 		dev->state = SMSUSB_DISCONNECTED;
335 
336 		smsusb_stop_streaming(dev);
337 
338 		/* unregister from smscore */
339 		if (dev->coredev)
340 			smscore_unregister_device(dev->coredev);
341 
342 		sms_info("device 0x%p destroyed", dev);
343 		kfree(dev);
344 	}
345 
346 	usb_set_intfdata(intf, NULL);
347 }
348 
349 static int smsusb_init_device(struct usb_interface *intf, int board_id)
350 {
351 	struct smsdevice_params_t params;
352 	struct smsusb_device_t *dev;
353 	int i, rc;
354 
355 	/* create device object */
356 	dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
357 	if (!dev) {
358 		sms_err("kzalloc(sizeof(struct smsusb_device_t) failed");
359 		return -ENOMEM;
360 	}
361 
362 	memset(&params, 0, sizeof(params));
363 	usb_set_intfdata(intf, dev);
364 	dev->udev = interface_to_usbdev(intf);
365 	dev->state = SMSUSB_DISCONNECTED;
366 
367 	params.device_type = sms_get_board(board_id)->type;
368 
369 	switch (params.device_type) {
370 	case SMS_STELLAR:
371 		dev->buffer_size = USB1_BUFFER_SIZE;
372 
373 		params.setmode_handler = smsusb1_setmode;
374 		params.detectmode_handler = smsusb1_detectmode;
375 		break;
376 	case SMS_UNKNOWN_TYPE:
377 		sms_err("Unspecified sms device type!");
378 		/* fall-thru */
379 	default:
380 		dev->buffer_size = USB2_BUFFER_SIZE;
381 		dev->response_alignment =
382 		    le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) -
383 		    sizeof(struct sms_msg_hdr);
384 
385 		params.flags |= SMS_DEVICE_FAMILY2;
386 		break;
387 	}
388 
389 	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
390 		if (intf->cur_altsetting->endpoint[i].desc. bEndpointAddress & USB_DIR_IN)
391 			dev->in_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress;
392 		else
393 			dev->out_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress;
394 	}
395 
396 	sms_info("in_ep = %02x, out_ep = %02x",
397 		dev->in_ep, dev->out_ep);
398 
399 	params.device = &dev->udev->dev;
400 	params.buffer_size = dev->buffer_size;
401 	params.num_buffers = MAX_BUFFERS;
402 	params.sendrequest_handler = smsusb_sendrequest;
403 	params.context = dev;
404 	usb_make_path(dev->udev, params.devpath, sizeof(params.devpath));
405 
406 	/* register in smscore */
407 	rc = smscore_register_device(&params, &dev->coredev);
408 	if (rc < 0) {
409 		sms_err("smscore_register_device(...) failed, rc %d", rc);
410 		smsusb_term_device(intf);
411 		return rc;
412 	}
413 
414 	smscore_set_board_id(dev->coredev, board_id);
415 
416 	dev->coredev->is_usb_device = true;
417 
418 	/* initialize urbs */
419 	for (i = 0; i < MAX_URBS; i++) {
420 		dev->surbs[i].dev = dev;
421 		usb_init_urb(&dev->surbs[i].urb);
422 	}
423 
424 	sms_info("smsusb_start_streaming(...).");
425 	rc = smsusb_start_streaming(dev);
426 	if (rc < 0) {
427 		sms_err("smsusb_start_streaming(...) failed");
428 		smsusb_term_device(intf);
429 		return rc;
430 	}
431 
432 	dev->state = SMSUSB_ACTIVE;
433 
434 	rc = smscore_start_device(dev->coredev);
435 	if (rc < 0) {
436 		sms_err("smscore_start_device(...) failed");
437 		smsusb_term_device(intf);
438 		return rc;
439 	}
440 
441 	sms_info("device 0x%p created", dev);
442 
443 	return rc;
444 }
445 
446 static int smsusb_probe(struct usb_interface *intf,
447 			const struct usb_device_id *id)
448 {
449 	struct usb_device *udev = interface_to_usbdev(intf);
450 	char devpath[32];
451 	int i, rc;
452 
453 	sms_info("board id=%lu, interface number %d",
454 		 id->driver_info,
455 		 intf->cur_altsetting->desc.bInterfaceNumber);
456 
457 	if (sms_get_board(id->driver_info)->intf_num !=
458 	    intf->cur_altsetting->desc.bInterfaceNumber) {
459 		sms_debug("interface %d won't be used. Expecting interface %d to popup",
460 			intf->cur_altsetting->desc.bInterfaceNumber,
461 			sms_get_board(id->driver_info)->intf_num);
462 		return -ENODEV;
463 	}
464 
465 	if (intf->num_altsetting > 1) {
466 		rc = usb_set_interface(udev,
467 				       intf->cur_altsetting->desc.bInterfaceNumber,
468 				       0);
469 		if (rc < 0) {
470 			sms_err("usb_set_interface failed, rc %d", rc);
471 			return rc;
472 		}
473 	}
474 
475 	sms_info("smsusb_probe %d",
476 	       intf->cur_altsetting->desc.bInterfaceNumber);
477 	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
478 		sms_info("endpoint %d %02x %02x %d", i,
479 		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
480 		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,
481 		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
482 		if (intf->cur_altsetting->endpoint[i].desc.bEndpointAddress &
483 		    USB_DIR_IN)
484 			rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev,
485 				intf->cur_altsetting->endpoint[i].desc.bEndpointAddress));
486 		else
487 			rc = usb_clear_halt(udev, usb_sndbulkpipe(udev,
488 				intf->cur_altsetting->endpoint[i].desc.bEndpointAddress));
489 	}
490 	if ((udev->actconfig->desc.bNumInterfaces == 2) &&
491 	    (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
492 		sms_debug("rom interface 0 is not used");
493 		return -ENODEV;
494 	}
495 
496 	if (id->driver_info == SMS1XXX_BOARD_SIANO_STELLAR_ROM) {
497 		/* Detected a Siano Stellar uninitialized */
498 
499 		snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
500 			 udev->bus->busnum, udev->devpath);
501 		sms_info("stellar device in cold state was found at %s.", devpath);
502 		rc = smsusb1_load_firmware(
503 				udev, smscore_registry_getmode(devpath),
504 				id->driver_info);
505 
506 		/* This device will reset and gain another USB ID */
507 		if (!rc)
508 			sms_info("stellar device now in warm state");
509 		else
510 			sms_err("Failed to put stellar in warm state. Error: %d", rc);
511 
512 		return rc;
513 	} else {
514 		rc = smsusb_init_device(intf, id->driver_info);
515 	}
516 
517 	sms_info("Device initialized with return code %d", rc);
518 	sms_board_load_modules(id->driver_info);
519 	return rc;
520 }
521 
522 static void smsusb_disconnect(struct usb_interface *intf)
523 {
524 	smsusb_term_device(intf);
525 }
526 
527 static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
528 {
529 	struct smsusb_device_t *dev = usb_get_intfdata(intf);
530 	printk(KERN_INFO "%s  Entering status %d.\n", __func__, msg.event);
531 	dev->state = SMSUSB_SUSPENDED;
532 	/*smscore_set_power_mode(dev, SMS_POWER_MODE_SUSPENDED);*/
533 	smsusb_stop_streaming(dev);
534 	return 0;
535 }
536 
537 static int smsusb_resume(struct usb_interface *intf)
538 {
539 	int rc, i;
540 	struct smsusb_device_t *dev = usb_get_intfdata(intf);
541 	struct usb_device *udev = interface_to_usbdev(intf);
542 
543 	printk(KERN_INFO "%s  Entering.\n", __func__);
544 	usb_clear_halt(udev, usb_rcvbulkpipe(udev, dev->in_ep));
545 	usb_clear_halt(udev, usb_sndbulkpipe(udev, dev->out_ep));
546 
547 	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
548 		printk(KERN_INFO "endpoint %d %02x %02x %d\n", i,
549 		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
550 		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,
551 		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
552 
553 	if (intf->num_altsetting > 0) {
554 		rc = usb_set_interface(udev,
555 				       intf->cur_altsetting->desc.
556 				       bInterfaceNumber, 0);
557 		if (rc < 0) {
558 			printk(KERN_INFO "%s usb_set_interface failed, "
559 			       "rc %d\n", __func__, rc);
560 			return rc;
561 		}
562 	}
563 
564 	smsusb_start_streaming(dev);
565 	return 0;
566 }
567 
568 static const struct usb_device_id smsusb_id_table[] = {
569 	/* This device is only present before firmware load */
570 	{ USB_DEVICE(0x187f, 0x0010),
571 		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR_ROM },
572 	/* This device pops up after firmware load */
573 	{ USB_DEVICE(0x187f, 0x0100),
574 		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
575 
576 	{ USB_DEVICE(0x187f, 0x0200),
577 		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
578 	{ USB_DEVICE(0x187f, 0x0201),
579 		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
580 	{ USB_DEVICE(0x187f, 0x0300),
581 		.driver_info = SMS1XXX_BOARD_SIANO_VEGA },
582 	{ USB_DEVICE(0x2040, 0x1700),
583 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
584 	{ USB_DEVICE(0x2040, 0x1800),
585 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
586 	{ USB_DEVICE(0x2040, 0x1801),
587 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
588 	{ USB_DEVICE(0x2040, 0x2000),
589 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
590 	{ USB_DEVICE(0x2040, 0x2009),
591 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
592 	{ USB_DEVICE(0x2040, 0x200a),
593 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
594 	{ USB_DEVICE(0x2040, 0x2010),
595 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
596 	{ USB_DEVICE(0x2040, 0x2011),
597 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
598 	{ USB_DEVICE(0x2040, 0x2019),
599 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
600 	{ USB_DEVICE(0x2040, 0x5500),
601 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
602 	{ USB_DEVICE(0x2040, 0x5510),
603 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
604 	{ USB_DEVICE(0x2040, 0x5520),
605 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
606 	{ USB_DEVICE(0x2040, 0x5530),
607 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
608 	{ USB_DEVICE(0x2040, 0x5580),
609 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
610 	{ USB_DEVICE(0x2040, 0x5590),
611 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
612 	{ USB_DEVICE(0x187f, 0x0202),
613 		.driver_info = SMS1XXX_BOARD_SIANO_NICE },
614 	{ USB_DEVICE(0x187f, 0x0301),
615 		.driver_info = SMS1XXX_BOARD_SIANO_VENICE },
616 	{ USB_DEVICE(0x2040, 0xb900),
617 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
618 	{ USB_DEVICE(0x2040, 0xb910),
619 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
620 	{ USB_DEVICE(0x2040, 0xb980),
621 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
622 	{ USB_DEVICE(0x2040, 0xb990),
623 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
624 	{ USB_DEVICE(0x2040, 0xc000),
625 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
626 	{ USB_DEVICE(0x2040, 0xc010),
627 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
628 	{ USB_DEVICE(0x2040, 0xc080),
629 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
630 	{ USB_DEVICE(0x2040, 0xc090),
631 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
632 	{ USB_DEVICE(0x2040, 0xc0a0),
633 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
634 	{ USB_DEVICE(0x2040, 0xf5a0),
635 		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
636 	{ USB_DEVICE(0x187f, 0x0202),
637 		.driver_info = SMS1XXX_BOARD_SIANO_NICE },
638 	{ USB_DEVICE(0x187f, 0x0301),
639 		.driver_info = SMS1XXX_BOARD_SIANO_VENICE },
640 	{ USB_DEVICE(0x187f, 0x0302),
641 		.driver_info = SMS1XXX_BOARD_SIANO_VENICE },
642 	{ USB_DEVICE(0x187f, 0x0310),
643 		.driver_info = SMS1XXX_BOARD_SIANO_MING },
644 	{ USB_DEVICE(0x187f, 0x0500),
645 		.driver_info = SMS1XXX_BOARD_SIANO_PELE },
646 	{ USB_DEVICE(0x187f, 0x0600),
647 		.driver_info = SMS1XXX_BOARD_SIANO_RIO },
648 	{ USB_DEVICE(0x187f, 0x0700),
649 		.driver_info = SMS1XXX_BOARD_SIANO_DENVER_2160 },
650 	{ USB_DEVICE(0x187f, 0x0800),
651 		.driver_info = SMS1XXX_BOARD_SIANO_DENVER_1530 },
652 	{ USB_DEVICE(0x19D2, 0x0086),
653 		.driver_info = SMS1XXX_BOARD_ZTE_DVB_DATA_CARD },
654 	{ USB_DEVICE(0x19D2, 0x0078),
655 		.driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD },
656 	{ } /* Terminating entry */
657 	};
658 
659 MODULE_DEVICE_TABLE(usb, smsusb_id_table);
660 
661 static struct usb_driver smsusb_driver = {
662 	.name			= "smsusb",
663 	.probe			= smsusb_probe,
664 	.disconnect		= smsusb_disconnect,
665 	.id_table		= smsusb_id_table,
666 
667 	.suspend		= smsusb_suspend,
668 	.resume			= smsusb_resume,
669 };
670 
671 module_usb_driver(smsusb_driver);
672 
673 MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle");
674 MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
675 MODULE_LICENSE("GPL");
676