smsusb.c 19.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/****************************************************************

Siano Mobile Silicon, Inc.
MDTV receiver kernel modules.
Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

****************************************************************/
21

22 23
#include "smscoreapi.h"

24 25 26 27
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/firmware.h>
28
#include <linux/slab.h>
29
#include <linux/module.h>
30

31
#include "sms-cards.h"
32
#include "smsendian.h"
33

34 35 36 37
static int sms_dbg;
module_param_named(debug, sms_dbg, int, 0644);
MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");

38
#define USB1_BUFFER_SIZE		0x1000
39
#define USB2_BUFFER_SIZE		0x2000
40 41 42 43

#define MAX_BUFFERS		50
#define MAX_URBS		10

44
struct smsusb_device_t;
45

46 47 48 49 50 51
enum smsusb_state {
	SMSUSB_DISCONNECTED,
	SMSUSB_SUSPENDED,
	SMSUSB_ACTIVE
};

52
struct smsusb_urb_t {
53
	struct list_head entry;
54
	struct smscore_buffer_t *cb;
55
	struct smsusb_device_t *dev;
56

57 58
	struct urb urb;
};
59

60
struct smsusb_device_t {
61
	struct usb_device *udev;
62
	struct smscore_device_t *coredev;
63

64
	struct smsusb_urb_t 	surbs[MAX_URBS];
65

66 67
	int		response_alignment;
	int		buffer_size;
68 69 70 71

	unsigned char in_ep;
	unsigned char out_ep;
	enum smsusb_state state;
72
};
73

74 75
static int smsusb_submit_urb(struct smsusb_device_t *dev,
			     struct smsusb_urb_t *surb);
76

77 78 79 80 81 82 83 84
/**
 * Completing URB's callback handler - top half (interrupt context)
 * adds completing sms urb to the global surbs list and activtes the worker
 * thread the surb
 * IMPORTANT - blocking functions must not be called from here !!!

 * @param urb pointer to a completing urb object
 */
85
static void smsusb_onresponse(struct urb *urb)
86
{
87 88
	struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
	struct smsusb_device_t *dev = surb->dev;
89

90
	if (urb->status == -ESHUTDOWN) {
91
		pr_err("error, urb status %d (-ESHUTDOWN), %d bytes\n",
92
			urb->status, urb->actual_length);
93 94 95
		return;
	}

96
	if ((urb->actual_length > 0) && (urb->status == 0)) {
97
		struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)surb->cb->p;
98

99
		smsendian_handle_message_header(phdr);
100 101
		if (urb->actual_length >= phdr->msg_length) {
			surb->cb->size = phdr->msg_length;
102

103
			if (dev->response_alignment &&
104
			    (phdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG)) {
105 106 107

				surb->cb->offset =
					dev->response_alignment +
108
					((phdr->msg_flags >> 8) & 3);
109 110

				/* sanity check */
111
				if (((int) phdr->msg_length +
112
				     surb->cb->offset) > urb->actual_length) {
113
					pr_err("invalid response msglen %d offset %d size %d\n",
114
						phdr->msg_length,
115 116
						surb->cb->offset,
						urb->actual_length);
117 118 119
					goto exit_and_resubmit;
				}

120 121
				/* move buffer pointer and
				 * copy header to its new location */
122
				memcpy((char *) phdr + surb->cb->offset,
123
				       phdr, sizeof(struct sms_msg_hdr));
124
			} else
125 126
				surb->cb->offset = 0;

127
			pr_debug("received %s(%d) size: %d\n",
128 129
				  smscore_translate_msg(phdr->msg_type),
				  phdr->msg_type, phdr->msg_length);
130

131
			smsendian_handle_rx_message((struct sms_msg_data *) phdr);
132

133 134
			smscore_onresponse(dev->coredev, surb->cb);
			surb->cb = NULL;
135
		} else {
136
			pr_err("invalid response msglen %d actual %d\n",
137
				phdr->msg_length, urb->actual_length);
138
		}
139
	} else
140
		pr_err("error, urb status %d, %d bytes\n",
141 142
			urb->status, urb->actual_length);

