cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

smsusb.c (19571B)


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