smsusb.c 19.4 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

#define USB1_BUFFER_SIZE		0x1000
35
#define USB2_BUFFER_SIZE		0x2000
36 37 38 39

#define MAX_BUFFERS		50
#define MAX_URBS		10

40
struct smsusb_device_t;
41

42 43 44 45 46 47
enum smsusb_state {
	SMSUSB_DISCONNECTED,
	SMSUSB_SUSPENDED,
	SMSUSB_ACTIVE
};

48
struct smsusb_urb_t {
49
	struct list_head entry;
50
	struct smscore_buffer_t *cb;
51
	struct smsusb_device_t *dev;
52

53 54
	struct urb urb;
};
55

56
struct smsusb_device_t {
57
	struct usb_device *udev;
58
	struct smscore_device_t *coredev;
59

60
	struct smsusb_urb_t 	surbs[MAX_URBS];
61

62 63
	int		response_alignment;
	int		buffer_size;
64 65 66 67

	unsigned char in_ep;
	unsigned char out_ep;
	enum smsusb_state state;
68
};
69

70 71
static int smsusb_submit_urb(struct smsusb_device_t *dev,
			     struct smsusb_urb_t *surb);
72

73 74 75 76 77 78 79 80
/**
 * 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
 */
81
static void smsusb_onresponse(struct urb *urb)
82
{
83 84
	struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
	struct smsusb_device_t *dev = surb->dev;
85

86
	if (urb->status == -ESHUTDOWN) {
87
		pr_err("error, urb status %d (-ESHUTDOWN), %d bytes\n",
88
			urb->status, urb->actual_length);
89 90 91
		return;
	}

92
	if ((urb->actual_length > 0) && (urb->status == 0)) {
93
		struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)surb->cb->p;
94

95
		smsendian_handle_message_header(phdr);
96 97
		if (urb->actual_length >= phdr->msg_length) {
			surb->cb->size = phdr->msg_length;
98

99
			if (dev->response_alignment &&
100
			    (phdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG)) {
101 102 103

				surb->cb->offset =
					dev->response_alignment +
104
					((phdr->msg_flags >> 8) & 3);
105 106

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

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

123
			pr_debug("received %s(%d) size: %d\n",
124 125
				  smscore_translate_msg(phdr->msg_type),
				  phdr->msg_type, phdr->msg_length);
126

127
			smsendian_handle_rx_message((struct sms_msg_data *) phdr);
128

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

139 140 141 142 143

exit_and_resubmit:
	smsusb_submit_urb(dev, surb);
}

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

	usb_fill_bulk_urb(
		&surb->urb,
		dev->udev,
158
		usb_rcvbulkpipe(dev->udev, dev->in_ep),
159 160 161 162 163 164 165 166 167 168 169
		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);
}

170
static void smsusb_stop_streaming(struct smsusb_device_t *dev)
171 172 173
{
	int i;

174
	for (i = 0; i < MAX_URBS; i++) {
175 176
		usb_kill_urb(&dev->surbs[i].urb);

177
		if (dev->surbs[i].cb) {
178 179 180 181 182 183
			smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
			dev->surbs[i].cb = NULL;
		}
	}
}

184
static int smsusb_start_streaming(struct smsusb_device_t *dev)
185 186 187
{
	int i, rc;

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

	return rc;
}

200
static int smsusb_sendrequest(void *context, void *buffer, size_t size)
201
{
202
	struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
203
	struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer;
204 205
	int dummy;

206
	if (dev->state != SMSUSB_ACTIVE) {
207
		pr_debug("Device not active yet\n");
208
		return -ENOENT;
209
	}
210

211
	pr_debug("sending %s(%d) size: %d\n",
212 213
		  smscore_translate_msg(phdr->msg_type), phdr->msg_type,
		  phdr->msg_length);
214

215 216
	smsendian_handle_tx_message((struct sms_msg_data *) phdr);
	smsendian_handle_message_header((struct sms_msg_hdr *)buffer);
217 218
	return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
			    buffer, size, &dummy, 1000);
219 220
}

221
static char *smsusb1_fw_lkup[] = {
222 223 224 225 226 227 228
	"dvbt_stellar_usb.inp",
	"dvbh_stellar_usb.inp",
	"tdmb_stellar_usb.inp",
	"none",
	"dvbt_bda_stellar_usb.inp",
};

229 230 231 232 233 234 235
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)
236 237
{
	const struct firmware *fw;
238
	u8 *fw_buffer;
239
	int rc, dummy;
240
	char *fw_filename;
241

242 243 244
	if (id < 0)
		id = sms_get_board(board_id)->default_mode;

245
	if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
246
		pr_err("invalid firmware id specified %d\n", id);
247 248 249
		return -EINVAL;
	}

