em28xx-dvb.c revision ec994d0505fc3dde5f46203602c76b527e2ac69d
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
9e14b3658a7651ffd9b1f407eaf07f4dde17ef1e7Devin Heitmueller	- Fixes for the driver to properly work with AMD ATI TV Wonder HD 600
10bdfbf9520372daf2b4d6941474c92310848ccb27Devin Heitmueller
113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton (c) 2008 Aidan Thornton <makosoft@googlemail.com>
123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
143aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	(c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
153aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	(c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
163aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab This program is free software; you can redistribute it and/or modify
183aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab it under the terms of the GNU General Public License as published by
193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab the Free Software Foundation; either version 2 of the License.
203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab */
213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
223aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include <linux/kernel.h>
233aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include <linux/usb.h>
243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
253aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "em28xx.h"
263aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include <media/v4l2-common.h>
273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include <media/videobuf-vmalloc.h>
28d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng#include <media/tuner.h>
29d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng#include "tuner-simple.h"
303aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
313aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "lgdt330x.h"
327e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton#include "zl10353.h"
336e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora#include "s5h1409.h"
344fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller#include "mt352.h"
354fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller#include "mt352_priv.h" /* FIXME */
36285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari#include "tda1002x.h"
373aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
383aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_DESCRIPTION("driver for em28xx based DVB cards");
393aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
403aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_LICENSE("GPL");
413aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
423aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic unsigned int debug;
433aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_param(debug, int, 0644);
443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_PARM_DESC(debug, "enable debug messages [dvb]");
453aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
463aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
473aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
483aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#define dprintk(level, fmt, arg...) do {			\
493aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabif (debug >= level) 						\
503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg);	\
513aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab} while (0)
523aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton#define EM28XX_DVB_NUM_BUFS 5
543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton#define EM28XX_DVB_MAX_PACKETS 64
553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstruct em28xx_dvb {
573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_frontend        *frontend;
583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* feed count management */
603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct mutex               lock;
613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int                        nfeeds;
623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* general boilerplate stuff */
643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_adapter         adapter;
653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_demux           demux;
663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmxdev              dmxdev;
673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmx_frontend        fe_hw;
683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmx_frontend        fe_mem;
693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_net             net;
703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton};
713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic inline void print_err_status(struct em28xx *dev,
743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				     int packet, int status)
753aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	char *errmsg = "Unknown";
773aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	switch (status) {
793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ENOENT:
803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "unlinked synchronuously";
813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ECONNRESET:
833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "unlinked asynchronuously";
843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ENOSR:
863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Buffer error (overrun)";
873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EPIPE:
893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Stalled (device not responding)";
903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EOVERFLOW:
923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Babble (bad cable?)";
933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EPROTO:
953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Bit-stuff error (bad cable?)";
963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EILSEQ:
983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "CRC/Timeout (could be anything)";
993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
1003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ETIME:
1013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Device does not respond";
1023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
1033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (packet < 0) {
1053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dprintk(1, "URB status %d [%s].\n", status, errmsg);
1063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	} else {
1076ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		dprintk(1, "URB packet %d, status %d [%s].\n",
1086ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf			packet, status, errmsg);
1093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1113aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
1133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int i;
1153aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!dev)
1173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return 0;
1183aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
1203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return 0;
1213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (urb->status < 0) {
1233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		print_err_status(dev, -1, urb->status);
1243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (urb->status == -ENOENT)
1253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			return 0;
1263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	for (i = 0; i < urb->number_of_packets; i++) {
1293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		int status = urb->iso_frame_desc[i].status;
1303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (status < 0) {
1323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			print_err_status(dev, i, status);
1333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			if (urb->iso_frame_desc[i].status != -EPROTO)
1343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				continue;
1353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
1363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
1383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				 urb->iso_frame_desc[i].offset,
1393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				 urb->iso_frame_desc[i].actual_length);
1403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1423421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
1433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1443421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1456ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafstatic int start_streaming(struct em28xx_dvb *dvb)
1466ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf{
147c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	int rc;
1483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx *dev = dvb->adapter.priv;
149d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller	int max_dvb_packet_size;
1503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	usb_set_interface(dev->udev, 0, 1);
152c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
153c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	if (rc < 0)
154c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab		return rc;
1553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
156d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller	max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev);
157d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller
1583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
159d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller				EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
160c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab				dvb_isoc_copy);
1613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1636ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafstatic int stop_streaming(struct em28xx_dvb *dvb)
1646ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf{
1653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx *dev = dvb->adapter.priv;
1663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	em28xx_uninit_isoc(dev);
168c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab
1692fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_SUSPEND);
170c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab
1713aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
1723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
1733aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic int start_feed(struct dvb_demux_feed *feed)
1753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_demux *demux  = feed->demux;
1773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx_dvb *dvb = demux->priv;
1783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int rc, ret;
1793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!demux->dmx.frontend)
1813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return -EINVAL;
1823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_lock(&dvb->lock);
1843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->nfeeds++;
1853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	rc = dvb->nfeeds;
1863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (dvb->nfeeds == 1) {
1883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		ret = start_streaming(dvb);
1896ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		if (ret < 0)
1906ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf			rc = ret;
1913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_unlock(&dvb->lock);
1943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return rc;
1953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic int stop_feed(struct dvb_demux_feed *feed)
1983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_demux *demux  = feed->demux;
2003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx_dvb *dvb = demux->priv;
2013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int err = 0;
2023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_lock(&dvb->lock);
2043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->nfeeds--;
2056ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
2066ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (0 == dvb->nfeeds)
2073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		err = stop_streaming(dvb);
2086ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
2093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_unlock(&dvb->lock);
2103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return err;
2113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
2123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
214e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
215e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
216e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehabstatic int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
217e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab{
218e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	struct em28xx *dev = fe->dvb->priv;
219e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
220e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	if (acquire)
221e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
222e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	else
2232fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab		return em28xx_set_mode(dev, EM28XX_SUSPEND);
224e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab}
225e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
2263aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
2273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
228227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehabstatic struct lgdt330x_config em2880_lgdt3303_dev = {
229227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab	.demod_address = 0x0e,
230227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab	.demod_chip = LGDT3303,
231227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab};
2323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2337e6388a1b97cca57a1906df6104feb4001721576Aidan Thorntonstatic struct zl10353_config em28xx_zl10353_with_xc3028 = {
2347e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.demod_address = (0x1e >> 1),
2357e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.no_tuner = 1,
2367e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.parallel_ts = 1,
2377e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.if2 = 45600,
2387e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton};
2397e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton
2406e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakorastatic struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
2416e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.demod_address = 0x32 >> 1,
2426e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.output_mode   = S5H1409_PARALLEL_OUTPUT,
2436e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.gpio          = S5H1409_GPIO_OFF,
2446e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.inversion     = S5H1409_INVERSION_OFF,
2456e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.status_mode   = S5H1409_DEMODLOCKING,
2466e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
2476e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora};
2486e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora
249a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmuellerstatic struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
250f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller	.demod_address = (0x1e >> 1),
251f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller	.no_tuner = 1,
252f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller	.disable_i2c_gate_ctrl = 1,
253f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller	.parallel_ts = 1,
254f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller	.if2 = 45600,
255f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller};
256f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller
25717d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#ifdef EM28XX_DRX397XD_SUPPORT
25817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller/* [TODO] djh - not sure yet what the device config needs to contain */
25917d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmuellerstatic struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
26017d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	.demod_address = (0xe0 >> 1),
26117d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller};
26217d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#endif
26317d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller
2644fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmuellerstatic int mt352_terratec_xs_init(struct dvb_frontend *fe)
2654fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller{
2664fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	/* Values extracted from a USB trace of the Terratec Windows driver */
2674fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 clock_config[]   = { CLOCK_CTL,  0x38, 0x2c };
2684fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 reset[]          = { RESET,      0x80 };
2694fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 adc_ctl_1_cfg[]  = { ADC_CTL_1,  0x40 };
2704fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 agc_cfg[]        = { AGC_TARGET, 0x28, 0xa0 };
2714fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 input_freq_cfg[] = { INPUT_FREQ_1, 0x31, 0xb8 };
2724fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 rs_err_cfg[]     = { RS_ERR_PER_1, 0x00, 0x4d };
2734fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
2744fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 trl_nom_cfg[]    = { TRL_NOMINAL_RATE_1, 0x64, 0x00 };
2754fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 tps_given_cfg[]  = { TPS_GIVEN_1, 0x40, 0x80, 0x50 };
276ff69786b4ccd0d5b99a60ba0be98237f9b7d8f52Devin Heitmueller	static u8 tuner_go[]       = { TUNER_GO, 0x01};
2774fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller
2784fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, clock_config,   sizeof(clock_config));
2794fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	udelay(200);
2804fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, reset,          sizeof(reset));
2814fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
2824fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
2834fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, input_freq_cfg, sizeof(input_freq_cfg));
2844fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, rs_err_cfg,     sizeof(rs_err_cfg));
2854fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
2864fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, trl_nom_cfg,    sizeof(trl_nom_cfg));
2874fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, tps_given_cfg,  sizeof(tps_given_cfg));
2884fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, tuner_go,       sizeof(tuner_go));
2894fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	return 0;
2904fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller}
2914fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller
2924fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmuellerstatic struct mt352_config terratec_xs_mt352_cfg = {
2934fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	.demod_address = (0x1e >> 1),
2944fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	.no_tuner = 1,
2954fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	.if2 = 45600,
2964fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	.demod_init = mt352_terratec_xs_init,
2974fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller};
2984fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller
299285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaaristatic struct tda10023_config em28xx_tda10023_config = {
300285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari	.demod_address = 0x0c,
301285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari	.invert = 1,
302285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari};
303285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari
3043aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
3053aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
3063aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int attach_xc3028(u8 addr, struct em28xx *dev)
3073aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
3083aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	struct dvb_frontend *fe;
3093ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	struct xc2028_config cfg;
3103ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab
3116ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	memset(&cfg, 0, sizeof(cfg));
3123ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	cfg.i2c_adap  = &dev->i2c_adap;
3133ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	cfg.i2c_addr  = addr;
3143ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab
3153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!dev->dvb->frontend) {
3163aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR "%s/2: dvb frontend not attached. "
3173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab				"Can't attach xc3028\n",
3183aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
3193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		return -EINVAL;
3203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
3213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
3223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg);
3233aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	if (!fe) {
3243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR "%s/2: xc3028 attach failed\n",
3253aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
3263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb_frontend_detach(dev->dvb->frontend);
3273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dev->dvb->frontend = NULL;
3283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		return -EINVAL;
3293aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
3303aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
3313aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	printk(KERN_INFO "%s/2: xc3028 attached\n", dev->name);
3323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
3333aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
3343aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
3353aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
3363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* ------------------------------------------------------------------ */
3373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
338d45b9b8ab43c8973a9630ac54f4ede6c3e009f9eHans Verkuilstatic int register_dvb(struct em28xx_dvb *dvb,
3393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		 struct module *module,
3403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		 struct em28xx *dev,
3413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		 struct device *device)
3423aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
3433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int result;
3443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
3453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_init(&dvb->lock);
3463aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
3473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register adapter */
3483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
3493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				      adapter_nr);
3503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
3523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_adapter;
3543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
355e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
356e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	/* Ensure all frontends negotiate bus access */
357e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
358e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
3593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->adapter.priv = dev;
3603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register frontend */
3623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
3633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
3653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_frontend;
3673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register demux stuff */
3703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.capabilities =
3713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
3723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		DMX_MEMORY_BASED_FILTERING;
3733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.priv       = dvb;
3743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.filternum  = 256;
3753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.feednum    = 256;
3763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.start_feed = start_feed;
3773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.stop_feed  = stop_feed;
378e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
3793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_dmx_init(&dvb->demux);
3803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
3823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_dmx;
3843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.filternum    = 256;
3873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.demux        = &dvb->demux.dmx;
3883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.capabilities = 0;
3893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
3903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
3923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_dmxdev;
3943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
39552284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab
3963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->fe_hw.source = DMX_FRONTEND_0;
3973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
4003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
4013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_hw;
4023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
4033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->fe_mem.source = DMX_MEMORY_FE;
4053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
4063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
4073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
4083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
4093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_mem;
4103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
4113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
4133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
4143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
4153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
4163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_conn;
4173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
4183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register network adapter */
4203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
4213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
4223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_conn:
4243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
4253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_mem:
4263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
4273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_hw:
4283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmxdev_release(&dvb->dmxdev);
4293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_dmxdev:
4303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmx_release(&dvb->demux);
4313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_dmx:
4323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_frontend(dvb->frontend);
4333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_frontend:
4343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_frontend_detach(dvb->frontend);
4353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_adapter(&dvb->adapter);
4363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_adapter:
4373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return result;
4383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
4393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic void unregister_dvb(struct em28xx_dvb *dvb)
4413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
4423421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_net_release(&dvb->net);
4433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
4443421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
4453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmxdev_release(&dvb->dmxdev);
4463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmx_release(&dvb->demux);
4473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_frontend(dvb->frontend);
4483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_frontend_detach(dvb->frontend);
4493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_adapter(&dvb->adapter);
4503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
4513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic int dvb_init(struct em28xx *dev)
4543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
4553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int result = 0;
4563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx_dvb *dvb;
4573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
458505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab	if (!dev->board.has_dvb) {
459df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		/* This device does not support the extension */
460df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		return 0;
461df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	}
462df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller
4633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
4646ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
4656ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (dvb == NULL) {
4666ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		printk(KERN_INFO "em28xx_dvb: memory allocation failed\n");
4673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return -ENOMEM;
4683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
4693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dev->dvb = dvb;
4703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
471c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
4723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	/* init frontend */
4733aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	switch (dev->model) {
474f89bc32974a4376e8393001484af28d8c3350ab4Douglas Schilling Landgraf	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
47510ac6603613d46a43a4544fbbe9581e50879bd45Mauro Carvalho Chehab	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
4764fd305b2a2c4d16e8d4ebc95c84f946edd3385c5Devin Heitmueller	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
477e14b3658a7651ffd9b1f407eaf07f4dde17ef1e7Devin Heitmueller	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
4783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb->frontend = dvb_attach(lgdt330x_attach,
4793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &em2880_lgdt3303_dev,
4803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &dev->i2c_adap);
4813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (attach_xc3028(0x61, dev) < 0) {
4823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			result = -EINVAL;
4833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			goto out_free;
4843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
485227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab		break;
48646510b56ca56a25ce973d6a6e8490c1109ff94efThierry MERLE	case EM2880_BOARD_KWORLD_DVB_310U:
4873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb->frontend = dvb_attach(zl10353_attach,
4883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &em28xx_zl10353_with_xc3028,
4893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &dev->i2c_adap);
4903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (attach_xc3028(0x61, dev) < 0) {
4913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			result = -EINVAL;
4923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			goto out_free;
4933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
4947e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton		break;
495a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
496ec994d0505fc3dde5f46203602c76b527e2ac69dUroš Vampl	case EM2882_BOARD_TERRATEC_HYBRID_XS:
49701a5fd6ff3fbae9a599d3334a8cca0f00865e360Devin Heitmueller	case EM2880_BOARD_EMPIRE_DUAL_TV:
498a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller		dvb->frontend = dvb_attach(zl10353_attach,
499a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller					   &em28xx_zl10353_xc3028_no_i2c_gate,
500a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller					   &dev->i2c_adap);
501a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller		if (attach_xc3028(0x61, dev) < 0) {
502a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller			result = -EINVAL;
503a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller			goto out_free;
504a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller		}
505a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller		break;
506f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller	case EM2880_BOARD_TERRATEC_HYBRID_XS:
507d5b3ba9cb375620a109d79f2e3a7bc21e9b75d8fDevin Heitmueller	case EM2881_BOARD_PINNACLE_HYBRID_PRO:
508f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller		dvb->frontend = dvb_attach(zl10353_attach,
509a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller					   &em28xx_zl10353_xc3028_no_i2c_gate,
510f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller					   &dev->i2c_adap);
511f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller		if (dvb->frontend == NULL) {
512f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller			/* This board could have either a zl10353 or a mt352.
513f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller			   If the chip id isn't for zl10353, try mt352 */
5144fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller			dvb->frontend = dvb_attach(mt352_attach,
5154fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller						   &terratec_xs_mt352_cfg,
5164fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller						   &dev->i2c_adap);
517f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller		}
5184fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller
519f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller		if (attach_xc3028(0x61, dev) < 0) {
520f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller			result = -EINVAL;
521f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller			goto out_free;
522f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller		}
523f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller		break;
5246e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	case EM2883_BOARD_KWORLD_HYBRID_330U:
52519859229d7d98bc2d582ff45045dd7f73d649383Devin Heitmueller	case EM2882_BOARD_EVGA_INDTUBE:
5266e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		dvb->frontend = dvb_attach(s5h1409_attach,
5276e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora					   &em28xx_s5h1409_with_xc3028,
5286e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora					   &dev->i2c_adap);
5296e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		if (attach_xc3028(0x61, dev) < 0) {
5306e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora			result = -EINVAL;
5316e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora			goto out_free;
5326e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		}
5336e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		break;
534d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng	case EM2882_BOARD_KWORLD_ATSC_315U:
535d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng		dvb->frontend = dvb_attach(lgdt330x_attach,
536d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng					   &em2880_lgdt3303_dev,
537d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng					   &dev->i2c_adap);
538d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng		if (dvb->frontend != NULL) {
539d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng			if (!dvb_attach(simple_tuner_attach, dvb->frontend,
540d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng				&dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) {
541d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng				result = -EINVAL;
542d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng				goto out_free;
543d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng			}
544d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng		}
545d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng		break;
54617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
54717d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#ifdef EM28XX_DRX397XD_SUPPORT
54817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		/* We don't have the config structure properly populated, so
54917d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		   this is commented out for now */
55017d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		dvb->frontend = dvb_attach(drx397xD_attach,
55117d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller					   &em28xx_drx397xD_with_xc3028,
55217d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller					   &dev->i2c_adap);
55317d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		if (attach_xc3028(0x61, dev) < 0) {
55417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller			result = -EINVAL;
55517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller			goto out_free;
55617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		}
55717d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		break;
55817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#endif
559285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari	case EM2870_BOARD_REDDO_DVB_C_USB_BOX:
560285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari		/* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
561285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari		dvb->frontend = dvb_attach(tda10023_attach,
562285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari			&em28xx_tda10023_config,
563285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari			&dev->i2c_adap, 0x48);
564285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari		if (dvb->frontend) {
565285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari			if (!dvb_attach(simple_tuner_attach, dvb->frontend,
566285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari				&dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) {
567285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari				result = -EINVAL;
568285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari				goto out_free;
569285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari			}
570285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari		}
571285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari		break;
5723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	default:
5733aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
5743aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab				" isn't supported yet\n",
5753aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
5763aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		break;
5773aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
5783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (NULL == dvb->frontend) {
5793aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR
5803aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       "%s/2: frontend initialization failed\n",
5813aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
5823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		result = -EINVAL;
5833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto out_free;
5843aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
585d7cba043d7ec840d67bd5143779d1febe7d83407Michael Krufky	/* define general-purpose callback pointer */
586d7cba043d7ec840d67bd5143779d1febe7d83407Michael Krufky	dvb->frontend->callback = em28xx_tuner_callback;
5873aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5883aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	/* register everything */
5893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
5903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
5916ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (result < 0)
5923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto out_free;
5933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
5942fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_SUSPEND);
595102a0b0879a01a413ed5f667f7db9c2085ca8474Mauro Carvalho Chehab	printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
5963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
5973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
5983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonout_free:
5992fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_SUSPEND);
6003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	kfree(dvb);
6013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dev->dvb = NULL;
6023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return result;
6033aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
6043aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
6053aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int dvb_fini(struct em28xx *dev)
6063aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
607505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab	if (!dev->board.has_dvb) {
608df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		/* This device does not support the extension */
609df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		return 0;
610df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	}
611df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller
6123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (dev->dvb) {
6133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		unregister_dvb(dev->dvb);
6143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dev->dvb = NULL;
6153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
6163aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
6173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
6183aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
6193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
6203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic struct em28xx_ops dvb_ops = {
6213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.id   = EM28XX_DVB,
6223aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.name = "Em28xx dvb Extension",
6233aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.init = dvb_init,
6243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.fini = dvb_fini,
6253aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab};
6263aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
6273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int __init em28xx_dvb_register(void)
6283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
6293aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return em28xx_register_extension(&dvb_ops);
6303aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
6313aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
6323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic void __exit em28xx_dvb_unregister(void)
6333aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
6343aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	em28xx_unregister_extension(&dvb_ops);
6353aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
6363aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
6373aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_init(em28xx_dvb_register);
6383aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_exit(em28xx_dvb_unregister);
639