From 1a23f81b7dc3115b29cff0e4f58b5dd04a6242ad Mon Sep 17 00:00:00 2001
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Date: Sun, 28 Dec 2008 22:18:14 -0300
Subject: [PATCH] V4L/DVB (9979): em28xx: move usb probe code to a proper place

em28xx-video were holding several code that are not specific to V4L2
interface.

This patch moves the core code for em28xx-core, and usb probing code
into em28xx-cards.

This opens the possibility of breaking em28xx into a core module and a
V4L2 module, loaded only on devices that have analog interfaces.

Some cleanup may be done at em28xx-cards to optimize the config code.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
---
 drivers/media/video/em28xx/em28xx-cards.c | 430 +++++++++++++++
 drivers/media/video/em28xx/em28xx-core.c  | 143 +++++
 drivers/media/video/em28xx/em28xx-video.c | 619 ++--------------------
 drivers/media/video/em28xx/em28xx.h       |  16 +-
 4 files changed, 633 insertions(+), 575 deletions(-)

diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index e5d9424d03f9..42978f9592b7 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -37,6 +37,8 @@
 
 #include "em28xx.h"
 
+#define DRIVER_NAME         "em28xx"
+
 static int tuner = -1;
 module_param(tuner, int, 0444);
 MODULE_PARM_DESC(tuner, "tuner type");
@@ -45,6 +47,13 @@ static unsigned int disable_ir;
 module_param(disable_ir, int, 0444);
 MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
 
