--- /dev/null
+/*
+ * Hauppage HD PVR USB driver
+ *
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2008      Janne Grunau (j@jannau.net)
+ * Copyright (C) 2008      John Poet
+ *
+ *     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, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-common.h>
+
+#include "hdpvr.h"
+
+static int video_nr[HDPVR_MAX] = {[0 ... (HDPVR_MAX - 1)] = UNSET};
+module_param_array(video_nr, int, NULL, 0);
+MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)");
+
+/* holds the number of currently registered devices */
+static atomic_t dev_nr = ATOMIC_INIT(-1);
+
+int hdpvr_debug;
+module_param(hdpvr_debug, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(hdpvr_debug, "enable debugging output");
+
+uint default_video_input = HDPVR_VIDEO_INPUTS;
+module_param(default_video_input, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(default_video_input, "default video input: 0=Component / "
+                "1=S-Video / 2=Composite");
+
+uint default_audio_input = HDPVR_AUDIO_INPUTS;
+module_param(default_audio_input, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / "
+                "1=RCA front / 2=S/PDIF");
+
+static int boost_audio;
+module_param(boost_audio, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(boost_audio, "boost the audio signal");
+
+
+/* table of devices that work with this driver */
+static struct usb_device_id hdpvr_table[] = {
+       { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID) },
+       { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID1) },
+       { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID2) },
+       { }                                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, hdpvr_table);
+
+
+void hdpvr_delete(struct hdpvr_device *dev)
+{
+       hdpvr_free_buffers(dev);
+
+       if (dev->video_dev)
+               video_device_release(dev->video_dev);
+
+       usb_put_dev(dev->udev);
+}
+
+static void challenge(u8 *bytes)
+{
+       u64 *i64P, tmp64;
+       uint i, idx;
+
+       for (idx = 0; idx < 32; ++idx) {
+
+               if (idx & 0x3)
+                       bytes[(idx >> 3) + 3] = bytes[(idx >> 2) & 0x3];
+
+               switch (idx & 0x3) {
+               case 0x3:
+                       bytes[2] += bytes[3] * 4 + bytes[4] + bytes[5];
+                       bytes[4] += bytes[(idx & 0x1) * 2] * 9 + 9;
+                       break;
+               case 0x1:
+                       bytes[0] *= 8;
+                       bytes[0] += 7*idx + 4;
+                       bytes[6] += bytes[3] * 3;
+                       break;
+               case 0x0:
+                       bytes[3 - (idx >> 3)] = bytes[idx >> 2];
+                       bytes[5] += bytes[6] * 3;
+                       for (i = 0; i < 3; i++)
+                               bytes[3] *= bytes[3] + 1;
+                       break;
+               case 0x2:
+                       for (i = 0; i < 3; i++)
+                               bytes[1] *= bytes[6] + 1;
+                       for (i = 0; i < 3; i++) {
+                               i64P = (u64 *)bytes;
+                               tmp64 = le64_to_cpup(i64P);
+                               tmp64 <<= bytes[7] & 0x0f;
+                               *i64P += cpu_to_le64(tmp64);
+                       }
+                       break;
+               }
+       }
+}
+
+/* try to init the device like the windows driver */
+static int device_authorization(struct hdpvr_device *dev)
+{
+
+       int ret, retval = -ENOMEM;
+       char request_type = 0x38, rcv_request = 0x81;
+       char *response;
+#ifdef HDPVR_DEBUG
+       size_t buf_size = 46;
+       char *print_buf = kzalloc(5*buf_size+1, GFP_KERNEL);
+       if (!print_buf) {
+               dev_err(&dev->udev->dev, "Out of memory");
+               goto error;
+       }
+#endif
+
+       mutex_lock(&dev->usbc_mutex);
+       ret = usb_control_msg(dev->udev,
+                             usb_rcvctrlpipe(dev->udev, 0),
+                             rcv_request, 0x80 | request_type,
+                             0x0400, 0x0003,
+                             dev->usbc_buf, 46,
+                             10000);
+       if (ret != 46) {
+               dev_err(&dev->udev->dev,
+                       "unexpected answer of status request, len %d", ret);
+               goto error;
+       }
+#ifdef HDPVR_DEBUG
+       else {
+               hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf,
+                                  sizeof(print_buf), 0);
+               dev_dbg(&dev->udev->dev,
+                       "Status request returned, len %d: %s\n",
+                       ret, print_buf);
+       }
+#endif
+       if (dev->usbc_buf[1] == HDPVR_FIRMWARE_VERSION) {
+               dev->flags &= ~HDPVR_FLAG_AC3_CAP;
+       } else if (dev->usbc_buf[1] == HDPVR_FIRMWARE_VERSION_AC3) {
+               dev->flags |= HDPVR_FLAG_AC3_CAP;
+       } else if (dev->usbc_buf[1] > HDPVR_FIRMWARE_VERSION_AC3) {
+               dev_notice(&dev->udev->dev, "untested firmware version 0x%x, "
+                          "the driver might not work\n", dev->usbc_buf[1]);
+               dev->flags |= HDPVR_FLAG_AC3_CAP;
+       } else {
+               dev_err(&dev->udev->dev, "unknown firmware version 0x%x\n",
+                       dev->usbc_buf[1]);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       response = dev->usbc_buf+38;
+#ifdef HDPVR_DEBUG
+       hex_dump_to_buffer(response, 8, 16, 1, print_buf, sizeof(print_buf), 0);
+       dev_dbg(&dev->udev->dev, "challenge: %s\n", print_buf);
+#endif
+       challenge(response);
+#ifdef HDPVR_DEBUG
+       hex_dump_to_buffer(response, 8, 16, 1, print_buf, sizeof(print_buf), 0);
+       dev_dbg(&dev->udev->dev, " response: %s\n", print_buf);
+#endif
+
+       msleep(100);
+       ret = usb_control_msg(dev->udev,
+                             usb_sndctrlpipe(dev->udev, 0),
+                             0xd1, 0x00 | request_type,
+                             0x0000, 0x0000,
+                             response, 8,
+                             10000);
+       dev_dbg(&dev->udev->dev, "magic request returned %d\n", ret);
+       mutex_unlock(&dev->usbc_mutex);
+
+       retval = ret != 8;
+error:
+       return retval;
+}
+
+static int hdpvr_device_init(struct hdpvr_device *dev)
+{
+       int ret;
+       u8 *buf;
+       struct hdpvr_video_info *vidinf;
+
+       if (device_authorization(dev))
+               return -EACCES;
+
+       /* default options for init */
+       hdpvr_set_options(dev);
+
+       /* set filter options */
+       mutex_lock(&dev->usbc_mutex);
+       buf = dev->usbc_buf;
+       buf[0] = 0x03; buf[1] = 0x03; buf[2] = 0x00; buf[3] = 0x00;
+       ret = usb_control_msg(dev->udev,
+                             usb_sndctrlpipe(dev->udev, 0),
+                             0x01, 0x38,
+                             CTRL_LOW_PASS_FILTER_VALUE, CTRL_DEFAULT_INDEX,
+                             buf, 4,
+                             1000);
+       dev_dbg(&dev->udev->dev, "control request returned %d\n", ret);
+       mutex_unlock(&dev->usbc_mutex);
+
+       vidinf = get_video_info(dev);
+       if (!vidinf)
+               dev_dbg(&dev->udev->dev,
+                       "no valid video signal or device init failed\n");
+       else
+               kfree(vidinf);
+
+       /* enable fan and bling leds */
+       mutex_lock(&dev->usbc_mutex);
+       buf[0] = 0x1;
+       ret = usb_control_msg(dev->udev,
+                             usb_sndctrlpipe(dev->udev, 0),
+                             0xd4, 0x38, 0, 0, buf, 1,
+                             1000);
+       dev_dbg(&dev->udev->dev, "control request returned %d\n", ret);
+
+       /* boost analog audio */
+       buf[0] = boost_audio;
+       ret = usb_control_msg(dev->udev,
+                             usb_sndctrlpipe(dev->udev, 0),
+                             0xd5, 0x38, 0, 0, buf, 1,
+                             1000);
+       dev_dbg(&dev->udev->dev, "control request returned %d\n", ret);
+       mutex_unlock(&dev->usbc_mutex);
+
+       dev->status = STATUS_IDLE;
+       return 0;
+}
+
+static const struct hdpvr_options hdpvr_default_options = {
+       .video_std      = HDPVR_60HZ,
+       .video_input    = HDPVR_COMPONENT,
+       .audio_input    = HDPVR_RCA_BACK,
+       .bitrate        = 65, /* 6 mbps */
+       .peak_bitrate   = 90, /* 9 mbps */
+       .bitrate_mode   = HDPVR_CONSTANT,
+       .gop_mode       = HDPVR_SIMPLE_IDR_GOP,
+       .audio_codec    = V4L2_MPEG_AUDIO_ENCODING_AAC,
+       .brightness     = 0x86,
+       .contrast       = 0x80,
+       .hue            = 0x80,
+       .saturation     = 0x80,
+       .sharpness      = 0x80,
+};
+
+static int hdpvr_probe(struct usb_interface *interface,
+                      const struct usb_device_id *id)
+{
+       struct hdpvr_device *dev;
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
+       size_t buffer_size;
+       int i;
+       int retval = -ENOMEM;
+
+       /* allocate memory for our device state and initialize it */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               err("Out of memory");
+               goto error;
+       }
+       mutex_init(&dev->io_mutex);
+       mutex_init(&dev->i2c_mutex);
+       mutex_init(&dev->usbc_mutex);
+       dev->usbc_buf = kmalloc(64, GFP_KERNEL);
+       if (!dev->usbc_buf) {
+               dev_err(&dev->udev->dev, "Out of memory");
+               goto error;
+       }
+
+       init_waitqueue_head(&dev->wait_buffer);
+       init_waitqueue_head(&dev->wait_data);
+
+       dev->workqueue = create_singlethread_workqueue("hdpvr_buffer");
+       if (!dev->workqueue)
+               goto error;
+
+       /* init video transfer queues */
+       INIT_LIST_HEAD(&dev->free_buff_list);
+       INIT_LIST_HEAD(&dev->rec_buff_list);
+
+       dev->options = hdpvr_default_options;
+
+       if (default_video_input < HDPVR_VIDEO_INPUTS)
+               dev->options.video_input = default_video_input;
+
+       if (default_audio_input < HDPVR_AUDIO_INPUTS)
+               dev->options.audio_input = default_audio_input;
+
+       dev->udev = usb_get_dev(interface_to_usbdev(interface));
+
+       /* set up the endpoint information */
+       /* use only the first bulk-in and bulk-out endpoints */
+       iface_desc = interface->cur_altsetting;
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               endpoint = &iface_desc->endpoint[i].desc;
+
+               if (!dev->bulk_in_endpointAddr &&
+                   usb_endpoint_is_bulk_in(endpoint)) {
+                       /* USB interface description is buggy, reported max
+                        * packet size is 512 bytes, windows driver uses 8192 */
+                       buffer_size = 8192;
+                       dev->bulk_in_size = buffer_size;
+                       dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+               }
+
+       }
+       if (!dev->bulk_in_endpointAddr) {
+               err("Could not find bulk-in endpoint");
+               goto error;
+       }
+
+       /* init the device */
+       if (hdpvr_device_init(dev)) {
+               err("device init failed");
+               goto error;
+       }
+
+       mutex_lock(&dev->io_mutex);
+       if (hdpvr_alloc_buffers(dev, NUM_BUFFERS)) {
+               err("allocating transfer buffers failed");
+               goto error;
+       }
+       mutex_unlock(&dev->io_mutex);
+
+       if (hdpvr_register_videodev(dev,
+                                   video_nr[atomic_inc_return(&dev_nr)])) {
+               err("registering videodev failed");
+               goto error;
+       }
+
+
+       /* save our data pointer in this interface device */
+       usb_set_intfdata(interface, dev);
+
+       /* let the user know what node this device is now attached to */
+       v4l2_info(dev->video_dev, "device now attached to /dev/video%d\n",
+                 dev->video_dev->minor);
+       return 0;
+
+error:
+       if (dev) {
+               mutex_unlock(&dev->io_mutex);
+               /* this frees allocated memory */
+               hdpvr_delete(dev);
+       }
+       return retval;
+}
+
+static void hdpvr_disconnect(struct usb_interface *interface)
+{
+       struct hdpvr_device *dev;
+       int minor;
+
+       dev = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       minor = dev->video_dev->minor;
+
+       /* prevent more I/O from starting and stop any ongoing */
+       mutex_lock(&dev->io_mutex);
+       dev->status = STATUS_DISCONNECTED;
+       video_unregister_device(dev->video_dev);
+       wake_up_interruptible(&dev->wait_data);
+       wake_up_interruptible(&dev->wait_buffer);
+       msleep(100);
+       flush_workqueue(dev->workqueue);
+       hdpvr_cancel_queue(dev);
+       destroy_workqueue(dev->workqueue);
+       mutex_unlock(&dev->io_mutex);
+
+       /* deregister I2C adapter */
+       mutex_lock(&dev->i2c_mutex);
+       if (dev->i2c_adapter)
+               i2c_del_adapter(dev->i2c_adapter);
+       kfree(dev->i2c_adapter);
+       dev->i2c_adapter = NULL;
+       mutex_unlock(&dev->i2c_mutex);
+
+       atomic_dec(&dev_nr);
+
+       printk(KERN_INFO "Hauppauge HD PVR: device /dev/video%d disconnected\n",
+              minor);
+
+       kfree(dev->usbc_buf);
+       kfree(dev);
+}
+
+
+static struct usb_driver hdpvr_usb_driver = {
+       .name =         "hdpvr",
+       .probe =        hdpvr_probe,
+       .disconnect =   hdpvr_disconnect,
+       .id_table =     hdpvr_table,
+};
+
+static int __init hdpvr_init(void)
+{
+       int result;
+
+       /* register this driver with the USB subsystem */
+       result = usb_register(&hdpvr_usb_driver);
+       if (result)
+               err("usb_register failed. Error number %d", result);
+
+       return result;
+}
+
+static void __exit hdpvr_exit(void)
+{
+       /* deregister this driver with the USB subsystem */
+       usb_deregister(&hdpvr_usb_driver);
+}
+
+module_init(hdpvr_init);
+module_exit(hdpvr_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Janne Grunau");
+MODULE_DESCRIPTION("Hauppauge HD PVR driver");
 
--- /dev/null
+/*
+ * Hauppage HD PVR USB driver - video 4 linux 2 interface
+ *
+ * Copyright (C) 2008      Janne Grunau (j@jannau.net)
+ *
+ *     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, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include "hdpvr.h"
+
+#define BULK_URB_TIMEOUT 1250 /* 1.25 seconds */
+
+struct hdpvr_fh {
+       struct hdpvr_device     *dev;
+};
+
+static uint list_size(struct list_head *list)
+{
+       struct list_head *tmp;
+       uint count = 0;
+
+       list_for_each(tmp, list) {
+               count++;
+       }
+
+       return count;
+}
+
+/*=========================================================================*/
+/* urb callback */
+static void hdpvr_read_bulk_callback(struct urb *urb)
+{
+       struct hdpvr_buffer *buf = (struct hdpvr_buffer *)urb->context;
+       struct hdpvr_device *dev = buf->dev;
+
+       /* marking buffer as received and wake waiting */
+       buf->status = BUFSTAT_READY;
+       wake_up_interruptible(&dev->wait_data);
+}
+
+/*=========================================================================*/
+/* bufffer bits */
+
+/* function expects dev->io_mutex to be hold by caller */
+int hdpvr_cancel_queue(struct hdpvr_device *dev)
+{
+       struct hdpvr_buffer *buf;
+
+       list_for_each_entry(buf, &dev->rec_buff_list, buff_list) {
+               usb_kill_urb(buf->urb);
+               buf->status = BUFSTAT_AVAILABLE;
+       }
+
+       list_splice_init(&dev->rec_buff_list, dev->free_buff_list.prev);
+
+       return 0;
+}
+
+static int hdpvr_free_queue(struct list_head *q)
+{
+       struct list_head *tmp;
+       struct list_head *p;
+       struct hdpvr_buffer *buf;
+       struct urb *urb;
+
+       for (p = q->next; p != q;) {
+               buf = list_entry(p, struct hdpvr_buffer, buff_list);
+
+               urb = buf->urb;
+               usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+                               urb->transfer_buffer, urb->transfer_dma);
+               usb_free_urb(urb);
+               tmp = p->next;
+               list_del(p);
+               kfree(buf);
+               p = tmp;
+       }
+
+       return 0;
+}
+
+/* function expects dev->io_mutex to be hold by caller */
+int hdpvr_free_buffers(struct hdpvr_device *dev)
+{
+       hdpvr_cancel_queue(dev);
+
+       hdpvr_free_queue(&dev->free_buff_list);
+       hdpvr_free_queue(&dev->rec_buff_list);
+
+       return 0;
+}
+
+/* function expects dev->io_mutex to be hold by caller */
+int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
+{
+       uint i;
+       int retval = -ENOMEM;
+       u8 *mem;
+       struct hdpvr_buffer *buf;
+       struct urb *urb;
+
+       v4l2_dbg(MSG_INFO, hdpvr_debug, dev->video_dev,
+                "allocating %u buffers\n", count);
+
+       for (i = 0; i < count; i++) {
+
+               buf = kzalloc(sizeof(struct hdpvr_buffer), GFP_KERNEL);
+               if (!buf) {
+                       err("cannot allocate buffer");
+                       goto exit;
+               }
+               buf->dev = dev;
+
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!urb) {
+                       err("cannot allocate urb");
+                       goto exit;
+               }
+               buf->urb = urb;
+
+               mem = usb_buffer_alloc(dev->udev, dev->bulk_in_size, GFP_KERNEL,
+                                      &urb->transfer_dma);
+               if (!mem) {
+                       err("cannot allocate usb transfer buffer");
+                       goto exit;
+               }
+
+               usb_fill_bulk_urb(buf->urb, dev->udev,
+                                 usb_rcvbulkpipe(dev->udev,
+                                                 dev->bulk_in_endpointAddr),
+                                 mem, dev->bulk_in_size,
+                                 hdpvr_read_bulk_callback, buf);
+
+               buf->status = BUFSTAT_AVAILABLE;
+               list_add_tail(&buf->buff_list, &dev->free_buff_list);
+       }
+       return 0;
+exit:
+       hdpvr_free_buffers(dev);
+       return retval;
+}
+
+static int hdpvr_submit_buffers(struct hdpvr_device *dev)
+{
+       struct hdpvr_buffer *buf;
+       struct urb *urb;
+       int ret = 0, err_count = 0;
+
+       mutex_lock(&dev->io_mutex);
+
+       while (dev->status == STATUS_STREAMING &&
+              !list_empty(&dev->free_buff_list)) {
+
+               buf = list_entry(dev->free_buff_list.next, struct hdpvr_buffer,
+                                buff_list);
+               if (buf->status != BUFSTAT_AVAILABLE) {
+                       err("buffer not marked as availbale");
+                       ret = -EFAULT;
+                       goto err;
+               }
+
+               urb = buf->urb;
+               urb->status = 0;
+               urb->actual_length = 0;
+               ret = usb_submit_urb(urb, GFP_KERNEL);
+               if (ret) {
+                       err("usb_submit_urb in %s returned %d", __func__, ret);
+                       if (++err_count > 2)
+                               break;
+                       continue;
+               }
+               buf->status = BUFSTAT_INPROGRESS;
+               list_move_tail(&buf->buff_list, &dev->rec_buff_list);
+       }
+err:
+       v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
+                "buffer queue stat: %d free, %d proc\n",
+                list_size(&dev->free_buff_list),
+                list_size(&dev->rec_buff_list));
+       mutex_unlock(&dev->io_mutex);
+       return ret;
+}
+
+static struct hdpvr_buffer *hdpvr_get_next_buffer(struct hdpvr_device *dev)
+{
+       struct hdpvr_buffer *buf;
+
+       mutex_lock(&dev->io_mutex);
+
+       if (list_empty(&dev->rec_buff_list)) {
+               mutex_unlock(&dev->io_mutex);
+               return NULL;
+       }
+
+       buf = list_entry(dev->rec_buff_list.next, struct hdpvr_buffer,
+                        buff_list);
+       mutex_unlock(&dev->io_mutex);
+
+       return buf;
+}
+
+static void hdpvr_transmit_buffers(struct work_struct *work)
+{
+       struct hdpvr_device *dev = container_of(work, struct hdpvr_device,
+                                               worker);
+
+       while (dev->status == STATUS_STREAMING) {
+
+               if (hdpvr_submit_buffers(dev)) {
+                       v4l2_err(dev->video_dev, "couldn't submit buffers\n");
+                       goto error;
+               }
+               if (wait_event_interruptible(dev->wait_buffer,
+                               !list_empty(&dev->free_buff_list) ||
+                                            dev->status != STATUS_STREAMING))
+                       goto error;
+       }
+
+       v4l2_dbg(MSG_INFO, hdpvr_debug, dev->video_dev,
+                "transmit worker exited\n");
+       return;
+error:
+       v4l2_dbg(MSG_INFO, hdpvr_debug, dev->video_dev,
+                "transmit buffers errored\n");
+       dev->status = STATUS_ERROR;
+}
+
+/* function expects dev->io_mutex to be hold by caller */
+static int hdpvr_start_streaming(struct hdpvr_device *dev)
+{
+       int ret;
+       struct hdpvr_video_info *vidinf;
+
+       if (dev->status == STATUS_STREAMING)
+               return 0;
+       else if (dev->status != STATUS_IDLE)
+               return -EAGAIN;
+
+       vidinf = get_video_info(dev);
+
+       if (vidinf) {
+               v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
+                        "video signal: %dx%d@%dhz\n", vidinf->width,
+                        vidinf->height, vidinf->fps);
+               kfree(vidinf);
+
+               /* start streaming 2 request */
+               ret = usb_control_msg(dev->udev,
+                                     usb_sndctrlpipe(dev->udev, 0),
+                                     0xb8, 0x38, 0x1, 0, NULL, 0, 8000);
+               v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
+                        "encoder start control request returned %d\n", ret);
+
+               hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00);
+
+               INIT_WORK(&dev->worker, hdpvr_transmit_buffers);
+               queue_work(dev->workqueue, &dev->worker);
+
+               v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
+                        "streaming started\n");
+               dev->status = STATUS_STREAMING;
+
+               return 0;
+       }
+       msleep(250);
+       v4l2_dbg(MSG_INFO, hdpvr_debug, dev->video_dev,
+                "no video signal at input %d\n", dev->options.video_input);
+       return -EAGAIN;
+}
+
+
+/* function expects dev->io_mutex to be hold by caller */
+static int hdpvr_stop_streaming(struct hdpvr_device *dev)
+{
+       if (dev->status == STATUS_IDLE)
+               return 0;
+       else if (dev->status != STATUS_STREAMING)
+               return -EAGAIN;
+
+       dev->status = STATUS_SHUTTING_DOWN;
+       hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00);
+
+       wake_up_interruptible(&dev->wait_buffer);
+       msleep(50);
+
+       flush_workqueue(dev->workqueue);
+
+       /* kill the still outstanding urbs */
+       hdpvr_cancel_queue(dev);
+
+       dev->status = STATUS_IDLE;
+
+       return 0;
+}
+
+
+/*=======================================================================*/
+/*
+ * video 4 linux 2 file operations
+ */
+
+static int hdpvr_open(struct file *file)
+{
+       struct hdpvr_device *dev;
+       struct hdpvr_fh *fh;
+       int retval = -ENOMEM;
+
+       dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file));
+       if (!dev) {
+               err("open failing with with ENODEV");
+               retval = -ENODEV;
+               goto err;
+       }
+
+       fh = kzalloc(sizeof(struct hdpvr_fh), GFP_KERNEL);
+       if (!fh) {
+               err("Out of memory?");
+               goto err;
+       }
+       /* lock the device to allow correctly handling errors
+        * in resumption */
+       mutex_lock(&dev->io_mutex);
+       dev->open_count++;
+
+       fh->dev = dev;
+
+       /* save our object in the file's private structure */
+       file->private_data = fh;
+
+       retval = 0;
+err:
+       mutex_unlock(&dev->io_mutex);
+       return retval;
+}
+
+static int hdpvr_release(struct file *file)
+{
+       struct hdpvr_fh         *fh  = (struct hdpvr_fh *)file->private_data;
+       struct hdpvr_device     *dev = fh->dev;
+
+       if (!dev)
+               return -ENODEV;
+
+       mutex_lock(&dev->io_mutex);
+       if (!(--dev->open_count) && dev->status == STATUS_STREAMING)
+               hdpvr_stop_streaming(dev);
+
+       mutex_unlock(&dev->io_mutex);
+
+       return 0;
+}
+
+/*
+ * hdpvr_v4l2_read()
+ * will allocate buffers when called for the first time
+ */
+static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
+                         loff_t *pos)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       struct hdpvr_buffer *buf = NULL;
+       struct urb *urb;
+       unsigned int ret = 0;
+       int rem, cnt;
+
+       if (*pos)
+               return -ESPIPE;
+
+       if (!dev)
+               return -ENODEV;
+
+       mutex_lock(&dev->io_mutex);
+       if (dev->status == STATUS_IDLE) {
+               if (hdpvr_start_streaming(dev)) {
+                       v4l2_dbg(MSG_INFO, hdpvr_debug, dev->video_dev,
+                                "start_streaming failed");
+                       ret = -EIO;
+                       msleep(200);
+                       dev->status = STATUS_IDLE;
+                       mutex_unlock(&dev->io_mutex);
+                       goto err;
+               }
+
+               v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
+                        "buffer queue stat: %d free, %d proc\n",
+                        list_size(&dev->free_buff_list),
+                        list_size(&dev->rec_buff_list));
+       }
+       mutex_unlock(&dev->io_mutex);
+
+       /* wait for the first buffer */
+       if (!(file->f_flags & O_NONBLOCK)) {
+               if (wait_event_interruptible(dev->wait_data,
+                                            hdpvr_get_next_buffer(dev)))
+                       return -ERESTARTSYS;
+       }
+
+       buf = hdpvr_get_next_buffer(dev);
+
+       while (count > 0 && buf) {
+
+               if (buf->status != BUFSTAT_READY &&
+                   dev->status != STATUS_DISCONNECTED) {
+                       /* return nonblocking */
+                       if (file->f_flags & O_NONBLOCK) {
+                               if (!ret)
+                                       ret = -EAGAIN;
+                               goto err;
+                       }
+
+                       if (wait_event_interruptible(dev->wait_data,
+                                             buf->status == BUFSTAT_READY)) {
+                               ret = -ERESTARTSYS;
+                               goto err;
+                       }
+               }
+
+               if (buf->status != BUFSTAT_READY)
+                       break;
+
+               /* set remaining bytes to copy */
+               urb = buf->urb;
+               rem = urb->actual_length - buf->pos;
+               cnt = rem > count ? count : rem;
+
+               if (copy_to_user(buffer, urb->transfer_buffer + buf->pos,
+                                cnt)) {
+                       err("read: copy_to_user failed");
+                       if (!ret)
+                               ret = -EFAULT;
+                       goto err;
+               }
+
+               buf->pos += cnt;
+               count -= cnt;
+               buffer += cnt;
+               ret += cnt;
+
+               /* finished, take next buffer */
+               if (buf->pos == urb->actual_length) {
+                       mutex_lock(&dev->io_mutex);
+                       buf->pos = 0;
+                       buf->status = BUFSTAT_AVAILABLE;
+
+                       list_move_tail(&buf->buff_list, &dev->free_buff_list);
+
+                       v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
+                                "buffer queue stat: %d free, %d proc\n",
+                                list_size(&dev->free_buff_list),
+                                list_size(&dev->rec_buff_list));
+
+                       mutex_unlock(&dev->io_mutex);
+
+                       wake_up_interruptible(&dev->wait_buffer);
+
+                       buf = hdpvr_get_next_buffer(dev);
+               }
+       }
+err:
+       if (!ret && !buf)
+               ret = -EAGAIN;
+       return ret;
+}
+
+static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
+{
+       struct hdpvr_fh *fh = (struct hdpvr_fh *)filp->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       unsigned int mask = 0;
+
+       mutex_lock(&dev->io_mutex);
+
+       if (video_is_unregistered(dev->video_dev))
+               return -EIO;
+
+       if (dev->status == STATUS_IDLE) {
+               if (hdpvr_start_streaming(dev)) {
+                       v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
+                                "start_streaming failed");
+                       dev->status = STATUS_IDLE;
+               }
+
+               v4l2_dbg(MSG_BUFFER, hdpvr_debug, dev->video_dev,
+                        "buffer queue stat: %d free, %d proc\n",
+                        list_size(&dev->free_buff_list),
+                        list_size(&dev->rec_buff_list));
+       }
+       mutex_unlock(&dev->io_mutex);
+
+       poll_wait(filp, &dev->wait_data, wait);
+
+       mutex_lock(&dev->io_mutex);
+       if (!list_empty(&dev->rec_buff_list)) {
+
+               struct hdpvr_buffer *buf = list_entry(dev->rec_buff_list.next,
+                                                     struct hdpvr_buffer,
+                                                     buff_list);
+
+               if (buf->status == BUFSTAT_READY)
+                       mask |= POLLIN | POLLRDNORM;
+       }
+       mutex_unlock(&dev->io_mutex);
+
+       return mask;
+}
+
+
+static long hdpvr_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       struct hdpvr_fh *fh = (struct hdpvr_fh *)filp->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int res;
+
+       if (video_is_unregistered(dev->video_dev))
+               return -EIO;
+
+       mutex_lock(&dev->io_mutex);
+       switch (cmd) {
+       case VIDIOC_TRY_ENCODER_CMD:
+       case VIDIOC_ENCODER_CMD: {
+               struct v4l2_encoder_cmd *enc = (struct v4l2_encoder_cmd *)arg;
+               int try = cmd == VIDIOC_TRY_ENCODER_CMD;
+
+               memset(&enc->raw, 0, sizeof(enc->raw));
+               switch (enc->cmd) {
+               case V4L2_ENC_CMD_START:
+                       enc->flags = 0;
+                       if (try)
+                               return 0;
+                       res = hdpvr_start_streaming(dev);
+                       break;
+               case V4L2_ENC_CMD_STOP:
+                       if (try)
+                               return 0;
+                       res = hdpvr_stop_streaming(dev);
+                       break;
+               default:
+                       v4l2_dbg(MSG_INFO, hdpvr_debug, dev->video_dev,
+                                "Unsupported encoder cmd %d\n", enc->cmd);
+                       return -EINVAL;
+               }
+               break;
+       }
+       default:
+               res = video_ioctl2(filp, cmd, arg);
+       }
+       mutex_unlock(&dev->io_mutex);
+       return res;
+}
+
+static const struct v4l2_file_operations hdpvr_fops = {
+       .owner          = THIS_MODULE,
+       .open           = hdpvr_open,
+       .release        = hdpvr_release,
+       .read           = hdpvr_read,
+       .poll           = hdpvr_poll,
+       .unlocked_ioctl = hdpvr_ioctl,
+};
+
+/*=======================================================================*/
+/*
+ * V4L2 ioctl handling
+ */
+
+static int vidioc_querycap(struct file *file, void  *priv,
+                          struct v4l2_capability *cap)
+{
+       struct hdpvr_device *dev = video_drvdata(file);
+
+       strcpy(cap->driver, "hdpvr");
+       strcpy(cap->card, "Haupauge HD PVR");
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+       cap->version = HDPVR_VERSION;
+       cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_AUDIO         |
+                               V4L2_CAP_READWRITE;
+       return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *private_data,
+                       v4l2_std_id *std)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       u8 std_type = 1;
+
+       if (*std & (V4L2_STD_NTSC | V4L2_STD_PAL_60))
+               std_type = 0;
+
+       return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type);
+}
+
+static const char *iname[] = {
+       [HDPVR_COMPONENT] = "Component",
+       [HDPVR_SVIDEO]    = "S-Video",
+       [HDPVR_COMPOSITE] = "Composite",
+};
+
+static int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *i)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       unsigned int n;
+
+       n = i->index;
+       if (n >= HDPVR_VIDEO_INPUTS)
+               return -EINVAL;
+
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+
+       strncpy(i->name, iname[n], sizeof(i->name) - 1);
+       i->name[sizeof(i->name) - 1] = '\0';
+
+       i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF;
+
+       i->std = dev->video_dev->tvnorms;
+
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *private_data,
+                         unsigned int index)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int retval;
+
+       if (index >= HDPVR_VIDEO_INPUTS)
+               return -EINVAL;
+
+       if (dev->status != STATUS_IDLE)
+               return -EAGAIN;
+
+       retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1);
+       if (!retval)
+               dev->options.video_input = index;
+
+       return retval;
+}
+
+static int vidioc_g_input(struct file *file, void *private_data,
+                         unsigned int *index)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+
+       *index = dev->options.video_input;
+       return 0;
+}
+
+
+static const char *audio_iname[] = {
+       [HDPVR_RCA_FRONT] = "RCA front",
+       [HDPVR_RCA_BACK]  = "RCA back",
+       [HDPVR_SPDIF]     = "SPDIF",
+};
+
+static int vidioc_enumaudio(struct file *file, void *priv,
+                               struct v4l2_audio *audio)
+{
+       unsigned int n;
+
+       n = audio->index;
+       if (n >= HDPVR_AUDIO_INPUTS)
+               return -EINVAL;
+
+       audio->capability = V4L2_AUDCAP_STEREO;
+
+       strncpy(audio->name, audio_iname[n], sizeof(audio->name) - 1);
+       audio->name[sizeof(audio->name) - 1] = '\0';
+
+       return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *private_data,
+                         struct v4l2_audio *audio)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int retval;
+
+       if (audio->index >= HDPVR_AUDIO_INPUTS)
+               return -EINVAL;
+
+       if (dev->status != STATUS_IDLE)
+               return -EAGAIN;
+
+       retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec);
+       if (!retval)
+               dev->options.audio_input = audio->index;
+
+       return retval;
+}
+
+static int vidioc_g_audio(struct file *file, void *private_data,
+                         struct v4l2_audio *audio)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+
+       audio->index = dev->options.audio_input;
+       audio->capability = V4L2_AUDCAP_STEREO;
+       strncpy(audio->name, audio_iname[audio->index], sizeof(audio->name));
+       audio->name[sizeof(audio->name) - 1] = '\0';
+       return 0;
+}
+
+static const s32 supported_v4l2_ctrls[] = {
+       V4L2_CID_BRIGHTNESS,
+       V4L2_CID_CONTRAST,
+       V4L2_CID_SATURATION,
+       V4L2_CID_HUE,
+       V4L2_CID_SHARPNESS,
+       V4L2_CID_MPEG_AUDIO_ENCODING,
+       V4L2_CID_MPEG_VIDEO_ENCODING,
+       V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+       V4L2_CID_MPEG_VIDEO_BITRATE,
+       V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+};
+
+static int fill_queryctrl(struct hdpvr_options *opt, struct v4l2_queryctrl *qc,
+                         int ac3)
+{
+       int err;
+
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86);
+       case V4L2_CID_CONTRAST:
+               return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+       case V4L2_CID_SATURATION:
+               return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+       case V4L2_CID_SHARPNESS:
+               return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               return v4l2_ctrl_query_fill(
+                       qc, V4L2_MPEG_AUDIO_ENCODING_AAC,
+                       ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3
+                       : V4L2_MPEG_AUDIO_ENCODING_AAC,
+                       1, V4L2_MPEG_AUDIO_ENCODING_AAC);
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               return v4l2_ctrl_query_fill(
+                       qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC,
+                       V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
+                       V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
+
+/*     case V4L2_CID_MPEG_VIDEO_? maybe keyframe interval: */
+/*             return v4l2_ctrl_query_fill(qc, 0, 128, 128, 0); */
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               return v4l2_ctrl_query_fill(
+                       qc, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+                       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+                       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               return v4l2_ctrl_query_fill(qc, 1000000, 13500000, 100000,
+                                           6500000);
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               err = v4l2_ctrl_query_fill(qc, 1100000, 20200000, 100000,
+                                          9000000);
+               if (!err && opt->bitrate_mode == HDPVR_CONSTANT)
+                       qc->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return err;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int vidioc_queryctrl(struct file *file, void *private_data,
+                           struct v4l2_queryctrl *qc)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int i, next;
+       u32 id = qc->id;
+
+       memset(qc, 0, sizeof(*qc));
+
+       next = !!(id &  V4L2_CTRL_FLAG_NEXT_CTRL);
+       qc->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
+
+       for (i = 0; i < ARRAY_SIZE(supported_v4l2_ctrls); i++) {
+               if (next) {
+                       if (qc->id < supported_v4l2_ctrls[i])
+                               qc->id = supported_v4l2_ctrls[i];
+                       else
+                               continue;
+               }
+
+               if (qc->id == supported_v4l2_ctrls[i])
+                       return fill_queryctrl(&dev->options, qc,
+                                             dev->flags & HDPVR_FLAG_AC3_CAP);
+
+               if (qc->id < supported_v4l2_ctrls[i])
+                       break;
+       }
+
+       return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *private_data,
+                        struct v4l2_control *ctrl)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctrl->value = dev->options.brightness;
+               break;
+       case V4L2_CID_CONTRAST:
+               ctrl->value = dev->options.contrast;
+               break;
+       case V4L2_CID_SATURATION:
+               ctrl->value = dev->options.saturation;
+               break;
+       case V4L2_CID_HUE:
+               ctrl->value = dev->options.hue;
+               break;
+       case V4L2_CID_SHARPNESS:
+               ctrl->value = dev->options.sharpness;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *private_data,
+                        struct v4l2_control *ctrl)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int retval;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               retval = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->value);
+               if (!retval)
+                       dev->options.brightness = ctrl->value;
+               break;
+       case V4L2_CID_CONTRAST:
+               retval = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->value);
+               if (!retval)
+                       dev->options.contrast = ctrl->value;
+               break;
+       case V4L2_CID_SATURATION:
+               retval = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->value);
+               if (!retval)
+                       dev->options.saturation = ctrl->value;
+               break;
+       case V4L2_CID_HUE:
+               retval = hdpvr_config_call(dev, CTRL_HUE, ctrl->value);
+               if (!retval)
+                       dev->options.hue = ctrl->value;
+               break;
+       case V4L2_CID_SHARPNESS:
+               retval = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->value);
+               if (!retval)
+                       dev->options.sharpness = ctrl->value;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return retval;
+}
+
+
+static int hdpvr_get_ctrl(struct hdpvr_options *opt,
+                         struct v4l2_ext_control *ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               ctrl->value = opt->audio_codec;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
+               break;
+/*     case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
+/*             ctrl->value = (opt->gop_mode & 0x2) ? 0 : 128; */
+/*             break; */
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               ctrl->value = opt->bitrate_mode == HDPVR_CONSTANT
+                       ? V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
+                       : V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               ctrl->value = opt->bitrate * 100000;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               ctrl->value = opt->peak_bitrate * 100000;
+               break;
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+                             struct v4l2_ext_controls *ctrls)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int i, err = 0;
+
+       if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = hdpvr_get_ctrl(&dev->options, ctrl);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+
+       }
+
+       return -EINVAL;
+}
+
+
+static int hdpvr_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
+{
+       int ret = -EINVAL;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               if (ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AAC ||
+                   (ac3 && ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AC3))
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               if (ctrl->value == V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
+                       ret = 0;
+               break;
+/*     case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
+/*             if (ctrl->value == 0 || ctrl->value == 128) */
+/*                     ret = 0; */
+/*             break; */
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR ||
+                   ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
+                       ret = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+       {
+               uint bitrate = ctrl->value / 100000;
+               if (bitrate >= 10 && bitrate <= 135)
+                       ret = 0;
+               break;
+       }
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+       {
+               uint peak_bitrate = ctrl->value / 100000;
+               if (peak_bitrate >= 10 && peak_bitrate <= 202)
+                       ret = 0;
+               break;
+       }
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               if (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
+                       ret = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+                               struct v4l2_ext_controls *ctrls)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int i, err = 0;
+
+       if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = hdpvr_try_ctrl(ctrl,
+                                            dev->flags & HDPVR_FLAG_AC3_CAP);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+       }
+
+       return -EINVAL;
+}
+
+
+static int hdpvr_set_ctrl(struct hdpvr_device *dev,
+                         struct v4l2_ext_control *ctrl)
+{
+       struct hdpvr_options *opt = &dev->options;
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               if (dev->flags & HDPVR_FLAG_AC3_CAP) {
+                       opt->audio_codec = ctrl->value;
+                       ret = hdpvr_set_audio(dev, opt->audio_input,
+                                             opt->audio_codec);
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               break;
+/*     case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
+/*             if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */
+/*                     opt->gop_mode |= 0x2; */
+/*                     hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
+/*                                       opt->gop_mode); */
+/*             } */
+/*             if (ctrl->value == 128 && opt->gop_mode & 0x2) { */
+/*                     opt->gop_mode &= ~0x2; */
+/*                     hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, */
+/*                                       opt->gop_mode); */
+/*             } */
+/*             break; */
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR &&
+                   opt->bitrate_mode != HDPVR_CONSTANT) {
+                       opt->bitrate_mode = HDPVR_CONSTANT;
+                       hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
+                                         opt->bitrate_mode);
+               }
+               if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+                   opt->bitrate_mode == HDPVR_CONSTANT) {
+                       opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
+                       hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
+                                         opt->bitrate_mode);
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE: {
+               uint bitrate = ctrl->value / 100000;
+
+               opt->bitrate = bitrate;
+               if (bitrate >= opt->peak_bitrate)
+                       opt->peak_bitrate = bitrate+1;
+
+               hdpvr_set_bitrate(dev);
+               break;
+       }
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: {
+               uint peak_bitrate = ctrl->value / 100000;
+
+               if (opt->bitrate_mode == HDPVR_CONSTANT)
+                       break;
+
+               if (opt->bitrate < peak_bitrate) {
+                       opt->peak_bitrate = peak_bitrate;
+                       hdpvr_set_bitrate(dev);
+               } else
+                       ret = -EINVAL;
+               break;
+       }
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               break;
+       default:
+               return -EINVAL;
+       }
+       return ret;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+                             struct v4l2_ext_controls *ctrls)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       int i, err = 0;
+
+       if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               for (i = 0; i < ctrls->count; i++) {
+                       struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+                       err = hdpvr_try_ctrl(ctrl,
+                                            dev->flags & HDPVR_FLAG_AC3_CAP);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+                       err = hdpvr_set_ctrl(dev, ctrl);
+                       if (err) {
+                               ctrls->error_idx = i;
+                               break;
+                       }
+               }
+               return err;
+
+       }
+
+       return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
+                                   struct v4l2_fmtdesc *f)
+{
+
+       if (f->index != 0 || f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       f->flags = V4L2_FMT_FLAG_COMPRESSED;
+       strncpy(f->description, "MPEG2-TS with AVC/AAC streams", 32);
+       f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data,
+                               struct v4l2_format *f)
+{
+       struct hdpvr_fh *fh = file->private_data;
+       struct hdpvr_device *dev = fh->dev;
+       struct hdpvr_video_info *vid_info;
+
+       if (!dev)
+               return -ENODEV;
+
+       vid_info = get_video_info(dev);
+       if (!vid_info)
+               return -EFAULT;
+
+       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.width        = vid_info->width;
+       f->fmt.pix.height       = vid_info->height;
+       f->fmt.pix.sizeimage    = dev->bulk_in_size;
+       f->fmt.pix.colorspace   = 0;
+       f->fmt.pix.bytesperline = 0;
+       f->fmt.pix.field        = V4L2_FIELD_ANY;
+
+       kfree(vid_info);
+       return 0;
+}
+
+
+static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
+       .vidioc_querycap        = vidioc_querycap,
+       .vidioc_s_std           = vidioc_s_std,
+       .vidioc_enum_input      = vidioc_enum_input,
+       .vidioc_g_input         = vidioc_g_input,
+       .vidioc_s_input         = vidioc_s_input,
+       .vidioc_enumaudio       = vidioc_enumaudio,
+       .vidioc_g_audio         = vidioc_g_audio,
+       .vidioc_s_audio         = vidioc_s_audio,
+       .vidioc_queryctrl       = vidioc_queryctrl,
+       .vidioc_g_ctrl          = vidioc_g_ctrl,
+       .vidioc_s_ctrl          = vidioc_s_ctrl,
+       .vidioc_g_ext_ctrls     = vidioc_g_ext_ctrls,
+       .vidioc_s_ext_ctrls     = vidioc_s_ext_ctrls,
+       .vidioc_try_ext_ctrls   = vidioc_try_ext_ctrls,
+       .vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap           = vidioc_g_fmt_vid_cap,
+};
+
+static void hdpvr_device_release(struct video_device *vdev)
+{
+       struct hdpvr_device *dev = video_get_drvdata(vdev);
+
+       hdpvr_delete(dev);
+}
+
+static const struct video_device hdpvr_video_template = {
+/*     .type                   = VFL_TYPE_GRABBER, */
+/*     .type2                  = VID_TYPE_CAPTURE | VID_TYPE_MPEG_ENCODER, */
+       .fops                   = &hdpvr_fops,
+       .release                = hdpvr_device_release,
+       .ioctl_ops              = &hdpvr_ioctl_ops,
+       .tvnorms                =
+               V4L2_STD_NTSC  | V4L2_STD_SECAM | V4L2_STD_PAL_B |
+               V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I |
+               V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N |
+               V4L2_STD_PAL_60,
+};
+
+int hdpvr_register_videodev(struct hdpvr_device *dev, int devnum)
+{
+       /* setup and register video device */
+       dev->video_dev = video_device_alloc();
+       if (!dev->video_dev) {
+               err("video_device_alloc() failed");
+               goto error;
+       }
+
+       *(dev->video_dev) = hdpvr_video_template;
+       strcpy(dev->video_dev->name, "Hauppauge HD PVR");
+       dev->video_dev->parent = &dev->udev->dev;
+       video_set_drvdata(dev->video_dev, dev);
+
+       if (video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum)) {
+               err("V4L2 device registration failed");
+               goto error;
+       }
+
+       return 0;
+error:
+       return -ENOMEM;
+}
 