143 144 145 146 147

exit_and_resubmit:
	smsusb_submit_urb(dev, surb);
}

148 149
static int smsusb_submit_urb(struct smsusb_device_t *dev,
			     struct smsusb_urb_t *surb)
150
{
151
	if (!surb->cb) {
152
		surb->cb = smscore_getbuffer(dev->coredev);
153
		if (!surb->cb) {
154
			pr_err("smscore_getbuffer(...) returned NULL\n");
155 156 157 158 159 160 161
			return -ENOMEM;
		}
	}

	usb_fill_bulk_urb(
		&surb->urb,
		dev->udev,
162
		usb_rcvbulkpipe(dev->udev, dev->in_ep),
163 164 165 166 167 168 169 170 171 172 173
		surb->cb->p,
		dev->buffer_size,
		smsusb_onresponse,
		surb
	);
	surb->urb.transfer_dma = surb->cb->phys;
	surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

	return usb_submit_urb(&surb->urb, GFP_ATOMIC);
}

174
static void smsusb_stop_streaming(struct smsusb_device_t *dev)
175 176 177
{
	int i;

178
	for (i = 0; i < MAX_URBS; i++) {
179 180
		usb_kill_urb(&dev->surbs[i].urb);

181
		if (dev->surbs[i].cb) {
182 183 184 185 186 187
			smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
			dev->surbs[i].cb = NULL;
		}
	}
}

188
static int smsusb_start_streaming(struct smsusb_device_t *dev)
189 190 191
{
	int i, rc;

192
	for (i = 0; i < MAX_URBS; i++) {
193
		rc = smsusb_submit_urb(dev, &dev->surbs[i]);
194
		if (rc < 0) {
195
			pr_err("smsusb_submit_urb(...) failed\n");
196 197 198 199 200 201 202 203
			smsusb_stop_streaming(dev);
			break;
		}
	}

	return rc;
}

204
static int smsusb_sendrequest(void *context, void *buffer, size_t size)
205
{
206
	struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
207
	struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer;
208 209
	int dummy;

210
	if (dev->state != SMSUSB_ACTIVE) {
211
		pr_debug("Device not active yet\n");
212
		return -ENOENT;
213
	}
214

215
	pr_debug("sending %s(%d) size: %d\n",
216 217
		  smscore_translate_msg(phdr->msg_type), phdr->msg_type,
		  phdr->msg_length);
218

219 220
	smsendian_handle_tx_message((struct sms_msg_data *) phdr);
	smsendian_handle_message_header((struct sms_msg_hdr *)buffer);
221 222
	return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
			    buffer, size, &dummy, 1000);
223 224
}

225
static char *smsusb1_fw_lkup[] = {
226 227 228 229 230 231 232
	"dvbt_stellar_usb.inp",
	"dvbh_stellar_usb.inp",
	"tdmb_stellar_usb.inp",
	"none",
	"dvbt_bda_stellar_usb.inp",
};

233 234 235 236 237 238 239
static inline char *sms_get_fw_name(int mode, int board_id)
{
	char **fw = sms_get_board(board_id)->fw;
	return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode];
}

static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
240 241
{
	const struct firmware *fw;
242
	u8 *fw_buffer;
243
	int rc, dummy;
244
	char *fw_filename;
245

246 247 248
	if (id < 0)
		id = sms_get_board(board_id)->default_mode;

249
	if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
250
		pr_err("invalid firmware id specified %d\n", id);
251 252 253
		return -EINVAL;
	}

254 255 256
	fw_filename = sms_get_fw_name(id, board_id);

	rc = request_firmware(&fw, fw_filename, &udev->dev);
257
	if (rc < 0) {
258 259
		pr_warn("failed to open '%s' mode %d, trying again with default firmware\n",
			fw_filename, id);
260 261 262 263

		fw_filename = smsusb1_fw_lkup[id];
		rc = request_firmware(&fw, fw_filename, &udev->dev);
		if (rc < 0) {
264
			pr_warn("failed to open '%s' mode %d\n",
265 266 267 268
				 fw_filename, id);

			return rc;
		}
269 270 271
	}

	fw_buffer = kmalloc(fw->size, GFP_KERNEL);