+static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+module_param_array(card,  int, NULL, 0444);
+MODULE_PARM_DESC(card,     "card type");
+
+/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
+static unsigned long em28xx_devused;
+
 struct em28xx_hash_table {
 	unsigned long hash;
 	unsigned int  model;
@@ -1801,3 +1810,424 @@ void em28xx_card_setup(struct em28xx *dev)
 	em28xx_ir_init(dev);
 }
 
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+	struct em28xx *dev = container_of(work,
+			     struct em28xx, request_module_wk);
+
+	if (dev->has_audio_class)
+		request_module("snd-usb-audio");
+	else if (dev->has_alsa_audio)
+		request_module("em28xx-alsa");
+
+	if (dev->board.has_dvb)
+		request_module("em28xx-dvb");
+}
+
+static void request_modules(struct em28xx *dev)
+{
+	INIT_WORK(&dev->request_module_wk, request_module_async);
+	schedule_work(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#endif /* CONFIG_MODULES */
+
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void em28xx_release_resources(struct em28xx *dev)
+{
+	if (dev->sbutton_input_dev)
+		em28xx_deregister_snapshot_button(dev);
+
+	if (dev->ir)
+		em28xx_ir_fini(dev);
+
+	/*FIXME: I2C IR should be disconnected */
+
+	em28xx_release_analog_resources(dev);
+
+	em28xx_remove_from_devlist(dev);
+
+	em28xx_i2c_unregister(dev);
+	usb_put_dev(dev->udev);
+
+	/* Mark device as unused */
+	em28xx_devused &= ~(1 << dev->devno);
+};
+
+/*
+ * em28xx_init_dev()
+ * allocates and inits the device structs, registers i2c bus and v4l device
+ */
+int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+			   int minor)
+{
+	struct em28xx *dev = *devhandle;
+	int retval = -ENOMEM;
+	int errCode;
+
+	dev->udev = udev;
+	mutex_init(&dev->ctrl_urb_lock);
+	spin_lock_init(&dev->slock);
+	init_waitqueue_head(&dev->open);
+	init_waitqueue_head(&dev->wait_frame);
+	init_waitqueue_head(&dev->wait_stream);
+
+	dev->em28xx_write_regs = em28xx_write_regs;
+	dev->em28xx_read_reg = em28xx_read_reg;
+	dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
+	dev->em28xx_write_regs_req = em28xx_write_regs_req;
+	dev->em28xx_read_reg_req = em28xx_read_reg_req;
+	dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800;
+
+	em28xx_pre_card_setup(dev);
+
+	if (!dev->board.is_em2800) {
+		/* Sets I2C speed to 100 KHz */
+		retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+		if (retval < 0) {
+			em28xx_errdev("%s: em28xx_write_regs_req failed!"
+				      " retval [%d]\n",
+				      __func__, retval);
+			return retval;
+		}
+	}
+
+	/* register i2c bus */
+	errCode = em28xx_i2c_register(dev);
+	if (errCode < 0) {
+		em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n",
+			__func__, errCode);
+		return errCode;
+	}
+
+	/* Do board specific init and eeprom reading */
+	em28xx_card_setup(dev);
+
+	/* Configure audio */
+	errCode = em28xx_audio_setup(dev);
+	if (errCode < 0) {
+		em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n",
+			__func__, errCode);
+	}
+
+	/* wake i2c devices */
+	em28xx_wake_i2c(dev);
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->vidq.active);
+	INIT_LIST_HEAD(&dev->vidq.queued);
+
+
+	if (dev->board.has_msp34xx) {
+		/* Send a reset to other chips via gpio */
+		errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
+		if (errCode < 0) {
+			em28xx_errdev("%s: em28xx_write_regs_req - "
+				      "msp34xx(1) failed! errCode [%d]\n",
+				      __func__, errCode);
+			return errCode;
+		}
+		msleep(3);
+
+		errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+		if (errCode < 0) {
+			em28xx_errdev("%s: em28xx_write_regs_req - "
+				      "msp34xx(2) failed! errCode [%d]\n",
+				      __func__, errCode);
+			return errCode;
+		}
+		msleep(3);
+	}
+
+	em28xx_add_into_devlist(dev);
+
+	errCode = em28xx_analog_config(dev);
+	if (errCode) {
+		em28xx_errdev("error configuring device\n");
+		return -ENOMEM;
+	}
+
+	retval = em28xx_register_analog_devices(dev);
+	if (retval < 0) {
+		em28xx_release_resources(dev);
+		goto fail_reg_devices;
+	}
+
+	em28xx_init_extension(dev);
+
+	/* Save some power by putting tuner to sleep */
+	em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+
+	return 0;
+
+fail_reg_devices:
+	return retval;
+}
+
+/*
+ * em28xx_usb_probe()
+ * checks for supported devices
+ */
+static int em28xx_usb_probe(struct usb_interface *interface,
+			    const struct usb_device_id *id)
+{
+	const struct usb_endpoint_descriptor *endpoint;
+	struct usb_device *udev;
+	struct usb_interface *uif;
+	struct em28xx *dev = NULL;
+	int retval = -ENODEV;
+	int i, nr, ifnum, isoc_pipe;
+	char *speed;
+	char descr[255] = "";
+
+	udev = usb_get_dev(interface_to_usbdev(interface));
+	ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+
+	/* Check to see next free device and mark as used */
+	nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
+	em28xx_devused |= 1<<nr;
+
+	/* Don't register audio interfaces */
+	if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+		em28xx_err(DRIVER_NAME " audio device (%04x:%04x): "
+			"interface %i, class %i\n",
+			le16_to_cpu(udev->descriptor.idVendor),
+			le16_to_cpu(udev->descriptor.idProduct),
+			ifnum,
+			interface->altsetting[0].desc.bInterfaceClass);
+
+		em28xx_devused &= ~(1<<nr);
+		return -ENODEV;
+	}
+
+	endpoint = &interface->cur_altsetting->endpoint[0].desc;
+
+	/* check if the device has the iso in endpoint at the correct place */
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+	    USB_ENDPOINT_XFER_ISOC &&
+	    (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) {
+		/* It's a newer em2874/em2875 device */
+		isoc_pipe = 0;
+	} else {
+		int check_interface = 1;
+		isoc_pipe = 1;
+		endpoint = &interface->cur_altsetting->endpoint[1].desc;
+		if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+		    USB_ENDPOINT_XFER_ISOC)
+			check_interface = 0;
+
+		if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
+			check_interface = 0;
+
+		if (!check_interface) {
+			em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
+				"interface %i, class %i found.\n",
+				le16_to_cpu(udev->descriptor.idVendor),
+				le16_to_cpu(udev->descriptor.idProduct),
+				ifnum,
+				interface->altsetting[0].desc.bInterfaceClass);
+
+			em28xx_err(DRIVER_NAME " This is an anciliary "
+				"interface not used by the driver\n");
+
+			em28xx_devused &= ~(1<<nr);
+			return -ENODEV;
+		}
+	}
+
+	switch (udev->speed) {
+	case USB_SPEED_LOW:
+		speed = "1.5";
+		break;
+	case USB_SPEED_UNKNOWN:
+	case USB_SPEED_FULL:
+		speed = "12";
+		break;
+	case USB_SPEED_HIGH:
+		speed = "480";
+		break;
+	default:
+		speed = "unknown";
+	}
+
+	if (udev->manufacturer)
+		strlcpy(descr, udev->manufacturer, sizeof(descr));
+
+	if (udev->product) {
+		if (*descr)
+			strlcat(descr, " ", sizeof(descr));
+		strlcat(descr, udev->product, sizeof(descr));
+	}
+	if (*descr)
+		strlcat(descr, " ", sizeof(descr));
+
+	printk(DRIVER_NAME ": New device %s@ %s Mbps "
+		"(%04x:%04x, interface %d, class %d)\n",
+		descr,
+		speed,
+		le16_to_cpu(udev->descriptor.idVendor),
+		le16_to_cpu(udev->descriptor.idProduct),
+		ifnum,
+		interface->altsetting->desc.bInterfaceNumber);
+
+	if (nr >= EM28XX_MAXBOARDS) {
+		printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
+				EM28XX_MAXBOARDS);
+		em28xx_devused &= ~(1<<nr);
+		return -ENOMEM;
+	}
+
+	/* allocate memory for our device state and initialize it */
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		em28xx_err(DRIVER_NAME ": out of memory!\n");
+		em28xx_devused &= ~(1<<nr);
+		return -ENOMEM;
+	}
+
+	snprintf(dev->name, 29, "em28xx #%d", nr);
+	dev->devno = nr;
+	dev->model = id->driver_info;
+	dev->alt   = -1;
+
+	/* Checks if audio is provided by some interface */
+	for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
+		uif = udev->config->interface[i];
+		if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+			dev->has_audio_class = 1;
+			break;
+		}
+	}
+
+	/* compute alternate max packet sizes */
+	uif = udev->actconfig->interface[0];
+
+	dev->num_alt = uif->num_altsetting;
+	dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
+
+	if (dev->alt_max_pkt_size == NULL) {
+		em28xx_errdev("out of memory!\n");
+		em28xx_devused &= ~(1<<nr);
+		kfree(dev);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < dev->num_alt ; i++) {
+		u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
+		dev->alt_max_pkt_size[i] =
+		    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+	}
+
+	if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
+		dev->model = card[nr];
+
+	/* allocate device struct */
+	mutex_init(&dev->lock);
+	mutex_lock(&dev->lock);
+	retval = em28xx_init_dev(&dev, udev, nr);
+	if (retval) {
+		em28xx_devused &= ~(1<<dev->devno);
+		kfree(dev);
+
+		return retval;
+	}
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, dev);
+
+	request_modules(dev);
+
+	/* Should be the last thing to do, to avoid newer udev's to
+	   open the device before fully initializing it
+	 */
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+/*
+ * em28xx_usb_disconnect()
+ * called when the device gets diconencted
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void em28xx_usb_disconnect(struct usb_interface *interface)
+{
+	struct em28xx *dev;
+
+	dev = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	if (!dev)
+		return;
+
+	em28xx_info("disconnecting %s\n", dev->vdev->name);
+
+	/* wait until all current v4l2 io is finished then deallocate
+	   resources */
+	mutex_lock(&dev->lock);
+
+	wake_up_interruptible_all(&dev->open);
+
+	if (dev->users) {
+		em28xx_warn
+		    ("device /dev/video%d is open! Deregistration and memory "
+		     "deallocation are deferred on close.\n",
+				dev->vdev->num);
+
+		dev->state |= DEV_MISCONFIGURED;
+		em28xx_uninit_isoc(dev);
+		dev->state |= DEV_DISCONNECTED;
+		wake_up_interruptible(&dev->wait_frame);
+		wake_up_interruptible(&dev->wait_stream);
+	} else {
+		dev->state |= DEV_DISCONNECTED;
+		em28xx_release_resources(dev);
+	}
+
+	em28xx_close_extension(dev);
+
+	mutex_unlock(&dev->lock);
+
+	if (!dev->users) {
+		kfree(dev->alt_max_pkt_size);
+		kfree(dev);
+	}
+}
+
+static struct usb_driver em28xx_usb_driver = {
+	.name = "em28xx",
+	.probe = em28xx_usb_probe,
+	.disconnect = em28xx_usb_disconnect,
+	.id_table = em28xx_id_table,
+};
+
+static int __init em28xx_module_init(void)
+{
+	int result;
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&em28xx_usb_driver);
+	if (result)
+		em28xx_err(DRIVER_NAME
+			   " usb_register failed. Error number %d.\n", result);
+
+	printk(KERN_INFO DRIVER_NAME " driver loaded\n");
+
+	return result;
+}
+
+static void __exit em28xx_module_exit(void)
+{
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&em28xx_usb_driver);
+}
+
+module_init(em28xx_module_init);
+module_exit(em28xx_module_exit);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 5964998daf2e..ac735f25283c 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
+#include <media/v4l2-common.h>
 
 #include "em28xx.h"
 
