em28xx-dvb.c revision d18e2fda7133287bf8a81809816e646cf17c332e
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"
316e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora#include "s5h1409.h"
323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
333aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_DESCRIPTION("driver for em28xx based DVB cards");
343aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
353aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_LICENSE("GPL");
363aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
373aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic unsigned int debug;
383aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_param(debug, int, 0644);
393aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabMODULE_PARM_DESC(debug, "enable debug messages [dvb]");
403aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
413aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho ChehabDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
423aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
433aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab#define dprintk(level, fmt, arg...) do {			\
443aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabif (debug >= level) 						\
453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg);	\
463aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab} while (0)
473aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton#define EM28XX_DVB_NUM_BUFS 5
493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton#define EM28XX_DVB_MAX_PACKETS 64
503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstruct em28xx_dvb {
523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_frontend        *frontend;
533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* feed count management */
553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct mutex               lock;
563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int                        nfeeds;
573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* general boilerplate stuff */
593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_adapter         adapter;
603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_demux           demux;
613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmxdev              dmxdev;
623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmx_frontend        fe_hw;
633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dmx_frontend        fe_mem;
643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct dvb_net             net;
653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton};
663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic inline void print_err_status(struct em28xx *dev,
693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				     int packet, int status)
703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	char *errmsg = "Unknown";
723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	switch (status) {
743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ENOENT:
753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "unlinked synchronuously";
763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ECONNRESET:
783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "unlinked asynchronuously";
793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ENOSR:
813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Buffer error (overrun)";
823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EPIPE:
843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Stalled (device not responding)";
853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EOVERFLOW:
873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Babble (bad cable?)";
883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EPROTO:
903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Bit-stuff error (bad cable?)";
913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -EILSEQ:
933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "CRC/Timeout (could be anything)";
943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	case -ETIME:
963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		errmsg = "Device does not respond";
973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		break;
983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (packet < 0) {
1003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dprintk(1, "URB status %d [%s].\n", status, errmsg);
1013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	} else {
1026ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		dprintk(1, "URB packet %d, status %d [%s].\n",
1036ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf			packet, status, errmsg);
1043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1053421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1063aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
1083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
1093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int i;
1103aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!dev)
1123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return 0;
1133aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
1143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
1153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return 0;
1163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (urb->status < 0) {
1183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		print_err_status(dev, -1, urb->status);
1193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (urb->status == -ENOENT)
1203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			return 0;
1213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	for (i = 0; i < urb->number_of_packets; i++) {
1243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		int status = urb->iso_frame_desc[i].status;
1253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (status < 0) {
1273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			print_err_status(dev, i, status);
1283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			if (urb->iso_frame_desc[i].status != -EPROTO)
1293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				continue;
1303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
1313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
1333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				 urb->iso_frame_desc[i].offset,
1343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				 urb->iso_frame_desc[i].actual_length);
1353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
1363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
1383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
1393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1406ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgrafstatic int start_streaming(struct em28xx_dvb *dvb)
1416ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf{
142c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	int rc;
1433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx *dev = dvb->adapter.priv;
144d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller	int max_dvb_packet_size;
1453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
1463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	usb_set_interface(dev->udev, 0, 1);
147c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
148c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	if (rc < 0)
149c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab		return rc;
1503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
151d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller	max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev);
152d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller
1533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
154d18e2fda7133287bf8a81809816e646cf17c332eDevin Heitmueller				EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
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
1642fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_SUSPEND);
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
2182fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab		return em28xx_set_mode(dev, EM28XX_SUSPEND);
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
2356e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakorastatic struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
2366e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.demod_address = 0x32 >> 1,
2376e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.output_mode   = S5H1409_PARALLEL_OUTPUT,
2386e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.gpio          = S5H1409_GPIO_OFF,
2396e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.inversion     = S5H1409_INVERSION_OFF,
2406e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.status_mode   = S5H1409_DEMODLOCKING,
2416e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
2426e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora};
2436e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora
24417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#ifdef EM28XX_DRX397XD_SUPPORT
24517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller/* [TODO] djh - not sure yet what the device config needs to contain */
24617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmuellerstatic struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
24717d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	.demod_address = (0xe0 >> 1),
24817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller};
24917d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#endif
25017d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller
2513aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab/* ------------------------------------------------------------------ */
2523aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2533aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int attach_xc3028(u8 addr, struct em28xx *dev)
2543aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
2553aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	struct dvb_frontend *fe;
2563ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	struct xc2028_config cfg;
2573ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab
2586ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	memset(&cfg, 0, sizeof(cfg));
2593ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	cfg.i2c_adap  = &dev->i2c_adap;
2603ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab	cfg.i2c_addr  = addr;
2613ca9c09379e8f3be0744c47f72769457fa46e9f3Mauro Carvalho Chehab
2623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (!dev->dvb->frontend) {
2633aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR "%s/2: dvb frontend not attached. "
2643aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab				"Can't attach xc3028\n",
2653aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
2663aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		return -EINVAL;
2673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
2683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg);
2703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	if (!fe) {
2713aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR "%s/2: xc3028 attach failed\n",
2723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
2733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb_frontend_detach(dev->dvb->frontend);
2743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dev->dvb->frontend = NULL;
2753aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		return -EINVAL;
2763aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
2773aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2783aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	printk(KERN_INFO "%s/2: xc3028 attached\n", dev->name);
2793aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2803aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
2813aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
2823aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton/* ------------------------------------------------------------------ */
2843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
285d45b9b8ab43c8973a9630ac54f4ede6c3e009f9eHans Verkuilstatic int register_dvb(struct em28xx_dvb *dvb,
2863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		 struct module *module,
2873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		 struct em28xx *dev,
2883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		 struct device *device)
2893aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
2903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int result;
2913aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	mutex_init(&dvb->lock);
2933aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
2943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register adapter */
2953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
2963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton				      adapter_nr);
2973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
2983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
2993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_adapter;
3013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
302e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
303e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	/* Ensure all frontends negotiate bus access */
304e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab	dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
305e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
3063421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->adapter.priv = dev;
3073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register frontend */
3093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
3103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3113421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
3123421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3133421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_frontend;
3143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register demux stuff */
3173421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.capabilities =
3183421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
3193421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		DMX_MEMORY_BASED_FILTERING;
3203421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.priv       = dvb;
3213421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.filternum  = 256;
3223421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.feednum    = 256;
3233421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.start_feed = start_feed;
3243421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.stop_feed  = stop_feed;
325e3569abc1c51d24f9c64b214f85477e490b156e3Mauro Carvalho Chehab
3263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_dmx_init(&dvb->demux);
3273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
3293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_dmx;
3313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3323421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3333421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.filternum    = 256;
3343421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.demux        = &dvb->demux.dmx;
3353421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->dmxdev.capabilities = 0;
3363421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
3373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
3393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_dmxdev;
3413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
34252284c3e47bf502aaff72ab2ede509193b628b1bMauro Carvalho Chehab
3433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->fe_hw.source = DMX_FRONTEND_0;
3443421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3453421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3463421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
3473421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3483421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_hw;
3493421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3503421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3513421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->fe_mem.source = DMX_MEMORY_FE;
3523421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
3533421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3543421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
3553421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3563421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_mem;
3573421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3583421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3593421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3603421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (result < 0) {
3613421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
3623421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		       dev->name, result);
3633421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto fail_fe_conn;
3643421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
3653421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3663421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	/* register network adapter */
3673421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
3683421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
3693421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3703421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_conn:
3713421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
3723421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_mem:
3733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3743421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_fe_hw:
3753421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmxdev_release(&dvb->dmxdev);
3763421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_dmxdev:
3773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmx_release(&dvb->demux);
3783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_dmx:
3793421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_frontend(dvb->frontend);
3803421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_frontend:
3813421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_frontend_detach(dvb->frontend);
3823421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_adapter(&dvb->adapter);
3833421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonfail_adapter:
3843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return result;
3853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
3863421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic void unregister_dvb(struct em28xx_dvb *dvb)
3883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
3893421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_net_release(&dvb->net);
3903421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
3913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
3923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmxdev_release(&dvb->dmxdev);
3933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_dmx_release(&dvb->demux);
3943421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_frontend(dvb->frontend);
3953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_frontend_detach(dvb->frontend);
3963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb_unregister_adapter(&dvb->adapter);
3973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton}
3983421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
3993421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4003421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonstatic int dvb_init(struct em28xx *dev)
4013421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton{
4023421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	int result = 0;
4033421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	struct em28xx_dvb *dvb;
4043421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
405505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab	if (!dev->board.has_dvb) {
406df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		/* This device does not support the extension */
407df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		return 0;
408df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	}
409df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller
4103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
4116ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf
4126ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (dvb == NULL) {
4136ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf		printk(KERN_INFO "em28xx_dvb: memory allocation failed\n");
4143421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		return -ENOMEM;
4153421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
4163421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dev->dvb = dvb;
4173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
418c67ec53f8f4e90ebd482789e2f6d121f41a0bd90Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
4193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	/* init frontend */
4203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	switch (dev->model) {
421f89bc32974a4376e8393001484af28d8c3350ab4Douglas Schilling Landgraf	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
42210ac6603613d46a43a4544fbbe9581e50879bd45Mauro Carvalho Chehab	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
4234fd305b2a2c4d16e8d4ebc95c84f946edd3385c5Devin Heitmueller	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
424e14b3658a7651ffd9b1f407eaf07f4dde17ef1e7Devin Heitmueller	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
4253421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb->frontend = dvb_attach(lgdt330x_attach,
4263421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &em2880_lgdt3303_dev,
4273421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &dev->i2c_adap);
4283421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (attach_xc3028(0x61, dev) < 0) {
4293421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			result = -EINVAL;
4303421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			goto out_free;
4313421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
432227ad4ab9058ef2624934183e8083886cf64bf56Mauro Carvalho Chehab		break;
4337e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
43446510b56ca56a25ce973d6a6e8490c1109ff94efThierry MERLE	case EM2880_BOARD_TERRATEC_HYBRID_XS:
43546510b56ca56a25ce973d6a6e8490c1109ff94efThierry MERLE	case EM2880_BOARD_KWORLD_DVB_310U:
436e5db5d44432abc82b1250dd05bd0a4b011392d9dDouglas Schilling Landgraf	case EM2880_BOARD_EMPIRE_DUAL_TV:
4373421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dvb->frontend = dvb_attach(zl10353_attach,
4383421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &em28xx_zl10353_with_xc3028,
4393421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton					   &dev->i2c_adap);
4403421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		if (attach_xc3028(0x61, dev) < 0) {
4413421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			result = -EINVAL;
4423421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton			goto out_free;
4433421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		}
4447e6388a1b97cca57a1906df6104feb4001721576Aidan Thornton		break;
4456e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora	case EM2883_BOARD_KWORLD_HYBRID_330U:
4466e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		dvb->frontend = dvb_attach(s5h1409_attach,
4476e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora					   &em28xx_s5h1409_with_xc3028,
4486e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora					   &dev->i2c_adap);
4496e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		if (attach_xc3028(0x61, dev) < 0) {
4506e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora			result = -EINVAL;
4516e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora			goto out_free;
4526e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		}
4536e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1Robert Krakora		break;
45417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
45517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#ifdef EM28XX_DRX397XD_SUPPORT
45617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		/* We don't have the config structure properly populated, so
45717d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		   this is commented out for now */
45817d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		dvb->frontend = dvb_attach(drx397xD_attach,
45917d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller					   &em28xx_drx397xD_with_xc3028,
46017d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller					   &dev->i2c_adap);
46117d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		if (attach_xc3028(0x61, dev) < 0) {
46217d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller			result = -EINVAL;
46317d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller			goto out_free;
46417d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		}
46517d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller		break;
46617d9d558e818530cc7d210ffea575a36f48eaa1aDevin Heitmueller#endif
4673aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	default:
4683aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
4693aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab				" isn't supported yet\n",
4703aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
4713aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		break;
4723aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
4733421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (NULL == dvb->frontend) {
4743aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		printk(KERN_ERR
4753aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       "%s/2: frontend initialization failed\n",
4763aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab		       dev->name);
4773421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		result = -EINVAL;
4783421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto out_free;
4793aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	}
480d7cba043d7ec840d67bd5143779d1febe7d83407Michael Krufky	/* define general-purpose callback pointer */
481d7cba043d7ec840d67bd5143779d1febe7d83407Michael Krufky	dvb->frontend->callback = em28xx_tuner_callback;
4823aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
4833aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	/* register everything */
4843421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
4853421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4866ea54d938b6f81baa0952a8b15d3e67e6c268b8fDouglas Schilling Landgraf	if (result < 0)
4873421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		goto out_free;
4883421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4892fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_SUSPEND);
490102a0b0879a01a413ed5f667f7db9c2085ca8474Mauro Carvalho Chehab	printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
4913421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return 0;
4923421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton
4933421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thorntonout_free:
4942fe3e2ee72ef17daad1d3769321bb7dd69a003a9Mauro Carvalho Chehab	em28xx_set_mode(dev, EM28XX_SUSPEND);
4953421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	kfree(dvb);
4963421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	dev->dvb = NULL;
4973421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	return result;
4983aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
4993aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5003aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int dvb_fini(struct em28xx *dev)
5013aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
502505b6d0b774fa4475fedbd3cebf95199c17a0086Mauro Carvalho Chehab	if (!dev->board.has_dvb) {
503df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		/* This device does not support the extension */
504df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller		return 0;
505df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller	}
506df619181631217e3166bb6c7538f981e0272617fDevin Heitmueller
5073421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	if (dev->dvb) {
5083421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		unregister_dvb(dev->dvb);
5093421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton		dev->dvb = NULL;
5103421b7787a2cf41ac5edce9b5766bddd1e1d9986Aidan Thornton	}
5113aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5123aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return 0;
5133aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
5143aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5153aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic struct em28xx_ops dvb_ops = {
5163aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.id   = EM28XX_DVB,
5173aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.name = "Em28xx dvb Extension",
5183aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.init = dvb_init,
5193aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	.fini = dvb_fini,
5203aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab};
5213aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5223aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic int __init em28xx_dvb_register(void)
5233aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
5243aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	return em28xx_register_extension(&dvb_ops);
5253aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
5263aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5273aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabstatic void __exit em28xx_dvb_unregister(void)
5283aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab{
5293aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab	em28xx_unregister_extension(&dvb_ops);
5303aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab}
5313aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehab
5323aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_init(em28xx_dvb_register);
5333aefb79af8d41c85e11da7109d62038849421bb6Mauro Carvalho Chehabmodule_exit(em28xx_dvb_unregister);
534