272
	if (fw_buffer) {
273 274
		memcpy(fw_buffer, fw->data, fw->size);

275 276
		rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
				  fw_buffer, fw->size, &dummy, 1000);
277

278
		sms_info("sent %zu(%d) bytes, rc %d", fw->size, dummy, rc);
279 280

		kfree(fw_buffer);
281
	} else {
282
		pr_err("failed to allocate firmware buffer\n");
283 284
		rc = -ENOMEM;
	}
285
	sms_info("read FW %s, size=%zu", fw_filename, fw->size);
286 287 288 289 290 291

	release_firmware(fw);

	return rc;
}

292
static void smsusb1_detectmode(void *context, int *mode)
293
{
294 295
	char *product_string =
		((struct smsusb_device_t *) context)->udev->product;
296 297 298

	*mode = DEVICE_MODE_NONE;

299
	if (!product_string) {
300
		product_string = "none";
301
		pr_err("product string not found\n");
302 303 304 305 306 307 308 309
	} else if (strstr(product_string, "DVBH"))
		*mode = 1;
	else if (strstr(product_string, "BDA"))
		*mode = 4;
	else if (strstr(product_string, "DVBT"))
		*mode = 0;
	else if (strstr(product_string, "TDMB"))
		*mode = 2;
310

311
	sms_info("%d \"%s\"", *mode, product_string);
312 313
}

314
static int smsusb1_setmode(void *context, int mode)
315
{
316
	struct sms_msg_hdr msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
317
			     sizeof(struct sms_msg_hdr), 0 };
318

319
	if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
320
		pr_err("invalid firmware id specified %d\n", mode);
321 322 323
		return -EINVAL;
	}

324
	return smsusb_sendrequest(context, &msg, sizeof(msg));
325 326
}

327
static void smsusb_term_device(struct usb_interface *intf)
328
{
329
	struct smsusb_device_t *dev = usb_get_intfdata(intf);
330

331
	if (dev) {
332 333
		dev->state = SMSUSB_DISCONNECTED;

334 335
		smsusb_stop_streaming(dev);

336
		/* unregister from smscore */
337 338 339
		if (dev->coredev)
			smscore_unregister_device(dev->coredev);

340
		sms_info("device 0x%p destroyed", dev);
341
		kfree(dev);
342 343 344 345 346
	}

	usb_set_intfdata(intf, NULL);
}

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
static void siano_media_device_register(struct smsusb_device_t *dev)
{
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
	struct media_device *mdev;
	struct usb_device *udev = dev->udev;
	int board_id = smscore_get_board_id(dev->coredev);
	struct sms_board *board = sms_get_board(board_id);
	int ret;

	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
	if (!mdev)
		return;

	mdev->dev = &udev->dev;
	strlcpy(mdev->model, board->name, sizeof(mdev->model));
	if (udev->serial)
		strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial));
	strcpy(mdev->bus_info, udev->devpath);
	mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
	mdev->driver_version = LINUX_VERSION_CODE;

	ret = media_device_register(mdev);
	if (ret) {
370
		pr_err("Couldn't create a media device. Error: %d\n",
371 372 373 374 375 376 377 378 379 380 381 382
			ret);
		kfree(mdev);
		return;
	}

	dev->coredev->media_dev = mdev;

	sms_info("media controller created");

#endif
}