@@ -974,3 +975,145 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
 	return 0;
 }
 EXPORT_SYMBOL_GPL(em28xx_init_isoc);
+
+/*
+ * em28xx_wake_i2c()
+ * configure i2c attached devices
+ */
+void em28xx_wake_i2c(struct em28xx *dev)
+{
+	struct v4l2_routing route;
+	int zero = 0;
+
+	route.input = INPUT(dev->ctl_input)->vmux;
+	route.output = 0;
+	em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, &zero);
+	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+	em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
+}
+
+/*
+ * Device control list
+ */
+
+static LIST_HEAD(em28xx_devlist);
+static DEFINE_MUTEX(em28xx_devlist_mutex);
+
+struct em28xx *em28xx_get_device(struct inode *inode,
+				 enum v4l2_buf_type *fh_type,
+				 int *has_radio)
+{
+	struct em28xx *h, *dev = NULL;
+	int minor = iminor(inode);
+
+	*fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	*has_radio = 0;
+
+	mutex_lock(&em28xx_devlist_mutex);
+	list_for_each_entry(h, &em28xx_devlist, devlist) {
+		if (h->vdev->minor == minor)
+			dev = h;
+		if (h->vbi_dev->minor == minor) {
+			dev = h;
+			*fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
+		}
+		if (h->radio_dev &&
+		    h->radio_dev->minor == minor) {
+			dev = h;
+			*has_radio = 1;
+		}
+	}
+	mutex_unlock(&em28xx_devlist_mutex);
+
+	return dev;
+}
+
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void em28xx_remove_from_devlist(struct em28xx *dev)
+{
+	mutex_lock(&em28xx_devlist_mutex);
+	list_del(&dev->devlist);
+	mutex_unlock(&em28xx_devlist_mutex);
+};
+
+void em28xx_add_into_devlist(struct em28xx *dev)
+{
+	mutex_lock(&em28xx_devlist_mutex);
+	list_add_tail(&dev->devlist, &em28xx_devlist);
+	mutex_unlock(&em28xx_devlist_mutex);
+};
+
+/*
+ * Extension interface
+ */
+
+static LIST_HEAD(em28xx_extension_devlist);
+static DEFINE_MUTEX(em28xx_extension_devlist_lock);
+
+int em28xx_register_extension(struct em28xx_ops *ops)
+{
+	struct em28xx *dev = NULL;
+
+	mutex_lock(&em28xx_devlist_mutex);
+	mutex_lock(&em28xx_extension_devlist_lock);
+	list_add_tail(&ops->next, &em28xx_extension_devlist);
+	list_for_each_entry(dev, &em28xx_devlist, devlist) {
+		if (dev)
+			ops->init(dev);
+	}
+	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
+	mutex_unlock(&em28xx_extension_devlist_lock);
+	mutex_unlock(&em28xx_devlist_mutex);
+	return 0;
+}
+EXPORT_SYMBOL(em28xx_register_extension);
+
+void em28xx_unregister_extension(struct em28xx_ops *ops)
+{
+	struct em28xx *dev = NULL;
+
+	mutex_lock(&em28xx_devlist_mutex);
+	list_for_each_entry(dev, &em28xx_devlist, devlist) {
+		if (dev)
+			ops->fini(dev);
+	}
+
+	mutex_lock(&em28xx_extension_devlist_lock);
+	printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
+	list_del(&ops->next);
+	mutex_unlock(&em28xx_extension_devlist_lock);
+	mutex_unlock(&em28xx_devlist_mutex);
+}
+EXPORT_SYMBOL(em28xx_unregister_extension);
+
+void em28xx_init_extension(struct em28xx *dev)
+{
+	struct em28xx_ops *ops = NULL;
+
+	mutex_lock(&em28xx_extension_devlist_lock);
+	if (!list_empty(&em28xx_extension_devlist)) {
+		list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+			if (ops->init)
+				ops->init(dev);
+		}
+	}
+	mutex_unlock(&em28xx_extension_devlist_lock);
+}
+
+void em28xx_close_extension(struct em28xx *dev)
+{
+	struct em28xx_ops *ops = NULL;
+
+	mutex_lock(&em28xx_extension_devlist_lock);
+	if (!list_empty(&em28xx_extension_devlist)) {
+		list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+			if (ops->fini)
+				ops->fini(dev);
+		}
+	}
+	mutex_unlock(&em28xx_extension_devlist_lock);
+}
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index b5ea18e12290..4c0986920970 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -48,9 +48,8 @@
 		      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
 		      "Sascha Sommer <saschasommer@freenet.de>"
 
