tm6000-dvb.c 10.3 KB
Newer Older
1
/*
2 3 4 5 6 7 8 9 10 11 12 13
 *  tm6000-dvb.c - dvb-t support for TM5600/TM6000/TM6010 USB video capture devices
 *
 *  Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
 *
 *  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 version 2
 *
 *  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.
14 15
 */

16
#include <linux/kernel.h>
T
Tejun Heo 已提交
17
#include <linux/slab.h>
18 19 20 21 22 23 24 25 26
#include <linux/usb.h>

#include "tm6000.h"
#include "tm6000-regs.h"

#include "zl10353.h"

#include <media/tuner.h>

27
#include "tuner-xc2028.h"
28
#include "xc5000.h"
29

30
MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV cards");
31
MODULE_AUTHOR("Mauro Carvalho Chehab");
32 33
MODULE_LICENSE("GPL");

34
MODULE_SUPPORTED_DEVICE("{{Trident, tm5600},{{Trident, tm6000},{{Trident, tm6010}");
35 36 37 38 39 40

static int debug;

module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug message");

41 42
static inline void print_err_status(struct tm6000_core *dev,
				    int packet, int status)
43 44 45
{
	char *errmsg = "Unknown";

46
	switch (status) {
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
	case -ENOENT:
		errmsg = "unlinked synchronuously";
		break;
	case -ECONNRESET:
		errmsg = "unlinked asynchronuously";
		break;
	case -ENOSR:
		errmsg = "Buffer error (overrun)";
		break;
	case -EPIPE:
		errmsg = "Stalled (device not responding)";
		break;
	case -EOVERFLOW:
		errmsg = "Babble (bad cable?)";
		break;
	case -EPROTO:
		errmsg = "Bit-stuff error (bad cable?)";
		break;
	case -EILSEQ:
		errmsg = "CRC/Timeout (could be anything)";
		break;
	case -ETIME:
		errmsg = "Device does not respond";
		break;
	}
72
	if (packet < 0) {
73 74 75 76 77 78 79 80
		dprintk(dev, 1, "URB status %d [%s].\n",
			status, errmsg);
	} else {
		dprintk(dev, 1, "URB packet %d, status %d [%s].\n",
			packet, status, errmsg);
	}
}

81 82 83
static void tm6000_urb_received(struct urb *urb)
{
	int ret;
84
	struct tm6000_core *dev = urb->context;
85

86 87 88 89 90 91 92 93 94
	switch (urb->status) {
	case 0:
	case -ETIMEDOUT:
		break;
	case -ENOENT:
	case -ECONNRESET:
	case -ESHUTDOWN:
		return;
	default:
95
		print_err_status(dev, 0, urb->status);
96 97 98
	}

	if (urb->actual_length > 0)
99 100 101
		dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
						   urb->actual_length);

102
	if (dev->dvb->streams > 0) {
103
		ret = usb_submit_urb(urb, GFP_ATOMIC);
104
		if (ret < 0) {
105
			printk(KERN_ERR "tm6000:  error %s\n", __func__);
106 107 108 109 110 111
			kfree(urb->transfer_buffer);
			usb_free_urb(urb);
		}
	}
}

112
static int tm6000_start_stream(struct tm6000_core *dev)
113 114
{
	int ret;
115
	unsigned int pipe, size;
116 117
	struct tm6000_dvb *dvb = dev->dvb;

118
	printk(KERN_INFO "tm6000: got start stream request %s\n", __func__);
119

120 121 122 123
	if (dev->mode != TM6000_MODE_DIGITAL) {
		tm6000_init_digital_mode(dev);
		dev->mode = TM6000_MODE_DIGITAL;
	}
124 125

	dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
126
	if (!dvb->bulk_urb)
127 128
		return -ENOMEM;

129
	pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress
130 131 132 133
							  & USB_ENDPOINT_NUMBER_MASK);

	size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe));
	size = size * 15; /* 512 x 8 or 12 or 15 */
134

135
	dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL);
136
	if (!dvb->bulk_urb->transfer_buffer) {
137 138 139 140 141 142
		usb_free_urb(dvb->bulk_urb);
		return -ENOMEM;
	}

	usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
						 dvb->bulk_urb->transfer_buffer,
143
						 size,
144
						 tm6000_urb_received, dev);
145

146
	ret = usb_clear_halt(dev->udev, pipe);
147 148
	if (ret < 0) {
		printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",
149
							ret, __func__);
150
		return ret;
151
	} else
152 153
		printk(KERN_ERR "tm6000: pipe resetted\n");

154
/*	mutex_lock(&tm6000_driver.open_close_mutex); */
155
	ret = usb_submit_urb(dvb->bulk_urb, GFP_ATOMIC);
156

