smsusb.c 13.7 KB
Newer Older
1
/*
2
 *  Driver for the Siano SMS1xxx USB dongle
3
 *
4 5 6
 *  author: Anatoly Greenblat
 *
 *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
7 8
 *
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License version 2 as
10
 *  published by the Free Software Foundation;
11
 *
12 13
 *  Software distributed under the License is distributed on an "AS IS"
 *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
14
 *
15
 *  See the GNU General Public License for more details.
16 17 18 19 20 21
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

22 23 24 25 26 27
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/firmware.h>

#include "smscoreapi.h"
28
#include "sms-cards.h"
29 30 31 32 33 34 35

#define USB1_BUFFER_SIZE		0x1000
#define USB2_BUFFER_SIZE		0x4000

#define MAX_BUFFERS		50
#define MAX_URBS		10

36
struct smsusb_device_t;
37

38 39 40
struct smsusb_urb_t {
	struct smscore_buffer_t *cb;
	struct smsusb_device_t	*dev;
41

42 43
	struct urb urb;
};
44

45
struct smsusb_device_t {
46
	struct usb_device *udev;
47
	struct smscore_device_t *coredev;
48

49
	struct smsusb_urb_t 	surbs[MAX_URBS];
50

51 52
	int		response_alignment;
	int		buffer_size;
53
};
54

55 56
static int smsusb_submit_urb(struct smsusb_device_t *dev,
			     struct smsusb_urb_t *surb);
57

58
static void smsusb_onresponse(struct urb *urb)
59
{
60 61
	struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
	struct smsusb_device_t *dev = surb->dev;
62

63
	if (urb->status < 0) {
64 65
		sms_err("error, urb status %d, %d bytes",
			urb->status, urb->actual_length);
66 67 68
		return;
	}

69
	if (urb->actual_length > 0) {
70
		struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) surb->cb->p;
71

72
		if (urb->actual_length >= phdr->msgLength) {
73 74
			surb->cb->size = phdr->msgLength;

75 76 77 78 79 80 81 82 83 84
			if (dev->response_alignment &&
			    (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) {

				surb->cb->offset =
					dev->response_alignment +
					((phdr->msgFlags >> 8) & 3);

				/* sanity check */
				if (((int) phdr->msgLength +
				     surb->cb->offset) > urb->actual_length) {
85 86 87 88 89 90
					sms_err("invalid response "
						"msglen %d offset %d "
						"size %d",
						phdr->msgLength,
						surb->cb->offset,
						urb->actual_length);
91 92 93
					goto exit_and_resubmit;
				}

94 95
				/* move buffer pointer and
				 * copy header to its new location */
96
				memcpy((char *) phdr + surb->cb->offset,
97
				       phdr, sizeof(struct SmsMsgHdr_ST));
98
			} else
99 100 101 102
				surb->cb->offset = 0;

			smscore_onresponse(dev->coredev, surb->cb);
			surb->cb = NULL;
103
		} else {
104 105 106
			sms_err("invalid response "
				"msglen %d actual %d",
				phdr->msgLength, urb->actual_length);
107 108 109 110 111 112 113
		}
	}

exit_and_resubmit:
	smsusb_submit_urb(dev, surb);
}

114 115
static int smsusb_submit_urb(struct smsusb_device_t *dev,
			     struct smsusb_urb_t *surb)
116
{
117
	if (!surb->cb) {
118
		surb->cb = smscore_getbuffer(dev->coredev);
119
		if (!surb->cb) {
120
			sms_err("smscore_getbuffer(...) returned NULL");
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
			return -ENOMEM;
		}
	}

	usb_fill_bulk_urb(
		&surb->urb,
		dev->udev,
		usb_rcvbulkpipe(dev->udev, 0x81),
		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);
}

140
static void smsusb_stop_streaming(struct smsusb_device_t *dev)
141 142 143
{
	int i;

144
	for (i = 0; i < MAX_URBS; i++) {
145 146
		usb_kill_urb(&dev->surbs[i].urb);

147
		if (dev->surbs[i].cb) {
148 149 150 151 152 153
			smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
			dev->surbs[i].cb = NULL;
		}
	}
}

154
static int smsusb_start_streaming(struct smsusb_device_t *dev)
155 156 157
{
	int i, rc;

158
	for (i = 0; i < MAX_URBS; i++) {
159
		rc = smsusb_submit_urb(dev, &dev->surbs[i]);
160
		if (rc < 0) {
161
			sms_err("smsusb_submit_urb(...) failed");
162 163 164 165 166 167 168 169
			smsusb_stop_streaming(dev);
			break;
		}
	}

	return rc;
}

170
static int smsusb_sendrequest(void *context, void *buffer, size_t size)
171
{
172
	struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
173 174
	int dummy;

175 176
	return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
			    buffer, size, &dummy, 1000);