250 251 252
	fw_filename = sms_get_fw_name(id, board_id);

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

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

			return rc;
		}
265 266 267
	}

	fw_buffer = kmalloc(fw->size, GFP_KERNEL);
268
	if (fw_buffer) {
269 270
		memcpy(fw_buffer, fw->data, fw->size);

271 272
		rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
				  fw_buffer, fw->size, &dummy, 1000);
273

274
		pr_debug("sent %zu(%d) bytes, rc %d\n", fw->size, dummy, rc);
275 276

		kfree(fw_buffer);
277
	} else {
278
		pr_err("failed to allocate firmware buffer\n");
279 280
		rc = -ENOMEM;
	}
281
	pr_debug("read FW %s, size=%zu\n", fw_filename, fw->size);
282 283 284 285 286 287

	release_firmware(fw);

	return rc;
}

288
static void smsusb1_detectmode(void *context, int *mode)
289
{
290 291
	char *product_string =
		((struct smsusb_device_t *) context)->udev->product;
292 293 294

	*mode = DEVICE_MODE_NONE;

295
	if (!product_string) {
296
		product_string = "none";
297
		pr_err("product string not found\n");
298 299 300 301 302 303 304 305
	} 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;
306

307
	pr_debug("%d \"%s\"\n", *mode, product_string);
308 309
}

310
static int smsusb1_setmode(void *context, int mode)
311
{
312
	struct sms_msg_hdr msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
313
			     sizeof(struct sms_msg_hdr), 0 };
314

315
	if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
316
		pr_err("invalid firmware id specified %d\n", mode);
317 318 319
		return -EINVAL;
	}

320
	return smsusb_sendrequest(context, &msg, sizeof(msg));
321 322
}

323
static void smsusb_term_device(struct usb_interface *intf)
324
{
325
	struct smsusb_device_t *dev = usb_get_intfdata(intf);
326

327
	if (dev) {
328 329
		dev->state = SMSUSB_DISCONNECTED;

330 331
		smsusb_stop_streaming(dev);

332
		/* unregister from smscore */
333 334 335
		if (dev->coredev)
			smscore_unregister_device(dev->coredev);

336
		pr_debug("device 0x%p destroyed\n", dev);
337
		kfree(dev);
338 339 340 341 342
	}

	usb_set_intfdata(intf, NULL);
}

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
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) {
366
		pr_err("Couldn't create a media device. Error: %d\n",
367 368 369 370 371 372 373
			ret);
		kfree(mdev);
		return;
	}

	dev->coredev->media_dev = mdev;

374
	pr_info("media controller created\n");
375 376 377 378

#endif
}

379
static int smsusb_init_device(struct usb_interface *intf, int board_id)
380
{
381 382
	struct smsdevice_params_t params;
	struct smsusb_device_t *dev;
383 384
	int i, rc;

385
	/* create device object */
386
	dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
387
	if (!dev)
388 389 390 391 392
		return -ENOMEM;

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

395
	params.device_type = sms_get_board(board_id)->type;
396

397
	switch (params.device_type) {
398
	case SMS_STELLAR:
399 400 401 402 403
		dev->buffer_size = USB1_BUFFER_SIZE;

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

413 414
		params.flags |= SMS_DEVICE_FAMILY2;
		break;
415 416
	}

417 418 419 420 421 422 423
	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;
	}

424
	pr_debug("in_ep = %02x, out_ep = %02x\n",
425 426
		dev->in_ep, dev->out_ep);

427 428 429 430 431
	params.device = &dev->udev->dev;
	params.buffer_size = dev->buffer_size;
	params.num_buffers = MAX_BUFFERS;
	params.sendrequest_handler = smsusb_sendrequest;
	params.context = dev;
432
	usb_make_path(dev->udev, params.devpath, sizeof(params.devpath));
433

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

442 443
	smscore_set_board_id(dev->coredev, board_id);

444 445
	dev->coredev->is_usb_device = true;

446
	/* initialize urbs */
447
	for (i = 0; i < MAX_URBS; i++) {
448 449 450 451
		dev->surbs[i].dev = dev;
		usb_init_urb(&dev->surbs[i].urb);
	}

452
	pr_debug("smsusb_start_streaming(...).\n");
453
	rc = smsusb_start_streaming(dev);
454
	if (rc < 0) {
455
		pr_err("smsusb_start_streaming(...) failed\n");
456 457 458 459
		smsusb_term_device(intf);
		return rc;
	}

460 461
	dev->state = SMSUSB_ACTIVE;