157
/*	mutex_unlock(&tm6000_driver.open_close_mutex); */
158
	if (ret) {
159 160
		printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",
									ret);
161 162 163 164 165 166 167 168 169

		kfree(dvb->bulk_urb->transfer_buffer);
		usb_free_urb(dvb->bulk_urb);
		return ret;
	}

	return 0;
}

170
static void tm6000_stop_stream(struct tm6000_core *dev)
171 172 173
{
	struct tm6000_dvb *dvb = dev->dvb;

174 175
	if (dvb->bulk_urb) {
		printk(KERN_INFO "urb killing\n");
176
		usb_kill_urb(dvb->bulk_urb);
177
		printk(KERN_INFO "urb buffer free\n");
178 179 180 181 182 183
		kfree(dvb->bulk_urb->transfer_buffer);
		usb_free_urb(dvb->bulk_urb);
		dvb->bulk_urb = NULL;
	}
}

184
static int tm6000_start_feed(struct dvb_demux_feed *feed)
185 186 187 188
{
	struct dvb_demux *demux = feed->demux;
	struct tm6000_core *dev = demux->priv;
	struct tm6000_dvb *dvb = dev->dvb;
189
	printk(KERN_INFO "tm6000: got start feed request %s\n", __func__);
190 191

	mutex_lock(&dvb->mutex);
192
	if (dvb->streams == 0) {
193
		dvb->streams = 1;
194
/*		mutex_init(&tm6000_dev->streming_mutex); */
195
		tm6000_start_stream(dev);
196
	} else
197 198 199 200 201 202
		++(dvb->streams);
	mutex_unlock(&dvb->mutex);

	return 0;
}

203
static int tm6000_stop_feed(struct dvb_demux_feed *feed)
204
{
205 206 207 208
	struct dvb_demux *demux = feed->demux;
	struct tm6000_core *dev = demux->priv;
	struct tm6000_dvb *dvb = dev->dvb;

209
	printk(KERN_INFO "tm6000: got stop feed request %s\n", __func__);
210 211 212

	mutex_lock(&dvb->mutex);

213
	printk(KERN_INFO "stream %#x\n", dvb->streams);
214
	--(dvb->streams);
215 216
	if (dvb->streams == 0) {
		printk(KERN_INFO "stop stream\n");
217
		tm6000_stop_stream(dev);
218
/*		mutex_destroy(&tm6000_dev->streaming_mutex); */
219 220
	}
	mutex_unlock(&dvb->mutex);
221
/*	mutex_destroy(&tm6000_dev->streaming_mutex); */
222 223 224 225

	return 0;
}

226
static int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
227 228 229
{
	struct tm6000_dvb *dvb = dev->dvb;

230 231 232
	if (dev->caps.has_zl10353) {
		struct zl10353_config config = {
				     .demod_address = dev->demod_addr,
233
				     .no_tuner = 1,
234 235 236
				     .parallel_ts = 1,
				     .if2 = 45700,
				     .disable_i2c_gate_ctrl = 1,
237 238
				    };

239
		dvb->frontend = dvb_attach(zl10353_attach, &config,
240
							   &dev->i2c_adap);
241
	} else {
242 243 244 245
		printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
		return -1;
	}

246
	return (!dvb->frontend) ? -1 : 0;
247 248
}

249 250
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);

251
static int register_dvb(struct tm6000_core *dev)
252 253 254 255 256 257 258 259 260 261
{
	int ret = -1;
	struct tm6000_dvb *dvb = dev->dvb;

	mutex_init(&dvb->mutex);

	dvb->streams = 0;

	/* attach the frontend */
	ret = tm6000_dvb_attach_frontend(dev);
262
	if (ret < 0) {
263
		printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
264
		goto err;
265 266 267
	}

	ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
268
					THIS_MODULE, &dev->udev->dev, adapter_nr);
269 270
	dvb->adapter.priv = dev;

271
	if (dvb->frontend) {
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
		switch (dev->tuner_type) {
		case TUNER_XC2028: {
			struct xc2028_config cfg = {
				.i2c_adap = &dev->i2c_adap,
				.i2c_addr = dev->tuner_addr,
			};

			dvb->frontend->callback = tm6000_tuner_callback;
			ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
			if (ret < 0) {
				printk(KERN_ERR
					"tm6000: couldn't register frontend\n");
				goto adapter_err;
			}

			if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) {
288
				printk(KERN_ERR "tm6000: couldn't register frontend (xc3028)\n");
289 290 291
				ret = -EINVAL;
				goto frontend_err;
			}
292
			printk(KERN_INFO "tm6000: XC2028/3028 asked to be attached to frontend!\n");
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
			break;
			}
		case TUNER_XC5000: {
			struct xc5000_config cfg = {
				.i2c_address = dev->tuner_addr,
			};

			dvb->frontend->callback = tm6000_xc5000_callback;
			ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
			if (ret < 0) {
				printk(KERN_ERR
					"tm6000: couldn't register frontend\n");
				goto adapter_err;
			}

			if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) {
309
				printk(KERN_ERR "tm6000: couldn't register frontend (xc5000)\n");
310 311 312
				ret = -EINVAL;
				goto frontend_err;
			}
313
			printk(KERN_INFO "tm6000: XC5000 asked to be attached to frontend!\n");
314 315
			break;
			}
