brintos

brintos / linux-shallow public Read only

0
0
Text · 19.4 KiB · 2c8179a Raw
737 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/****************************************************************3 4Siano Mobile Silicon, Inc.5MDTV receiver kernel modules.6Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat7 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		0x100025#define USB2_BUFFER_SIZE		0x200026 27#define MAX_BUFFERS		5028#define MAX_URBS		1029 30struct smsusb_device_t;31 32enum smsusb_state {33	SMSUSB_DISCONNECTED,34	SMSUSB_SUSPENDED,35	SMSUSB_ACTIVE36};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 worker81 * thread the surb82 * IMPORTANT - blocking functions must not be called from here !!!83 84 * @param urb pointer to a completing urb object85 */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 and122				 * copy header to its new location */123				memcpy((char *) phdr + surb->cb->offset,124				       phdr, sizeof(struct sms_msg_hdr));125			} else126				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	} else141		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		surb170	);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		if (dev->surbs[i].wq.func)183			cancel_work_sync(&dev->surbs[i].wq);184 185		if (dev->surbs[i].cb) {186			smscore_putbuffer(dev->coredev, dev->surbs[i].cb);187			dev->surbs[i].cb = NULL;188		}189	}190}191 192static int smsusb_start_streaming(struct smsusb_device_t *dev)193{194	int i, rc;195 196	for (i = 0; i < MAX_URBS; i++) {197		rc = smsusb_submit_urb(dev, &dev->surbs[i]);198		if (rc < 0) {199			pr_err("smsusb_submit_urb(...) failed\n");200			smsusb_stop_streaming(dev);201			break;202		}203	}204 205	return rc;206}207 208static int smsusb_sendrequest(void *context, void *buffer, size_t size)209{210	struct smsusb_device_t *dev = (struct smsusb_device_t *) context;211	struct sms_msg_hdr *phdr;212	int dummy, ret;213 214	if (dev->state != SMSUSB_ACTIVE) {215		pr_debug("Device not active yet\n");216		return -ENOENT;217	}218 219	phdr = kmemdup(buffer, size, GFP_KERNEL);220	if (!phdr)221		return -ENOMEM;222 223	pr_debug("sending %s(%d) size: %d\n",224		  smscore_translate_msg(phdr->msg_type), phdr->msg_type,225		  phdr->msg_length);226 227	smsendian_handle_tx_message((struct sms_msg_data *) phdr);228	smsendian_handle_message_header((struct sms_msg_hdr *)phdr);229	ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),230			    phdr, size, &dummy, 1000);231 232	kfree(phdr);233	return ret;234}235 236static char *smsusb1_fw_lkup[] = {237	"dvbt_stellar_usb.inp",238	"dvbh_stellar_usb.inp",239	"tdmb_stellar_usb.inp",240	"none",241	"dvbt_bda_stellar_usb.inp",242};243 244static inline char *sms_get_fw_name(int mode, int board_id)245{246	char **fw = sms_get_board(board_id)->fw;247	return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode];248}249 250static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)251{252	const struct firmware *fw;253	u8 *fw_buffer;254	int rc, dummy;255	char *fw_filename;256 257	if (id < 0)258		id = sms_get_board(board_id)->default_mode;259 260	if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {261		pr_err("invalid firmware id specified %d\n", id);262		return -EINVAL;263	}264 265	fw_filename = sms_get_fw_name(id, board_id);266 267	rc = request_firmware(&fw, fw_filename, &udev->dev);268	if (rc < 0) {269		pr_warn("failed to open '%s' mode %d, trying again with default firmware\n",270			fw_filename, id);271 272		fw_filename = smsusb1_fw_lkup[id];273		rc = request_firmware(&fw, fw_filename, &udev->dev);274		if (rc < 0) {275			pr_warn("failed to open '%s' mode %d\n",276				 fw_filename, id);277 278			return rc;279		}280	}281 282	fw_buffer = kmemdup(fw->data, fw->size, GFP_KERNEL);283	if (fw_buffer) {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		int i;342 343		dev->state = SMSUSB_DISCONNECTED;344 345		smsusb_stop_streaming(dev);346 347		/* unregister from smscore */348		if (dev->coredev)349			smscore_unregister_device(dev->coredev);350 351		for (i = 0; i < MAX_URBS; i++)352			usb_free_urb(dev->surbs[i].urb);353 354		pr_debug("device 0x%p destroyed\n", dev);355		kfree(dev);356	}357 358	usb_set_intfdata(intf, NULL);359}360 361static void *siano_media_device_register(struct smsusb_device_t *dev,362					int board_id)363{364#ifdef CONFIG_MEDIA_CONTROLLER_DVB365	struct media_device *mdev;366	struct usb_device *udev = dev->udev;367	struct sms_board *board = sms_get_board(board_id);368	int ret;369 370	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);371	if (!mdev)372		return NULL;373 374	media_device_usb_init(mdev, udev, board->name);375 376	ret = media_device_register(mdev);377	if (ret) {378		media_device_cleanup(mdev);379		kfree(mdev);380		return NULL;381	}382 383	pr_info("media controller created\n");384 385	return mdev;386#else387	return NULL;388#endif389}390 391static int smsusb_init_device(struct usb_interface *intf, int board_id)392{393	struct smsdevice_params_t params;394	struct smsusb_device_t *dev;395	void *mdev;396	int i, rc;397	int align = 0;398 399	/* create device object */400	dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);401	if (!dev)402		return -ENOMEM;403 404	memset(&params, 0, sizeof(params));405	usb_set_intfdata(intf, dev);406	dev->udev = interface_to_usbdev(intf);407	dev->state = SMSUSB_DISCONNECTED;408 409	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {410		struct usb_endpoint_descriptor *desc =411				&intf->cur_altsetting->endpoint[i].desc;412 413		if (desc->bEndpointAddress & USB_DIR_IN) {414			dev->in_ep = desc->bEndpointAddress;415			align = usb_endpoint_maxp(desc) - sizeof(struct sms_msg_hdr);416		} else {417			dev->out_ep = desc->bEndpointAddress;418		}419	}420 421	pr_debug("in_ep = %02x, out_ep = %02x\n", dev->in_ep, dev->out_ep);422	if (!dev->in_ep || !dev->out_ep || align < 0) {  /* Missing endpoints? */423		smsusb_term_device(intf);424		return -ENODEV;425	}426 427	params.device_type = sms_get_board(board_id)->type;428 429	switch (params.device_type) {430	case SMS_STELLAR:431		dev->buffer_size = USB1_BUFFER_SIZE;432 433		params.setmode_handler = smsusb1_setmode;434		params.detectmode_handler = smsusb1_detectmode;435		break;436	case SMS_UNKNOWN_TYPE:437		pr_err("Unspecified sms device type!\n");438		fallthrough;439	default:440		dev->buffer_size = USB2_BUFFER_SIZE;441		dev->response_alignment = align;442 443		params.flags |= SMS_DEVICE_FAMILY2;444		break;445	}446 447	params.device = &dev->udev->dev;448	params.usb_device = dev->udev;449	params.buffer_size = dev->buffer_size;450	params.num_buffers = MAX_BUFFERS;451	params.sendrequest_handler = smsusb_sendrequest;452	params.context = dev;453	usb_make_path(dev->udev, params.devpath, sizeof(params.devpath));454 455	mdev = siano_media_device_register(dev, board_id);456 457	/* register in smscore */458	rc = smscore_register_device(&params, &dev->coredev, 0, mdev);459	if (rc < 0) {460		pr_err("smscore_register_device(...) failed, rc %d\n", rc);461		goto err_unregister_device;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		dev->surbs[i].urb = usb_alloc_urb(0, GFP_KERNEL);472		if (!dev->surbs[i].urb)473			goto err_unregister_device;474	}475 476	pr_debug("smsusb_start_streaming(...).\n");477	rc = smsusb_start_streaming(dev);478	if (rc < 0) {479		pr_err("smsusb_start_streaming(...) failed\n");480		goto err_unregister_device;481	}482 483	dev->state = SMSUSB_ACTIVE;484 485	rc = smscore_start_device(dev->coredev);486	if (rc < 0) {487		pr_err("smscore_start_device(...) failed\n");488		goto err_unregister_device;489	}490 491	pr_debug("device 0x%p created\n", dev);492 493	return rc;494 495err_unregister_device:496	/* smsusb_term_device() frees any allocated urb. */497	smsusb_term_device(intf);498#ifdef CONFIG_MEDIA_CONTROLLER_DVB499	media_device_unregister(mdev);500#endif501	kfree(mdev);502	return rc;503}504 505static int smsusb_probe(struct usb_interface *intf,506			const struct usb_device_id *id)507{508	struct usb_device *udev = interface_to_usbdev(intf);509	char devpath[32];510	int i, rc;511 512	pr_info("board id=%lu, interface number %d\n",513		 id->driver_info,514		 intf->cur_altsetting->desc.bInterfaceNumber);515 516	if (sms_get_board(id->driver_info)->intf_num !=517	    intf->cur_altsetting->desc.bInterfaceNumber) {518		pr_debug("interface %d won't be used. Expecting interface %d to popup\n",519			intf->cur_altsetting->desc.bInterfaceNumber,520			sms_get_board(id->driver_info)->intf_num);521		return -ENODEV;522	}523 524	if (intf->num_altsetting > 1) {525		rc = usb_set_interface(udev,526				       intf->cur_altsetting->desc.bInterfaceNumber,527				       0);528		if (rc < 0) {529			pr_err("usb_set_interface failed, rc %d\n", rc);530			return rc;531		}532	}533 534	pr_debug("smsusb_probe %d\n",535	       intf->cur_altsetting->desc.bInterfaceNumber);536	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {537		pr_debug("endpoint %d %02x %02x %d\n", i,538		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,539		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,540		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);541		if (intf->cur_altsetting->endpoint[i].desc.bEndpointAddress &542		    USB_DIR_IN)543			rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev,544				intf->cur_altsetting->endpoint[i].desc.bEndpointAddress));545		else546			rc = usb_clear_halt(udev, usb_sndbulkpipe(udev,547				intf->cur_altsetting->endpoint[i].desc.bEndpointAddress));548	}549	if ((udev->actconfig->desc.bNumInterfaces == 2) &&550	    (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {551		pr_debug("rom interface 0 is not used\n");552		return -ENODEV;553	}554 555	if (id->driver_info == SMS1XXX_BOARD_SIANO_STELLAR_ROM) {556		/* Detected a Siano Stellar uninitialized */557 558		snprintf(devpath, sizeof(devpath), "usb\\%d-%s",559			 udev->bus->busnum, udev->devpath);560		pr_info("stellar device in cold state was found at %s.\n",561			devpath);562		rc = smsusb1_load_firmware(563				udev, smscore_registry_getmode(devpath),564				id->driver_info);565 566		/* This device will reset and gain another USB ID */567		if (!rc)568			pr_info("stellar device now in warm state\n");569		else570			pr_err("Failed to put stellar in warm state. Error: %d\n",571			       rc);572 573		return rc;574	} else {575		rc = smsusb_init_device(intf, id->driver_info);576	}577 578	pr_info("Device initialized with return code %d\n", rc);579	sms_board_load_modules(id->driver_info);580	return rc;581}582 583static void smsusb_disconnect(struct usb_interface *intf)584{585	smsusb_term_device(intf);586}587 588static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)589{590	struct smsusb_device_t *dev = usb_get_intfdata(intf);591	printk(KERN_INFO "%s  Entering status %d.\n", __func__, msg.event);592	dev->state = SMSUSB_SUSPENDED;593	/*smscore_set_power_mode(dev, SMS_POWER_MODE_SUSPENDED);*/594	smsusb_stop_streaming(dev);595	return 0;596}597 598static int smsusb_resume(struct usb_interface *intf)599{600	int rc, i;601	struct smsusb_device_t *dev = usb_get_intfdata(intf);602	struct usb_device *udev = interface_to_usbdev(intf);603 604	printk(KERN_INFO "%s  Entering.\n", __func__);605	usb_clear_halt(udev, usb_rcvbulkpipe(udev, dev->in_ep));606	usb_clear_halt(udev, usb_sndbulkpipe(udev, dev->out_ep));607 608	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)609		printk(KERN_INFO "endpoint %d %02x %02x %d\n", i,610		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,611		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,612		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);613 614	if (intf->num_altsetting > 0) {615		rc = usb_set_interface(udev,616				       intf->cur_altsetting->desc.617				       bInterfaceNumber, 0);618		if (rc < 0) {619			printk(KERN_INFO "%s usb_set_interface failed, rc %d\n",620			       __func__, rc);621			return rc;622		}623	}624 625	smsusb_start_streaming(dev);626	return 0;627}628 629static const struct usb_device_id smsusb_id_table[] = {630	/* This device is only present before firmware load */631	{ USB_DEVICE(0x187f, 0x0010),632		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR_ROM },633	/* This device pops up after firmware load */634	{ USB_DEVICE(0x187f, 0x0100),635		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },636 637	{ USB_DEVICE(0x187f, 0x0200),638		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },639	{ USB_DEVICE(0x187f, 0x0201),640		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },641	{ USB_DEVICE(0x187f, 0x0300),642		.driver_info = SMS1XXX_BOARD_SIANO_VEGA },643	{ USB_DEVICE(0x2040, 0x1700),644		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },645	{ USB_DEVICE(0x2040, 0x1800),646		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },647	{ USB_DEVICE(0x2040, 0x1801),648		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },649	{ USB_DEVICE(0x2040, 0x2000),650		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },651	{ USB_DEVICE(0x2040, 0x2009),652		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },653	{ USB_DEVICE(0x2040, 0x200a),654		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },655	{ USB_DEVICE(0x2040, 0x2010),656		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },657	{ USB_DEVICE(0x2040, 0x2011),658		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },659	{ USB_DEVICE(0x2040, 0x2019),660		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },661	{ USB_DEVICE(0x2040, 0x5500),662		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },663	{ USB_DEVICE(0x2040, 0x5510),664		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },665	{ USB_DEVICE(0x2040, 0x5520),666		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },667	{ USB_DEVICE(0x2040, 0x5530),668		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },669	{ USB_DEVICE(0x2040, 0x5580),670		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },671	{ USB_DEVICE(0x2040, 0x5590),672		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },673	{ USB_DEVICE(0x2040, 0xb900),674		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },675	{ USB_DEVICE(0x2040, 0xb910),676		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },677	{ USB_DEVICE(0x2040, 0xb980),678		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },679	{ USB_DEVICE(0x2040, 0xb990),680		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },681	{ USB_DEVICE(0x2040, 0xc000),682		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },683	{ USB_DEVICE(0x2040, 0xc010),684		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },685	{ USB_DEVICE(0x2040, 0xc080),686		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },687	{ USB_DEVICE(0x2040, 0xc090),688		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },689	{ USB_DEVICE(0x2040, 0xc0a0),690		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },691	{ USB_DEVICE(0x2040, 0xf5a0),692		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },693	{ USB_DEVICE(0x187f, 0x0202),694		.driver_info = SMS1XXX_BOARD_SIANO_NICE },695	{ USB_DEVICE(0x187f, 0x0301),696		.driver_info = SMS1XXX_BOARD_SIANO_VENICE },697	{ USB_DEVICE(0x187f, 0x0302),698		.driver_info = SMS1XXX_BOARD_SIANO_VENICE },699	{ USB_DEVICE(0x187f, 0x0310),700		.driver_info = SMS1XXX_BOARD_SIANO_MING },701	{ USB_DEVICE(0x187f, 0x0500),702		.driver_info = SMS1XXX_BOARD_SIANO_PELE },703	{ USB_DEVICE(0x187f, 0x0600),704		.driver_info = SMS1XXX_BOARD_SIANO_RIO },705	{ USB_DEVICE(0x187f, 0x0700),706		.driver_info = SMS1XXX_BOARD_SIANO_DENVER_2160 },707	{ USB_DEVICE(0x187f, 0x0800),708		.driver_info = SMS1XXX_BOARD_SIANO_DENVER_1530 },709	{ USB_DEVICE(0x19D2, 0x0086),710		.driver_info = SMS1XXX_BOARD_ZTE_DVB_DATA_CARD },711	{ USB_DEVICE(0x19D2, 0x0078),712		.driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD },713	{ USB_DEVICE(0x3275, 0x0080),714		.driver_info = SMS1XXX_BOARD_SIANO_RIO },715	{ USB_DEVICE(0x2013, 0x0257),716		.driver_info = SMS1XXX_BOARD_PCTV_77E },717	{ } /* Terminating entry */718	};719 720MODULE_DEVICE_TABLE(usb, smsusb_id_table);721 722static struct usb_driver smsusb_driver = {723	.name			= "smsusb",724	.probe			= smsusb_probe,725	.disconnect		= smsusb_disconnect,726	.id_table		= smsusb_id_table,727 728	.suspend		= smsusb_suspend,729	.resume			= smsusb_resume,730};731 732module_usb_driver(smsusb_driver);733 734MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle");735MODULE_AUTHOR("Siano Mobile Silicon, Inc. <uris@siano-ms.com>");736MODULE_LICENSE("GPL");737