em28xx-dvb.c revision 0b8bd83cf393832f1d00096b866d888b75b374c3
13aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/*
23aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab DVB device driver for em28xx
33aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab (c) 2008-2011 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>
235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include <linux/usb.h>
253aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
263aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "em28xx.h"
273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include <media/v4l2-common.h>
283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include <media/videobuf-vmalloc.h>
29d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng#include <media/tuner.h>
30d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng#include "tuner-simple.h"
313aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "lgdt330x.h"
337e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson#include "lgdt3305.h"
347e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton#include "zl10353.h"
356e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora#include "s5h1409.h"
364fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller#include "mt352.h"
374fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller#include "mt352_priv.h" /* FIXME */
38285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari#include "tda1002x.h"
397e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson#include "tda18271.h"
40ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehab#include "s921.h"
4175e2b8694f0b1f8faea1851a39cb7ba07640aa7dDevin Heitmueller#include "drxd.h"
42d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari#include "cxd2820r.h"
43fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab#include "tda18271c2dd.h"
44fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab#include "drxk.h"
453aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
463aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_DESCRIPTION("driver for em28xx based DVB cards");
473aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
483aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_LICENSE("GPL");
493aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
503aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic unsigned int debug;
513aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_param(debug, int, 0644);
523aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_PARM_DESC(debug, "enable debug messages [dvb]");
533aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
543aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
553aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
563aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#define dprintk(level, fmt, arg...) do {			\
573aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabif (debug >= level) 						\
583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg);	\
593aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab} while (0)
603aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton#define EM28XX_DVB_NUM_BUFS 5
623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton#define EM28XX_DVB_MAX_PACKETS 64
633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstruct em28xx_dvb {
65f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	struct dvb_frontend        *fe[2];
663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* feed count management */
683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct mutex               lock;
693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int                        nfeeds;
703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* general boilerplate stuff */
723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_adapter         adapter;
733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_demux           demux;
743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmxdev              dmxdev;
753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmx_frontend        fe_hw;
763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmx_frontend        fe_mem;
773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_net             net;
78fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab
79c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab	/* Due to DRX-K - probably need changes */
80fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	int (*gate_ctrl)(struct dvb_frontend *, int);
81fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	struct semaphore      pll_mutex;
82c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab	bool			dont_attach_fe1;
833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton};
843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic inline void print_err_status(struct em28xx *dev,
873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				     int packet, int status)
883aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	char *errmsg = "Unknown";
903aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	switch (status) {
923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ENOENT:
933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "unlinked synchronuously";
943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ECONNRESET:
963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "unlinked asynchronuously";
973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ENOSR:
993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Buffer error (overrun)";
1003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
1013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EPIPE:
1023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Stalled (device not responding)";
1033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
1043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EOVERFLOW:
1053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Babble (bad cable?)";
1063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
1073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EPROTO:
1083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Bit-stuff error (bad cable?)";
1093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
1103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EILSEQ:
1113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "CRC/Timeout (could be anything)";
1123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
1133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ETIME:
1143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Device does not respond";
1153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
1163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (packet < 0) {
1183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dprintk(1, "URB status %d [%s].\n", status, errmsg);
1193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	} else {
1206ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		dprintk(1, "URB packet %d, status %d [%s].\n",
1216ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf			packet, status, errmsg);
1223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
125f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilsonstatic inline int em28xx_dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
1263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int i;
1283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!dev)
1303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return 0;
1313aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
1333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return 0;
1343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (urb->status < 0) {
1363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		print_err_status(dev, -1, urb->status);
1373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (urb->status == -ENOENT)
1383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			return 0;
1393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	for (i = 0; i < urb->number_of_packets; i++) {
1423421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		int status = urb->iso_frame_desc[i].status;
1433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1443421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (status < 0) {
1453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			print_err_status(dev, i, status);
1463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			if (urb->iso_frame_desc[i].status != -EPROTO)
1473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				continue;
1483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
1493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
1513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				 urb->iso_frame_desc[i].offset,
1523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				 urb->iso_frame_desc[i].actual_length);
1533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
1563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
158f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilsonstatic int em28xx_start_streaming(struct em28xx_dvb *dvb)
1596ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf{
160c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	int rc;
1613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx *dev = dvb->adapter.priv;
162d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller	int max_dvb_packet_size;
1633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	usb_set_interface(dev->udev, 0, 1);
165c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
166c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	if (rc < 0)
167c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab		return rc;
1683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
169d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller	max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev);
170f7acc4bb86594d78aa41c07b7670df3e03738b18Mauro Carvalho Chehab	if (max_dvb_packet_size < 0)
171f7acc4bb86594d78aa41c07b7670df3e03738b18Mauro Carvalho Chehab		return max_dvb_packet_size;
172f7acc4bb86594d78aa41c07b7670df3e03738b18Mauro Carvalho Chehab	dprintk(1, "Using %d buffers each with %d bytes\n",
173f7acc4bb86594d78aa41c07b7670df3e03738b18Mauro Carvalho Chehab		EM28XX_DVB_NUM_BUFS,
174f7acc4bb86594d78aa41c07b7670df3e03738b18Mauro Carvalho Chehab		max_dvb_packet_size);
175d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller
1763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
177d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller				EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
178f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson				em28xx_dvb_isoc_copy);
1793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
181f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilsonstatic int em28xx_stop_streaming(struct em28xx_dvb *dvb)
1826ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf{
1833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx *dev = dvb->adapter.priv;
1843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	em28xx_uninit_isoc(dev);
186c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab
1872fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_SUSPEND);
188c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab
1893aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
1903aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
1913aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
192f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilsonstatic int em28xx_start_feed(struct dvb_demux_feed *feed)
1933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_demux *demux  = feed->demux;
1953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx_dvb *dvb = demux->priv;
1963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int rc, ret;
1973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!demux->dmx.frontend)
1993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return -EINVAL;
2003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_lock(&dvb->lock);
2023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->nfeeds++;
2033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	rc = dvb->nfeeds;
2043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (dvb->nfeeds == 1) {
206f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson		ret = em28xx_start_streaming(dvb);
2076ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		if (ret < 0)
2086ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf			rc = ret;
2093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
2103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_unlock(&dvb->lock);
2123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return rc;
2133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
2143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
215f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilsonstatic int em28xx_stop_feed(struct dvb_demux_feed *feed)
2163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
2173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_demux *demux  = feed->demux;
2183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx_dvb *dvb = demux->priv;
2193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int err = 0;
2203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_lock(&dvb->lock);
2223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->nfeeds--;
2236ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
2246ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (0 == dvb->nfeeds)
225f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson		err = em28xx_stop_streaming(dvb);
2266ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
2273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_unlock(&dvb->lock);
2283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return err;
2293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
2303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
232e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
233e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
234e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehabstatic int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
235e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab{
236e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	struct em28xx *dev = fe->dvb->priv;
237e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
238e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	if (acquire)
239e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
240e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	else
2412fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab		return em28xx_set_mode(dev, EM28XX_SUSPEND);
242e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab}
243e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
2443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
2453aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
246227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehabstatic struct lgdt330x_config em2880_lgdt3303_dev = {
247227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab	.demod_address = 0x0e,
248227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab	.demod_chip = LGDT3303,
249227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab};
2503aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2517e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilsonstatic struct lgdt3305_config em2870_lgdt3304_dev = {
2527e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	.i2c_addr           = 0x0e,
2537e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	.demod_chip         = LGDT3304,
2547e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	.spectral_inversion = 1,
2557e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	.deny_i2c_rptr      = 1,
2567e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	.mpeg_mode          = LGDT3305_MPEG_PARALLEL,
2577e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	.tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
2587e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	.tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
2597e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	.vsb_if_khz         = 3250,
2607e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	.qam_if_khz         = 4000,
2617e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson};
2627e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson
263ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehabstatic struct s921_config sharp_isdbt = {
264ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehab	.demod_address = 0x30 >> 1
265ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehab};
266ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehab
2677e6388a1b97cca57a1906df6104feb4001721576Aidan Thorntonstatic struct zl10353_config em28xx_zl10353_with_xc3028 = {
2687e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.demod_address = (0x1e >> 1),
2697e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.no_tuner = 1,
2707e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.parallel_ts = 1,
2717e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.if2 = 45600,
2727e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton};
2737e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton
2746e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakorastatic struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
2756e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.demod_address = 0x32 >> 1,
2766e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.output_mode   = S5H1409_PARALLEL_OUTPUT,
2776e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.gpio          = S5H1409_GPIO_OFF,
2786e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.inversion     = S5H1409_INVERSION_OFF,
2796e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.status_mode   = S5H1409_DEMODLOCKING,
2806e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
2816e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora};
2826e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora
2837e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilsonstatic struct tda18271_std_map kworld_a340_std_map = {
2847e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	.atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 0,
2857e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson		      .if_lvl = 1, .rfagc_top = 0x37, },
2867e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 1,
2877e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson		      .if_lvl = 1, .rfagc_top = 0x37, },
2887e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson};
2897e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson
2907e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilsonstatic struct tda18271_config kworld_a340_config = {
2917e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	.std_map           = &kworld_a340_std_map,
2927e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson};
2937e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson
294a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmuellerstatic struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
295f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller	.demod_address = (0x1e >> 1),
296f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller	.no_tuner = 1,
297f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller	.disable_i2c_gate_ctrl = 1,
298f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller	.parallel_ts = 1,
299f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller	.if2 = 45600,
300f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller};
301f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller
30275e2b8694f0b1f8faea1851a39cb7ba07640aa7dDevin Heitmuellerstatic struct drxd_config em28xx_drxd = {
30375e2b8694f0b1f8faea1851a39cb7ba07640aa7dDevin Heitmueller	.index = 0, .demod_address = 0x70, .demod_revision = 0xa2,
30475e2b8694f0b1f8faea1851a39cb7ba07640aa7dDevin Heitmueller	.demoda_address = 0x00, .pll_address = 0x00,
30575e2b8694f0b1f8faea1851a39cb7ba07640aa7dDevin Heitmueller	.pll_type = DRXD_PLL_NONE, .clock = 12000, .insert_rs_byte = 1,
30675e2b8694f0b1f8faea1851a39cb7ba07640aa7dDevin Heitmueller	.pll_set = NULL, .osc_deviation = NULL, .IF = 42800000,
3076b142b3c81e6e532dfad7256fcc7e75fded49245Devin Heitmueller	.disable_i2c_gate_ctrl = 1,
30817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller};
30917d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller
310fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehabstruct drxk_config terratec_h5_drxk = {
311fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	.adr = 0x29,
312e4f4f8758b4c3702761e46f24ee99e34823a0f28Mauro Carvalho Chehab	.single_master = 1,
313f1fe1b75d64046b693075045fe9fc5cafed9c981Mauro Carvalho Chehab	.no_i2c_bridge = 1,
3148b9456ae04b1cb7adcaa57735324f7b518eae07dMauro Carvalho Chehab	.microcode_name = "dvb-usb-terratec-h5-drxk.fw",
315fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab};
316fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab
317fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehabstatic int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
318fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab{
319fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	struct em28xx_dvb *dvb = fe->sec_priv;
320fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	int status;
321fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab
322fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	if (!dvb)
323fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		return -EINVAL;
324fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab
325fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	if (enable) {
326fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		down(&dvb->pll_mutex);
327fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		status = dvb->gate_ctrl(fe, 1);
328fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	} else {
329fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		status = dvb->gate_ctrl(fe, 0);
330fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		up(&dvb->pll_mutex);
331fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	}
332fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	return status;
333fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab}
334fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab
335fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehabstatic void terratec_h5_init(struct em28xx *dev)
336fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab{
337fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	int i;
338fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	struct em28xx_reg_seq terratec_h5_init[] = {
339fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{EM28XX_R08_GPIO,	0xff,	0xff,	10},
340fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{EM2874_R80_GPIO,	0xf6,	0xff,	100},
341fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{EM2874_R80_GPIO,	0xf2,	0xff,	50},
342fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{EM2874_R80_GPIO,	0xf6,	0xff,	100},
343fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{ -1,                   -1,     -1,     -1},
344fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	};
345fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	struct em28xx_reg_seq terratec_h5_end[] = {
346fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{EM2874_R80_GPIO,	0xe6,	0xff,	100},
347fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{EM2874_R80_GPIO,	0xa6,	0xff,	50},
348fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{EM2874_R80_GPIO,	0xe6,	0xff,	100},
349fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{ -1,                   -1,     -1,     -1},
350fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	};
351fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	struct {
352fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		unsigned char r[4];
353fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		int len;
354fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	} regs[] = {
355fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x06, 0x02, 0x00, 0x31 }, 4},
356fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x01, 0x02 }, 2},
357fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x01, 0x02, 0x00, 0xc6 }, 4},
358fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x01, 0x00 }, 2},
359fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x01, 0x00, 0xff, 0xaf }, 4},
360fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x01, 0x00, 0x03, 0xa0 }, 4},
361fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x01, 0x00 }, 2},
362fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x01, 0x00, 0x73, 0xaf }, 4},
363fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x04, 0x00 }, 2},
364fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x00, 0x04 }, 2},
365fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x00, 0x04, 0x00, 0x0a }, 4},
366fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x04, 0x14 }, 2},
367fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		{{ 0x04, 0x14, 0x00, 0x00 }, 4},
368fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	};
369fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab
370fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	em28xx_gpio_set(dev, terratec_h5_init);
371fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
372fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	msleep(10);
373fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
374fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	msleep(10);
375fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab
376fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	dev->i2c_client.addr = 0x82 >> 1;
377fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab
378fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	for (i = 0; i < ARRAY_SIZE(regs); i++)
379fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
380fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	em28xx_gpio_set(dev, terratec_h5_end);
381fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab};
382fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab
383f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilsonstatic int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe)
3844fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller{
3854fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	/* Values extracted from a USB trace of the Terratec Windows driver */
3864fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 clock_config[]   = { CLOCK_CTL,  0x38, 0x2c };
3874fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 reset[]          = { RESET,      0x80 };
3884fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 adc_ctl_1_cfg[]  = { ADC_CTL_1,  0x40 };
3894fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 agc_cfg[]        = { AGC_TARGET, 0x28, 0xa0 };
3904fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 input_freq_cfg[] = { INPUT_FREQ_1, 0x31, 0xb8 };
3914fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 rs_err_cfg[]     = { RS_ERR_PER_1, 0x00, 0x4d };
3924fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
3934fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 trl_nom_cfg[]    = { TRL_NOMINAL_RATE_1, 0x64, 0x00 };
3944fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	static u8 tps_given_cfg[]  = { TPS_GIVEN_1, 0x40, 0x80, 0x50 };
395ff69786b4ccd0d5b99a60ba0be98237f9b7d8f52Devin Heitmueller	static u8 tuner_go[]       = { TUNER_GO, 0x01};
3964fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller
3974fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, clock_config,   sizeof(clock_config));
3984fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	udelay(200);
3994fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, reset,          sizeof(reset));
4004fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
4014fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
4024fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, input_freq_cfg, sizeof(input_freq_cfg));
4034fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, rs_err_cfg,     sizeof(rs_err_cfg));
4044fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
4054fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, trl_nom_cfg,    sizeof(trl_nom_cfg));
4064fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, tps_given_cfg,  sizeof(tps_given_cfg));
4074fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	mt352_write(fe, tuner_go,       sizeof(tuner_go));
4084fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	return 0;
4094fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller}
4104fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller
4114fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmuellerstatic struct mt352_config terratec_xs_mt352_cfg = {
4124fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	.demod_address = (0x1e >> 1),
4134fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	.no_tuner = 1,
4144fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller	.if2 = 45600,
415f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson	.demod_init = em28xx_mt352_terratec_xs_init,
4164fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller};
4174fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller
418285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaaristatic struct tda10023_config em28xx_tda10023_config = {
419285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari	.demod_address = 0x0c,
420285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari	.invert = 1,
421285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari};
422285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari
423d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaaristatic struct cxd2820r_config em28xx_cxd2820r_config = {
424d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	.i2c_address = (0xd8 >> 1),
425d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	.ts_mode = CXD2820R_TS_SERIAL,
426d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	.if_dvbt_6  = 3300,
427d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	.if_dvbt_7  = 3500,
428d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	.if_dvbt_8  = 4000,
429d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	.if_dvbt2_6 = 3300,
430d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	.if_dvbt2_7 = 3500,
431d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	.if_dvbt2_8 = 4000,
432d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	.if_dvbc    = 5000,
433d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari
434d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	/* enable LNA for DVB-T2 and DVB-C */
435d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	.gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
436d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	.gpio_dvbc[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
437d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari};
438d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari
439d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaaristatic struct tda18271_config em28xx_cxd2820r_tda18271_config = {
440d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	.output_opt = TDA18271_OUTPUT_LT_OFF,
4410db4bf42baae95ddd457b0c4911e851c9169750eSteve Kerrison	.gate = TDA18271_GATE_DIGITAL,
442d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari};
443d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari
4443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
4453aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
446f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilsonstatic int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
4473aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
4483aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	struct dvb_frontend *fe;
4493ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	struct xc2028_config cfg;
4503ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab
4516ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	memset(&cfg, 0, sizeof(cfg));
4523ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	cfg.i2c_adap  = &dev->i2c_adap;
4533ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	cfg.i2c_addr  = addr;
4543ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab
455f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	if (!dev->dvb->fe[0]) {
456480be1851aebcb0b9c5b0fb9acefe5da97cc702aFilipe Rosset		em28xx_errdev("/2: dvb frontend not attached. "
457480be1851aebcb0b9c5b0fb9acefe5da97cc702aFilipe Rosset				"Can't attach xc3028\n");
4583aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		return -EINVAL;
4593aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
4603aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
461f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg);
4623aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	if (!fe) {
463480be1851aebcb0b9c5b0fb9acefe5da97cc702aFilipe Rosset		em28xx_errdev("/2: xc3028 attach failed\n");
464f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb_frontend_detach(dev->dvb->fe[0]);
465f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dev->dvb->fe[0] = NULL;
4663aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		return -EINVAL;
4673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
4683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
469480be1851aebcb0b9c5b0fb9acefe5da97cc702aFilipe Rosset	em28xx_info("%s/2: xc3028 attached\n", dev->name);
4703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4713aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
4723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
4733aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* ------------------------------------------------------------------ */
4753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
476f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilsonstatic int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module,
477f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson			       struct em28xx *dev, struct device *device)
4783aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
4793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int result;
4803aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_init(&dvb->lock);
4823aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register adapter */
4843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
4853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				      adapter_nr);
4863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
4873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
4883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
4893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_adapter;
4903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
491e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
492e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	/* Ensure all frontends negotiate bus access */
493f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	dvb->fe[0]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
494f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	if (dvb->fe[1])
495f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb->fe[1]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
496e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
4973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->adapter.priv = dev;
4983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register frontend */
500f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]);
5013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
5023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
5033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
504f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		goto fail_frontend0;
505f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	}
506f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari
507f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	/* register 2nd frontend */
508f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	if (dvb->fe[1]) {
509f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]);
510f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		if (result < 0) {
511f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari			printk(KERN_WARNING "%s: 2nd dvb_register_frontend failed (errno = %d)\n",
512f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari				dev->name, result);
513f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari			goto fail_frontend1;
514f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		}
5153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
5163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
5173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register demux stuff */
5183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.capabilities =
5193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
5203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		DMX_MEMORY_BASED_FILTERING;
5213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.priv       = dvb;
5223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.filternum  = 256;
5233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.feednum    = 256;
524f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson	dvb->demux.start_feed = em28xx_start_feed;
525f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson	dvb->demux.stop_feed  = em28xx_stop_feed;
526e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
5273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_dmx_init(&dvb->demux);
5283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
5293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
5303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
5313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_dmx;
5323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
5333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
5343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.filternum    = 256;
5353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.demux        = &dvb->demux.dmx;
5363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.capabilities = 0;
5373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
5383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
5393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
5403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
5413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_dmxdev;
5423421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
54352284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab
5443421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->fe_hw.source = DMX_FRONTEND_0;
5453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
5463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
5473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
5483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
5493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_hw;
5503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
5513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
5523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->fe_mem.source = DMX_MEMORY_FE;
5533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
5543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
5553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
5563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
5573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_mem;
5583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
5593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
5603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
5613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
5623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
5633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
5643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_conn;
5653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
5663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
5673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register network adapter */
5683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
5693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
5703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
5713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_conn:
5723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
5733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_mem:
5743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
5753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_hw:
5763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmxdev_release(&dvb->dmxdev);
5773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_dmxdev:
5783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmx_release(&dvb->demux);
5793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_dmx:
580f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	if (dvb->fe[1])
581f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb_unregister_frontend(dvb->fe[1]);
582f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	dvb_unregister_frontend(dvb->fe[0]);
583f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaarifail_frontend1:
584f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	if (dvb->fe[1])
585f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb_frontend_detach(dvb->fe[1]);
586f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaarifail_frontend0:
587f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	dvb_frontend_detach(dvb->fe[0]);
5883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_adapter(&dvb->adapter);
5893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_adapter:
5903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return result;
5913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
5923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
593f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilsonstatic void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
5943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
5953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_net_release(&dvb->net);
5963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
5973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
5983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmxdev_release(&dvb->dmxdev);
5993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmx_release(&dvb->demux);
600f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	if (dvb->fe[1])
601f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb_unregister_frontend(dvb->fe[1]);
602f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	dvb_unregister_frontend(dvb->fe[0]);
603c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab	if (dvb->fe[1] && !dvb->dont_attach_fe1)
604f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb_frontend_detach(dvb->fe[1]);
605f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	dvb_frontend_detach(dvb->fe[0]);
6063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_adapter(&dvb->adapter);
6073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
6083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
609f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilsonstatic int em28xx_dvb_init(struct em28xx *dev)
6103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
611e36454376a8f4637c0767daa78cf1d96d162d71aAntti Palosaari	int result = 0, mfe_shared = 0;
6123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx_dvb *dvb;
6133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
614505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab	if (!dev->board.has_dvb) {
615df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		/* This device does not support the extension */
616ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehab		printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
617df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		return 0;
618df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	}
619df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller
6203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
6216ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
6226ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (dvb == NULL) {
623480be1851aebcb0b9c5b0fb9acefe5da97cc702aFilipe Rosset		em28xx_info("em28xx_dvb: memory allocation failed\n");
6243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return -ENOMEM;
6253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
6263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dev->dvb = dvb;
627f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	dvb->fe[0] = dvb->fe[1] = NULL;
6283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
6295013318ca4fd22e30fd891f234b60daa3ca2f62dMauro Carvalho Chehab	mutex_lock(&dev->lock);
630c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
6313aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	/* init frontend */
6323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	switch (dev->model) {
633ebaefdb7651383645f17d2d32398914175d1bcddMauro Carvalho Chehab	case EM2874_BOARD_LEADERSHIP_ISDBT:
634f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb->fe[0] = dvb_attach(s921_attach,
635ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehab				&sharp_isdbt, &dev->i2c_adap);
636ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehab
637f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		if (!dvb->fe[0]) {
638ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehab			result = -EINVAL;
639ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehab			goto out_free;
640ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehab		}
641ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehab
642ca3dfd6a6f8364c1d51e548adb4564702f1141e9Mauro Carvalho Chehab		break;
643f89bc32974a4376e8393001484af28d8c3350ab4Douglas Schilling Landgraf	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
64410ac6603613d46a43a4544fbbe9581e50879bd45Mauro Carvalho Chehab	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
6454fd305b2a2c4d16e8d4ebc95c84f946edd3385c5Devin Heitmueller	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
646e14b3658a7651ffd9b1f407eaf07f4dde17ef1e7Devin Heitmueller	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
647f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb->fe[0] = dvb_attach(lgdt330x_attach,
6483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &em2880_lgdt3303_dev,
6493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &dev->i2c_adap);
650f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson		if (em28xx_attach_xc3028(0x61, dev) < 0) {
6513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			result = -EINVAL;
6523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			goto out_free;
6533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
654227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab		break;
65546510b56ca56a25ce973d6a6e8490c1109ff94efThierry MERLE	case EM2880_BOARD_KWORLD_DVB_310U:
656f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb->fe[0] = dvb_attach(zl10353_attach,
6573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &em28xx_zl10353_with_xc3028,
6583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &dev->i2c_adap);
659f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson		if (em28xx_attach_xc3028(0x61, dev) < 0) {
6603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			result = -EINVAL;
6613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			goto out_free;
6623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
6637e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton		break;
664a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
665ec994d0505fc3dde5f46203602c76b527e2ac69dUroš Vampl	case EM2882_BOARD_TERRATEC_HYBRID_XS:
66601a5fd6ff3fbae9a599d3334a8cca0f00865e360Devin Heitmueller	case EM2880_BOARD_EMPIRE_DUAL_TV:
667f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb->fe[0] = dvb_attach(zl10353_attach,
668a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller					   &em28xx_zl10353_xc3028_no_i2c_gate,
669a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller					   &dev->i2c_adap);
670f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson		if (em28xx_attach_xc3028(0x61, dev) < 0) {
671a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller			result = -EINVAL;
672a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller			goto out_free;
673a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller		}
674a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller		break;
675f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller	case EM2880_BOARD_TERRATEC_HYBRID_XS:
676656380118d1a1c0176e58e4e3e46d736d0dd2000Catimimi	case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
677d5b3ba9cb375620a109d79f2e3a7bc21e9b75d8fDevin Heitmueller	case EM2881_BOARD_PINNACLE_HYBRID_PRO:
6787ca7ef6011e92b52a365ddc78f6668e01793c572Andrea.Amorosi	case EM2882_BOARD_DIKOM_DK300:
679811fab623f435932f2a26aa64b40ec6102618cc6Antonio Larrosa	case EM2882_BOARD_KWORLD_VS_DVBT:
680f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb->fe[0] = dvb_attach(zl10353_attach,
681a84f79aed688a94197387830df3a2f2068f49dc0Devin Heitmueller					   &em28xx_zl10353_xc3028_no_i2c_gate,
682f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller					   &dev->i2c_adap);
683f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		if (dvb->fe[0] == NULL) {
684f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller			/* This board could have either a zl10353 or a mt352.
685f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller			   If the chip id isn't for zl10353, try mt352 */
686f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari			dvb->fe[0] = dvb_attach(mt352_attach,
6874fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller						   &terratec_xs_mt352_cfg,
6884fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller						   &dev->i2c_adap);
689f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller		}
6904fb202a8d9d936f7080ab631140b447a0625e36cDevin Heitmueller
691f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson		if (em28xx_attach_xc3028(0x61, dev) < 0) {
692f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller			result = -EINVAL;
693f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller			goto out_free;
694f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller		}
695f797608cc4f19b44b83ec39c87e14af6fa07826dDevin Heitmueller		break;
6966e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	case EM2883_BOARD_KWORLD_HYBRID_330U:
69719859229d7d98bc2d582ff45045dd7f73d649383Devin Heitmueller	case EM2882_BOARD_EVGA_INDTUBE:
698f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb->fe[0] = dvb_attach(s5h1409_attach,
6996e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora					   &em28xx_s5h1409_with_xc3028,
7006e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora					   &dev->i2c_adap);
701f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson		if (em28xx_attach_xc3028(0x61, dev) < 0) {
7026e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora			result = -EINVAL;
7036e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora			goto out_free;
7046e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		}
7056e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		break;
706d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng	case EM2882_BOARD_KWORLD_ATSC_315U:
707f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb->fe[0] = dvb_attach(lgdt330x_attach,
708d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng					   &em2880_lgdt3303_dev,
709d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng					   &dev->i2c_adap);
710f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		if (dvb->fe[0] != NULL) {
711f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari			if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
712d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng				&dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) {
713d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng				result = -EINVAL;
714d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng				goto out_free;
715d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng			}
716d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng		}
717d7de5d8ff74efd01916b01af875a0e87419a3599Franklin Meng		break;
71817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
719ad9b4bb265cecbfc9b0c495741e331ce199964e0Devin Heitmueller	case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
720f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL,
72175e2b8694f0b1f8faea1851a39cb7ba07640aa7dDevin Heitmueller					   &dev->i2c_adap, &dev->udev->dev);
722f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson		if (em28xx_attach_xc3028(0x61, dev) < 0) {
72317d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller			result = -EINVAL;
72417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller			goto out_free;
72517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		}
72617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		break;
727285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari	case EM2870_BOARD_REDDO_DVB_C_USB_BOX:
728285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari		/* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
729f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb->fe[0] = dvb_attach(tda10023_attach,
730285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari			&em28xx_tda10023_config,
731285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari			&dev->i2c_adap, 0x48);
732f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		if (dvb->fe[0]) {
733f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari			if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
734285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari				&dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) {
735285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari				result = -EINVAL;
736285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari				goto out_free;
737285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari			}
738285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari		}
739285eb1a40242adb3feaf9c73d352cbfeee1bea1cAntti Palosaari		break;
7407e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson	case EM2870_BOARD_KWORLD_A340:
741f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		dvb->fe[0] = dvb_attach(lgdt3305_attach,
7427e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson					   &em2870_lgdt3304_dev,
7437e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson					   &dev->i2c_adap);
744f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari		if (dvb->fe[0] != NULL)
745f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari			dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
7467e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson				   &dev->i2c_adap, &kworld_a340_config);
7477e48b30af033076c85ab48a8306b5588faf5fb4bJarod Wilson		break;
748d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari	case EM28174_BOARD_PCTV_290E:
749d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari		/* MFE
750d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari		 * FE 0 = DVB-T/T2 + FE 1 = DVB-C, both sharing same tuner. */
751d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari		/* FE 0 */
752d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari		dvb->fe[0] = dvb_attach(cxd2820r_attach,
753d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari			&em28xx_cxd2820r_config, &dev->i2c_adap, NULL);
754d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari		if (dvb->fe[0]) {
755d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari			/* FE 0 attach tuner */
756d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari			if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
7570db4bf42baae95ddd457b0c4911e851c9169750eSteve Kerrison				&dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) {
758d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari				dvb_frontend_detach(dvb->fe[0]);
759d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari				result = -EINVAL;
760d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari				goto out_free;
761d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari			}
762d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari			/* FE 1. This dvb_attach() cannot fail. */
763d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari			dvb->fe[1] = dvb_attach(cxd2820r_attach, NULL, NULL,
764d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari				dvb->fe[0]);
765d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari			dvb->fe[1]->id = 1;
766d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari			/* FE 1 attach tuner */
767d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari			if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60,
7680db4bf42baae95ddd457b0c4911e851c9169750eSteve Kerrison				&dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) {
769d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari				dvb_frontend_detach(dvb->fe[1]);
770d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari				/* leave FE 0 still active */
771d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari			}
772e36454376a8f4637c0767daa78cf1d96d162d71aAntti Palosaari
773e36454376a8f4637c0767daa78cf1d96d162d71aAntti Palosaari			mfe_shared = 1;
774d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari		}
775d6a5f921fb8cbd418b298e5bbe83e5c8c8e1da16Antti Palosaari		break;
776fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab	case EM2884_BOARD_TERRATEC_H5:
777fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		terratec_h5_init(dev);
778fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab
779c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab		dvb->dont_attach_fe1 = 1;
780c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab
781fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap, &dvb->fe[1]);
782c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab		if (!dvb->fe[0]) {
783fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab			result = -EINVAL;
784fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab			goto out_free;
785fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		}
786c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab
787fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		/* FIXME: do we need a pll semaphore? */
788fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		dvb->fe[0]->sec_priv = dvb;
789fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		sema_init(&dvb->pll_mutex, 1);
790fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
791fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
792fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		dvb->fe[1]->id = 1;
793fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab
794c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab		/* Attach tda18271 to DVB-C frontend */
795fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		if (dvb->fe[0]->ops.i2c_gate_ctrl)
796fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
797fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap, 0x60)) {
798fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab			result = -EINVAL;
799fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab			goto out_free;
800fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		}
801fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		if (dvb->fe[0]->ops.i2c_gate_ctrl)
802fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
803c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab
804c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab		/* Hack - needed by drxk/tda18271c2dd */
805c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab		dvb->fe[1]->tuner_priv = dvb->fe[0]->tuner_priv;
806c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab		memcpy(&dvb->fe[1]->ops.tuner_ops,
807c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab		       &dvb->fe[0]->ops.tuner_ops,
808c4c3a3d32a2eac18dba04683bb5b7357402405c7Mauro Carvalho Chehab		       sizeof(dvb->fe[0]->ops.tuner_ops));
809fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab
810fec528b77f9be3e7ebb8d7c25888b0cf9fb8e8d6Mauro Carvalho Chehab		break;
8113aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	default:
812480be1851aebcb0b9c5b0fb9acefe5da97cc702aFilipe Rosset		em28xx_errdev("/2: The frontend of your DVB/ATSC card"
813480be1851aebcb0b9c5b0fb9acefe5da97cc702aFilipe Rosset				" isn't supported yet\n");
8143aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		break;
8153aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
816f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	if (NULL == dvb->fe[0]) {
817480be1851aebcb0b9c5b0fb9acefe5da97cc702aFilipe Rosset		em28xx_errdev("/2: frontend initialization failed\n");
8183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		result = -EINVAL;
8193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto out_free;
8203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
821d7cba043d7ec840d67bd5143779d1febe7d83407Michael Krufky	/* define general-purpose callback pointer */
822f71095be6645aee0828623701e35e7e7d52910d8Antti Palosaari	dvb->fe[0]->callback = em28xx_tuner_callback;
8233aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
8243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	/* register everything */
825f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson	result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
8263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
8276ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (result < 0)
8283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto out_free;
8293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
830e36454376a8f4637c0767daa78cf1d96d162d71aAntti Palosaari	/* MFE lock */
831e36454376a8f4637c0767daa78cf1d96d162d71aAntti Palosaari	dvb->adapter.mfe_shared = mfe_shared;
832e36454376a8f4637c0767daa78cf1d96d162d71aAntti Palosaari
833480be1851aebcb0b9c5b0fb9acefe5da97cc702aFilipe Rosset	em28xx_info("Successfully loaded em28xx-dvb\n");
8345013318ca4fd22e30fd891f234b60daa3ca2f62dMauro Carvalho Chehabret:
8355013318ca4fd22e30fd891f234b60daa3ca2f62dMauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_SUSPEND);
8365013318ca4fd22e30fd891f234b60daa3ca2f62dMauro Carvalho Chehab	mutex_unlock(&dev->lock);
8375013318ca4fd22e30fd891f234b60daa3ca2f62dMauro Carvalho Chehab	return result;
8383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
8393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonout_free:
8403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	kfree(dvb);
8413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dev->dvb = NULL;
8425013318ca4fd22e30fd891f234b60daa3ca2f62dMauro Carvalho Chehab	goto ret;
8433aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
8443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
8450b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankinstatic inline void prevent_sleep(struct dvb_frontend_ops *ops)
8460b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin{
8470b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin	ops->set_voltage = NULL;
8480b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin	ops->sleep = NULL;
8490b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin	ops->tuner_ops.sleep = NULL;
8500b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin}
8510b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin
852f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilsonstatic int em28xx_dvb_fini(struct em28xx *dev)
8533aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
854505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab	if (!dev->board.has_dvb) {
855df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		/* This device does not support the extension */
856df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		return 0;
857df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	}
858df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller
8593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (dev->dvb) {
8600b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin		struct em28xx_dvb *dvb = dev->dvb;
8610b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin
8620b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin		if (dev->state & DEV_DISCONNECTED) {
8630b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin			/* We cannot tell the device to sleep
8640b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin			 * once it has been unplugged. */
8650b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin			if (dvb->fe[0])
8660b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin				prevent_sleep(&dvb->fe[0]->ops);
8670b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin			if (dvb->fe[1])
8680b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin				prevent_sleep(&dvb->fe[1]->ops);
8690b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin		}
8700b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin
8710b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin		em28xx_unregister_dvb(dvb);
8720b8bd83cf393832f1d00096b866d888b75b374c3Chris Rankin		kfree(dvb);
8733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dev->dvb = NULL;
8743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
8753aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
8763aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
8773aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
8783aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
8793aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic struct em28xx_ops dvb_ops = {
8803aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.id   = EM28XX_DVB,
8813aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.name = "Em28xx dvb Extension",
882f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson	.init = em28xx_dvb_init,
883f2d0c1c625bc79aa524b52eea2de4262a9be1d90Jarod Wilson	.fini = em28xx_dvb_fini,
8843aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab};
8853aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
8863aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int __init em28xx_dvb_register(void)
8873aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
8883aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return em28xx_register_extension(&dvb_ops);
8893aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
8903aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
8913aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic void __exit em28xx_dvb_unregister(void)
8923aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
8933aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	em28xx_unregister_extension(&dvb_ops);
8943aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
8953aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
8963aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_init(em28xx_dvb_register);
8973aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_exit(em28xx_dvb_unregister);
898