177 178
}

179
static char *smsusb1_fw_lkup[] = {
180 181 182 183 184 185 186
	"dvbt_stellar_usb.inp",
	"dvbh_stellar_usb.inp",
	"tdmb_stellar_usb.inp",
	"none",
	"dvbt_bda_stellar_usb.inp",
};

187 188 189 190 191 192 193
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)
194 195
{
	const struct firmware *fw;
196
	u8 *fw_buffer;
197
	int rc, dummy;
198
	char *fw_filename;
199

200
	if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
201
		sms_err("invalid firmware id specified %d", id);
202 203 204
		return -EINVAL;
	}

205 206 207
	fw_filename = sms_get_fw_name(id, board_id);

	rc = request_firmware(&fw, fw_filename, &udev->dev);
208
	if (rc < 0) {
209 210 211 212 213 214 215 216 217 218 219
		sms_warn("failed to open \"%s\" mode %d, "
			 "trying again with default firmware", fw_filename, id);

		fw_filename = smsusb1_fw_lkup[id];
		rc = request_firmware(&fw, fw_filename, &udev->dev);
		if (rc < 0) {
			sms_warn("failed to open \"%s\" mode %d",
				 fw_filename, id);

			return rc;
		}
220 221 222
	}

	fw_buffer = kmalloc(fw->size, GFP_KERNEL);
223
	if (fw_buffer) {
224 225
		memcpy(fw_buffer, fw->data, fw->size);

226 227
		rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
				  fw_buffer, fw->size, &dummy, 1000);
228

229
		sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
230 231

		kfree(fw_buffer);
232
	} else {
233
		sms_err("failed to allocate firmware buffer");
234 235
		rc = -ENOMEM;
	}
236
	sms_info("read FW %s, size=%zd", fw_filename, fw->size);
237 238 239 240 241 242

	release_firmware(fw);

	return rc;
}

243
static void smsusb1_detectmode(void *context, int *mode)
244
{
245 246
	char *product_string =
		((struct smsusb_device_t *) context)->udev->product;
247 248 249

	*mode = DEVICE_MODE_NONE;

250
	if (!product_string) {
251
		product_string = "none";
252
		sms_err("product string not found");
253 254 255 256 257 258 259 260
	} 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;
261

262
	sms_info("%d \"%s\"", *mode, product_string);
263 264
}

265
static int smsusb1_setmode(void *context, int mode)
266
{
267 268
	struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
			     sizeof(struct SmsMsgHdr_ST), 0 };
269

270
	if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
271
		sms_err("invalid firmware id specified %d", mode);
272 273 274 275 276 277
		return -EINVAL;
	}

	return smsusb_sendrequest(context, &Msg, sizeof(Msg));
}

278
static void smsusb_term_device(struct usb_interface *intf)
279
{
280 281
	struct smsusb_device_t *dev =
		(struct smsusb_device_t *) usb_get_intfdata(intf);
282

283
	if (dev) {
284 285
		smsusb_stop_streaming(dev);

286
		/* unregister from smscore */
287 288 289 290 291
		if (dev->coredev)
			smscore_unregister_device(dev->coredev);

		kfree(dev);

292
		sms_info("device %p destroyed", dev);
293 294 295 296 297
	}

	usb_set_intfdata(intf, NULL);
}