383
static int smsusb_init_device(struct usb_interface *intf, int board_id)
384
{
385 386
	struct smsdevice_params_t params;
	struct smsusb_device_t *dev;
387 388
	int i, rc;

389
	/* create device object */
390
	dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
391
	if (!dev)
392 393 394 395 396
		return -ENOMEM;

	memset(&params, 0, sizeof(params));
	usb_set_intfdata(intf, dev);
	dev->udev = interface_to_usbdev(intf);
397
	dev->state = SMSUSB_DISCONNECTED;
398

399
	params.device_type = sms_get_board(board_id)->type;
400

401
	switch (params.device_type) {
402
	case SMS_STELLAR:
403 404 405 406 407
		dev->buffer_size = USB1_BUFFER_SIZE;

		params.setmode_handler = smsusb1_setmode;
		params.detectmode_handler = smsusb1_detectmode;
		break;
408
	case SMS_UNKNOWN_TYPE:
409
		pr_err("Unspecified sms device type!\n");
410
		/* fall-thru */
411
	default:
412
		dev->buffer_size = USB2_BUFFER_SIZE;
413
		dev->response_alignment =
414
		    le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) -
415
		    sizeof(struct sms_msg_hdr);
416

417 418
		params.flags |= SMS_DEVICE_FAMILY2;
		break;
419 420
	}

421 422 423 424 425 426 427 428 429 430
	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
		if (intf->cur_altsetting->endpoint[i].desc. bEndpointAddress & USB_DIR_IN)
			dev->in_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress;
		else
			dev->out_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress;
	}

	sms_info("in_ep = %02x, out_ep = %02x",
		dev->in_ep, dev->out_ep);

431 432 433 434 435
	params.device = &dev->udev->dev;
	params.buffer_size = dev->buffer_size;
	params.num_buffers = MAX_BUFFERS;
	params.sendrequest_handler = smsusb_sendrequest;
	params.context = dev;
436
	usb_make_path(dev->udev, params.devpath, sizeof(params.devpath));
437

438
	/* register in smscore */
439
	rc = smscore_register_device(&params, &dev->coredev);
440
	if (rc < 0) {
441
		pr_err("smscore_register_device(...) failed, rc %d\n", rc);
442 443 444 445
		smsusb_term_device(intf);
		return rc;
	}

446 447
	smscore_set_board_id(dev->coredev, board_id);

448 449
	dev->coredev->is_usb_device = true;

450
	/* initialize urbs */
451
	for (i = 0; i < MAX_URBS; i++) {
452 453 454 455
		dev->surbs[i].dev = dev;
		usb_init_urb(&dev->surbs[i].urb);
	}

456
	sms_info("smsusb_start_streaming(...).");
457
	rc = smsusb_start_streaming(dev);
458
	if (rc < 0) {
459
		pr_err("smsusb_start_streaming(...) failed\n");
460 461 462 463
		smsusb_term_device(intf);
		return rc;
	}

464 465
	dev->state = SMSUSB_ACTIVE;

466
	rc = smscore_start_device(dev->coredev);
467
	if (rc < 0) {
468
		pr_err("smscore_start_device(...) failed\n");
469 470 471 472
		smsusb_term_device(intf);
		return rc;
	}

473
	sms_info("device 0x%p created", dev);
474
	siano_media_device_register(dev);
475 476 477 478

	return rc;
}

479
static int smsusb_probe(struct usb_interface *intf,
480
			const struct usb_device_id *id)
481 482
{
	struct usb_device *udev = interface_to_usbdev(intf);
483
	char devpath[32];
484 485
	int i, rc;

486 487
	sms_info("board id=%lu, interface number %d",
		 id->driver_info,
488
		 intf->cur_altsetting->desc.bInterfaceNumber);
489

490 491
	if (sms_get_board(id->driver_info)->intf_num !=
	    intf->cur_altsetting->desc.bInterfaceNumber) {
492
		pr_debug("interface %d won't be used. Expecting interface %d to popup\n",
493 494
			intf->cur_altsetting->desc.bInterfaceNumber,
			sms_get_board(id->driver_info)->intf_num);
495 496 497 498 499 500 501
		return -ENODEV;
	}

	if (intf->num_altsetting > 1) {
		rc = usb_set_interface(udev,
				       intf->cur_altsetting->desc.bInterfaceNumber,
				       0);
502
		if (rc < 0) {
503
			pr_err("usb_set_interface failed, rc %d\n", rc);
504 505 506 507
			return rc;
		}
	}

508
	sms_info("smsusb_probe %d",
509
	       intf->cur_altsetting->desc.bInterfaceNumber);
510
	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
511
		sms_info("endpoint %d %02x %02x %d", i,
512 513 514
		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,
		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
515 516 517 518 519 520 521 522
		if (intf->cur_altsetting->endpoint[i].desc.bEndpointAddress &
		    USB_DIR_IN)
			rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev,
				intf->cur_altsetting->endpoint[i].desc.bEndpointAddress));
		else
			rc = usb_clear_halt(udev, usb_sndbulkpipe(udev,
				intf->cur_altsetting->endpoint[i].desc.bEndpointAddress));
	}