-#define DRIVER_NAME         "em28xx"
 #define DRIVER_DESC         "Empia em28xx based USB video device driver"
-#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 1, 0)
+#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 1, 1)
 
 #define em28xx_videodbg(fmt, arg...) do {\
 	if (video_debug) \
@@ -73,19 +72,13 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static LIST_HEAD(em28xx_devlist);
-static DEFINE_MUTEX(em28xx_devlist_mutex);
-
-static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 
-module_param_array(card,  int, NULL, 0444);
 module_param_array(video_nr, int, NULL, 0444);
 module_param_array(vbi_nr, int, NULL, 0444);
 module_param_array(radio_nr, int, NULL, 0444);
-MODULE_PARM_DESC(card,     "card type");
 MODULE_PARM_DESC(video_nr, "video device numbers");
 MODULE_PARM_DESC(vbi_nr,   "vbi device numbers");
 MODULE_PARM_DESC(radio_nr, "radio device numbers");
@@ -94,9 +87,6 @@ static unsigned int video_debug;
 module_param(video_debug, int, 0644);
 MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
 
-/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
-static unsigned long em28xx_devused;
-
 /* supported video standards */
 static struct em28xx_fmt format[] = {
 	{
@@ -131,8 +121,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
 	}
 };
 
-static struct usb_driver em28xx_usb_driver;
-
 /* ------------------------------------------------------------------
 	DMA and thread functions
    ------------------------------------------------------------------*/
