em28xx-dvb.c revision e14b3658a7651ffd9b1f407eaf07f4dde17ef1e7
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>
283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
293aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#include "lgdt330x.h"
307e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton#include "zl10353.h"
3117d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#ifdef EM28XX_DRX397XD_SUPPORT
3217d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#include "drx397xD.h"
3317d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#endif
343aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
353aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_DESCRIPTION("driver for em28xx based DVB cards");
363aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
373aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_LICENSE("GPL");
383aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
393aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic unsigned int debug;
403aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_param(debug, int, 0644);
413aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_PARM_DESC(debug, "enable debug messages [dvb]");
423aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
433aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
453aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#define dprintk(level, fmt, arg...) do {			\
463aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabif (debug >= level) 						\
473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg);	\
483aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab} while (0)
493aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton#define EM28XX_DVB_NUM_BUFS 5
513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton#define EM28XX_DVB_MAX_PACKETSIZE 564
523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton#define EM28XX_DVB_MAX_PACKETS 64
533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstruct em28xx_dvb {
553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_frontend        *frontend;
563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* feed count management */
583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct mutex               lock;
593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int                        nfeeds;
603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* general boilerplate stuff */
623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_adapter         adapter;
633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_demux           demux;
643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmxdev              dmxdev;
653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmx_frontend        fe_hw;
663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmx_frontend        fe_mem;
673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_net             net;
683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton};
693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic inline void print_err_status(struct em28xx *dev,
723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				     int packet, int status)
733aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	char *errmsg = "Unknown";
753aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	switch (status) {
773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ENOENT:
783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "unlinked synchronuously";
793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ECONNRESET:
813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "unlinked asynchronuously";
823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ENOSR:
843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Buffer error (overrun)";
853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EPIPE:
873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Stalled (device not responding)";
883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EOVERFLOW:
903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Babble (bad cable?)";
913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EPROTO:
933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Bit-stuff error (bad cable?)";
943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EILSEQ:
963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "CRC/Timeout (could be anything)";
973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ETIME:
993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Device does not respond";
1003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
1013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (packet < 0) {
1033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dprintk(1, "URB status %d [%s].\n", status, errmsg);
1043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	} else {
1056ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		dprintk(1, "URB packet %d, status %d [%s].\n",
1066ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf			packet, status, errmsg);
1073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1093aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
1113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int i;
1133aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!dev)
1153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return 0;
1163aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
1183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return 0;
1193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (urb->status < 0) {
1213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		print_err_status(dev, -1, urb->status);
1223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (urb->status == -ENOENT)
1233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			return 0;
1243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	for (i = 0; i < urb->number_of_packets; i++) {
1273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		int status = urb->iso_frame_desc[i].status;
1283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (status < 0) {
1303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			print_err_status(dev, i, status);
1313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			if (urb->iso_frame_desc[i].status != -EPROTO)
1323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				continue;
1333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
1343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
1363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				 urb->iso_frame_desc[i].offset,
1373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				 urb->iso_frame_desc[i].actual_length);
1383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
1413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1423421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1436ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafstatic int start_streaming(struct em28xx_dvb *dvb)
1446ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf{
145c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	int rc;
1463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx *dev = dvb->adapter.priv;
1473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	usb_set_interface(dev->udev, 0, 1);
149c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
150c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	if (rc < 0)
151c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab		return rc;
1523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
1543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE,
155c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab				dvb_isoc_copy);
1563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1586ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafstatic int stop_streaming(struct em28xx_dvb *dvb)
1596ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf{
1603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx *dev = dvb->adapter.priv;
1613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	em28xx_uninit_isoc(dev);
163c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab
164c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
165c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab
1663aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
1673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
1683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic int start_feed(struct dvb_demux_feed *feed)
1703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_demux *demux  = feed->demux;
1723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx_dvb *dvb = demux->priv;
1733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int rc, ret;
1743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!demux->dmx.frontend)
1763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return -EINVAL;
1773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_lock(&dvb->lock);
1793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->nfeeds++;
1803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	rc = dvb->nfeeds;
1813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (dvb->nfeeds == 1) {
1833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		ret = start_streaming(dvb);
1846ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		if (ret < 0)
1856ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf			rc = ret;
1863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_unlock(&dvb->lock);
1893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return rc;
1903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic int stop_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 err = 0;
1973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_lock(&dvb->lock);
1993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->nfeeds--;
2006ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
2016ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (0 == dvb->nfeeds)
2023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		err = stop_streaming(dvb);
2036ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
2043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_unlock(&dvb->lock);
2053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return err;
2063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
2073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
209e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
210e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
211e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehabstatic int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
212e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab{
213e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	struct em28xx *dev = fe->dvb->priv;
214e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
215e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	if (acquire)
216e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
217e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	else
218e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab		return em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
219e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab}
220e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
2213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
2223aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
223227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehabstatic struct lgdt330x_config em2880_lgdt3303_dev = {
224227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab	.demod_address = 0x0e,
225227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab	.demod_chip = LGDT3303,
226227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab};
2273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2287e6388a1b97cca57a1906df6104feb4001721576Aidan Thorntonstatic struct zl10353_config em28xx_zl10353_with_xc3028 = {
2297e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.demod_address = (0x1e >> 1),
2307e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.no_tuner = 1,
2317e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.parallel_ts = 1,
2327e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	.if2 = 45600,
2337e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton};
2347e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton
23517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#ifdef EM28XX_DRX397XD_SUPPORT
23617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller/* [TODO] djh - not sure yet what the device config needs to contain */
23717d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmuellerstatic struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
23817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	.demod_address = (0xe0 >> 1),
23917d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller};
24017d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#endif
24117d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller
2423aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
2433aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int attach_xc3028(u8 addr, struct em28xx *dev)
2453aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
2463aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	struct dvb_frontend *fe;
2473ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	struct xc2028_config cfg;
2483ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab
2496ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	memset(&cfg, 0, sizeof(cfg));
2503ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	cfg.i2c_adap  = &dev->i2c_adap;
2513ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	cfg.i2c_addr  = addr;
2523ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	cfg.callback  = em28xx_tuner_callback;
2533ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab
2543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!dev->dvb->frontend) {
2553aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR "%s/2: dvb frontend not attached. "
2563aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab				"Can't attach xc3028\n",
2573aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
2583aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		return -EINVAL;
2593aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
2603aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg);
2623aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	if (!fe) {
2633aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR "%s/2: xc3028 attach failed\n",
2643aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
2653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb_frontend_detach(dev->dvb->frontend);
2663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dev->dvb->frontend = NULL;
2673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		return -EINVAL;
2683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
2693aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	printk(KERN_INFO "%s/2: xc3028 attached\n", dev->name);
2713aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
2733aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
2743aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* ------------------------------------------------------------------ */
2763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
2773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonint register_dvb(struct em28xx_dvb *dvb,
2783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		 struct module *module,
2793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		 struct em28xx *dev,
2803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		 struct device *device)
2813aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
2823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int result;
2833aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_init(&dvb->lock);
2853aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register adapter */
2873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
2883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				      adapter_nr);
2893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
2903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
2913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
2923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_adapter;
2933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
294e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
295e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	/* Ensure all frontends negotiate bus access */
296e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
297e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
2983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->adapter.priv = dev;
2993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register frontend */
3013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
3023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
3043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_frontend;
3063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register demux stuff */
3093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.capabilities =
3103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
3113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		DMX_MEMORY_BASED_FILTERING;
3123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.priv       = dvb;
3133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.filternum  = 256;
3143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.feednum    = 256;
3153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.start_feed = start_feed;
3163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.stop_feed  = stop_feed;
317e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
3183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_dmx_init(&dvb->demux);
3193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
3213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_dmx;
3233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.filternum    = 256;
3263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.demux        = &dvb->demux.dmx;
3273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.capabilities = 0;
3283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
3293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
3313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_dmxdev;
3333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
33452284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab
3353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->fe_hw.source = DMX_FRONTEND_0;
3363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
3393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_hw;
3413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3423421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->fe_mem.source = DMX_MEMORY_FE;
3443421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
3453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
3473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_mem;
3493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
3543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_conn;
3563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register network adapter */
3593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
3603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
3613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_conn:
3633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
3643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_mem:
3653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_hw:
3673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmxdev_release(&dvb->dmxdev);
3683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_dmxdev:
3693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmx_release(&dvb->demux);
3703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_dmx:
3713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_frontend(dvb->frontend);
3723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_frontend:
3733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_frontend_detach(dvb->frontend);
3743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_adapter(&dvb->adapter);
3753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_adapter:
3763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return result;
3773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
3783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic void unregister_dvb(struct em28xx_dvb *dvb)
3803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
3813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_net_release(&dvb->net);
3823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
3833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmxdev_release(&dvb->dmxdev);
3853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmx_release(&dvb->demux);
3863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_frontend(dvb->frontend);
3873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_frontend_detach(dvb->frontend);
3883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_adapter(&dvb->adapter);
3893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
3903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic int dvb_init(struct em28xx *dev)
3933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
3943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int result = 0;
3953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx_dvb *dvb;
3963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
397df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	if (!dev->has_dvb) {
398df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		/* This device does not support the extension */
399df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		return 0;
400df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	}
401df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller
4023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
4036ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
4046ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (dvb == NULL) {
4056ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		printk(KERN_INFO "em28xx_dvb: memory allocation failed\n");
4063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return -ENOMEM;
4073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
4083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dev->dvb = dvb;
4093aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
410c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
4113aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	/* init frontend */
4123aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	switch (dev->model) {
413227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
4144fd305b2a2c4d16e8d4ebc95c84f946edd3385c5Devin Heitmueller	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
415e14b3658a7651ffd9b1f407eaf07f4dde17ef1e7Devin Heitmueller	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
4163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb->frontend = dvb_attach(lgdt330x_attach,
4173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &em2880_lgdt3303_dev,
4183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &dev->i2c_adap);
4193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (attach_xc3028(0x61, dev) < 0) {
4203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			result = -EINVAL;
4213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			goto out_free;
4223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
423227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab		break;
4247e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
4253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb->frontend = dvb_attach(zl10353_attach,
4263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &em28xx_zl10353_with_xc3028,
4273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &dev->i2c_adap);
4283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (attach_xc3028(0x61, dev) < 0) {
4293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			result = -EINVAL;
4303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			goto out_free;
4313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
4327e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton		break;
43317d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
43417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#ifdef EM28XX_DRX397XD_SUPPORT
43517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		/* We don't have the config structure properly populated, so
43617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		   this is commented out for now */
43717d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		dvb->frontend = dvb_attach(drx397xD_attach,
43817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller					   &em28xx_drx397xD_with_xc3028,
43917d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller					   &dev->i2c_adap);
44017d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		if (attach_xc3028(0x61, dev) < 0) {
44117d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller			result = -EINVAL;
44217d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller			goto out_free;
44317d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		}
44417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		break;
44517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#endif
446655b8408557d586212d0797d423babdc464c587freinhard schwab	case EM2880_BOARD_TERRATEC_HYBRID_XS:
447655b8408557d586212d0797d423babdc464c587freinhard schwab		dvb->frontend = dvb_attach(zl10353_attach,
448655b8408557d586212d0797d423babdc464c587freinhard schwab						&em28xx_zl10353_with_xc3028,
449655b8408557d586212d0797d423babdc464c587freinhard schwab						&dev->i2c_adap);
450655b8408557d586212d0797d423babdc464c587freinhard schwab		if (attach_xc3028(0x61, dev) < 0) {
451655b8408557d586212d0797d423babdc464c587freinhard schwab			 result = -EINVAL;
452655b8408557d586212d0797d423babdc464c587freinhard schwab			goto out_free;
453655b8408557d586212d0797d423babdc464c587freinhard schwab		}
454655b8408557d586212d0797d423babdc464c587freinhard schwab		break;
4553aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	default:
4563aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
4573aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab				" isn't supported yet\n",
4583aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
4593aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		break;
4603aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
4613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (NULL == dvb->frontend) {
4623aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR
4633aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       "%s/2: frontend initialization failed\n",
4643aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
4653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		result = -EINVAL;
4663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto out_free;
4673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
4683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4693aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	/* register everything */
4703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
4713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4726ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (result < 0)
4733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto out_free;
4743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
475c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
476102a0b0879a01a413ed5f667f7db9c2085ca8474Mauro Carvalho Chehab	printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
4773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
4783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonout_free:
480c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
4813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	kfree(dvb);
4823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dev->dvb = NULL;
4833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return result;
4843aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
4853aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4863aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int dvb_fini(struct em28xx *dev)
4873aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
488df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	if (!dev->has_dvb) {
489df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		/* This device does not support the extension */
490df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		return 0;
491df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	}
492df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller
4933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (dev->dvb) {
4943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		unregister_dvb(dev->dvb);
4953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dev->dvb = NULL;
4963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
4973aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4983aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
4993aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
5003aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5013aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic struct em28xx_ops dvb_ops = {
5023aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.id   = EM28XX_DVB,
5033aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.name = "Em28xx dvb Extension",
5043aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.init = dvb_init,
5053aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.fini = dvb_fini,
5063aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab};
5073aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5083aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int __init em28xx_dvb_register(void)
5093aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
5103aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return em28xx_register_extension(&dvb_ops);
5113aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
5123aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5133aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic void __exit em28xx_dvb_unregister(void)
5143aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
5153aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	em28xx_unregister_extension(&dvb_ops);
5163aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
5173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5183aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_init(em28xx_dvb_register);
5193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_exit(em28xx_dvb_unregister);
520