523 524
	if ((udev->actconfig->desc.bNumInterfaces == 2) &&
	    (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
525
		pr_debug("rom interface 0 is not used\n");
526 527 528
		return -ENODEV;
	}

529
	if (id->driver_info == SMS1XXX_BOARD_SIANO_STELLAR_ROM) {
530 531
		/* Detected a Siano Stellar uninitialized */

532 533
		snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
			 udev->bus->busnum, udev->devpath);
534 535
		sms_info("stellar device in cold state was found at %s.", devpath);
		rc = smsusb1_load_firmware(
536 537
				udev, smscore_registry_getmode(devpath),
				id->driver_info);
538 539 540 541 542

		/* This device will reset and gain another USB ID */
		if (!rc)
			sms_info("stellar device now in warm state");
		else
543 544
			pr_err("Failed to put stellar in warm state. Error: %d\n",
			       rc);
545 546 547 548

		return rc;
	} else {
		rc = smsusb_init_device(intf, id->driver_info);
549 550
	}

551
	sms_info("Device initialized with return code %d", rc);
552
	sms_board_load_modules(id->driver_info);
553
	return rc;
554 555
}

556
static void smsusb_disconnect(struct usb_interface *intf)
557 558 559 560
{
	smsusb_term_device(intf);
}

561 562
static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
{
563
	struct smsusb_device_t *dev = usb_get_intfdata(intf);
564 565 566
	printk(KERN_INFO "%s  Entering status %d.\n", __func__, msg.event);
	dev->state = SMSUSB_SUSPENDED;
	/*smscore_set_power_mode(dev, SMS_POWER_MODE_SUSPENDED);*/
567 568 569 570 571 572 573
	smsusb_stop_streaming(dev);
	return 0;
}

static int smsusb_resume(struct usb_interface *intf)
{
	int rc, i;
574
	struct smsusb_device_t *dev = usb_get_intfdata(intf);
575 576
	struct usb_device *udev = interface_to_usbdev(intf);

577 578 579
	printk(KERN_INFO "%s  Entering.\n", __func__);
	usb_clear_halt(udev, usb_rcvbulkpipe(udev, dev->in_ep));
	usb_clear_halt(udev, usb_sndbulkpipe(udev, dev->out_ep));
580 581 582 583 584 585 586 587 588 589 590 591

	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
		printk(KERN_INFO "endpoint %d %02x %02x %d\n", i,
		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,
		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);

	if (intf->num_altsetting > 0) {
		rc = usb_set_interface(udev,
				       intf->cur_altsetting->desc.
				       bInterfaceNumber, 0);
		if (rc < 0) {
592 593
			printk(KERN_INFO "%s usb_set_interface failed, "
			       "rc %d\n", __func__, rc);
594 595 596 597 598 599 600 601
			return rc;
		}
	}

	smsusb_start_streaming(dev);
	return 0;
}