@@ -519,56 +507,6 @@ static struct videobuf_queue_ops em28xx_video_qops = {
 
 /*********************  v4l2 interface  **************************************/
 
-/*
- * em28xx_config()
- * inits registers with sane defaults
- */
-static int em28xx_config(struct em28xx *dev)
-{
-	int retval;
-
-	/* Sets I2C speed to 100 KHz */
-	if (!dev->board.is_em2800) {
-		retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
-		if (retval < 0) {
-			em28xx_errdev("%s: em28xx_write_regs_req failed! retval [%d]\n",
-				__func__, retval);
-			return retval;
-		}
-	}
-
-	/* enable vbi capturing */
-
-/*	em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
-/*	em28xx_write_reg(dev, EM28XX_R0F_XCLK, 0x80); clk register */
-	em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51);
-
-	dev->mute = 1;		/* maybe not the right place... */
-	dev->volume = 0x1f;
-
-	em28xx_set_outfmt(dev);
-	em28xx_colorlevels_set_default(dev);
-	em28xx_compression_disable(dev);
-
-	return 0;
-}
-
-/*
- * em28xx_config_i2c()
- * configure i2c attached devices
- */
-static void em28xx_config_i2c(struct em28xx *dev)
-{
-	struct v4l2_routing route;
-	int zero = 0;
-
-	route.input = INPUT(dev->ctl_input)->vmux;
-	route.output = 0;
-	em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, &zero);
-	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
-	em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
-}
-
 static void video_mux(struct em28xx *dev, int index)
 {
 	struct v4l2_routing route;
@@ -1647,28 +1585,12 @@ static int radio_queryctrl(struct file *file, void *priv,
 static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
 {
 	int minor = iminor(inode);
-	int errCode = 0, radio = 0;
-	struct em28xx *h, *dev = NULL;
+	int errCode = 0, radio;
+	struct em28xx *dev;
+	enum v4l2_buf_type fh_type;
 	struct em28xx_fh *fh;
-	enum v4l2_buf_type fh_type = 0;
 
-	mutex_lock(&em28xx_devlist_mutex);
-	list_for_each_entry(h, &em28xx_devlist, devlist) {
-		if (h->vdev->minor == minor) {
-			dev  = h;
-			fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		}
-		if (h->vbi_dev->minor == minor) {
-			dev  = h;
-			fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
-		}
-		if (h->radio_dev &&
-		    h->radio_dev->minor == minor) {
-			radio = 1;
-			dev   = h;
-		}
-	}
-	mutex_unlock(&em28xx_devlist_mutex);
+	dev = em28xx_get_device(inode, &fh_type, &radio);
 
 	if (NULL == dev)
 		return -ENODEV;
@@ -1703,7 +1625,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
 		/* Needed, since GPIO might have disabled power of
 		   some i2c device
 		 */
-		em28xx_config_i2c(dev);
+		em28xx_wake_i2c(dev);
 
 	}
 	if (fh->radio) {
@@ -1727,18 +1649,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
  * unregisters the v4l2,i2c and usb devices
  * called when the device gets disconected or at module unload
 */
-static void em28xx_release_resources(struct em28xx *dev)
+void em28xx_release_analog_resources(struct em28xx *dev)
 {
 
 	/*FIXME: I2C IR should be disconnected */
 
-	list_del(&dev->devlist);
-	if (dev->sbutton_input_dev)
-		em28xx_deregister_snapshot_button(dev);
-
-	if (dev->ir)
-		em28xx_ir_fini(dev);
-
 	if (dev->radio_dev) {
 		if (-1 != dev->radio_dev->minor)
 			video_unregister_device(dev->radio_dev);
@@ -1764,11 +1679,6 @@ static void em28xx_release_resources(struct em28xx *dev)
 			video_device_release(dev->vdev);
 		dev->vdev = NULL;
 	}
-	em28xx_i2c_unregister(dev);
-	usb_put_dev(dev->udev);
-
-	/* Mark device as unused */
-	em28xx_devused &= ~(1<<dev->devno);
 }
 
 /*
@@ -2018,44 +1928,6 @@ static struct video_device em28xx_radio_template = {
 /******************************** usb interface ******************************/
 
 
-static LIST_HEAD(em28xx_extension_devlist);
-static DEFINE_MUTEX(em28xx_extension_devlist_lock);
-
-int em28xx_register_extension(struct em28xx_ops *ops)
-{
-	struct em28xx *dev = NULL;
-
-	mutex_lock(&em28xx_devlist_mutex);
-	mutex_lock(&em28xx_extension_devlist_lock);
-	list_add_tail(&ops->next, &em28xx_extension_devlist);
-	list_for_each_entry(dev, &em28xx_devlist, devlist) {
-		if (dev)
-			ops->init(dev);
-	}
-	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
-	mutex_unlock(&em28xx_extension_devlist_lock);
-	mutex_unlock(&em28xx_devlist_mutex);
-	return 0;
-}
-EXPORT_SYMBOL(em28xx_register_extension);
-
-void em28xx_unregister_extension(struct em28xx_ops *ops)
-{
-	struct em28xx *dev = NULL;
-
-	mutex_lock(&em28xx_devlist_mutex);
-	list_for_each_entry(dev, &em28xx_devlist, devlist) {
-		if (dev)
-			ops->fini(dev);
-	}
-
-	mutex_lock(&em28xx_extension_devlist_lock);
-	printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
-	list_del(&ops->next);
-	mutex_unlock(&em28xx_extension_devlist_lock);
-	mutex_unlock(&em28xx_devlist_mutex);
-}
-EXPORT_SYMBOL(em28xx_unregister_extension);
 
 static struct video_device *em28xx_vdev_init(struct em28xx *dev,
 					     const struct video_device *template,
@@ -2078,7 +1950,45 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
 	return vfd;
 }
 
-static int register_analog_devices(struct em28xx *dev)
+int em28xx_analog_config(struct em28xx *dev)
+{
+	printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n",
+		dev->name,
+		(EM28XX_VERSION_CODE >> 16) & 0xff,
+		(EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
+
+	/* Analog specific initialization */
+	dev->format = &format[0];
+	video_mux(dev, 0);
+
+	/* enable vbi capturing */
+
+/*	em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
+/*	em28xx_write_reg(dev, EM28XX_R0F_XCLK, 0x80); clk register */
+	em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51);
+
+	dev->mute = 1;		/* maybe not the right place... */
+	dev->volume = 0x1f;
+
+	em28xx_set_outfmt(dev);
+	em28xx_colorlevels_set_default(dev);
+	em28xx_compression_disable(dev);
+
+	/* set default norm */
+	dev->norm = em28xx_video_template.current_norm;
+	dev->width = norm_maxw(dev);
+	dev->height = norm_maxh(dev);
+	dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+	dev->hscale = 0;
+	dev->vscale = 0;
+
+	/* FIXME: This is a very bad hack! Not all devices have TV on input 2 */
+	dev->ctl_input = 2;
+
+	return 0;
+}
+
+int em28xx_register_analog_devices(struct em28xx *dev)
 {
 	int ret;
 
@@ -2130,440 +2040,3 @@ static int register_analog_devices(struct em28xx *dev)
 
 	return 0;
 }
-
-
-/*
- * em28xx_init_dev()
- * allocates and inits the device structs, registers i2c bus and v4l device
- */
-static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
-			   int minor)
-{
-	struct em28xx_ops *ops = NULL;
-	struct em28xx *dev = *devhandle;
-	int retval = -ENOMEM;
-	int errCode;
-	unsigned int maxh, maxw;
-
-	dev->udev = udev;
-	mutex_init(&dev->ctrl_urb_lock);
-	spin_lock_init(&dev->slock);
-	init_waitqueue_head(&dev->open);
-	init_waitqueue_head(&dev->wait_frame);
-	init_waitqueue_head(&dev->wait_stream);
-
-	dev->em28xx_write_regs = em28xx_write_regs;
-	dev->em28xx_read_reg = em28xx_read_reg;
-	dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
-	dev->em28xx_write_regs_req = em28xx_write_regs_req;
-	dev->em28xx_read_reg_req = em28xx_read_reg_req;
-	dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800;
-	dev->format = &format[0];
-
-	em28xx_pre_card_setup(dev);
-
-	errCode = em28xx_config(dev);
-	if (errCode) {
-		em28xx_errdev("error configuring device\n");
-		return -ENOMEM;
-	}
-
-	/* register i2c bus */
-	errCode = em28xx_i2c_register(dev);
-	if (errCode < 0) {
-		em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n",
-			__func__, errCode);
-		return errCode;
-	}
-
-	/* Do board specific init and eeprom reading */
-	em28xx_card_setup(dev);
-
-	/* Configure audio */
-	errCode = em28xx_audio_setup(dev);
-	if (errCode < 0) {
-		em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n",
-			__func__, errCode);
-	}
-
-	/* configure the device */
-	em28xx_config_i2c(dev);
-
-	/* set default norm */
-	dev->norm = em28xx_video_template.current_norm;
-
-	maxw = norm_maxw(dev);
-	maxh = norm_maxh(dev);
-
-	/* set default image size */
-	dev->width = maxw;
-	dev->height = maxh;
-	dev->interlaced = EM28XX_INTERLACED_DEFAULT;
-	dev->hscale = 0;
-	dev->vscale = 0;
-	dev->ctl_input = 2;
-
-	errCode = em28xx_config(dev);
-	if (errCode < 0) {
-		em28xx_errdev("%s: em28xx_config - errCode [%d]!\n",
-			__func__, errCode);
-		return errCode;
-	}
-
-	/* init video dma queues */
-	INIT_LIST_HEAD(&dev->vidq.active);
-	INIT_LIST_HEAD(&dev->vidq.queued);
-
-
-	if (dev->board.has_msp34xx) {
-		/* Send a reset to other chips via gpio */
-		errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
-		if (errCode < 0) {
-			em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(1) failed! errCode [%d]\n",
-				__func__, errCode);
-			return errCode;
-		}
-		msleep(3);
-
-		errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
-		if (errCode < 0) {
-			em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(2) failed! errCode [%d]\n",
-				__func__, errCode);
-			return errCode;
-		}
-		msleep(3);
-	}
-
-	video_mux(dev, 0);
-
-	mutex_lock(&em28xx_devlist_mutex);
-	list_add_tail(&dev->devlist, &em28xx_devlist);
-	retval = register_analog_devices(dev);
-	if (retval < 0) {
-		em28xx_release_resources(dev);
-		mutex_unlock(&em28xx_devlist_mutex);
-		goto fail_reg_devices;
-	}
-
-	mutex_lock(&em28xx_extension_devlist_lock);
-	if (!list_empty(&em28xx_extension_devlist)) {
-		list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-			if (ops->id)
-				ops->init(dev);
-		}
-	}
-	mutex_unlock(&em28xx_extension_devlist_lock);
-	mutex_unlock(&em28xx_devlist_mutex);
-
-	/* Save some power by putting tuner to sleep */
-	em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
-
-	return 0;
-
-fail_reg_devices:
-	return retval;
-}
-
-#if defined(CONFIG_MODULES) && defined(MODULE)
-static void request_module_async(struct work_struct *work)
-{
-	struct em28xx *dev = container_of(work,
-			     struct em28xx, request_module_wk);
-
-	if (dev->has_audio_class)
-		request_module("snd-usb-audio");
-	else if (dev->has_alsa_audio)
-		request_module("em28xx-alsa");
-
-	if (dev->board.has_dvb)
-		request_module("em28xx-dvb");
-}
-
-static void request_modules(struct em28xx *dev)
-{
-	INIT_WORK(&dev->request_module_wk, request_module_async);
-	schedule_work(&dev->request_module_wk);
-}
-#else
-#define request_modules(dev)
-#endif /* CONFIG_MODULES */
-
-/*
- * em28xx_usb_probe()
- * checks for supported devices
- */
-static int em28xx_usb_probe(struct usb_interface *interface,
-			    const struct usb_device_id *id)
-{
-	const struct usb_endpoint_descriptor *endpoint;
-	struct usb_device *udev;
-	struct usb_interface *uif;
-	struct em28xx *dev = NULL;
-	int retval = -ENODEV;
-	int i, nr, ifnum, isoc_pipe;
-	char *speed;
-	char descr[255] = "";
-
-	udev = usb_get_dev(interface_to_usbdev(interface));
-	ifnum = interface->altsetting[0].desc.bInterfaceNumber;
-
-	/* Check to see next free device and mark as used */
-	nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
-	em28xx_devused |= 1<<nr;
-
-	/* Don't register audio interfaces */
-	if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
-		em28xx_err(DRIVER_NAME " audio device (%04x:%04x): "
-			"interface %i, class %i\n",
-			le16_to_cpu(udev->descriptor.idVendor),
-			le16_to_cpu(udev->descriptor.idProduct),
-			ifnum,
-			interface->altsetting[0].desc.bInterfaceClass);
-
-		em28xx_devused &= ~(1<<nr);
-		return -ENODEV;
-	}
-
-	endpoint = &interface->cur_altsetting->endpoint[0].desc;
-
-	/* check if the device has the iso in endpoint at the correct place */
-	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
-	    USB_ENDPOINT_XFER_ISOC &&
-	    (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940))
-	{
-		/* It's a newer em2874/em2875 device */
-		isoc_pipe = 0;
-	} else {
-		int check_interface = 1;
-		isoc_pipe = 1;
-		endpoint = &interface->cur_altsetting->endpoint[1].desc;
-		if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
-		    USB_ENDPOINT_XFER_ISOC)
-			check_interface = 0;
-
-		if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
-			check_interface = 0;
-
-		if (!check_interface) {
-			em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
-				"interface %i, class %i found.\n",
-				le16_to_cpu(udev->descriptor.idVendor),
-				le16_to_cpu(udev->descriptor.idProduct),
-				ifnum,
-				interface->altsetting[0].desc.bInterfaceClass);
-
-			em28xx_err(DRIVER_NAME " This is an anciliary "
-				"interface not used by the driver\n");
-
-			em28xx_devused &= ~(1<<nr);
-			return -ENODEV;
-		}
-	}
-
-	switch (udev->speed) {
-	case USB_SPEED_LOW:
-		speed = "1.5";
-		break;
-	case USB_SPEED_UNKNOWN:
-	case USB_SPEED_FULL:
-		speed = "12";
-		break;
-	case USB_SPEED_HIGH:
-		speed = "480";
-		break;
-	default:
-		speed = "unknown";
-	}
-
-	if (udev->manufacturer)
-		strlcpy(descr, udev->manufacturer, sizeof(descr));
-
-	if (udev->product) {
-		if (*descr)
-			strlcat(descr, " ", sizeof(descr));
-		strlcat(descr, udev->product, sizeof(descr));
-	}
-	if (*descr)
-		strlcat(descr, " ", sizeof(descr));
-
-	printk(DRIVER_NAME ": New device %s@ %s Mbps "
-		"(%04x:%04x, interface %d, class %d)\n",
-		descr,
-		speed,
-		le16_to_cpu(udev->descriptor.idVendor),
-		le16_to_cpu(udev->descriptor.idProduct),
-		ifnum,
-		interface->altsetting->desc.bInterfaceNumber);
-
-	if (nr >= EM28XX_MAXBOARDS) {
-		printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
-				EM28XX_MAXBOARDS);
-		em28xx_devused &= ~(1<<nr);
-		return -ENOMEM;
-	}
-
-	/* allocate memory for our device state and initialize it */
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (dev == NULL) {
-		em28xx_err(DRIVER_NAME ": out of memory!\n");
-		em28xx_devused &= ~(1<<nr);
-		return -ENOMEM;
-	}
-
-	snprintf(dev->name, 29, "em28xx #%d", nr);
-	dev->devno = nr;
-	dev->model = id->driver_info;
-	dev->alt   = -1;
-
-	/* Checks if audio is provided by some interface */
-	for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
-		uif = udev->config->interface[i];
-		if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
-			dev->has_audio_class = 1;
-			break;
-		}
-	}
-
-	/* compute alternate max packet sizes */
-	uif = udev->actconfig->interface[0];
-
-	dev->num_alt = uif->num_altsetting;
-	em28xx_videodbg("Alternate settings: %i\n", dev->num_alt);
-/*	dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)* */
-	dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
-
-	if (dev->alt_max_pkt_size == NULL) {
-		em28xx_errdev("out of memory!\n");
-		em28xx_devused &= ~(1<<nr);
-		kfree(dev);
-		return -ENOMEM;
-	}
-
-	for (i = 0; i < dev->num_alt ; i++) {
-		u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.
-							wMaxPacketSize);
-		dev->alt_max_pkt_size[i] =
-		    (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
-		em28xx_videodbg("Alternate setting %i, max size= %i\n", i,
-						dev->alt_max_pkt_size[i]);
-	}
-
-	if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
-		dev->model = card[nr];
-
-	/* allocate device struct */
-	mutex_init(&dev->lock);
-	mutex_lock(&dev->lock);
-	retval = em28xx_init_dev(&dev, udev, nr);
-	if (retval) {
-		em28xx_devused &= ~(1<<dev->devno);
-		kfree(dev);
-
-		return retval;
-	}
-
-	/* save our data pointer in this interface device */
-	usb_set_intfdata(interface, dev);
-
-	request_modules(dev);
-
-	/* Should be the last thing to do, to avoid newer udev's to
-	   open the device before fully initializing it
-	 */
-	mutex_unlock(&dev->lock);
-
-	return 0;
-}
-
-/*
- * em28xx_usb_disconnect()
- * called when the device gets diconencted
- * video device will be unregistered on v4l2_close in case it is still open
- */
-static void em28xx_usb_disconnect(struct usb_interface *interface)
-{
-	struct em28xx *dev;
-	struct em28xx_ops *ops = NULL;
-
-	dev = usb_get_intfdata(interface);
-	usb_set_intfdata(interface, NULL);
-
-	if (!dev)
-		return;
-
-	em28xx_info("disconnecting %s\n", dev->vdev->name);
-
-	/* wait until all current v4l2 io is finished then deallocate
-	   resources */
-	mutex_lock(&dev->lock);
-
-	wake_up_interruptible_all(&dev->open);
-
-	if (dev->users) {
-		em28xx_warn
-		    ("device /dev/video%d is open! Deregistration and memory "
-		     "deallocation are deferred on close.\n",
-				dev->vdev->num);
-
-		dev->state |= DEV_MISCONFIGURED;
-		em28xx_uninit_isoc(dev);
-		dev->state |= DEV_DISCONNECTED;
-		wake_up_interruptible(&dev->wait_frame);
-		wake_up_interruptible(&dev->wait_stream);
-	} else {
-		dev->state |= DEV_DISCONNECTED;
-		em28xx_release_resources(dev);
-	}
-	mutex_unlock(&dev->lock);
-
-	mutex_lock(&em28xx_extension_devlist_lock);
-	if (!list_empty(&em28xx_extension_devlist)) {
-		list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-			ops->fini(dev);
-		}
-	}
-	mutex_unlock(&em28xx_extension_devlist_lock);
-
-	if (!dev->users) {
-		kfree(dev->alt_max_pkt_size);
-		kfree(dev);
-	}
-}
-
-static struct usb_driver em28xx_usb_driver = {
-	.name = "em28xx",
-	.probe = em28xx_usb_probe,
-	.disconnect = em28xx_usb_disconnect,
-	.id_table = em28xx_id_table,
-};
-
-static int __init em28xx_module_init(void)
-{
-	int result;
-
-	printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n",
-	       (EM28XX_VERSION_CODE >> 16) & 0xff,
-	       (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-	printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n",
-	       SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100);
-#endif
-
-	/* register this driver with the USB subsystem */
-	result = usb_register(&em28xx_usb_driver);
-	if (result)
-		em28xx_err(DRIVER_NAME
-			   " usb_register failed. Error number %d.\n", result);
-
-	return result;
-}
-
-static void __exit em28xx_module_exit(void)
-{
-	/* deregister this driver with the USB subsystem */
-	usb_deregister(&em28xx_usb_driver);
-}
-
-module_init(em28xx_module_init);
-module_exit(em28xx_module_exit);
-
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 100f27819cdc..c8e71edbfea7 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -581,10 +581,21 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
 void em28xx_uninit_isoc(struct em28xx *dev);
 int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
 int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