462
	rc = smscore_start_device(dev->coredev);
463
	if (rc < 0) {
464
		pr_err("smscore_start_device(...) failed\n");
465 466 467 468
		smsusb_term_device(intf);
		return rc;
	}

469
	pr_debug("device 0x%p created\n", dev);
470
	siano_media_device_register(dev);
471 472 473 474

	return rc;
}

475
static int smsusb_probe(struct usb_interface *intf,
476
			const struct usb_device_id *id)
477 478
{
	struct usb_device *udev = interface_to_usbdev(intf);
479
	char devpath[32];
480 481
	int i, rc;

482
	pr_info("board id=%lu, interface number %d\n",
483
		 id->driver_info,
484
		 intf->cur_altsetting->desc.bInterfaceNumber);
485

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

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

504
	pr_debug("smsusb_probe %d\n",
505
	       intf->cur_altsetting->desc.bInterfaceNumber);
506
	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
507
		pr_debug("endpoint %d %02x %02x %d\n", i,
508 509 510
		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,
		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
511 512 513 514 515 516 517 518
		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));
	}
519 520
	if ((udev->actconfig->desc.bNumInterfaces == 2) &&
	    (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
521
		pr_debug("rom interface 0 is not used\n");
522 523 524
		return -ENODEV;
	}

525
	if (id->driver_info == SMS1XXX_BOARD_SIANO_STELLAR_ROM) {
526 527
		/* Detected a Siano Stellar uninitialized */

528 529
		snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
			 udev->bus->busnum, udev->devpath);
530 531
		pr_info("stellar device in cold state was found at %s.\n",
			devpath);
532
		rc = smsusb1_load_firmware(
533 534
				udev, smscore_registry_getmode(devpath),
				id->driver_info);
535 536 537

		/* This device will reset and gain another USB ID */
		if (!rc)
538
			pr_info("stellar device now in warm state\n");
539
		else
540 541
			pr_err("Failed to put stellar in warm state. Error: %d\n",
			       rc);
542 543 544 545

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

548
	pr_info("Device initialized with return code %d\n", rc);
549
	sms_board_load_modules(id->driver_info);
550
	return rc;
551 552
}

553
static void smsusb_disconnect(struct usb_interface *intf)
554 555 556 557
{
	smsusb_term_device(intf);
}

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

static int smsusb_resume(struct usb_interface *intf)
{
	int rc, i;
571
	struct smsusb_device_t *dev = usb_get_intfdata(intf);
572 573
	struct usb_device *udev = interface_to_usbdev(intf);

574 575 576
	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));
577 578 579 580 581 582 583 584 585 586 587 588

	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) {
589 590
			printk(KERN_INFO "%s usb_set_interface failed, "
			       "rc %d\n", __func__, rc);
591 592 593 594 595 596 597 598
			return rc;
		}
	}

	smsusb_start_streaming(dev);
	return 0;
}

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

607 608 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
	{ 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 },
643 644 645 646
	{ USB_DEVICE(0x187f, 0x0202),
		.driver_info = SMS1XXX_BOARD_SIANO_NICE },
	{ USB_DEVICE(0x187f, 0x0301),
		.driver_info = SMS1XXX_BOARD_SIANO_VENICE },
647 648 649 650
	{ USB_DEVICE(0x2040, 0xb900),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
	{ USB_DEVICE(0x2040, 0xb910),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
651 652 653 654
	{ USB_DEVICE(0x2040, 0xb980),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
	{ USB_DEVICE(0x2040, 0xb990),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
655 656
	{ USB_DEVICE(0x2040, 0xc000),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
657 658 659 660 661 662
	{ 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 },
663 664
	{ USB_DEVICE(0x2040, 0xc0a0),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
665 666
	{ USB_DEVICE(0x2040, 0xf5a0),
		.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
	{ 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 },
687 688
	{ USB_DEVICE(0x3275, 0x0080),
		.driver_info = SMS1XXX_BOARD_SIANO_RIO },
689 690
	{ USB_DEVICE(0x2013, 0x0257),
		.driver_info = SMS1XXX_BOARD_PCTV_77E },
691 692 693
	{ } /* Terminating entry */
	};

694 695
MODULE_DEVICE_TABLE(usb, smsusb_id_table);

696
static struct usb_driver smsusb_driver = {
697
	.name			= "smsusb",
698
	.probe			= smsusb_probe,
699
	.disconnect		= smsusb_disconnect,
700
	.id_table		= smsusb_id_table,
701 702 703

	.suspend		= smsusb_suspend,
	.resume			= smsusb_resume,
704 705
};

706
module_usb_driver(smsusb_driver);
707

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