602
static const struct usb_device_id smsusb_id_table[] = {
603
	/* This device is only present before firmware load */
604
	{ USB_DEVICE(0x187f, 0x0010),
605 606
		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR_ROM },
	/* This device pops up after firmware load */
607 608
	{ USB_DEVICE(0x187f, 0x0100),
		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
609

610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
	{ USB_DEVICE(0x187f, 0x0200),
		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
	{ USB_DEVICE(0x187f, 0x0201),
		.driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
	{ USB_DEVICE(0x187f, 0x0300),
		.driver_info = SMS1XXX_BOARD_SIANO_VEGA },
	{ USB_DEVICE(0x2040, 0x1700),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
	{ USB_DEVICE(0x2040, 0x1800),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
	{ USB_DEVICE(0x2040, 0x1801),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
	{ USB_DEVICE(0x2040, 0x2000),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
	{ USB_DEVICE(0x2040, 0x2009),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
	{ USB_DEVICE(0x2040, 0x200a),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
	{ USB_DEVICE(0x2040, 0x2010),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
	{ USB_DEVICE(0x2040, 0x2011),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
	{ USB_DEVICE(0x2040, 0x2019),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
	{ USB_DEVICE(0x2040, 0x5500),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
	{ USB_DEVICE(0x2040, 0x5510),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
	{ USB_DEVICE(0x2040, 0x5520),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
	{ USB_DEVICE(0x2040, 0x5530),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
	{ USB_DEVICE(0x2040, 0x5580),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
	{ USB_DEVICE(0x2040, 0x5590),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
646 647 648 649
	{ USB_DEVICE(0x187f, 0x0202),
		.driver_info = SMS1XXX_BOARD_SIANO_NICE },
	{ USB_DEVICE(0x187f, 0x0301),
		.driver_info = SMS1XXX_BOARD_SIANO_VENICE },
650 651 652 653
	{ USB_DEVICE(0x2040, 0xb900),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
	{ USB_DEVICE(0x2040, 0xb910),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
654 655 656 657
	{ USB_DEVICE(0x2040, 0xb980),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
	{ USB_DEVICE(0x2040, 0xb990),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
658 659
	{ USB_DEVICE(0x2040, 0xc000),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
660 661 662 663 664 665
	{ USB_DEVICE(0x2040, 0xc010),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
	{ USB_DEVICE(0x2040, 0xc080),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
	{ USB_DEVICE(0x2040, 0xc090),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
666 667
	{ USB_DEVICE(0x2040, 0xc0a0),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
668 669
	{ USB_DEVICE(0x2040, 0xf5a0),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
	{ USB_DEVICE(0x187f, 0x0202),
		.driver_info = SMS1XXX_BOARD_SIANO_NICE },
	{ USB_DEVICE(0x187f, 0x0301),
		.driver_info = SMS1XXX_BOARD_SIANO_VENICE },
	{ USB_DEVICE(0x187f, 0x0302),
		.driver_info = SMS1XXX_BOARD_SIANO_VENICE },
	{ USB_DEVICE(0x187f, 0x0310),
		.driver_info = SMS1XXX_BOARD_SIANO_MING },
	{ USB_DEVICE(0x187f, 0x0500),
		.driver_info = SMS1XXX_BOARD_SIANO_PELE },
	{ USB_DEVICE(0x187f, 0x0600),
		.driver_info = SMS1XXX_BOARD_SIANO_RIO },
	{ USB_DEVICE(0x187f, 0x0700),
		.driver_info = SMS1XXX_BOARD_SIANO_DENVER_2160 },
	{ USB_DEVICE(0x187f, 0x0800),
		.driver_info = SMS1XXX_BOARD_SIANO_DENVER_1530 },
	{ USB_DEVICE(0x19D2, 0x0086),
		.driver_info = SMS1XXX_BOARD_ZTE_DVB_DATA_CARD },
	{ USB_DEVICE(0x19D2, 0x0078),
		.driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD },
690 691
	{ USB_DEVICE(0x3275, 0x0080),
		.driver_info = SMS1XXX_BOARD_SIANO_RIO },
692 693
	{ USB_DEVICE(0x2013, 0x0257),
		.driver_info = SMS1XXX_BOARD_PCTV_77E },
694 695 696
	{ } /* Terminating entry */
	};

697 698
MODULE_DEVICE_TABLE(usb, smsusb_id_table);

699
static struct usb_driver smsusb_driver = {
700
	.name			= "smsusb",
701
	.probe			= smsusb_probe,
702
	.disconnect		= smsusb_disconnect,
703
	.id_table		= smsusb_id_table,
704 705 706

	.suspend		= smsusb_suspend,
	.resume			= smsusb_resume,
707 708
};

709
module_usb_driver(smsusb_driver);
710

711
MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle");
712 713
MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
MODULE_LICENSE("GPL");