em28xx-dvb.c revision 4fd305b2a2c4d16e8d4ebc95c84f946edd3385c5
13aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/*
23aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab DVB device driver for em28xx
33aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
43aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org>
53aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
6bdfbf9520372daf2b4d6941474c92310848ccb27Devin Heitmueller (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
7bdfbf9520372daf2b4d6941474c92310848ccb27Devin Heitmueller	- Fixes for the driver to properly work with HVR-950
84fd305b2a2c4d16e8d4ebc95c84f946edd3385c5Devin Heitmueller	- Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick
9bdfbf9520372daf2b4d6941474c92310848ccb27Devin Heitmueller
103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton (c) 2008 Aidan Thornton <makosoft@googlemail.com>
113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
133aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	(c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
143aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	(c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
153aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
163aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab This program is free software; you can redistribute it and/or modify
173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab it under the terms of the GNU General Public License as published by
183aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab the Free Software Foundation; either version 2 of the License.
193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */
203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include <linux/kernel.h>
223aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include <linux/usb.h>
233aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "em28xx.h"
253aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include <media/v4l2-common.h>
263aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include <media/videobuf-vmalloc.h>
273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "lgdt330x.h"
297e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton#include "zl10353.h"
303aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
313aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_DESCRIPTION("driver for em28xx based DVB cards");
323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
333aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_LICENSE("GPL");
343aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
353aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic unsigned int debug;
363aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_param(debug, int, 0644);
373aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_PARM_DESC(debug, "enable debug messages [dvb]");
383aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
393aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
403aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
413aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#define dprintk(level, fmt, arg...) do {			\
423aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabif (debug >= level) 						\
433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg);	\
443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab} while (0)
453aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton#define EM28XX_DVB_NUM_BUFS 5
473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton#define EM28XX_DVB_MAX_PACKETSIZE 564
483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton#define EM28XX_DVB_MAX_PACKETS 64
493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstruct em28xx_dvb {
513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_frontend        *frontend;
523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* feed count management */
543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct mutex               lock;
553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int                        nfeeds;
563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* general boilerplate stuff */
583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_adapter         adapter;
593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_demux           demux;
603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmxdev              dmxdev;
613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmx_frontend        fe_hw;
623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmx_frontend        fe_mem;
633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_net             net;
643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton};
653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic inline void print_err_status(struct em28xx *dev,
683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				     int packet, int status)
693aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	char *errmsg = "Unknown";
713aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	switch (status) {
733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ENOENT:
743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "unlinked synchronuously";
753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ECONNRESET:
773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "unlinked asynchronuously";
783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ENOSR:
803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Buffer error (overrun)";
813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EPIPE:
833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Stalled (device not responding)";
843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EOVERFLOW:
863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Babble (bad cable?)";
873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EPROTO:
893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Bit-stuff error (bad cable?)";
903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EILSEQ:
923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "CRC/Timeout (could be anything)";
933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ETIME:
953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Device does not respond";
963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (packet < 0) {
993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dprintk(1, "URB status %d [%s].\n", status, errmsg);
1003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	} else {
1016ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		dprintk(1, "URB packet %d, status %d [%s].\n",
1026ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf			packet, status, errmsg);
1033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1053aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
1073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int i;
1093aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!dev)
1113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return 0;
1123aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
1143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return 0;
1153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (urb->status < 0) {
1173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		print_err_status(dev, -1, urb->status);
1183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (urb->status == -ENOENT)
1193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			return 0;
1203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	for (i = 0; i < urb->number_of_packets; i++) {
1233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		int status = urb->iso_frame_desc[i].status;
1243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (status < 0) {
1263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			print_err_status(dev, i, status);
1273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			if (urb->iso_frame_desc[i].status != -EPROTO)
1283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				continue;
1293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
1303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
1323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				 urb->iso_frame_desc[i].offset,
1333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				 urb->iso_frame_desc[i].actual_length);
1343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
1373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1396ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafstatic int start_streaming(struct em28xx_dvb *dvb)
1406ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf{
141c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	int rc;
1423421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx *dev = dvb->adapter.priv;
1433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1443421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	usb_set_interface(dev->udev, 0, 1);
145c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
146c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	if (rc < 0)
147c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab		return rc;
1483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
1503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE,
151c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab				dvb_isoc_copy);
1523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1546ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafstatic int stop_streaming(struct em28xx_dvb *dvb)
1556ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf{
1563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx *dev = dvb->adapter.priv;
1573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	em28xx_uninit_isoc(dev);
159c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab
160c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
161c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab
1623aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
1633aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
1643aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic int start_feed(struct dvb_demux_feed *feed)
1663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_demux *demux  = feed->demux;
1683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx_dvb *dvb = demux->priv;
1693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int rc, ret;
1703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!demux->dmx.frontend)
1723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return -EINVAL;
1733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_lock(&dvb->lock);
1753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->nfeeds++;
1763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	rc = dvb->nfeeds;
1773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (dvb->nfeeds == 1) {
1793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		ret = start_streaming(dvb);
1806ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		if (ret < 0)
1816ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf			rc = ret;
1823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_unlock(&dvb->lock);
1853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return rc;
1863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic int stop_feed(struct dvb_demux_feed *feed)
1893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_demux *demux  = feed->demux;
1913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx_dvb *dvb = demux->priv;
1923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int err = 0;
1933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_lock(&dvb->lock);
1953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->nfeeds--;
1966ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
1976ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (0 == dvb->nfeeds)
1983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		err = stop_streaming(dvb);
1996ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
2003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_unlock(&dvb->lock);
2013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return err;
2023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
2033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
205e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
206e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
207e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehabstatic int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
208e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab{
209e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	struct em28xx *dev = fe->dvb->priv;
210e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
211e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	if (acquire)
212e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
213e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	else
214e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab		return em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
215e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab}
216e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
2173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
2183aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
219227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehabstatic struct lgdt330x_config em2880_lgdt3303_dev = {
220227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab	.demod_address = 0x0e,
221227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab	.demod_chip = LGDT3303,
222227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab};
2233aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2247e6388a1b97cca57a1906df6104feb4001721576Aidan Thorntonstatic struct zl10353_config em28xx_zl10353_with_xc3028 = {
2257e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.demod_address = (0x1e >> 1),
2267e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.no_tuner = 1,
2277e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.parallel_ts = 1,
2287e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.if2 = 45600,
2297e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton};
2307e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton
2313aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
2323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2333aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int attach_xc3028(u8 addr, struct em28xx *dev)
2343aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
2353aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	struct dvb_frontend *fe;
2363ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	struct xc2028_config cfg;
2373ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab
2386ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	memset(&cfg, 0, sizeof(cfg));
2393ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	cfg.i2c_adap  = &dev->i2c_adap;
2403ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	cfg.i2c_addr  = addr;
2413ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	cfg.callback  = em28xx_tuner_callback;
2423ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab
2433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!dev->dvb->frontend) {
2443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR "%s/2: dvb frontend not attached. "
2453aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab				"Can't attach xc3028\n",
2463aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
2473aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		return -EINVAL;
2483aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
2493aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg);
2513aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	if (!fe) {
2523aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR "%s/2: xc3028 attach failed\n",
2533aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
2543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb_frontend_detach(dev->dvb->frontend);
2553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dev->dvb->frontend = NULL;
2563aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		return -EINVAL;
2573aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
2583aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2593aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	printk(KERN_INFO "%s/2: xc3028 attached\n", dev->name);
2603aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2613aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
2623aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
2633aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* ------------------------------------------------------------------ */
2653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonint register_dvb(struct em28xx_dvb *dvb,
2673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		 struct module *module,
2683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		 struct em28xx *dev,
2693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		 struct device *device)
2703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
2713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int result;
2723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_init(&dvb->lock);
2743aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register adapter */
2763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
2773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				      adapter_nr);
2783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
2793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
2803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
2813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_adapter;
2823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
283e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
284e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	/* Ensure all frontends negotiate bus access */
285e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
286e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
2873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->adapter.priv = dev;
2883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register frontend */
2903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
2913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
2923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
2933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
2943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_frontend;
2953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
2963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register demux stuff */
2983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.capabilities =
2993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
3003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		DMX_MEMORY_BASED_FILTERING;
3013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.priv       = dvb;
3023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.filternum  = 256;
3033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.feednum    = 256;
3043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.start_feed = start_feed;
3053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.stop_feed  = stop_feed;
306e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
3073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_dmx_init(&dvb->demux);
3083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
3103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_dmx;
3123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.filternum    = 256;
3153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.demux        = &dvb->demux.dmx;
3163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.capabilities = 0;
3173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
3183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
3203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_dmxdev;
3223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
32352284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab
3243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->fe_hw.source = DMX_FRONTEND_0;
3253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
3283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_hw;
3303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->fe_mem.source = DMX_MEMORY_FE;
3333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
3343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
3363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_mem;
3383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3423421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
3433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3443421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_conn;
3453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register network adapter */
3483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
3493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
3503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_conn:
3523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
3533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_mem:
3543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_hw:
3563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmxdev_release(&dvb->dmxdev);
3573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_dmxdev:
3583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmx_release(&dvb->demux);
3593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_dmx:
3603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_frontend(dvb->frontend);
3613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_frontend:
3623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_frontend_detach(dvb->frontend);
3633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_adapter(&dvb->adapter);
3643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_adapter:
3653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return result;
3663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
3673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic void unregister_dvb(struct em28xx_dvb *dvb)
3693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
3703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_net_release(&dvb->net);
3713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
3723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmxdev_release(&dvb->dmxdev);
3743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmx_release(&dvb->demux);
3753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_frontend(dvb->frontend);
3763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_frontend_detach(dvb->frontend);
3773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_adapter(&dvb->adapter);
3783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
3793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic int dvb_init(struct em28xx *dev)
3823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
3833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int result = 0;
3843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx_dvb *dvb;
3853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
386df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	if (!dev->has_dvb) {
387df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		/* This device does not support the extension */
388df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		return 0;
389df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	}
390df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller
3913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
3926ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
3936ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (dvb == NULL) {
3946ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		printk(KERN_INFO "em28xx_dvb: memory allocation failed\n");
3953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return -ENOMEM;
3963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dev->dvb = dvb;
3983aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
399c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
4003aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	/* init frontend */
4013aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	switch (dev->model) {
402227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
4034fd305b2a2c4d16e8d4ebc95c84f946edd3385c5Devin Heitmueller	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
4043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb->frontend = dvb_attach(lgdt330x_attach,
4053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &em2880_lgdt3303_dev,
4063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &dev->i2c_adap);
4073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (attach_xc3028(0x61, dev) < 0) {
4083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			result = -EINVAL;
4093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			goto out_free;
4103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
411227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab		break;
4127e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
4133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb->frontend = dvb_attach(zl10353_attach,
4143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &em28xx_zl10353_with_xc3028,
4153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &dev->i2c_adap);
4163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (attach_xc3028(0x61, dev) < 0) {
4173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			result = -EINVAL;
4183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			goto out_free;
4193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
4207e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton		break;
4213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	default:
4223aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
4233aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab				" isn't supported yet\n",
4243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
4253aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		break;
4263aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
4273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (NULL == dvb->frontend) {
4283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR
4293aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       "%s/2: frontend initialization failed\n",
4303aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
4313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		result = -EINVAL;
4323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto out_free;
4333aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
4343aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4353aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	/* register everything */
4363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
4373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4386ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (result < 0)
4393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto out_free;
4403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
441c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
442102a0b0879a01a413ed5f667f7db9c2085ca8474Mauro Carvalho Chehab	printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
4433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
4443421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonout_free:
446c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
4473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	kfree(dvb);
4483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dev->dvb = NULL;
4493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return result;
4503aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
4513aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4523aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int dvb_fini(struct em28xx *dev)
4533aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
454df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	if (!dev->has_dvb) {
455df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		/* This device does not support the extension */
456df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		return 0;
457df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	}
458df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller
4593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (dev->dvb) {
4603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		unregister_dvb(dev->dvb);
4613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dev->dvb = NULL;
4623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
4633aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4643aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
4653aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
4663aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic struct em28xx_ops dvb_ops = {
4683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.id   = EM28XX_DVB,
4693aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.name = "Em28xx dvb Extension",
4703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.init = dvb_init,
4713aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.fini = dvb_fini,
4723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab};
4733aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4743aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int __init em28xx_dvb_register(void)
4753aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
4763aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return em28xx_register_extension(&dvb_ops);
4773aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
4783aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4793aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic void __exit em28xx_dvb_unregister(void)
4803aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
4813aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	em28xx_unregister_extension(&dvb_ops);
4823aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
4833aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4843aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_init(em28xx_dvb_register);
4853aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_exit(em28xx_dvb_unregister);
486