316
		}
317
	} else
318
		printk(KERN_ERR "tm6000: no frontend found\n");
319 320 321 322

	dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
							    | DMX_MEMORY_BASED_FILTERING;
	dvb->demux.priv = dev;
323 324
	dvb->demux.filternum = 8;
	dvb->demux.feednum = 8;
325 326 327 328
	dvb->demux.start_feed = tm6000_start_feed;
	dvb->demux.stop_feed = tm6000_stop_feed;
	dvb->demux.write_to_decoder = NULL;
	ret = dvb_dmx_init(&dvb->demux);
329
	if (ret < 0) {
330
		printk(KERN_ERR "tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
331 332 333 334 335 336 337 338
		goto frontend_err;
	}

	dvb->dmxdev.filternum = dev->dvb->demux.filternum;
	dvb->dmxdev.demux = &dev->dvb->demux.dmx;
	dvb->dmxdev.capabilities = 0;

	ret =  dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
339
	if (ret < 0) {
340
		printk(KERN_ERR "tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
341 342 343 344 345 346 347 348
		goto dvb_dmx_err;
	}

	return 0;

dvb_dmx_err:
	dvb_dmx_release(&dvb->demux);
frontend_err:
349
	if (dvb->frontend) {
350
		dvb_unregister_frontend(dvb->frontend);
351
		dvb_frontend_detach(dvb->frontend);
352 353 354 355 356 357 358
	}
adapter_err:
	dvb_unregister_adapter(&dvb->adapter);
err:
	return ret;
}

359
static void unregister_dvb(struct tm6000_core *dev)
360 361 362
{
	struct tm6000_dvb *dvb = dev->dvb;

363
	if (dvb->bulk_urb) {
364 365 366 367 368 369 370 371
		struct urb *bulk_urb = dvb->bulk_urb;

		kfree(bulk_urb->transfer_buffer);
		bulk_urb->transfer_buffer = NULL;
		usb_unlink_urb(bulk_urb);
		usb_free_urb(bulk_urb);
	}

372
/*	mutex_lock(&tm6000_driver.open_close_mutex); */
373
	if (dvb->frontend) {
374
		dvb_unregister_frontend(dvb->frontend);
375
		dvb_frontend_detach(dvb->frontend);
376 377 378 379 380 381
	}

	dvb_dmxdev_release(&dvb->dmxdev);
	dvb_dmx_release(&dvb->demux);
	dvb_unregister_adapter(&dvb->adapter);
	mutex_destroy(&dvb->mutex);
382
/*	mutex_unlock(&tm6000_driver.open_close_mutex); */
383
}
384 385 386 387 388 389 390 391 392 393 394 395

static int dvb_init(struct tm6000_core *dev)
{
	struct tm6000_dvb *dvb;
	int rc;

	if (!dev)
		return 0;

	if (!dev->caps.has_dvb)
		return 0;

396 397 398 399 400
	if (dev->udev->speed == USB_SPEED_FULL) {
		printk(KERN_INFO "This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)\n");
		return 0;
	}

401
	dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL);
402
	if (!dvb)
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
		return -ENOMEM;

	dev->dvb = dvb;

	rc = register_dvb(dev);
	if (rc < 0) {
		kfree(dvb);
		dev->dvb = NULL;
		return 0;
	}

	return 0;
}

static int dvb_fini(struct tm6000_core *dev)
{
	if (!dev)
		return 0;

	if (!dev->caps.has_dvb)
		return 0;

	if (dev->dvb) {
		unregister_dvb(dev);
		kfree(dev->dvb);
		dev->dvb = NULL;
	}

	return 0;
}

static struct tm6000_ops dvb_ops = {
435
	.type	= TM6000_DVB,
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
	.name	= "TM6000 dvb Extension",
	.init	= dvb_init,
	.fini	= dvb_fini,
};

static int __init tm6000_dvb_register(void)
{
	return tm6000_register_extension(&dvb_ops);
}

static void __exit tm6000_dvb_unregister(void)
{
	tm6000_unregister_extension(&dvb_ops);
}

module_init(tm6000_dvb_register);
module_exit(tm6000_dvb_unregister);