298
static int smsusb_init_device(struct usb_interface *intf, int board_id)
299
{
300 301
	struct smsdevice_params_t params;
	struct smsusb_device_t *dev;
302 303
	int i, rc;

304
	/* create device object */
305
	dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
306
	if (!dev) {
307
		sms_err("kzalloc(sizeof(struct smsusb_device_t) failed");
308 309 310 311 312 313 314
		return -ENOMEM;
	}

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

315
	params.device_type = sms_get_board(board_id)->type;
316

317
	switch (params.device_type) {
318
	case SMS_STELLAR:
319 320 321 322 323 324
		dev->buffer_size = USB1_BUFFER_SIZE;

		params.setmode_handler = smsusb1_setmode;
		params.detectmode_handler = smsusb1_detectmode;
		break;
	default:
325 326 327 328 329
		sms_err("Unspecified sms device type!");
		/* fall-thru */
	case SMS_NOVA_A0:
	case SMS_NOVA_B0:
	case SMS_VEGA:
330
		dev->buffer_size = USB2_BUFFER_SIZE;
331 332
		dev->response_alignment =
			dev->udev->ep_in[1]->desc.wMaxPacketSize -
333
			sizeof(struct SmsMsgHdr_ST);
334

335 336
		params.flags |= SMS_DEVICE_FAMILY2;
		break;
337 338 339 340 341 342 343
	}

	params.device = &dev->udev->dev;
	params.buffer_size = dev->buffer_size;
	params.num_buffers = MAX_BUFFERS;
	params.sendrequest_handler = smsusb_sendrequest;
	params.context = dev;
344 345
	snprintf(params.devpath, sizeof(params.devpath),
		 "usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath);
346

347
	/* register in smscore */
348
	rc = smscore_register_device(&params, &dev->coredev);
349
	if (rc < 0) {
350
		sms_err("smscore_register_device(...) failed, rc %d", rc);
351 352 353 354
		smsusb_term_device(intf);
		return rc;
	}

355 356
	smscore_set_board_id(dev->coredev, board_id);

357
	/* initialize urbs */
358
	for (i = 0; i < MAX_URBS; i++) {
359 360 361 362
		dev->surbs[i].dev = dev;
		usb_init_urb(&dev->surbs[i].urb);
	}

363
	sms_info("smsusb_start_streaming(...).");
364
	rc = smsusb_start_streaming(dev);
365
	if (rc < 0) {
366
		sms_err("smsusb_start_streaming(...) failed");
367 368 369 370 371
		smsusb_term_device(intf);
		return rc;
	}

	rc = smscore_start_device(dev->coredev);
372
	if (rc < 0) {
373
		sms_err("smscore_start_device(...) failed");
374 375 376 377
		smsusb_term_device(intf);
		return rc;
	}

378
	sms_info("device %p created", dev);
379 380 381 382

	return rc;
}

383 384
static int smsusb_probe(struct usb_interface *intf,
			const struct usb_device_id *id)
385 386 387 388 389
{
	struct usb_device *udev = interface_to_usbdev(intf);
	char devpath[32];
	int i, rc;

390 391 392
	rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
	rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));

393
	if (intf->num_altsetting > 0) {
394 395
		rc = usb_set_interface(
			udev, intf->cur_altsetting->desc.bInterfaceNumber, 0);
396
		if (rc < 0) {
397
			sms_err("usb_set_interface failed, rc %d", rc);
398 399 400 401
			return rc;
		}
	}

402
	sms_info("smsusb_probe %d",
403
	       intf->cur_altsetting->desc.bInterfaceNumber);
404
	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
405
		sms_info("endpoint %d %02x %02x %d", i,
406 407 408
		       intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
		       intf->cur_altsetting->endpoint[i].desc.bmAttributes,
		       intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
409

410 411
	if ((udev->actconfig->desc.bNumInterfaces == 2) &&
	    (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
412
		sms_err("rom interface 0 is not used");
413 414 415
		return -ENODEV;
	}

416 417 418
	if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
		snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
			 udev->bus->busnum, udev->devpath);
419
		sms_info("stellar device was found.");
420
		return smsusb1_load_firmware(
421 422
				udev, smscore_registry_getmode(devpath),
				id->driver_info);
423 424
	}

425
	rc = smsusb_init_device(intf, id->driver_info);
426
	sms_info("rc %d", rc);
427
	return rc;
428 429
}

430
static void smsusb_disconnect(struct usb_interface *intf)
431 432 433 434
{
	smsusb_term_device(intf);
}

435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
{
	struct smsusb_device_t *dev =
		(struct smsusb_device_t *)usb_get_intfdata(intf);
	printk(KERN_INFO "%s  Entering status %d.\n", __func__, msg.event);
	smsusb_stop_streaming(dev);
	return 0;
}

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

	printk(KERN_INFO "%s  Entering.\n", __func__);
	usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
	usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));

	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) {
			printk(KERN_INFO
			       "%s usb_set_interface failed, rc %d\n",
			       __func__, rc);
			return rc;
		}
	}

	smsusb_start_streaming(dev);
	return 0;
}

477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
struct usb_device_id smsusb_id_table[] = {
#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
	{ USB_DEVICE(0x187f, 0x0010),
		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
	{ USB_DEVICE(0x187f, 0x0100),
		.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
	{ 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 },
#endif
	{ 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 },
	{ }		/* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, smsusb_id_table);

524
static struct usb_driver smsusb_driver = {
525
	.name			= "smsusb",
526
	.probe			= smsusb_probe,
527
	.disconnect		= smsusb_disconnect,
528
	.id_table		= smsusb_id_table,
529 530 531

	.suspend		= smsusb_suspend,
	.resume			= smsusb_resume,
532 533
};

534
int smsusb_register(void)
535 536 537
{
	int rc = usb_register(&smsusb_driver);
	if (rc)
538
		sms_err("usb_register failed. Error number %d", rc);
539

540
	sms_debug("");
541 542 543 544

	return rc;
}

545
void smsusb_unregister(void)
546
{
547
	sms_debug("");
548
	/* Regular USB Cleanup */
549 550 551
	usb_deregister(&smsusb_driver);
}