-
-/* Provided by em28xx-video.c */
+void em28xx_wake_i2c(struct em28xx *dev);
+void em28xx_remove_from_devlist(struct em28xx *dev);
+void em28xx_add_into_devlist(struct em28xx *dev);
+struct em28xx *em28xx_get_device(struct inode *inode,
+				 enum v4l2_buf_type *fh_type,
+				 int *has_radio);
 int em28xx_register_extension(struct em28xx_ops *dev);
 void em28xx_unregister_extension(struct em28xx_ops *dev);
+void em28xx_init_extension(struct em28xx *dev);
+void em28xx_close_extension(struct em28xx *dev);
+
+/* Provided by em28xx-video.c */
+int em28xx_analog_config(struct em28xx *dev);
+int em28xx_register_analog_devices(struct em28xx *dev);
+void em28xx_release_analog_resources(struct em28xx *dev);
 
 /* Provided by em28xx-cards.c */
 extern int em2800_variant_detect(struct usb_device *udev, int model);
@@ -595,6 +606,7 @@ extern struct usb_device_id em28xx_id_table[];
 extern const unsigned int em28xx_bcount;
 void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
+void em28xx_release_resources(struct em28xx *dev);
 
 /* Provided by em28xx-input.c */
 int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
-- 
2.20.1