---
 debian/config/amd64                |    4 
 debian/config/i386                 |    4 
 ubuntu/media/Makefile              |    3 
 ubuntu/media/au0828/Makefile       |   15 
 ubuntu/media/au0828/au0828-cards.c |  178 ++++++
 ubuntu/media/au0828/au0828-cards.h |   25 
 ubuntu/media/au0828/au0828-core.c  |  262 +++++++++
 ubuntu/media/au0828/au0828-dvb.c   |  399 +++++++++++++++
 ubuntu/media/au0828/au0828-i2c.c   |  388 ++++++++++++++
 ubuntu/media/au0828/au0828-reg.h   |   38 +
 ubuntu/media/au0828/au0828.h       |  133 +++++
 ubuntu/media/au0828/au8522.c       |  716 ++++++++++++++++++++++++++
 ubuntu/media/au0828/au8522.h       |   57 ++
 ubuntu/media/au0828/compat.h       |  583 +++++++++++++++++++++
 ubuntu/media/au0828/xc5000.c       |  984 +++++++++++++++++++++++++++++++++++++
 ubuntu/media/au0828/xc5000.h       |   66 ++
 ubuntu/media/au0828/xc5000_priv.h  |   38 +
 17 files changed, 3893 insertions(+)

--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/Makefile
@@ -0,0 +1,15 @@
+include $(src)/../../.config
+
+au0828-objs	:= au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
+
+obj-$(CONFIG_VIDEO_AU0828) += au0828.o
+
+obj-$(CONFIG_DVB_AU8522) += au8522.o
+
+obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Imedia/au8522
+EXTRA_CFLAGS += -Imedia/xc5000
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/au0828-cards.c
@@ -0,0 +1,178 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "au0828.h"
+#include "au0828-cards.h"
+
+struct au0828_board au0828_boards[] = {
+	[AU0828_BOARD_UNKNOWN] = {
+		.name	= "Unknown board",
+	},
+	[AU0828_BOARD_HAUPPAUGE_HVR850] = {
+		.name	= "Hauppauge HVR850",
+	},
+	[AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
+		.name	= "Hauppauge HVR950Q",
+	},
+	[AU0828_BOARD_DELL_HVR950Q] = {
+		.name	= "Dell Digital TV Receiver",
+	},
+};
+
+/* Tuner callback function for au0828 boards. Currently only needed
+ * for HVR1500Q, which has an xc5000 tuner.
+ */
+int au0828_tuner_callback(void *priv, int command, int arg)
+{
+	struct au0828_dev *dev = priv;
+
+	dprintk(1, "%s()\n", __func__);
+
+	switch (dev->board) {
+	case AU0828_BOARD_HAUPPAUGE_HVR850:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+	case AU0828_BOARD_DELL_HVR950Q:
+		if (command == 0) {
+			/* Tuner Reset Command from xc5000 */
+			/* Drive the tuner into reset and out */
+			au0828_clear(dev, REG_001, 2);
+			mdelay(200);
+			au0828_set(dev, REG_001, 2);
+			mdelay(50);
+			return 0;
+		} else {
+			printk(KERN_ERR
+				"%s(): Unknown command.\n", __func__);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	return 0; /* Should never be here */
+}
+
+static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
+{
+	struct tveeprom tv;
+
+	tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+
+	/* Make sure we support the board model */
+	switch (tv.model) {
+	case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
+	case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
+	case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+	case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+	case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+	case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and basic analog video */
+	case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */
+	case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
+		break;
+	default:
+		printk(KERN_WARNING "%s: warning: "
+		       "unknown hauppauge model #%d\n", __func__, tv.model);
+		break;
+	}
+
+	printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+	       __func__, tv.model);
+}
+
+void au0828_card_setup(struct au0828_dev *dev)
+{
+	static u8 eeprom[256];
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (dev->i2c_rc == 0) {
+		dev->i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
+	}
+
+	switch (dev->board) {
+	case AU0828_BOARD_HAUPPAUGE_HVR850:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+	case AU0828_BOARD_DELL_HVR950Q:
+		if (dev->i2c_rc == 0)
+			hauppauge_eeprom(dev, eeprom+0xa0);
+		break;
+	}
+}
+
+/*
+ * The bridge has between 8 and 12 gpios.
+ * Regs 1 and 0 deal with output enables.
+ * Regs 3 and 2 deal with direction.
+ */
+void au0828_gpio_setup(struct au0828_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	switch (dev->board) {
+	case AU0828_BOARD_HAUPPAUGE_HVR850:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+	case AU0828_BOARD_DELL_HVR950Q:
+		/* GPIO's
+		 * 4 - CS5340
+		 * 5 - AU8522 Demodulator
+		 * 6 - eeprom W/P
+		 * 9 - XC5000 Tuner
+		 */
+
+		/* Into reset */
+		au0828_write(dev, REG_003, 0x02);
+		au0828_write(dev, REG_002, 0x88 | 0x20);
+		au0828_write(dev, REG_001, 0x0);
+		au0828_write(dev, REG_000, 0x0);
+		msleep(100);
+
+		/* Out of reset */
+		au0828_write(dev, REG_003, 0x02);
+		au0828_write(dev, REG_001, 0x02);
+		au0828_write(dev, REG_002, 0x88 | 0x20);
+		au0828_write(dev, REG_000, 0x88 | 0x20 | 0x40);
+		msleep(250);
+		break;
+	}
+}
+
+/* table of devices that work with this driver */
+struct usb_device_id au0828_usb_id_table [] = {
+	{ USB_DEVICE(0x2040, 0x7200),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x7240),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
+	{ USB_DEVICE(0x2040, 0x7210),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x7217),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x721b),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x0fd9, 0x0008),
+		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x721f),
+		.driver_info = AU0828_BOARD_DELL_HVR950Q },
+	{ USB_DEVICE(0x2040, 0x7280),
+		.driver_info = AU0828_BOARD_DELL_HVR950Q },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/au0828-cards.h
@@ -0,0 +1,25 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define AU0828_BOARD_UNKNOWN		0
+#define AU0828_BOARD_HAUPPAUGE_HVR950Q	1
+#define AU0828_BOARD_HAUPPAUGE_HVR850 	2
+#define AU0828_BOARD_DELL_HVR950Q	3
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/au0828-core.c
@@ -0,0 +1,262 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include "compat.h"
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+#include <linux/mutex.h>
+#endif
+
+#include "au0828.h"
+
+/*
+ * 1 = General debug messages
+ * 2 = USB handling
+ * 4 = I2C related
+ * 8 = Bridge related
+ */
+int au0828_debug;
+module_param_named(debug, au0828_debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+#define _AU0828_BULKPIPE 0x03
+#define _BULKPIPESIZE 0xffff
+
+static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+	u16 index, unsigned char *cp, u16 size);
+static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+	u16 index, unsigned char *cp, u16 size);
+
+/* USB Direction */
+#define CMD_REQUEST_IN		0x00
+#define CMD_REQUEST_OUT		0x01
+
+u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
+{
+	recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1);
+	dprintk(8, "%s(0x%x) = 0x%x\n", __func__, reg, dev->ctrlmsg[0]);
+	return dev->ctrlmsg[0];
+}
+
+u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
+{
+	dprintk(8, "%s(0x%x, 0x%x)\n", __func__, reg, val);
+	return send_control_msg(dev, CMD_REQUEST_OUT, val, reg,
+				dev->ctrlmsg, 0);
+}
+
+static void cmd_msg_dump(struct au0828_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < sizeof(dev->ctrlmsg); i += 16)
+		dprintk(2, "%s() %02x %02x %02x %02x %02x %02x %02x %02x "
+				"%02x %02x %02x %02x %02x %02x %02x %02x\n",
+			__func__,
+			dev->ctrlmsg[i+0], dev->ctrlmsg[i+1],
+			dev->ctrlmsg[i+2], dev->ctrlmsg[i+3],
+			dev->ctrlmsg[i+4], dev->ctrlmsg[i+5],
+			dev->ctrlmsg[i+6], dev->ctrlmsg[i+7],
+			dev->ctrlmsg[i+8], dev->ctrlmsg[i+9],
+			dev->ctrlmsg[i+10], dev->ctrlmsg[i+11],
+			dev->ctrlmsg[i+12], dev->ctrlmsg[i+13],
+			dev->ctrlmsg[i+14], dev->ctrlmsg[i+15]);
+}
+
+static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+	u16 index, unsigned char *cp, u16 size)
+{
+	int status = -ENODEV;
+	mutex_lock(&dev->mutex);
+	if (dev->usbdev) {
+
+		/* cp must be memory that has been allocated by kmalloc */
+		status = usb_control_msg(dev->usbdev,
+				usb_sndctrlpipe(dev->usbdev, 0),
+				request,
+				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				value, index,
+				cp, size, 1000);
+
+		status = min(status, 0);
+
+		if (status < 0) {
+			printk(KERN_ERR "%s() Failed sending control message, error %d.\n",
+				__func__, status);
+		}
+
+	}
+	mutex_unlock(&dev->mutex);
+	return status;
+}
+
+static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+	u16 index, unsigned char *cp, u16 size)
+{
+	int status = -ENODEV;
+	mutex_lock(&dev->mutex);
+	if (dev->usbdev) {
+
+		memset(dev->ctrlmsg, 0, sizeof(dev->ctrlmsg));
+
+		/* cp must be memory that has been allocated by kmalloc */
+		status = usb_control_msg(dev->usbdev,
+				usb_rcvctrlpipe(dev->usbdev, 0),
+				request,
+				USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				value, index,
+				cp, size, 1000);
+
+		status = min(status, 0);
+
+		if (status < 0) {
+			printk(KERN_ERR "%s() Failed receiving control message, error %d.\n",
+				__func__, status);
+		} else
+			cmd_msg_dump(dev);
+	}
+	mutex_unlock(&dev->mutex);
+	return status;
+}
+
+static void au0828_usb_disconnect(struct usb_interface *interface)
+{
+	struct au0828_dev *dev = usb_get_intfdata(interface);
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* Digital TV */
+	au0828_dvb_unregister(dev);
+
+	/* I2C */
+	au0828_i2c_unregister(dev);
+
+	usb_set_intfdata(interface, NULL);
+
+	mutex_lock(&dev->mutex);
+	dev->usbdev = NULL;
+	mutex_unlock(&dev->mutex);
+
+	kfree(dev);
+
+}
+
+static int au0828_usb_probe(struct usb_interface *interface,
+	const struct usb_device_id *id)
+{
+	int ifnum;
+	struct au0828_dev *dev;
+	struct usb_device *usbdev = interface_to_usbdev(interface);
+
+	ifnum = interface->altsetting->desc.bInterfaceNumber;
+
+	if (ifnum != 0)
+		return -ENODEV;
+
+	dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
+		le16_to_cpu(usbdev->descriptor.idVendor),
+		le16_to_cpu(usbdev->descriptor.idProduct),
+		ifnum);
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	mutex_init(&dev->mutex);
+	mutex_init(&dev->dvb.lock);
+	dev->usbdev = usbdev;
+	dev->board = id->driver_info;
+
+	usb_set_intfdata(interface, dev);
+
+	/* Power Up the bridge */
+	au0828_write(dev, REG_600, 1 << 4);
+
+	/* Bring up the GPIO's and supporting devices */
+	au0828_gpio_setup(dev);
+
+	/* I2C */
+	au0828_i2c_register(dev);
+
+	/* Setup */
+	au0828_card_setup(dev);
+
+	/* Digital TV */
+	au0828_dvb_register(dev);
+
+	printk(KERN_INFO "Registered device AU0828 [%s]\n",
+		au0828_boards[dev->board].name == NULL ? "Unset" :
+		au0828_boards[dev->board].name);
+
+	return 0;
+}
+
+static struct usb_driver au0828_usb_driver = {
+	.name		= DRIVER_NAME,
+	.probe		= au0828_usb_probe,
+	.disconnect	= au0828_usb_disconnect,
+	.id_table	= au0828_usb_id_table,
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15)
+	.owner		= THIS_MODULE,
+#endif
+};
+
+static int __init au0828_init(void)
+{
+	int ret;
+
+	if (au0828_debug & 1)
+		printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
+
+	if (au0828_debug & 2)
+		printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
+
+	if (au0828_debug & 4)
+		printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
+
+	if (au0828_debug & 8)
+		printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
+		       __func__);
+
+	printk(KERN_INFO "au0828 driver loaded\n");
+
+	ret = usb_register(&au0828_usb_driver);
+	if (ret)
+		printk(KERN_ERR "usb_register failed, error = %d\n", ret);
+
+	return ret;
+}
+
+static void __exit au0828_exit(void)
+{
+	usb_deregister(&au0828_usb_driver);
+}
+
+module_init(au0828_init);
+module_exit(au0828_exit);
+
+MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
+MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_LICENSE("GPL");
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/au0828-dvb.c
@@ -0,0 +1,399 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <media/v4l2-common.h>
+#include "compat.h"
+
+#include "au0828.h"
+#include "au8522.h"
+#include "xc5000.h"
+
+#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+#endif
+
+#define _AU0828_BULKPIPE 0x83
+#define _BULKPIPESIZE 0xe522
+
+static struct au8522_config hauppauge_hvr950q_config = {
+	.demod_address = 0x8e >> 1,
+	.status_mode   = AU8522_DEMODLOCKING,
+};
+
+static struct xc5000_config hauppauge_hvr950q_tunerconfig = {
+	.i2c_address      = 0x61,
+	.if_khz           = 6000,
+	.tuner_callback   = au0828_tuner_callback
+};
+
+/*-------------------------------------------------------------------*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static void urb_completion(struct urb *purb, struct pt_regs *regs)
+#else
+static void urb_completion(struct urb *purb)
+#endif
+{
+	u8 *ptr;
+	struct au0828_dev *dev = purb->context;
+	int ptype = usb_pipetype(purb->pipe);
+
+	dprintk(2, "%s()\n", __func__);
+
+	if (!dev)
+		return;
+
+	if (dev->urb_streaming == 0)
+		return;
+
+	if (ptype != PIPE_BULK) {
+		printk(KERN_ERR "%s() Unsupported URB type %d\n",
+		       __func__, ptype);
+		return;
+	}
+
+	ptr = (u8 *)purb->transfer_buffer;
+
+	/* Feed the transport payload into the kernel demux */
+	dvb_dmx_swfilter_packets(&dev->dvb.demux,
+		purb->transfer_buffer, purb->actual_length / 188);
+
+	/* Clean the buffer before we requeue */
+	memset(purb->transfer_buffer, 0, URB_BUFSIZE);
+
+	/* Requeue URB */
+	usb_submit_urb(purb, GFP_ATOMIC);
+}
+
+static int stop_urb_transfer(struct au0828_dev *dev)
+{
+	int i;
+
+	dprintk(2, "%s()\n", __func__);
+
+	for (i = 0; i < URB_COUNT; i++) {
+		usb_kill_urb(dev->urbs[i]);
+		kfree(dev->urbs[i]->transfer_buffer);
+		usb_free_urb(dev->urbs[i]);
+	}
+
+	dev->urb_streaming = 0;
+
+	return 0;
+}
+
+static int start_urb_transfer(struct au0828_dev *dev)
+{
+	struct urb *purb;
+	int i, ret = -ENOMEM;
+
+	dprintk(2, "%s()\n", __func__);
+
+	if (dev->urb_streaming) {
+		dprintk(2, "%s: iso xfer already running!\n", __func__);
+		return 0;
+	}
+
+	for (i = 0; i < URB_COUNT; i++) {
+
+		dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
+		if (!dev->urbs[i])
+			goto err;
+
+		purb = dev->urbs[i];
+
+		purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL);
+		if (!purb->transfer_buffer) {
+			usb_free_urb(purb);
+			dev->urbs[i] = NULL;
+			goto err;
+		}
+
+		purb->status = -EINPROGRESS;
+		usb_fill_bulk_urb(purb,
+				  dev->usbdev,
+				  usb_rcvbulkpipe(dev->usbdev, _AU0828_BULKPIPE),
+				  purb->transfer_buffer,
+				  URB_BUFSIZE,
+				  urb_completion,
+				  dev);
+
+	}
+
+	for (i = 0; i < URB_COUNT; i++) {
+		ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);
+		if (ret != 0) {
+			stop_urb_transfer(dev);
+			printk(KERN_ERR "%s: failed urb submission, "
+			       "err = %d\n", __func__, ret);
+			return ret;
+		}
+	}
+
+	dev->urb_streaming = 1;
+	ret = 0;
+
+err:
+	return ret;
+}
+
+static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+	struct au0828_dvb *dvb = &dev->dvb;
+	int ret = 0;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (!demux->dmx.frontend)
+		return -EINVAL;
+
+	if (dvb) {
+		mutex_lock(&dvb->lock);
+		if (dvb->feeding++ == 0) {
+			/* Start transport */
+			au0828_write(dev, 0x608, 0x90);
+			au0828_write(dev, 0x609, 0x72);
+			au0828_write(dev, 0x60a, 0x71);
+			au0828_write(dev, 0x60b, 0x01);
+			ret = start_urb_transfer(dev);
+		}
+		mutex_unlock(&dvb->lock);
+	}
+
+	return ret;
+}
+
+static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+	struct au0828_dvb *dvb = &dev->dvb;
+	int ret = 0;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (dvb) {
+		mutex_lock(&dvb->lock);
+		if (--dvb->feeding == 0) {
+			/* Stop transport */
+			au0828_write(dev, 0x608, 0x00);
+			au0828_write(dev, 0x609, 0x00);
+			au0828_write(dev, 0x60a, 0x00);
+			au0828_write(dev, 0x60b, 0x00);
+			ret = stop_urb_transfer(dev);
+		}
+		mutex_unlock(&dvb->lock);
+	}
+
+	return ret;
+}
+
+static int dvb_register(struct au0828_dev *dev)
+{
+	struct au0828_dvb *dvb = &dev->dvb;
+	int result;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* register adapter */
+	result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
+#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR
+				      &dev->usbdev->dev, adapter_nr);
+#else
+				      &dev->usbdev->dev);
+#endif
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_register_adapter failed "
+		       "(errno = %d)\n", DRIVER_NAME, result);
+		goto fail_adapter;
+	}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+	dvb->adapter.priv = dev;
+
+	/* register frontend */
+	result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+#else
+	dvb->adapter->priv = dev;
+
+	/* register frontend */
+	result = dvb_register_frontend(dvb->adapter, dvb->frontend);
+#endif
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_register_frontend failed "
+		       "(errno = %d)\n", DRIVER_NAME, result);
+		goto fail_frontend;
+	}
+
+	/* register demux stuff */
+	dvb->demux.dmx.capabilities =
+		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+		DMX_MEMORY_BASED_FILTERING;
+	dvb->demux.priv       = dev;
+	dvb->demux.filternum  = 256;
+	dvb->demux.feednum    = 256;
+	dvb->demux.start_feed = au0828_dvb_start_feed;
+	dvb->demux.stop_feed  = au0828_dvb_stop_feed;
+	result = dvb_dmx_init(&dvb->demux);
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",
+		       DRIVER_NAME, result);
+		goto fail_dmx;
+	}
+
+	dvb->dmxdev.filternum    = 256;
+	dvb->dmxdev.demux        = &dvb->demux.dmx;
+	dvb->dmxdev.capabilities = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+#else
+	result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter);
+#endif
+	if (result < 0) {
+		printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
+		       DRIVER_NAME, result);
+		goto fail_dmxdev;
+	}
+
+	dvb->fe_hw.source = DMX_FRONTEND_0;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_ERR "%s: add_frontend failed "
+		       "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);
+		goto fail_fe_hw;
+	}
+
+	dvb->fe_mem.source = DMX_MEMORY_FE;
+	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	if (result < 0) {
+		printk(KERN_ERR "%s: add_frontend failed "
+		       "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);
+		goto fail_fe_mem;
+	}
+
+	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	if (result < 0) {
+		printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",
+		       DRIVER_NAME, result);
+		goto fail_fe_conn;
+	}
+
+	/* register network adapter */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+#else
+	dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx);
+#endif
+	return 0;
+
+fail_fe_conn:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+	dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+	dvb_dmx_release(&dvb->demux);
+fail_dmx:
+	dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+	dvb_frontend_detach(dvb->frontend);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+	dvb_unregister_adapter(&dvb->adapter);
+#else
+	dvb_unregister_adapter(dvb->adapter);
+#endif
+fail_adapter:
+	return result;
+}
+
+void au0828_dvb_unregister(struct au0828_dev *dev)
+{
+	struct au0828_dvb *dvb = &dev->dvb;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (dvb->frontend == NULL)
+		return;
+
+	dvb_net_release(&dvb->net);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+	dvb_dmxdev_release(&dvb->dmxdev);
+	dvb_dmx_release(&dvb->demux);
+	dvb_unregister_frontend(dvb->frontend);
+	dvb_frontend_detach(dvb->frontend);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+	dvb_unregister_adapter(&dvb->adapter);
+#else
+	dvb_unregister_adapter(dvb->adapter);
+#endif
+}
+
+/* All the DVB attach calls go here, this function get's modified
+ * for each new card. No other function in this file needs
+ * to change.
+ */
+int au0828_dvb_register(struct au0828_dev *dev)
+{
+	struct au0828_dvb *dvb = &dev->dvb;
+	int ret;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* init frontend */
+	switch (dev->board) {
+	case AU0828_BOARD_HAUPPAUGE_HVR850:
+	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+	case AU0828_BOARD_DELL_HVR950Q:
+		dvb->frontend = dvb_attach(au8522_attach,
+				&hauppauge_hvr950q_config,
+				&dev->i2c_adap);
+		if (dvb->frontend != NULL)
+			dvb_attach(xc5000_attach, dvb->frontend,
+				&dev->i2c_adap,
+				&hauppauge_hvr950q_tunerconfig, dev);
+		break;
+	default:
+		printk(KERN_WARNING "The frontend of your DVB/ATSC card "
+		       "isn't supported yet\n");
+		break;
+	}
+	if (NULL == dvb->frontend) {
+		printk(KERN_ERR "%s() Frontend initialization failed\n",
+		       __func__);
+		return -1;
+	}
+
+	/* register everything */
+	ret = dvb_register(dev);
+	if (ret < 0) {
+		if (dvb->frontend->ops.release)
+			dvb->frontend->ops.release(dvb->frontend);
+		return ret;
+	}
+
+	return 0;
+}
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/au0828-i2c.c
@@ -0,0 +1,388 @@
+/*
+ *  Driver for the Auvitek AU0828 USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "compat.h"
+#include "au0828.h"
+
+#include <media/v4l2-common.h>
+
+#ifndef I2C_HW_B_AU0828
+#define I2C_HW_B_AU0828		0x010023 /* auvitek au0828 usb bridge */
+#endif /* I2C_HW_B_AU0828 */
+
+static int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+#define I2C_WAIT_DELAY 512
+#define I2C_WAIT_RETRY 64
+
+static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, REG_201) & 0x08 ? 0 : 1;
+}
+
+static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, REG_201) & 0x02 ? 0 : 1;
+}
+
+static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (!i2c_slave_did_read_ack(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, REG_201) & 0x01 ? 0 : 1;
+}
+
+static int i2c_wait_read_done(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (!i2c_is_read_busy(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, REG_201) & 0x04 ? 1 : 0;
+}
+
+static int i2c_wait_write_done(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (i2c_is_write_done(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	return au0828_read(dev, REG_201) & 0x10 ? 1 : 0;
+}
+
+static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (!i2c_is_busy(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+/* FIXME: Implement join handling correctly */
+static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+	const struct i2c_msg *msg, int joined_rlen)
+{
+	int i, strobe = 0;
+	struct au0828_dev *dev = i2c_adap->algo_data;
+
+	dprintk(4, "%s()\n", __func__);
+
+	au0828_write(dev, REG_2FF, 0x01);
+	au0828_write(dev, REG_202, 0x07);
+
+	/* Hardware needs 8 bit addresses */
+	au0828_write(dev, REG_203, msg->addr << 1);
+
+	dprintk(4, "SEND: %02x\n", msg->addr);
+
+	for (i = 0; i < msg->len;) {
+
+		dprintk(4, " %02x\n", msg->buf[i]);
+
+		au0828_write(dev, REG_205, msg->buf[i]);
+
+		strobe++;
+		i++;
+
+		if ((strobe >= 4) || (i >= msg->len)) {
+
+			/* Strobe the byte into the bus */
+			if (i < msg->len)
+				au0828_write(dev, REG_200, 0x41);
+			else
+				au0828_write(dev, REG_200, 0x01);
+
+			/* Reset strobe trigger */
+			strobe = 0;
+
+			if (!i2c_wait_write_done(i2c_adap))
+				return -EIO;
+
+		}
+
+	}
+	if (!i2c_wait_done(i2c_adap))
+		return -EIO;
+
+	dprintk(4, "\n");
+
+	return msg->len;
+}
+
+/* FIXME: Implement join handling correctly */
+static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+	const struct i2c_msg *msg, int joined)
+{
+	struct au0828_dev *dev = i2c_adap->algo_data;
+	int i;
+
+	dprintk(4, "%s()\n", __func__);
+
+	au0828_write(dev, REG_2FF, 0x01);
+	au0828_write(dev, REG_202, 0x07);
+
+	/* Hardware needs 8 bit addresses */
+	au0828_write(dev, REG_203, msg->addr << 1);
+
+	dprintk(4, " RECV:\n");
+
+	/* Deal with i2c_scan */
+	if (msg->len == 0) {
+		au0828_write(dev, REG_200, 0x20);
+		if (i2c_wait_read_ack(i2c_adap))
+			return -EIO;
+		return 0;
+	}
+
+	for (i = 0; i < msg->len;) {
+
+		i++;
+
+		if (i < msg->len)
+			au0828_write(dev, REG_200, 0x60);
+		else
+			au0828_write(dev, REG_200, 0x20);
+
+		if (!i2c_wait_read_done(i2c_adap))
+			return -EIO;
+
+		msg->buf[i-1] = au0828_read(dev, REG_209) & 0xff;
+
+		dprintk(4, " %02x\n", msg->buf[i-1]);
+	}
+	if (!i2c_wait_done(i2c_adap))
+		return -EIO;
+
+	dprintk(4, "\n");
+
+	return msg->len;
+}
+
+static int i2c_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg *msgs, int num)
+{
+	int i, retval = 0;
+
+	dprintk(4, "%s(num = %d)\n", __func__, num);
+
+	for (i = 0; i < num; i++) {
+		dprintk(4, "%s(num = %d) addr = 0x%02x  len = 0x%x\n",
+			__func__, num, msgs[i].addr, msgs[i].len);
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read */
+			retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
+		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
+			   msgs[i].addr == msgs[i + 1].addr) {
+			/* write then read from same address */
+			retval = i2c_sendbytes(i2c_adap, &msgs[i],
+					       msgs[i + 1].len);
+			if (retval < 0)
+				goto err;
+			i++;
+			retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
+		} else {
+			/* write */
+			retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
+		}
+		if (retval < 0)
+			goto err;
+	}
+	return num;
+
+err:
+	return retval;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
+	dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+		client->driver->driver.name, client->addr, client->name);
+
+	if (!client->driver->command)
+		return 0;
+
+	return 0;
+}
+
+static int detach_inform(struct i2c_client *client)
+{
+	dprintk(1, "i2c detach [client=%s]\n", client->name);
+
+	return 0;
+}
+
+void au0828_call_i2c_clients(struct au0828_dev *dev,
+			      unsigned int cmd, void *arg)
+{
+	if (dev->i2c_rc != 0)
+		return;
+
+	i2c_clients_command(&dev->i2c_adap, cmd, arg);
+}
+
+static u32 au0828_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm au0828_i2c_algo_template = {
+	.master_xfer	= i2c_xfer,
+	.functionality	= au0828_functionality,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter au0828_i2c_adap_template = {
+	.name              = DRIVER_NAME,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+	.owner             = THIS_MODULE,
+#endif
+	.id                = I2C_HW_B_AU0828,
+	.algo              = &au0828_i2c_algo_template,
+	.class             = I2C_CLASS_TV_ANALOG,
+	.client_register   = attach_inform,
+	.client_unregister = detach_inform,
+};
+
+static struct i2c_client au0828_i2c_client_template = {
+	.name	= "au0828 internal",
+};
+
+static char *i2c_devs[128] = {
+	[0x8e >> 1] = "au8522",
+	[0xa0 >> 1] = "eeprom",
+	[0xc2 >> 1] = "tuner/xc5000",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+	unsigned char buf;
+	int i, rc;
+
+	for (i = 0; i < 128; i++) {
+		c->addr = i;
+		rc = i2c_master_recv(c, &buf, 0);
+		if (rc < 0)
+			continue;
+		printk(KERN_INFO "%s: i2c scan: found device @ 0x%x  [%s]\n",
+		       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+	}
+}
+
+/* init + register i2c algo-bit adapter */
+int au0828_i2c_register(struct au0828_dev *dev)
+{
+	dprintk(1, "%s()\n", __func__);
+
+	memcpy(&dev->i2c_adap, &au0828_i2c_adap_template,
+	       sizeof(dev->i2c_adap));
+	memcpy(&dev->i2c_algo, &au0828_i2c_algo_template,
+	       sizeof(dev->i2c_algo));
+	memcpy(&dev->i2c_client, &au0828_i2c_client_template,
+	       sizeof(dev->i2c_client));
+
+	dev->i2c_adap.dev.parent = &dev->usbdev->dev;
+
+	strlcpy(dev->i2c_adap.name, DRIVER_NAME,
+		sizeof(dev->i2c_adap.name));
+
+	dev->i2c_algo.data = dev;
+	dev->i2c_adap.algo_data = dev;
+	i2c_set_adapdata(&dev->i2c_adap, dev);
+	i2c_add_adapter(&dev->i2c_adap);
+
+	dev->i2c_client.adapter = &dev->i2c_adap;
+
+	if (0 == dev->i2c_rc) {
+		printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME);
+		if (i2c_scan)
+			do_i2c_scan(DRIVER_NAME, &dev->i2c_client);
+	} else
+		printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME);
+
+	return dev->i2c_rc;
+}
+
+int au0828_i2c_unregister(struct au0828_dev *dev)
+{
+	i2c_del_adapter(&dev->i2c_adap);
+	return 0;
+}
+
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/au0828-reg.h
@@ -0,0 +1,38 @@
+/*
+ *  Driver for the Auvitek USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* We'll start to rename these registers once we have a better
+ * understanding of their meaning.
+ */
+#define REG_000 0x000
+#define REG_001 0x001
+#define REG_002 0x002
+#define REG_003 0x003
+
+#define REG_200 0x200
+#define REG_201 0x201
+#define REG_202 0x202
+#define REG_203 0x203
+#define REG_205 0x205
+#define REG_209 0x209
+#define REG_2FF 0x2ff
+
+#define REG_600 0x600
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/au0828.h
@@ -0,0 +1,133 @@
+/*
+ *  Driver for the Auvitek AU0828 USB bridge
+ *
+ *  Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <media/tveeprom.h>
+#include "compat.h"
+
+/* DVB */
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+
+#include "au0828-reg.h"
+#include "au0828-cards.h"
+
+#define DRIVER_NAME "au0828"
+#define URB_COUNT   16
+#define URB_BUFSIZE (0xe522)
+
+struct au0828_board {
+	char *name;
+};
+
+struct au0828_dvb {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+	struct mutex lock;
+#else
+	struct semaphore lock;
+#endif
+	struct dvb_adapter adapter;
+	struct dvb_frontend *frontend;
+	struct dvb_demux demux;
+	struct dmxdev dmxdev;
+	struct dmx_frontend fe_hw;
+	struct dmx_frontend fe_mem;
+	struct dvb_net net;
+	int feeding;
+};
+
+struct au0828_dev {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+	struct mutex mutex;
+#else
+	struct semaphore mutex;
+#endif
+	struct usb_device	*usbdev;
+	int			board;
+	u8			ctrlmsg[64];
+
+	/* I2C */
+	struct i2c_adapter		i2c_adap;
+	struct i2c_algo_bit_data	i2c_algo;
+	struct i2c_client		i2c_client;
+	u32 				i2c_rc;
+
+	/* Digital */
+	struct au0828_dvb		dvb;
+
+	/* USB / URB Related */
+	int		urb_streaming;
+	struct urb	*urbs[URB_COUNT];
+
+};
+
+struct au0828_buff {
+	struct au0828_dev	*dev;
+	struct urb		*purb;
+	struct list_head	buff_list;
+};
+
+/* ----------------------------------------------------------- */
+#define au0828_read(dev, reg) au0828_readreg(dev, reg)
+#define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value)
+#define au0828_andor(dev, reg, mask, value) 				\
+	 au0828_writereg(dev, reg, 					\
+	(au0828_readreg(dev, reg) & ~(mask)) | ((value) & (mask)))
+
+#define au0828_set(dev, reg, bit) au0828_andor(dev, (reg), (bit), (bit))
+#define au0828_clear(dev, reg, bit) au0828_andor(dev, (reg), (bit), 0)
+
+/* ----------------------------------------------------------- */
+/* au0828-core.c */
+extern u32 au0828_read(struct au0828_dev *dev, u16 reg);
+extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val);
+extern int au0828_debug;
+
+/* ----------------------------------------------------------- */
+/* au0828-cards.c */
+extern struct au0828_board au0828_boards[];
+extern struct usb_device_id au0828_usb_id_table[];
+extern void au0828_gpio_setup(struct au0828_dev *dev);
+extern int au0828_tuner_callback(void *priv, int command, int arg);
+extern void au0828_card_setup(struct au0828_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* au0828-i2c.c */
+extern int au0828_i2c_register(struct au0828_dev *dev);
+extern int au0828_i2c_unregister(struct au0828_dev *dev);
+extern void au0828_call_i2c_clients(struct au0828_dev *dev,
+	unsigned int cmd, void *arg);
+
+/* ----------------------------------------------------------- */
+/* au0828-dvb.c */
+extern int au0828_dvb_register(struct au0828_dev *dev);
+extern void au0828_dvb_unregister(struct au0828_dev *dev);
+
+#define dprintk(level, fmt, arg...)\
+	do { if (au0828_debug & level)\
+		printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
+	} while (0)
--- linux-ubuntu-modules-2.6.24-2.6.24.orig/debian/config/amd64
+++ linux-ubuntu-modules-2.6.24-2.6.24/debian/config/amd64
@@ -95,3 +95,7 @@
 CONFIG_WIMAX_I2400M=m
 
 CONFIG_AGP_INTEL_ICH9M=m
+
+CONFIG_VIDEO_AU0828=m
+CONFIG_DVB_AU8522=m
+CONFIG_MEDIA_TUNER_XC5000=m
--- linux-ubuntu-modules-2.6.24-2.6.24.orig/debian/config/i386
+++ linux-ubuntu-modules-2.6.24-2.6.24/debian/config/i386
@@ -103,3 +103,7 @@
 endif
 
 CONFIG_AGP_INTEL_ICH9M=m
+
+CONFIG_VIDEO_AU0828=m
+CONFIG_DVB_AU8522=m
+CONFIG_MEDIA_TUNER_XC5000=m
--- linux-ubuntu-modules-2.6.24-2.6.24.orig/ubuntu/media/Makefile
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/Makefile
@@ -18,3 +18,6 @@
 
 obj-$(CONFIG_CX88)		+= cx88/
 obj-$(CONFIG_SAA7134)		+= saa7134/
+
+obj-$(CONFIG_VIDEO_AU0828)	+= au0828/
+
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/compat.h
@@ -0,0 +1,583 @@
+/*
+ * $Id: compat.h,v 1.44 2006/01/15 09:35:16 mchehab Exp $
+ */
+
+#ifndef _COMPAT_H
+#define _COMPAT_H
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+#define	KERN_CONT	""
+#endif
+
+/* To allow I2C compatibility code to work */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+#include <linux/i2c-dev.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+#ifdef CONFIG_PROC_FS
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#endif
+#endif
+
+/* To allow alsa code to work */
+#ifdef NEED_SOUND_DRIVER_H
+#include <sound/driver.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
+#define set_freezable()
+#define cancel_delayed_work_sync cancel_rearming_delayed_work
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
+# define minor(x) MINOR(x)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
+# define DEVICE_ATTR(a,b,c,d) CLASS_DEVICE_ATTR(a,b,c,d)
+# define device_create_file(a,b) class_device_create_file(a,b)
+# define device_remove_file(a,b) class_device_remove_file(a,b)
+# define device_register(a) class_device_register(a)
+# define device_unregister(a) class_device_unregister(a)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+# include <linux/moduleparam.h>
+# include <linux/delay.h>
+# define need_resched() (current->need_resched)
+# define work_struct tq_struct
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
+# define BUG_ON(condition) do { if ((condition)!=0) BUG(); } while(0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
+# define irqreturn_t void
+# define IRQ_RETVAL(foobar)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,71)
+# define strlcpy(dest,src,len) strncpy(dest,src,(len)-1)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+# define iminor(inode) minor(inode->i_rdev)
+#endif
+
+#if defined(I2C_ADAP_CLASS_TV_ANALOG) && !defined(I2C_CLASS_TV_ANALOG)
+# define  I2C_CLASS_TV_ANALOG  I2C_ADAP_CLASS_TV_ANALOG
+# define  I2C_CLASS_TV_DIGITAL I2C_ADAP_CLASS_TV_DIGITAL
+#endif
+
+#ifndef __pure
+#  define __pure __attribute__((pure))
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+# define __user
+# define __kernel
+# define __iomem
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+# define pm_message_t                      u32
+# define pci_choose_state(pci_dev, state)  (state)
+# define PCI_D0                            (0)
+# define assert_spin_locked(foobar)
+#endif
+
+/* Since v4l-dvb now includes it's own copy of linux/i2c-id.h these
+   are no longer necessary */
+/*
+#if !defined(I2C_ALGO_SAA7134)
+#define I2C_ALGO_SAA7134 I2C_HW_B_BT848
+#endif
+#if !defined(I2C_HW_B_CX2388x)
+# define I2C_HW_B_CX2388x I2C_HW_B_BT848
+#endif
+#if !defined(I2C_HW_SAA7134)
+# define I2C_HW_SAA7134 I2C_ALGO_SAA7134
+#endif
+#if !defined(I2C_HW_SAA7146)
+# define I2C_HW_SAA7146 I2C_ALGO_SAA7146
+#endif
+#if !defined(I2C_HW_B_EM2820)
+#define I2C_HW_B_EM2820 0x99
+#endif
+*/
+
+#ifndef I2C_M_IGNORE_NAK
+# define I2C_M_IGNORE_NAK 0x1000
+#endif
+
+/* v4l-dvb uses an out of kernel copy of i2c-id.h, which does not have
+   some stuff that previous versions of i2c-id.h defined. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) && defined(LINUX_I2C_ID_H)
+# define I2C_ALGO_BIT 0x010000
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+#define __le32 __u32
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7))
+static inline unsigned long msecs_to_jiffies(const unsigned int m)
+{
+#if HZ <= 1000 && !(1000 % HZ)
+	return (m + (1000 / HZ) - 1) / (1000 / HZ);
+#else
+#if HZ > 1000 && !(HZ % 1000)
+	return m * (HZ / 1000);
+#else
+	return (m * HZ + 999) / 1000;
+#endif
+#endif
+}
+static inline unsigned int jiffies_to_msecs(const unsigned long j)
+{
+#if HZ <= 1000 && !(1000 % HZ)
+	return (1000 / HZ) * j;
+#else
+#if HZ > 1000 && !(HZ % 1000)
+	return (j + (HZ / 1000) - 1)/(HZ / 1000);
+#else
+	return (j * 1000) / HZ;
+#endif
+#endif
+}
+static inline void msleep(unsigned int msecs)
+{
+	unsigned long timeout = msecs_to_jiffies(msecs);
+	while (timeout) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		timeout = schedule_timeout(timeout);
+	}
+}
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+static inline unsigned long msleep_interruptible(unsigned int msecs)
+{
+	unsigned long timeout = msecs_to_jiffies(msecs);
+
+	while (timeout) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		timeout = schedule_timeout(timeout);
+	}
+	return jiffies_to_msecs(timeout);
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+/* some keys from 2.6.x which are not (yet?) in 2.4.x */
+# define KEY_PLAY                207
+# define KEY_PRINT		 210
+# define KEY_EMAIL         215
+# define KEY_SEARCH              217
+# define KEY_SELECT 		 0x161
+# define KEY_GOTO                0x162
+# define KEY_INFO                0x166
+# define KEY_CHANNEL             0x16b
+# define KEY_LANGUAGE            0x170
+# define KEY_SUBTITLE		 0x172
+# define KEY_ZOOM                0x174
+# define KEY_MODE		 0x175
+# define KEY_TV                  0x179
+# define KEY_CD                  0x17f
+# define KEY_TUNER               0x182
+# define KEY_TEXT                0x184
+# define KEY_DVD		 0x185
+# define KEY_AUDIO               0x188
+# define KEY_VIDEO               0x189
+# define KEY_RED                 0x18e
+# define KEY_GREEN               0x18f
+# define KEY_YELLOW              0x190
+# define KEY_BLUE                0x191
+# define KEY_CHANNELUP           0x192
+# define KEY_CHANNELDOWN         0x193
+# define KEY_RESTART		 0x198
+# define KEY_SHUFFLE     	 0x19a
+# define KEY_NEXT                0x197
+# define KEY_RADIO               0x181
+# define KEY_PREVIOUS            0x19c
+# define KEY_MHP                 0x16f
+# define KEY_EPG                 0x16d
+# define KEY_FASTFORWARD         208
+# define KEY_LIST                0x18b
+# define KEY_LAST                0x195
+# define KEY_CLEAR               0x163
+# define KEY_AUX                 0x186
+# define KEY_SCREEN              0x177
+# define KEY_PC                  0x178
+# define KEY_MEDIA               226
+# define KEY_SLOW                0x199
+# define KEY_OK                  0x160
+# define KEY_DIGITS              0x19d
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+# define KEY_SEND		231
+# define KEY_REPLY		232
+# define KEY_FORWARDMAIL	233
+# define KEY_SAVE		234
+# define KEY_DOCUMENTS		235
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#define container_of(ptr, type, member) ({                      \
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+#include <linux/mm.h>
+static inline unsigned long vmalloc_to_pfn(void * vmalloc_addr)
+{
+    return page_to_pfn(vmalloc_to_page(vmalloc_addr));
+}
+
+static unsigned long kvirt_to_pa(unsigned long adr)
+{
+	unsigned long kva, ret;
+
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+	ret = __pa(kva);
+	return ret;
+}
+
+#ifndef wait_event_timeout
+#define wait_event_timeout(wq, condition, timeout)                   	     \
+({                                                                           \
+     long __ret = timeout;                                                   \
+     if (!(condition))                                                       \
+     do {                                                                    \
+	     DEFINE_WAIT(__wait);                                            \
+	     for (;;) {                                                      \
+		     prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);    \
+		     if (condition)                                          \
+			 break;                                              \
+		     __ret = schedule_timeout(__ret);                        \
+		     if (!__ret)                                             \
+			 break;                                              \
+	     }                                                               \
+	     finish_wait(&wq, &__wait);                                      \
+     } while (0);							     \
+     __ret;                                                                  \
+})
+#endif
+
+#define remap_pfn_range remap_page_range
+
+#endif
+
+/* vm_insert_page() was added in 2.6.15 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) && defined(_LINUX_MM_H)
+static inline int vm_insert_page(struct vm_area_struct *vma,
+	unsigned long addr, struct page *page)
+{
+	return remap_pfn_range(vma, addr, page_to_pfn(page), PAGE_SIZE,
+			       vma->vm_page_prot);
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
+#ifndef kcalloc
+#define kcalloc(n,size,flags)			\
+({						\
+  void * __ret = NULL;				\
+  __ret = kmalloc(n * size, flags);		\
+  if (__ret)					\
+	 memset(__ret, 0, n * size);		\
+  __ret;					\
+})
+#endif
+#endif
+
+/* try_to_freeze() lost its argument.  Must appear after linux/sched.h */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) && defined(_LINUX_SCHED_H)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#  define try_to_freeze() try_to_freeze(PF_FREEZE)
+# else
+#  define try_to_freeze() (0)
+# endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
+#ifndef kzalloc
+#define kzalloc(size, flags)				\
+({							\
+	void *__ret = kmalloc(size, flags);		\
+	if (__ret)					\
+		memset(__ret, 0, size);			\
+	__ret;						\
+})
+#endif
+#endif
+
+/* The class_device system didn't appear until 2.5.69 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#define class_device_create_file(a, b) (0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
+# define class_device_create(a, b, c, d, e, f, g, h) class_simple_device_add(a, c, d, e, f, g, h)
+# define class_device_destroy(a, b) class_simple_device_remove(b)
+# define class_create(a, b) class_simple_create(a, b)
+# define class_destroy(a) class_simple_destroy(a)
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+# define class_device_create(a, b, c, d, e, f, g, h) class_device_create(a, c, d, e, f, g, h)
+#endif
+/* device_create/destroy added in 2.6.18 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+/* on older kernels, class_device_create will in turn be a compat macro */
+# define device_create(a, b, c, d, e, f, g) class_device_create(a, NULL, c, b, d, e, f, g)
+# define device_destroy(a, b) class_device_destroy(a, b)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+# define input_allocate_device() kzalloc(sizeof(struct input_dev),GFP_KERNEL);
+# define input_free_device(input_dev) kfree(input_dev)
+# ifdef _INPUT_H  /* input.h must be included _before_ compat.h for this to work */
+   /* input_register_device() was changed to return an error code in 2.6.15 */
+#  define input_register_device(x) (input_register_device(x), 0)
+# endif
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
+#define DEFINE_MUTEX(a) DECLARE_MUTEX(a)
+#define mutex_lock_interruptible(a) down_interruptible(a)
+#define mutex_unlock(a) up(a)
+#define mutex_lock(a) down(a)
+#define mutex_init(a) init_MUTEX(a)
+#define mutex_trylock(a) down_trylock(a)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) && defined(_LINUX_SCHED_H)
+static inline signed long __sched
+schedule_timeout_interruptible(signed long timeout)
+{
+	__set_current_state(TASK_INTERRUPTIBLE);
+	return schedule_timeout(timeout);
+}
+#endif
+
+/* New 4GB DMA zone was added in 2.6.15-rc2 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+#  define __GFP_DMA32	__GFP_DMA
+#endif
+
+/* setup_timer() helper added 10/31/05, 2.6.15-rc1 */
+/* Need linux/timer.h to be included for struct timer_list */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) && defined(_LINUX_TIMER_H)
+static inline void setup_timer(struct timer_list * timer,
+			       void (*function)(unsigned long),
+			       unsigned long data)
+{
+	timer->function = function;
+	timer->data = data;
+	init_timer(timer);
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+#define IRQF_SHARED		SA_SHIRQ
+#define IRQF_DISABLED		SA_INTERRUPT
+#endif
+
+/* linux/usb.h must be included _before_ compat.h for this code to get
+   turned on.  We can not just include usb.h here, because there is a
+   lot of code which will not compile if it has usb.h included, due to
+   conflicts with symbol names.  */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) && \
+    defined(__LINUX_USB_H) && defined(_INPUT_H)
+#include <linux/input.h>
+/* Found in linux/usb_input.h in 2.6.13 */
+/* Moved to linux/usb/input.h in 2.6.18 */
+static inline void
+usb_to_input_id(const struct usb_device *dev, struct input_id *id)
+{
+	id->bustype = BUS_USB;
+	id->vendor = le16_to_cpu(dev->descriptor.idVendor);
+	id->product = le16_to_cpu(dev->descriptor.idProduct);
+	id->version = le16_to_cpu(dev->descriptor.bcdDevice);
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+# define PCIAGP_FAIL 0
+
+#define vmalloc_32_user(a) vmalloc_32(a)
+
+#endif
+
+/* bool type and enum-based definition of true and false was added in 2.6.19 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+typedef int bool;
+#define true 1
+#define false 0
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
+#define sony_pic_camera_command(a,b) sonypi_camera_command(a,b)
+
+#define SONY_PIC_COMMAND_SETCAMERAAGC        SONYPI_COMMAND_SETCAMERAAGC
+#define SONY_PIC_COMMAND_SETCAMERABRIGHTNESS SONYPI_COMMAND_SETCAMERABRIGHTNESS
+#define SONY_PIC_COMMAND_SETCAMERACOLOR      SONYPI_COMMAND_SETCAMERACOLOR
+#define SONY_PIC_COMMAND_SETCAMERACONTRAST   SONYPI_COMMAND_SETCAMERACONTRAST
+#define SONY_PIC_COMMAND_SETCAMERAHUE        SONYPI_COMMAND_SETCAMERAHUE
+#define SONY_PIC_COMMAND_SETCAMERAPICTURE    SONYPI_COMMAND_SETCAMERAPICTURE
+#define SONY_PIC_COMMAND_SETCAMERASHARPNESS  SONYPI_COMMAND_SETCAMERASHARPNESS
+#define SONY_PIC_COMMAND_SETCAMERA           SONYPI_COMMAND_SETCAMERA
+#endif
+
+/* Parameter to pci_match_device() changed in 2.6.13-rc2 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) && defined(LINUX_PCI_H)
+#define pci_match_device(drv, dev)	pci_match_device((drv)->id_table, dev)
+#endif
+
+/* pci_dev got a new revision field in 2.6.23-rc1 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) && defined(LINUX_PCI_H)
+/* Just make it easier to subsitute pci_dev->revision with
+ * v4l_compat_pci_rev(pci_dev).  It's too bad there isn't some kind of context
+ * sensitive macro in C that could do this for us.  */
+static inline u8 v4l_compat_pci_rev(struct pci_dev *pci)
+{ u8 rev; pci_read_config_byte(pci, PCI_REVISION_ID, &rev); return rev; }
+#endif
+
+/* ALSA removed a bunch of typedefs and renamed some structs in 2.6.16 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+# ifdef __SOUND_CORE_H
+#  define snd_card _snd_card /* struct _snd_card became struct snd_card */
+#  define snd_pcm _snd_pcm
+#  undef snd_device
+#  define snd_device _snd_device
+# endif
+# ifdef __SOUND_PCM_H
+#  define snd_pcm_substream _snd_pcm_substream
+#  define snd_pcm_hardware _snd_pcm_hardware
+#  define snd_pcm_runtime _snd_pcm_runtime
+#  define snd_pcm_ops _snd_pcm_ops
+# endif
+# ifdef __SOUND_ASOUND_H
+#  define snd_pcm_hw_params sndrv_pcm_hw_params
+#  define snd_ctl_elem_info sndrv_ctl_elem_info
+#  define snd_ctl_elem_value sndrv_ctl_elem_value
+# endif
+# ifdef __SOUND_CONTROL_H
+#  undef snd_kcontrol
+#  define snd_kcontrol _snd_kcontrol
+#  define snd_kcontrol_new _snd_kcontrol_new
+# endif
+#endif
+
+#if defined(COMPAT_PCM_TO_RATE_BIT) && defined(__SOUND_PCM_H)
+/* New alsa core utility function */
+static inline unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
+{
+	static const unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050,
+		32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 };
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(rates); i++)
+		if (rates[i] == rate)
+			return 1u << i;
+	return SNDRV_PCM_RATE_KNOT;
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+# define task_pid_nr(current) ((current)->pid)
+
+# define sg_init_table(a,b)
+# define sg_page(p) (sg->page)
+# define sg_set_page(sglist,pg,sz,off)					\
+do {									\
+	struct scatterlist *p=sglist;					\
+	p->page   = pg;							\
+	p->length = sz;							\
+	p->offset = off;						\
+} while (0)
+#endif
+
+#ifndef BIT_MASK
+# define BIT_MASK(nr)            (1UL << ((nr) % BITS_PER_LONG))
+# define BIT_WORD(nr)            ((nr) / BITS_PER_LONG)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+#define i2c_verify_client(dev)	\
+	((dev->bus == &i2c_bus_type) ? to_i2c_client(dev) : NULL)
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+#define i2c_verify_client(dev) \
+	((dev->bus && 0 == strcmp(dev->bus->name, "i2c")) ? to_i2c_client(dev) : NULL)
+#endif
+
+#ifndef USB_DEVICE_AND_INTERFACE_INFO
+# define USB_DEVICE_AND_INTERFACE_INFO(vend,prod,cl,sc,pr) \
+	.match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
+		| USB_DEVICE_ID_MATCH_DEVICE, \
+	.idVendor = (vend), .idProduct = (prod), \
+	.bInterfaceClass = (cl), \
+	.bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+#define get_unaligned_be16(a)					\
+	be16_to_cpu(get_unaligned((unsigned short *)(a)))
+#define put_unaligned_be16(r, a)				\
+	put_unaligned(cpu_to_be16(r), ((unsigned short *)(a)))
+#define get_unaligned_le16(a)					\
+	le16_to_cpu(get_unaligned((unsigned short *)(a)))
+#define put_unaligned_le16(r, a)				\
+	put_unaligned(cpu_to_le16(r), ((unsigned short *)(a)))
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
+#ifdef CONFIG_PROC_FS
+static inline struct proc_dir_entry *proc_create(const char *a,
+	mode_t b, struct proc_dir_entry *c, const struct file_operations *d)
+{
+	struct proc_dir_entry *e;
+
+	e = create_proc_entry(a, b, c);
+	if (e) {
+		e->owner = THIS_MODULE;
+		e->proc_fops = d;
+
+	}
+	return e;
+}
+
+static inline struct proc_dir_entry *proc_create_data(const char *a,
+	mode_t b, struct proc_dir_entry *c, const struct file_operations *d,
+	void *f)
+{
+	struct proc_dir_entry *e;
+
+	e = create_proc_entry(a, b, c);
+	if (e) {
+		e->owner = THIS_MODULE;
+		e->proc_fops = d;
+		e->data = f;
+	}
+	return e;
+}
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+#define div64_u64(a,b) div64_64(a,b)
+
+#define clamp( x, l, h )        max_t( __typeof__( x ),		\
+				      ( l ),			\
+				      min_t( __typeof__( x ),	\
+					     ( h ),        	\
+					     ( x ) ) )
+
+#endif
+
+#endif
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/au8522.c
@@ -0,0 +1,716 @@
+/*
+    Auvitek AU8522 QAM/8VSB demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "au8522.h"
+
+struct au8522_state {
+
+	struct i2c_adapter *i2c;
+
+	/* configuration settings */
+	const struct au8522_config *config;
+
+	struct dvb_frontend frontend;
+
+	u32 current_frequency;
+	fe_modulation_t current_modulation;
+
+};
+
+static int debug;
+
+#define dprintk(arg...) do {		\
+	if (debug) 			\
+		 printk(arg); 		\
+	} while (0)
+
+/* 16 bit registers, 8 bit values */
+static int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
+{
+	int ret;
+	u8 buf [] = { reg >> 8, reg & 0xff, data };
+
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+			       .flags = 0, .buf = buf, .len = 3 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+		       "ret == %i)\n", __func__, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static u8 au8522_readreg(struct au8522_state *state, u16 reg)
+{
+	int ret;
+	u8 b0 [] = { reg >> 8, reg & 0xff };
+	u8 b1 [] = { 0 };
+
+	struct i2c_msg msg [] = {
+		{ .addr = state->config->demod_address, .flags = 0,
+		  .buf = b0, .len = 2 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
+		  .buf = b1, .len = 1 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+		       __func__, ret);
+	return b1[0];
+}
+
+static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __func__, enable);
+
+	if (enable)
+		return au8522_writereg(state, 0x106, 1);
+	else
+		return au8522_writereg(state, 0x106, 0);
+}
+
+struct mse2snr_tab {
+	u16 val;
+	u16 data;
+};
+
+/* VSB SNR lookup table */
+static struct mse2snr_tab vsb_mse2snr_tab[] = {
+	{   0, 270 },
+	{   2, 250 },
+	{   3, 240 },
+	{   5, 230 },
+	{   7, 220 },
+	{   9, 210 },
+	{  12, 200 },
+	{  13, 195 },
+	{  15, 190 },
+	{  17, 185 },
+	{  19, 180 },
+	{  21, 175 },
+	{  24, 170 },
+	{  27, 165 },
+	{  31, 160 },
+	{  32, 158 },
+	{  33, 156 },
+	{  36, 152 },
+	{  37, 150 },
+	{  39, 148 },
+	{  40, 146 },
+	{  41, 144 },
+	{  43, 142 },
+	{  44, 140 },
+	{  48, 135 },
+	{  50, 130 },
+	{  43, 142 },
+	{  53, 125 },
+	{  56, 120 },
+	{ 256, 115 },
+};
+
+/* QAM64 SNR lookup table */
+static struct mse2snr_tab qam64_mse2snr_tab[] = {
+	{  15,   0 },
+	{  16, 290 },
+	{  17, 288 },
+	{  18, 286 },
+	{  19, 284 },
+	{  20, 282 },
+	{  21, 281 },
+	{  22, 279 },
+	{  23, 277 },
+	{  24, 275 },
+	{  25, 273 },
+	{  26, 271 },
+	{  27, 269 },
+	{  28, 268 },
+	{  29, 266 },
+	{  30, 264 },
+	{  31, 262 },
+	{  32, 260 },
+	{  33, 259 },
+	{  34, 258 },
+	{  35, 256 },
+	{  36, 255 },
+	{  37, 254 },
+	{  38, 252 },
+	{  39, 251 },
+	{  40, 250 },
+	{  41, 249 },
+	{  42, 248 },
+	{  43, 246 },
+	{  44, 245 },
+	{  45, 244 },
+	{  46, 242 },
+	{  47, 241 },
+	{  48, 240 },
+	{  50, 239 },
+	{  51, 238 },
+	{  53, 237 },
+	{  54, 236 },
+	{  56, 235 },
+	{  57, 234 },
+	{  59, 233 },
+	{  60, 232 },
+	{  62, 231 },
+	{  63, 230 },
+	{  65, 229 },
+	{  67, 228 },
+	{  68, 227 },
+	{  70, 226 },
+	{  71, 225 },
+	{  73, 224 },
+	{  74, 223 },
+	{  76, 222 },
+	{  78, 221 },
+	{  80, 220 },
+	{  82, 219 },
+	{  85, 218 },
+	{  88, 217 },
+	{  90, 216 },
+	{  92, 215 },
+	{  93, 214 },
+	{  94, 212 },
+	{  95, 211 },
+	{  97, 210 },
+	{  99, 209 },
+	{ 101, 208 },
+	{ 102, 207 },
+	{ 104, 206 },
+	{ 107, 205 },
+	{ 111, 204 },
+	{ 114, 203 },
+	{ 118, 202 },
+	{ 122, 201 },
+	{ 125, 200 },
+	{ 128, 199 },
+	{ 130, 198 },
+	{ 132, 197 },
+	{ 256, 190 },
+};
+
+/* QAM256 SNR lookup table */
+static struct mse2snr_tab qam256_mse2snr_tab[] = {
+	{  16,   0 },
+	{  17, 400 },
+	{  18, 398 },
+	{  19, 396 },
+	{  20, 394 },
+	{  21, 392 },
+	{  22, 390 },
+	{  23, 388 },
+	{  24, 386 },
+	{  25, 384 },
+	{  26, 382 },
+	{  27, 380 },
+	{  28, 379 },
+	{  29, 378 },
+	{  30, 377 },
+	{  31, 376 },
+	{  32, 375 },
+	{  33, 374 },
+	{  34, 373 },
+	{  35, 372 },
+	{  36, 371 },
+	{  37, 370 },
+	{  38, 362 },
+	{  39, 354 },
+	{  40, 346 },
+	{  41, 338 },
+	{  42, 330 },
+	{  43, 328 },
+	{  44, 326 },
+	{  45, 324 },
+	{  46, 322 },
+	{  47, 320 },
+	{  48, 319 },
+	{  49, 318 },
+	{  50, 317 },
+	{  51, 316 },
+	{  52, 315 },
+	{  53, 314 },
+	{  54, 313 },
+	{  55, 312 },
+	{  56, 311 },
+	{  57, 310 },
+	{  58, 308 },
+	{  59, 306 },
+	{  60, 304 },
+	{  61, 302 },
+	{  62, 300 },
+	{  63, 298 },
+	{  65, 295 },
+	{  68, 294 },
+	{  70, 293 },
+	{  73, 292 },
+	{  76, 291 },
+	{  78, 290 },
+	{  79, 289 },
+	{  81, 288 },
+	{  82, 287 },
+	{  83, 286 },
+	{  84, 285 },
+	{  85, 284 },
+	{  86, 283 },
+	{  88, 282 },
+	{  89, 281 },
+	{ 256, 280 },
+};
+
+static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
+				 u16 *snr)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __func__);
+
+	for (i = 0; i < sz; i++) {
+		if (mse < tab[i].val) {
+			*snr = tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	dprintk("%s() snr=%d\n", __func__, *snr);
+	return ret;
+}
+
+/* VSB Modulation table */
+static struct {
+	u16 reg;
+	u16 data;
+} VSB_mod_tab[] = {
+	{ 0x8090, 0x84 },
+	{ 0x4092, 0x11 },
+	{ 0x2005, 0x00 },
+	{ 0x8091, 0x80 },
+	{ 0x80a3, 0x0c },
+	{ 0x80a4, 0xe8 },
+	{ 0x8081, 0xc4 },
+	{ 0x80a5, 0x40 },
+	{ 0x80a7, 0x40 },
+	{ 0x80a6, 0x67 },
+	{ 0x8262, 0x20 },
+	{ 0x821c, 0x30 },
+	{ 0x80d8, 0x1a },
+	{ 0x8227, 0xa0 },
+	{ 0x8121, 0xff },
+	{ 0x80a8, 0xf0 },
+	{ 0x80a9, 0x05 },
+	{ 0x80aa, 0x77 },
+	{ 0x80ab, 0xf0 },
+	{ 0x80ac, 0x05 },
+	{ 0x80ad, 0x77 },
+	{ 0x80ae, 0x41 },
+	{ 0x80af, 0x66 },
+	{ 0x821b, 0xcc },
+	{ 0x821d, 0x80 },
+	{ 0x80b5, 0xfb },
+	{ 0x80b6, 0x8e },
+	{ 0x80b7, 0x39 },
+	{ 0x80a4, 0xe8 },
+	{ 0x8231, 0x13 },
+};
+
+/* QAM Modulation table */
+static struct {
+	u16 reg;
+	u16 data;
+} QAM_mod_tab[] = {
+	{ 0x80a3, 0x09 },
+	{ 0x80a4, 0x00 },
+	{ 0x8081, 0xc4 },
+	{ 0x80a5, 0x40 },
+	{ 0x80b5, 0xfb },
+	{ 0x80b6, 0x8e },
+	{ 0x80b7, 0x39 },
+	{ 0x80aa, 0x77 },
+	{ 0x80ad, 0x77 },
+	{ 0x80a6, 0x67 },
+	{ 0x8262, 0x20 },
+	{ 0x821c, 0x30 },
+	{ 0x80b8, 0x3e },
+	{ 0x80b9, 0xf0 },
+	{ 0x80ba, 0x01 },
+	{ 0x80bb, 0x18 },
+	{ 0x80bc, 0x50 },
+	{ 0x80bd, 0x00 },
+	{ 0x80be, 0xea },
+	{ 0x80bf, 0xef },
+	{ 0x80c0, 0xfc },
+	{ 0x80c1, 0xbd },
+	{ 0x80c2, 0x1f },
+	{ 0x80c3, 0xfc },
+	{ 0x80c4, 0xdd },
+	{ 0x80c5, 0xaf },
+	{ 0x80c6, 0x00 },
+	{ 0x80c7, 0x38 },
+	{ 0x80c8, 0x30 },
+	{ 0x80c9, 0x05 },
+	{ 0x80ca, 0x4a },
+	{ 0x80cb, 0xd0 },
+	{ 0x80cc, 0x01 },
+	{ 0x80cd, 0xd9 },
+	{ 0x80ce, 0x6f },
+	{ 0x80cf, 0xf9 },
+	{ 0x80d0, 0x70 },
+	{ 0x80d1, 0xdf },
+	{ 0x80d2, 0xf7 },
+	{ 0x80d3, 0xc2 },
+	{ 0x80d4, 0xdf },
+	{ 0x80d5, 0x02 },
+	{ 0x80d6, 0x9a },
+	{ 0x80d7, 0xd0 },
+	{ 0x8250, 0x0d },
+	{ 0x8251, 0xcd },
+	{ 0x8252, 0xe0 },
+	{ 0x8253, 0x05 },
+	{ 0x8254, 0xa7 },
+	{ 0x8255, 0xff },
+	{ 0x8256, 0xed },
+	{ 0x8257, 0x5b },
+	{ 0x8258, 0xae },
+	{ 0x8259, 0xe6 },
+	{ 0x825a, 0x3d },
+	{ 0x825b, 0x0f },
+	{ 0x825c, 0x0d },
+	{ 0x825d, 0xea },
+	{ 0x825e, 0xf2 },
+	{ 0x825f, 0x51 },
+	{ 0x8260, 0xf5 },
+	{ 0x8261, 0x06 },
+	{ 0x821a, 0x00 },
+	{ 0x8546, 0x40 },
+	{ 0x8210, 0x26 },
+	{ 0x8211, 0xf6 },
+	{ 0x8212, 0x84 },
+	{ 0x8213, 0x02 },
+	{ 0x8502, 0x01 },
+	{ 0x8121, 0x04 },
+	{ 0x8122, 0x04 },
+	{ 0x852e, 0x10 },
+	{ 0x80a4, 0xca },
+	{ 0x80a7, 0x40 },
+	{ 0x8526, 0x01 },
+};
+
+static int au8522_enable_modulation(struct dvb_frontend *fe,
+				    fe_modulation_t m)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	int i;
+
+	dprintk("%s(0x%08x)\n", __func__, m);
+
+	switch (m) {
+	case VSB_8:
+		dprintk("%s() VSB_8\n", __func__);
+		for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++)
+			au8522_writereg(state,
+				VSB_mod_tab[i].reg,
+				VSB_mod_tab[i].data);
+		break;
+	case QAM_64:
+	case QAM_256:
+		dprintk("%s() QAM 64/256\n", __func__);
+		for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++)
+			au8522_writereg(state,
+				QAM_mod_tab[i].reg,
+				QAM_mod_tab[i].data);
+		break;
+	default:
+		dprintk("%s() Invalid modulation\n", __func__);
+		return -EINVAL;
+	}
+
+	state->current_modulation = m;
+
+	return 0;
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int au8522_set_frontend(struct dvb_frontend *fe,
+			       struct dvb_frontend_parameters *p)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	int ret = -EINVAL;
+
+	dprintk("%s(frequency=%d)\n", __func__, p->frequency);
+
+	if ((state->current_frequency == p->frequency) &&
+	    (state->current_modulation == p->u.vsb.modulation))
+		return 0;
+
+	au8522_enable_modulation(fe, p->u.vsb.modulation);
+
+	/* Allow the demod to settle */
+	msleep(100);
+
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		ret = fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	if (ret < 0)
+		return ret;
+
+	state->current_frequency = p->frequency;
+
+	return 0;
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+   to a default state. */
+static int au8522_init(struct dvb_frontend *fe)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	dprintk("%s()\n", __func__);
+
+	au8522_writereg(state, 0xa4, 1 << 5);
+
+	au8522_i2c_gate_ctrl(fe, 1);
+
+	return 0;
+}
+
+static int au8522_sleep(struct dvb_frontend *fe)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	dprintk("%s()\n", __func__);
+
+	state->current_frequency = 0;
+
+	return 0;
+}
+
+static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	u8 reg;
+	u32 tuner_status = 0;
+
+	*status = 0;
+
+	if (state->current_modulation == VSB_8) {
+		dprintk("%s() Checking VSB_8\n", __func__);
+		reg = au8522_readreg(state, 0x4088);
+		if (reg & 0x01)
+			*status |= FE_HAS_VITERBI;
+		if (reg & 0x02)
+			*status |= FE_HAS_LOCK | FE_HAS_SYNC;
+	} else {
+		dprintk("%s() Checking QAM\n", __func__);
+		reg = au8522_readreg(state, 0x4541);
+		if (reg & 0x80)
+			*status |= FE_HAS_VITERBI;
+		if (reg & 0x20)
+			*status |= FE_HAS_LOCK | FE_HAS_SYNC;
+	}
+
+	switch (state->config->status_mode) {
+	case AU8522_DEMODLOCKING:
+		dprintk("%s() DEMODLOCKING\n", __func__);
+		if (*status & FE_HAS_VITERBI)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	case AU8522_TUNERLOCKING:
+		/* Get the tuner status */
+		dprintk("%s() TUNERLOCKING\n", __func__);
+		if (fe->ops.tuner_ops.get_status) {
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 1);
+
+			fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (tuner_status)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	}
+
+	dprintk("%s() status 0x%08x\n", __func__, *status);
+
+	return 0;
+}
+
+static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	int ret = -EINVAL;
+
+	dprintk("%s()\n", __func__);
+
+	if (state->current_modulation == QAM_256)
+		ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
+					    ARRAY_SIZE(qam256_mse2snr_tab),
+					    au8522_readreg(state, 0x4522),
+					    snr);
+	else if (state->current_modulation == QAM_64)
+		ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
+					    ARRAY_SIZE(qam64_mse2snr_tab),
+					    au8522_readreg(state, 0x4522),
+					    snr);
+	else /* VSB_8 */
+		ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
+					    ARRAY_SIZE(vsb_mse2snr_tab),
+					    au8522_readreg(state, 0x4311),
+					    snr);
+
+	return ret;
+}
+
+static int au8522_read_signal_strength(struct dvb_frontend *fe,
+				       u16 *signal_strength)
+{
+	return au8522_read_snr(fe, signal_strength);
+}
+
+static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+
+	if (state->current_modulation == VSB_8)
+		*ucblocks = au8522_readreg(state, 0x4087);
+	else
+		*ucblocks = au8522_readreg(state, 0x4543);
+
+	return 0;
+}
+
+static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	return au8522_read_ucblocks(fe, ber);
+}
+
+static int au8522_get_frontend(struct dvb_frontend *fe,
+				struct dvb_frontend_parameters *p)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+
+	p->frequency = state->current_frequency;
+	p->u.vsb.modulation = state->current_modulation;
+
+	return 0;
+}
+
+static int au8522_get_tune_settings(struct dvb_frontend *fe,
+				    struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void au8522_release(struct dvb_frontend *fe)
+{
+	struct au8522_state *state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops au8522_ops;
+
+struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+				   struct i2c_adapter *i2c)
+{
+	struct au8522_state *state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct au8522_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+#if 0
+	/* check if the demod exists */
+	reg = au8522_readreg(state, 0x04);
+	if ((reg != 0x0066) && (reg != 0x007f))
+		goto error;
+#endif
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &au8522_ops,
+	       sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	if (au8522_init(&state->frontend) != 0) {
+		printk(KERN_ERR "%s: Failed to initialize correctly\n",
+			__func__);
+		goto error;
+	}
+
+	/* Note: Leaving the I2C gate open here. */
+	au8522_i2c_gate_ctrl(&state->frontend, 1);
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+EXPORT_SYMBOL(au8522_attach);
+
+static struct dvb_frontend_ops au8522_ops = {
+
+	.info = {
+		.name			= "Auvitek AU8522 QAM/8VSB Frontend",
+		.type			= FE_ATSC,
+		.frequency_min		= 54000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 62500,
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+
+	.init                 = au8522_init,
+	.sleep                = au8522_sleep,
+	.i2c_gate_ctrl        = au8522_i2c_gate_ctrl,
+	.set_frontend         = au8522_set_frontend,
+	.get_frontend         = au8522_get_frontend,
+	.get_tune_settings    = au8522_get_tune_settings,
+	.read_status          = au8522_read_status,
+	.read_ber             = au8522_read_ber,
+	.read_signal_strength = au8522_read_signal_strength,
+	.read_snr             = au8522_read_snr,
+	.read_ucblocks        = au8522_read_ucblocks,
+	.release              = au8522_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/au8522.h
@@ -0,0 +1,57 @@
+/*
+    Auvitek AU8522 QAM/8VSB demodulator driver
+
+    Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __AU8522_H__
+#define __AU8522_H__
+
+#include <linux/dvb/frontend.h>
+
+struct au8522_config {
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* Return lock status based on tuner lock, or demod lock */
+#define AU8522_TUNERLOCKING 0
+#define AU8522_DEMODLOCKING 1
+	u8 status_mode;
+};
+
+#define CONFIG_DVB_AU8522
+#if defined(CONFIG_DVB_AU8522) || 				\
+	    (defined(CONFIG_DVB_AU8522_MODULE) && defined(MODULE))
+extern struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+					  struct i2c_adapter *i2c);
+#else
+static inline
+struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+				   struct i2c_adapter *i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_AU8522 */
+
+#endif /* __AU8522_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/xc5000.c
@@ -0,0 +1,984 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Xceive Corporation
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "xc5000.h"
+#include "xc5000_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
+
+#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
+#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
+
+/* Misc Defines */
+#define MAX_TV_STANDARD			23
+#define XC_MAX_I2C_WRITE_LENGTH		64
+
+/* Signal Types */
+#define XC_RF_MODE_AIR			0
+#define XC_RF_MODE_CABLE		1
+
+/* Result codes */
+#define XC_RESULT_SUCCESS		0
+#define XC_RESULT_RESET_FAILURE		1
+#define XC_RESULT_I2C_WRITE_FAILURE	2
+#define XC_RESULT_I2C_READ_FAILURE	3
+#define XC_RESULT_OUT_OF_RANGE		5
+
+/* Product id */
+#define XC_PRODUCT_ID_FW_NOT_LOADED	0x2000
+#define XC_PRODUCT_ID_FW_LOADED 	0x1388
+
+/* Registers */
+#define XREG_INIT         0x00
+#define XREG_VIDEO_MODE   0x01
+#define XREG_AUDIO_MODE   0x02
+#define XREG_RF_FREQ      0x03
+#define XREG_D_CODE       0x04
+#define XREG_IF_OUT       0x05
+#define XREG_SEEK_MODE    0x07
+#define XREG_POWER_DOWN   0x0A
+#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
+#define XREG_SMOOTHEDCVBS 0x0E
+#define XREG_XTALFREQ     0x0F
+#define XREG_FINERFFREQ   0x10
+#define XREG_DDIMODE      0x11
+
+#define XREG_ADC_ENV      0x00
+#define XREG_QUALITY      0x01
+#define XREG_FRAME_LINES  0x02
+#define XREG_HSYNC_FREQ   0x03
+#define XREG_LOCK         0x04
+#define XREG_FREQ_ERROR   0x05
+#define XREG_SNR          0x06
+#define XREG_VERSION      0x07
+#define XREG_PRODUCT_ID   0x08
+#define XREG_BUSY         0x09
+
+/*
+   Basic firmware description. This will remain with
+   the driver for documentation purposes.
+
+   This represents an I2C firmware file encoded as a
+   string of unsigned char. Format is as follows:
+
+   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
+   char[1  ]=len0_LSB  -> length of first write transaction
+   char[2  ]=data0 -> first byte to be sent
+   char[3  ]=data1
+   char[4  ]=data2
+   char[   ]=...
+   char[M  ]=dataN  -> last byte to be sent
+   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
+   char[M+2]=len1_LSB  -> length of second write transaction
+   char[M+3]=data0
+   char[M+4]=data1
+   ...
+   etc.
+
+   The [len] value should be interpreted as follows:
+
+   len= len_MSB _ len_LSB
+   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
+   len=0000_0000_0000_0000   : Reset command: Do hardware reset
+   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
+   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
+
+   For the RESET and WAIT commands, the two following bytes will contain
+   immediately the length of the following transaction.
+
+*/
+typedef struct {
+	char *Name;
+	u16 AudioMode;
+	u16 VideoMode;
+} XC_TV_STANDARD;
+
+/* Tuner standards */
+#define MN_NTSC_PAL_BTSC	0
+#define MN_NTSC_PAL_A2		1
+#define MN_NTSC_PAL_EIAJ	2
+#define MN_NTSC_PAL_Mono	3
+#define BG_PAL_A2		4
+#define BG_PAL_NICAM		5
+#define BG_PAL_MONO		6
+#define I_PAL_NICAM		7
+#define I_PAL_NICAM_MONO	8
+#define DK_PAL_A2		9
+#define DK_PAL_NICAM		10
+#define DK_PAL_MONO		11
+#define DK_SECAM_A2DK1		12
+#define DK_SECAM_A2LDK3 	13
+#define DK_SECAM_A2MONO 	14
+#define L_SECAM_NICAM		15
+#define LC_SECAM_NICAM		16
+#define DTV6			17
+#define DTV8			18
+#define DTV7_8			19
+#define DTV7			20
+#define FM_Radio_INPUT2 	21
+#define FM_Radio_INPUT1 	22
+
+static XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
+	{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
+	{"M/N-NTSC/PAL-A2",   0x0600, 0x8020},
+	{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
+	{"M/N-NTSC/PAL-Mono", 0x0478, 0x8020},
+	{"B/G-PAL-A2",        0x0A00, 0x8049},
+	{"B/G-PAL-NICAM",     0x0C04, 0x8049},
+	{"B/G-PAL-MONO",      0x0878, 0x8059},
+	{"I-PAL-NICAM",       0x1080, 0x8009},
+	{"I-PAL-NICAM-MONO",  0x0E78, 0x8009},
+	{"D/K-PAL-A2",        0x1600, 0x8009},
+	{"D/K-PAL-NICAM",     0x0E80, 0x8009},
+	{"D/K-PAL-MONO",      0x1478, 0x8009},
+	{"D/K-SECAM-A2 DK1",  0x1200, 0x8009},
+	{"D/K-SECAM-A2 L/DK3",0x0E00, 0x8009},
+	{"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
+	{"L-SECAM-NICAM",     0x8E82, 0x0009},
+	{"L'-SECAM-NICAM",    0x8E82, 0x4009},
+	{"DTV6",              0x00C0, 0x8002},
+	{"DTV8",              0x00C0, 0x800B},
+	{"DTV7/8",            0x00C0, 0x801B},
+	{"DTV7",              0x00C0, 0x8007},
+	{"FM Radio-INPUT2",   0x9802, 0x9002},
+	{"FM Radio-INPUT1",   0x0208, 0x9002}
+};
+
+static int  xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
+static int  xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
+static void xc5000_TunerReset(struct dvb_frontend *fe);
+
+static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
+{
+	return xc5000_writeregs(priv, buf, len)
+		? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS;
+}
+
+static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
+{
+	return xc5000_readregs(priv, buf, len)
+		? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS;
+}
+
+static int xc_reset(struct dvb_frontend *fe)
+{
+	xc5000_TunerReset(fe);
+	return XC_RESULT_SUCCESS;
+}
+
+static void xc_wait(int wait_ms)
+{
+	msleep(wait_ms);
+}
+
+static void xc5000_TunerReset(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk(1, "%s()\n", __func__);
+
+	if (priv->cfg->tuner_callback) {
+		ret = priv->cfg->tuner_callback(priv->devptr,
+						XC5000_TUNER_RESET, 0);
+		if (ret)
+			printk(KERN_ERR "xc5000: reset failed\n");
+	} else
+		printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
+}
+
+static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
+{
+	u8 buf[4];
+	int WatchDogTimer = 5;
+	int result;
+
+	buf[0] = (regAddr >> 8) & 0xFF;
+	buf[1] = regAddr & 0xFF;
+	buf[2] = (i2cData >> 8) & 0xFF;
+	buf[3] = i2cData & 0xFF;
+	result = xc_send_i2c_data(priv, buf, 4);
+	if (result == XC_RESULT_SUCCESS) {
+		/* wait for busy flag to clear */
+		while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
+			buf[0] = 0;
+			buf[1] = XREG_BUSY;
+
+			result = xc_send_i2c_data(priv, buf, 2);
+			if (result == XC_RESULT_SUCCESS) {
+				result = xc_read_i2c_data(priv, buf, 2);
+				if (result == XC_RESULT_SUCCESS) {
+					if ((buf[0] == 0) && (buf[1] == 0)) {
+						/* busy flag cleared */
+					break;
+					} else {
+						xc_wait(100); /* wait 5 ms */
+						WatchDogTimer--;
+					}
+				}
+			}
+		}
+	}
+	if (WatchDogTimer < 0)
+		result = XC_RESULT_I2C_WRITE_FAILURE;
+
+	return result;
+}
+
+static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData)
+{
+	u8 buf[2];
+	int result;
+
+	buf[0] = (regAddr >> 8) & 0xFF;
+	buf[1] = regAddr & 0xFF;
+	result = xc_send_i2c_data(priv, buf, 2);
+	if (result != XC_RESULT_SUCCESS)
+		return result;
+
+	result = xc_read_i2c_data(priv, buf, 2);
+	if (result != XC_RESULT_SUCCESS)
+		return result;
+
+	*i2cData = buf[0] * 256 + buf[1];
+	return result;
+}
+
+static int xc_load_i2c_sequence(struct dvb_frontend *fe, u8 i2c_sequence[])
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+
+	int i, nbytes_to_send, result;
+	unsigned int len, pos, index;
+	u8 buf[XC_MAX_I2C_WRITE_LENGTH];
+
+	index=0;
+	while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) {
+		len = i2c_sequence[index]* 256 + i2c_sequence[index+1];
+		if (len == 0x0000) {
+			/* RESET command */
+			result = xc_reset(fe);
+			index += 2;
+			if (result != XC_RESULT_SUCCESS)
+				return result;
+		} else if (len & 0x8000) {
+			/* WAIT command */
+			xc_wait(len & 0x7FFF);
+			index += 2;
+		} else {
+			/* Send i2c data whilst ensuring individual transactions
+			 * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
+			 */
+			index += 2;
+			buf[0] = i2c_sequence[index];
+			buf[1] = i2c_sequence[index + 1];
+			pos = 2;
+			while (pos < len) {
+				if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) {
+					nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH;
+				} else {
+					nbytes_to_send = (len - pos + 2);
+				}
+				for (i=2; i<nbytes_to_send; i++) {
+					buf[i] = i2c_sequence[index + pos + i - 2];
+				}
+				result = xc_send_i2c_data(priv, buf, nbytes_to_send);
+
+				if (result != XC_RESULT_SUCCESS)
+					return result;
+
+				pos += nbytes_to_send - 2;
+			}
+			index += len;
+		}
+	}
+	return XC_RESULT_SUCCESS;
+}
+
+static int xc_initialize(struct xc5000_priv *priv)
+{
+	dprintk(1, "%s()\n", __func__);
+	return xc_write_reg(priv, XREG_INIT, 0);
+}
+
+static int xc_SetTVStandard(struct xc5000_priv *priv,
+	u16 VideoMode, u16 AudioMode)
+{
+	int ret;
+	dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode);
+	dprintk(1, "%s() Standard = %s\n",
+		__func__,
+		XC5000_Standard[priv->video_standard].Name);
+
+	ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
+	if (ret == XC_RESULT_SUCCESS)
+		ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode);
+
+	return ret;
+}
+
+static int xc_shutdown(struct xc5000_priv *priv)
+{
+	return 0;
+	/* Fixme: cannot bring tuner back alive once shutdown
+	 *        without reloading the driver modules.
+	 *    return xc_write_reg(priv, XREG_POWER_DOWN, 0);
+	 */
+}
+
+static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
+{
+	dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
+		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
+
+	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE))
+	{
+		rf_mode = XC_RF_MODE_CABLE;
+		printk(KERN_ERR
+			"%s(), Invalid mode, defaulting to CABLE",
+			__func__);
+	}
+	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
+}
+
+static const struct dvb_tuner_ops xc5000_tuner_ops;
+
+static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
+{
+	u16 freq_code;
+
+	dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+	if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
+		(freq_hz < xc5000_tuner_ops.info.frequency_min))
+		return XC_RESULT_OUT_OF_RANGE;
+
+	freq_code = (u16)(freq_hz / 15625);
+
+	return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
+}
+
+#if 0
+/* We'll probably need these for analog support */
+static int xc_FineTune_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
+{
+	u16 freq_code = (u16)(freq_hz / 15625);
+
+	if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
+		(freq_hz < xc5000_tuner_ops.info.frequency_min))
+		return XC_RESULT_OUT_OF_RANGE;
+
+	return xc_write_reg(priv, XREG_FINERFFREQ, freq_code);
+}
+
+static int xc_set_Xtal_frequency(struct xc5000_priv *priv, u32 xtalFreqInKHz)
+{
+	u16 xtalRatio = (32000 * 0x8000)/xtalFreqInKHz;
+	return xc_write_reg(priv, XREG_XTALFREQ, xtalRatio);
+}
+#endif
+
+static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
+{
+	u32 freq_code = (freq_khz * 1024)/1000;
+	dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n",
+		__func__, freq_khz, freq_code);
+
+	return xc_write_reg(priv, XREG_IF_OUT, freq_code);
+}
+
+
+static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
+{
+	return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope);
+}
+
+static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
+{
+	int result;
+	u16 regData;
+	u32 tmp;
+
+	result = xc_read_reg(priv, XREG_FREQ_ERROR, &regData);
+	if (result)
+		return result;
+
+	tmp = (u32)regData;
+	(*freq_error_hz) = (tmp * 15625) / 1000;
+	return result;
+}
+
+static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
+{
+	return xc_read_reg(priv, XREG_LOCK, lock_status);
+}
+
+static int xc_get_version(struct xc5000_priv *priv,
+	u8 *hw_majorversion, u8 *hw_minorversion,
+	u8 *fw_majorversion, u8 *fw_minorversion)
+{
+	u16 data;
+	int result;
+
+	result = xc_read_reg(priv, XREG_VERSION, &data);
+	if (result)
+		return result;
+
+	(*hw_majorversion) = (data >> 12) & 0x0F;
+	(*hw_minorversion) = (data >>  8) & 0x0F;
+	(*fw_majorversion) = (data >>  4) & 0x0F;
+	(*fw_minorversion) = data & 0x0F;
+
+	return 0;
+}
+
+static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
+{
+	u16 regData;
+	int result;
+
+	result = xc_read_reg(priv, XREG_HSYNC_FREQ, &regData);
+	if (result)
+		return result;
+
+	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
+	return result;
+}
+
+static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
+{
+	return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines);
+}
+
+static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
+{
+	return xc_read_reg(priv, XREG_QUALITY, quality);
+}
+
+static u16 WaitForLock(struct xc5000_priv *priv)
+{
+	u16 lockState = 0;
+	int watchDogCount = 40;
+
+	while ((lockState == 0) && (watchDogCount > 0)) {
+		xc_get_lock_status(priv, &lockState);
+		if (lockState != 1) {
+			xc_wait(5);
+			watchDogCount--;
+		}
+	}
+	return lockState;
+}
+
+static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
+{
+	int found = 0;
+
+	dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+	if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
+		return 0;
+
+	if (WaitForLock(priv) == 1)
+		found = 1;
+
+	return found;
+}
+
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
+{
+	u8 buf[2] = { reg >> 8, reg & 0xff };
+	u8 bval[2] = { 0, 0 };
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->cfg->i2c_address,
+			.flags = 0, .buf = &buf[0], .len = 2 },
+		{ .addr = priv->cfg->i2c_address,
+			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "xc5000: I2C read failed\n");
+		return -EREMOTEIO;
+	}
+
+	*val = (bval[0] << 8) | bval[1];
+	return 0;
+}
+
+static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
+{
+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+		.flags = 0, .buf = buf, .len = len };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
+			(int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
+{
+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+		.flags = I2C_M_RD, .buf = buf, .len = len };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int xc5000_fwupload(struct dvb_frontend* fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	const struct firmware *fw;
+	int ret;
+
+	/* request the firmware, this will block and timeout */
+	printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
+		XC5000_DEFAULT_FIRMWARE);
+
+	ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
+	if (ret) {
+		printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
+		ret = XC_RESULT_RESET_FAILURE;
+		goto out;
+	} else {
+		printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n",
+		       fw->size);
+		ret = XC_RESULT_SUCCESS;
+	}
+
+	if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) {
+		printk(KERN_ERR "xc5000: firmware incorrect size\n");
+		ret = XC_RESULT_RESET_FAILURE;
+	} else {
+		printk(KERN_INFO "xc5000: firmware upload\n");
+		ret = xc_load_i2c_sequence(fe,  fw->data );
+	}
+
+out:
+	release_firmware(fw);
+	return ret;
+}
+
+static void xc_debug_dump(struct xc5000_priv *priv)
+{
+	u16 adc_envelope;
+	u32 freq_error_hz = 0;
+	u16 lock_status;
+	u32 hsync_freq_hz = 0;
+	u16 frame_lines;
+	u16 quality;
+	u8 hw_majorversion = 0, hw_minorversion = 0;
+	u8 fw_majorversion = 0, fw_minorversion = 0;
+
+	/* Wait for stats to stabilize.
+	 * Frame Lines needs two frame times after initial lock
+	 * before it is valid.
+	 */
+	xc_wait(100);
+
+	xc_get_ADC_Envelope(priv,  &adc_envelope);
+	dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
+
+	xc_get_frequency_error(priv, &freq_error_hz);
+	dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
+
+	xc_get_lock_status(priv,  &lock_status);
+	dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
+		lock_status);
+
+	xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
+		&fw_majorversion, &fw_minorversion);
+	dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
+		hw_majorversion, hw_minorversion,
+		fw_majorversion, fw_minorversion);
+
+	xc_get_hsync_freq(priv,  &hsync_freq_hz);
+	dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
+
+	xc_get_frame_lines(priv,  &frame_lines);
+	dprintk(1, "*** Frame lines = %d\n", frame_lines);
+
+	xc_get_quality(priv,  &quality);
+	dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
+}
+
+static int xc5000_set_params(struct dvb_frontend *fe,
+	struct dvb_frontend_parameters *params)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
+
+	switch(params->u.vsb.modulation) {
+	case VSB_8:
+	case VSB_16:
+		dprintk(1, "%s() VSB modulation\n", __func__);
+		priv->rf_mode = XC_RF_MODE_AIR;
+		priv->freq_hz = params->frequency - 1750000;
+		priv->bandwidth = BANDWIDTH_6_MHZ;
+		priv->video_standard = DTV6;
+		break;
+	case QAM_64:
+	case QAM_256:
+	case QAM_AUTO:
+		dprintk(1, "%s() QAM modulation\n", __func__);
+		priv->rf_mode = XC_RF_MODE_CABLE;
+		priv->freq_hz = params->frequency - 1750000;
+		priv->bandwidth = BANDWIDTH_6_MHZ;
+		priv->video_standard = DTV6;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dprintk(1, "%s() frequency=%d (compensated)\n",
+		__func__, priv->freq_hz);
+
+	ret = xc_SetSignalSource(priv, priv->rf_mode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR
+			"xc5000: xc_SetSignalSource(%d) failed\n",
+			priv->rf_mode);
+		return -EREMOTEIO;
+	}
+
+	ret = xc_SetTVStandard(priv,
+		XC5000_Standard[priv->video_standard].VideoMode,
+		XC5000_Standard[priv->video_standard].AudioMode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+		return -EREMOTEIO;
+	}
+
+	ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
+			priv->cfg->if_khz);
+		return -EIO;
+	}
+
+	xc_tune_channel(priv, priv->freq_hz);
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	return 0;
+}
+
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
+
+static int xc5000_set_analog_params(struct dvb_frontend *fe,
+	struct analog_parameters *params)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	if(priv->fwloaded == 0)
+		xc_load_fw_and_init_tuner(fe);
+
+	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
+		__func__, params->frequency);
+
+	priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */
+
+	/* params->frequency is in units of 62.5khz */
+	priv->freq_hz = params->frequency * 62500;
+
+	/* FIX ME: Some video standards may have several possible audio
+		   standards. We simply default to one of them here.
+	 */
+	if(params->std & V4L2_STD_MN) {
+		/* default to BTSC audio standard */
+		priv->video_standard = MN_NTSC_PAL_BTSC;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_PAL_BG) {
+		/* default to NICAM audio standard */
+		priv->video_standard = BG_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_PAL_I) {
+		/* default to NICAM audio standard */
+		priv->video_standard = I_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_PAL_DK) {
+		/* default to NICAM audio standard */
+		priv->video_standard = DK_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_SECAM_DK) {
+		/* default to A2 DK1 audio standard */
+		priv->video_standard = DK_SECAM_A2DK1;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_SECAM_L) {
+		priv->video_standard = L_SECAM_NICAM;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_SECAM_LC) {
+		priv->video_standard = LC_SECAM_NICAM;
+		goto tune_channel;
+	}
+
+tune_channel:
+	ret = xc_SetSignalSource(priv, priv->rf_mode);
+	if (ret != XC_RESULT_SUCCESS) {
+	printk(KERN_ERR
+			"xc5000: xc_SetSignalSource(%d) failed\n",
+			priv->rf_mode);
+		return -EREMOTEIO;
+	}
+
+	ret = xc_SetTVStandard(priv,
+		XC5000_Standard[priv->video_standard].VideoMode,
+		XC5000_Standard[priv->video_standard].AudioMode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+		return -EREMOTEIO;
+	}
+
+	xc_tune_channel(priv, priv->freq_hz);
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	return 0;
+}
+
+static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+	*freq = priv->freq_hz;
+	return 0;
+}
+
+static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+
+	*bw = priv->bandwidth;
+	return 0;
+}
+
+static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	u16 lock_status = 0;
+
+	xc_get_lock_status(priv, &lock_status);
+
+	dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status);
+
+	*status = lock_status;
+
+	return 0;
+}
+
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret = 0;
+
+	if (priv->fwloaded == 0) {
+		ret = xc5000_fwupload(fe);
+		if (ret != XC_RESULT_SUCCESS)
+			return ret;
+		priv->fwloaded = 1;
+	}
+
+	/* Start the tuner self-calibration process */
+	ret |= xc_initialize(priv);
+
+	/* Wait for calibration to complete.
+	 * We could continue but XC5000 will clock stretch subsequent
+	 * I2C transactions until calibration is complete.  This way we
+	 * don't have to rely on clock stretching working.
+	 */
+	xc_wait( 100 );
+
+	/* Default to "CABLE" mode */
+	ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
+
+	return ret;
+}
+
+static int xc5000_sleep(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk(1, "%s()\n", __func__);
+
+	/* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
+	 * once shutdown without reloading the driver. Maybe I am not
+	 * doing something right.
+	 *
+	 */
+
+	ret = xc_shutdown(priv);
+	if(ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR
+			"xc5000: %s() unable to shutdown tuner\n",
+			__func__);
+		return -EREMOTEIO;
+	}
+	else {
+		/* priv->fwloaded = 0; */
+		return XC_RESULT_SUCCESS;
+	}
+}
+
+static int xc5000_init(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __func__);
+
+	if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
+		return -EREMOTEIO;
+	}
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	return 0;
+}
+
+static int xc5000_release(struct dvb_frontend *fe)
+{
+	dprintk(1, "%s()\n", __func__);
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops xc5000_tuner_ops = {
+	.info = {
+		.name           = "Xceive XC5000",
+		.frequency_min  =    1000000,
+		.frequency_max  = 1023000000,
+		.frequency_step =      50000,
+	},
+
+	.release	   = xc5000_release,
+	.init		   = xc5000_init,
+	.sleep		   = xc5000_sleep,
+
+	.set_params	   = xc5000_set_params,
+	.set_analog_params = xc5000_set_analog_params,
+	.get_frequency	   = xc5000_get_frequency,
+	.get_bandwidth	   = xc5000_get_bandwidth,
+	.get_status	   = xc5000_get_status
+};
+
+struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
+				   struct i2c_adapter *i2c,
+				   struct xc5000_config *cfg, void *devptr)
+{
+	struct xc5000_priv *priv = NULL;
+	u16 id = 0;
+
+	dprintk(1, "%s()\n", __func__);
+
+	priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg = cfg;
+	priv->bandwidth = BANDWIDTH_6_MHZ;
+	priv->i2c = i2c;
+	priv->devptr = devptr;
+
+	/* Check if firmware has been loaded. It is possible that another
+	   instance of the driver has loaded the firmware.
+	 */
+	if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) {
+		kfree(priv);
+		return NULL;
+	}
+
+	switch(id) {
+	case XC_PRODUCT_ID_FW_LOADED:
+		printk(KERN_INFO
+			"xc5000: Successfully identified at address 0x%02x\n",
+			cfg->i2c_address);
+		printk(KERN_INFO
+			"xc5000: Firmware has been loaded previously\n");
+		priv->fwloaded = 1;
+		break;
+	case XC_PRODUCT_ID_FW_NOT_LOADED:
+		printk(KERN_INFO
+			"xc5000: Successfully identified at address 0x%02x\n",
+			cfg->i2c_address);
+		printk(KERN_INFO
+			"xc5000: Firmware has not been loaded previously\n");
+		priv->fwloaded = 0;
+		break;
+	default:
+		printk(KERN_ERR
+			"xc5000: Device not found at addr 0x%02x (0x%x)\n",
+			cfg->i2c_address, id);
+		kfree(priv);
+		return NULL;
+	}
+
+	memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+
+	return fe;
+}
+EXPORT_SYMBOL(xc5000_attach);
+
+MODULE_AUTHOR("Steven Toth");
+MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/xc5000.h
@@ -0,0 +1,66 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __XC5000_H__
+#define __XC5000_H__
+
+#include <linux/firmware.h>
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct xc5000_config {
+	u8   i2c_address;
+	u32  if_khz;
+
+	int  (*tuner_callback) (void *priv, int command, int arg);
+};
+
+/* xc5000 callback command */
+#define XC5000_TUNER_RESET		0
+
+/* For each bridge framework, when it attaches either analog or digital,
+ * it has to store a reference back to its _core equivalent structure,
+ * so that it can service the hardware by steering gpio's etc.
+ * Each bridge implementation is different so cast devptr accordingly.
+ * The xc5000 driver cares not for this value, other than ensuring
+ * it's passed back to a bridge during tuner_callback().
+ */
+
+#define CONFIG_MEDIA_TUNER_XC5000
+#if defined(CONFIG_MEDIA_TUNER_XC5000) || \
+    (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
+extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
+					  struct i2c_adapter *i2c,
+					  struct xc5000_config *cfg,
+					  void *devptr);
+#else
+static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
+						 struct i2c_adapter *i2c,
+						 struct xc5000_config *cfg,
+						 void *devptr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+#endif // CONFIG_MEDIA_TUNER_XC5000
+
+#endif // __XC5000_H__
--- /dev/null
+++ linux-ubuntu-modules-2.6.24-2.6.24/ubuntu/media/au0828/xc5000_priv.h
@@ -0,0 +1,38 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef XC5000_PRIV_H
+#define XC5000_PRIV_H
+
+struct xc5000_priv {
+	struct xc5000_config *cfg;
+	struct i2c_adapter   *i2c;
+
+	u32 freq_hz;
+	u32 bandwidth;
+	u8  video_standard;
+	u8  rf_mode;
+	u8  fwloaded;
+
+	void *devptr;
+};
+
+#endif