--- /dev/null
+/*
+ * Hauppage HD PVR USB driver
+ *
+ * Copyright (C) 2008      Janne Grunau (j@jannau.net)
+ *
+ *     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, version 2.
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/videodev2.h>
+
+#define HDPVR_MAJOR_VERSION 0
+#define HDPVR_MINOR_VERSION 2
+#define HDPVR_RELEASE 0
+#define HDPVR_VERSION \
+       KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE)
+
+#define HDPVR_MAX 8
+
+/* Define these values to match your devices */
+#define HD_PVR_VENDOR_ID       0x2040
+#define HD_PVR_PRODUCT_ID      0x4900
+#define HD_PVR_PRODUCT_ID1     0x4901
+#define HD_PVR_PRODUCT_ID2     0x4902
+
+#define UNSET    (-1U)
+
+#define NUM_BUFFERS 64
+
+#define HDPVR_FIRMWARE_VERSION         0x8
+#define HDPVR_FIRMWARE_VERSION_AC3     0xd
+
+/* #define HDPVR_DEBUG */
+
+extern int hdpvr_debug;
+
+#define MSG_INFO       1
+#define MSG_BUFFER     2
+
+struct hdpvr_options {
+       u8      video_std;
+       u8      video_input;
+       u8      audio_input;
+       u8      bitrate;        /* in 100kbps */
+       u8      peak_bitrate;   /* in 100kbps */
+       u8      bitrate_mode;
+       u8      gop_mode;
+       enum v4l2_mpeg_audio_encoding   audio_codec;
+       u8      brightness;
+       u8      contrast;
+       u8      hue;
+       u8      saturation;
+       u8      sharpness;
+};
+
+/* Structure to hold all of our device specific stuff */
+struct hdpvr_device {
+       /* the v4l device for this device */
+       struct video_device     *video_dev;
+       /* the usb device for this device */
+       struct usb_device       *udev;
+
+       /* the max packet size of the bulk endpoint */
+       size_t                  bulk_in_size;
+       /* the address of the bulk in endpoint */
+       __u8                    bulk_in_endpointAddr;
+
+       /* holds the current device status */
+       __u8                    status;
+       /* count the number of openers */
+       uint                    open_count;
+
+       /* holds the cureent set options */
+       struct hdpvr_options    options;
+
+       uint                    flags;
+
+       /* synchronize I/O */
+       struct mutex            io_mutex;
+       /* available buffers */
+       struct list_head        free_buff_list;
+       /* in progress buffers */
+       struct list_head        rec_buff_list;
+       /* waitqueue for buffers */
+       wait_queue_head_t       wait_buffer;
+       /* waitqueue for data */
+       wait_queue_head_t       wait_data;
+       /**/
+       struct workqueue_struct *workqueue;
+       /**/
+       struct work_struct      worker;
+
+       /* I2C adapter */
+       struct i2c_adapter      *i2c_adapter;
+       /* I2C lock */
+       struct mutex            i2c_mutex;
+
+       /* usb control transfer buffer and lock */
+       struct mutex            usbc_mutex;
+       u8                      *usbc_buf;
+};
+
+
+/* buffer one bulk urb of data */
+struct hdpvr_buffer {
+       struct list_head        buff_list;
+
+       struct urb              *urb;
+
+       struct hdpvr_device     *dev;
+
+       uint                    pos;
+
+       __u8                    status;
+};
+
+/* */
+
+struct hdpvr_video_info {
+       u16     width;
+       u16     height;
+       u8      fps;
+};
+
+enum {
+       STATUS_UNINITIALIZED    = 0,
+       STATUS_IDLE,
+       STATUS_STARTING,
+       STATUS_SHUTTING_DOWN,
+       STATUS_STREAMING,
+       STATUS_ERROR,
+       STATUS_DISCONNECTED,
+};
+
+enum {
+       HDPVR_FLAG_AC3_CAP = 1,
+};
+
+enum {
+       BUFSTAT_UNINITIALIZED = 0,
+       BUFSTAT_AVAILABLE,
+       BUFSTAT_INPROGRESS,
+       BUFSTAT_READY,
+};
+
+#define CTRL_START_STREAMING_VALUE     0x0700
+#define CTRL_STOP_STREAMING_VALUE      0x0800
+#define CTRL_BITRATE_VALUE             0x1000
+#define CTRL_BITRATE_MODE_VALUE                0x1200
+#define CTRL_GOP_MODE_VALUE            0x1300
+#define CTRL_VIDEO_INPUT_VALUE         0x1500
+#define CTRL_VIDEO_STD_TYPE            0x1700
+#define CTRL_AUDIO_INPUT_VALUE         0x2500
+#define CTRL_BRIGHTNESS                        0x2900
+#define CTRL_CONTRAST                  0x2a00
+#define CTRL_HUE                       0x2b00
+#define CTRL_SATURATION                        0x2c00
+#define CTRL_SHARPNESS                 0x2d00
+#define CTRL_LOW_PASS_FILTER_VALUE     0x3100
+
+#define CTRL_DEFAULT_INDEX             0x0003
+
+
+       /* :0 s 38 01 1000 0003 0004 4 = 0a00ca00
+        * BITRATE SETTING
+        *   1st and 2nd byte (little endian): average bitrate in 100 000 bit/s
+        *                                     min: 1 mbit/s, max: 13.5 mbit/s
+        *   3rd and 4th byte (little endian): peak bitrate in 100 000 bit/s
+        *                                     min: average + 100kbit/s,
+        *                                      max: 20.2 mbit/s
+        */
+
+       /* :0 s 38 01 1200 0003 0001 1 = 02
+        * BIT RATE MODE
+        *  constant = 1, variable (peak) = 2, variable (average) = 3
+        */
+
+       /* :0 s 38 01 1300 0003 0001 1 = 03
+        * GOP MODE (2 bit)
+        *    low bit 0/1: advanced/simple GOP
+        *   high bit 0/1: IDR(4/32/128) / no IDR (4/32/0)
+        */
+
+       /* :0 s 38 01 1700 0003 0001 1 = 00
+        * VIDEO STANDARD or FREQUNCY 0 = 60hz, 1 = 50hz
+        */
+
+       /* :0 s 38 01 3100 0003 0004 4 = 03030000
+        * FILTER CONTROL
+        *   1st byte luma low pass filter strength,
+        *   2nd byte chroma low pass filter strength,
+        *   3rd byte MF enable chroma, min=0, max=1
+        *   4th byte n
+        */
+
+
+       /* :0 s 38 b9 0001 0000 0000 0 */
+
+
+
+/* :0 s 38 d3 0000 0000 0001 1 = 00 */
+/*             ret = usb_control_msg(dev->udev, */
+/*                                   usb_sndctrlpipe(dev->udev, 0), */
+/*                                   0xd3, 0x38, */
+/*                                   0, 0, */
+/*                                   "\0", 1, */
+/*                                   1000); */
+
+/*             info("control request returned %d", ret); */
+/*             msleep(5000); */
+
+
+       /* :0 s b8 81 1400 0003 0005 5 <
+        * :0 0 5 = d0024002 19
+        * QUERY FRAME SIZE AND RATE
+        *   1st and 2nd byte (little endian): horizontal resolution
+        *   3rd and 4th byte (little endian): vertical resolution
+        *   5th byte: frame rate
+        */
+
+       /* :0 s b8 81 1800 0003 0003 3 <
+        * :0 0 3 = 030104
+        * QUERY SIGNAL AND DETECTED LINES, maybe INPUT
+        */
+
+enum hdpvr_video_std {
+       HDPVR_60HZ = 0,
+       HDPVR_50HZ,
+};
+
+enum hdpvr_video_input {
+       HDPVR_COMPONENT = 0,
+       HDPVR_SVIDEO,
+       HDPVR_COMPOSITE,
+       HDPVR_VIDEO_INPUTS
+};
+
+enum hdpvr_audio_inputs {
+       HDPVR_RCA_BACK = 0,
+       HDPVR_RCA_FRONT,
+       HDPVR_SPDIF,
+       HDPVR_AUDIO_INPUTS
+};
+
+enum hdpvr_bitrate_mode {
+       HDPVR_CONSTANT = 1,
+       HDPVR_VARIABLE_PEAK,
+       HDPVR_VARIABLE_AVERAGE,
+};
+
+enum hdpvr_gop_mode {
+       HDPVR_ADVANCED_IDR_GOP = 0,
+       HDPVR_SIMPLE_IDR_GOP,
+       HDPVR_ADVANCED_NOIDR_GOP,
+       HDPVR_SIMPLE_NOIDR_GOP,
+};
+
+void hdpvr_delete(struct hdpvr_device *dev);
+
+/*========================================================================*/
+/* hardware control functions */
+int hdpvr_set_options(struct hdpvr_device *dev);
+
+int hdpvr_set_bitrate(struct hdpvr_device *dev);
+
+int hdpvr_set_audio(struct hdpvr_device *dev, u8 input,
+                   enum v4l2_mpeg_audio_encoding codec);
+
+int hdpvr_config_call(struct hdpvr_device *dev, uint value,
+                     unsigned char valbuf);
+
+struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev);
+
+/* :0 s b8 81 1800 0003 0003 3 < */
+/* :0 0 3 = 0301ff */
+int get_input_lines_info(struct hdpvr_device *dev);
+
+
+/*========================================================================*/
+/* v4l2 registration */
+int hdpvr_register_videodev(struct hdpvr_device *dev, int devnumber);
+
+int hdpvr_cancel_queue(struct hdpvr_device *dev);
+
+/*========================================================================*/
+/* i2c adapter registration */
+int hdpvr_register_i2c_adapter(struct hdpvr_device *dev);
+
+/*========================================================================*/
+/* buffer management */
+int hdpvr_free_buffers(struct hdpvr_device *dev);
+int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count);