V4L/DVB (11096): V4L2 Driver for the Hauppauge HD PVR usb capture device

The device encodes component video up to 1080i to a MPEG-TS stream with
H.264 video and stereo AAC audio. Newer firmwares accept also AC3
(up to 5.1) audio over optical SPDIF without reencoding.
Firmware upgrade is unimplemeted but rather unimportant since
the firmware sits on a flash chip.

The I2C adapter to drive the integrated infrared receiver/sender is
currently disabled due to a conflict with cx18-based devices.

Tested-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Janne Grunau <j@jannau.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Janne Grunau 2009-03-18 18:10:04 -03:00 committed by Mauro Carvalho Chehab
parent 8c84cfda3e
commit 9aba42efe8
10 changed files with 2333 additions and 0 deletions

View File

@ -789,6 +789,8 @@ source "drivers/media/video/gspca/Kconfig"
source "drivers/media/video/pvrusb2/Kconfig"
source "drivers/media/video/hdpvr/Kconfig"
source "drivers/media/video/em28xx/Kconfig"
source "drivers/media/video/usbvision/Kconfig"

View File

@ -119,6 +119,8 @@ obj-$(CONFIG_USB_PWC) += pwc/
obj-$(CONFIG_USB_ZC0301) += zc0301/
obj-$(CONFIG_USB_GSPCA) += gspca/
obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/
obj-$(CONFIG_USB_IBMCAM) += usbvideo/
obj-$(CONFIG_USB_KONICAWC) += usbvideo/
obj-$(CONFIG_USB_VICAM) += usbvideo/

View File

@ -0,0 +1,10 @@
config VIDEO_HDPVR
tristate "Hauppauge HD PVR support"
depends on VIDEO_DEV
---help---
This is a video4linux driver for Hauppauge's HD PVR USB device.
To compile this driver as a module, choose M here: the
module will be called hdpvr

View File

@ -0,0 +1,7 @@
hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-i2c.o hdpvr-video.o
obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o
EXTRA_CFLAGS += -Idrivers/media/video
EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)

View File

@ -0,0 +1,201 @@
/*
* 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/usb.h>
#include <linux/mutex.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include "hdpvr.h"
int hdpvr_config_call(struct hdpvr_device *dev, uint value, u8 valbuf)
{
int ret;
char request_type = 0x38, snd_request = 0x01;
msleep(10);
mutex_lock(&dev->usbc_mutex);
dev->usbc_buf[0] = valbuf;
ret = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
snd_request, 0x00 | request_type,
value, CTRL_DEFAULT_INDEX,
dev->usbc_buf, 1, 10000);
mutex_unlock(&dev->usbc_mutex);
dev_dbg(&dev->udev->dev,
"config call request for value 0x%x returned %d\n", value,
ret);
return ret < 0 ? ret : 0;
}
struct hdpvr_video_info *get_video_info(struct hdpvr_device *dev)
{
struct hdpvr_video_info *vidinf = NULL;
#ifdef HDPVR_DEBUG
char print_buf[15];
#endif
int ret;
vidinf = kzalloc(sizeof(struct hdpvr_video_info), GFP_KERNEL);
if (!vidinf) {
dev_err(&dev->udev->dev, "out of memory");
goto err;
}
mutex_lock(&dev->usbc_mutex);
ret = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
0x81, 0x80 | 0x38,
0x1400, 0x0003,
dev->usbc_buf, 5,
1000);
if (ret == 5) {
vidinf->width = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
vidinf->height = dev->usbc_buf[3] << 8 | dev->usbc_buf[2];
vidinf->fps = dev->usbc_buf[4];
}
#ifdef HDPVR_DEBUG
if (hdpvr_debug & MSG_INFO) {
hex_dump_to_buffer(dev->usbc_buf, 5, 16, 1, print_buf,
sizeof(print_buf), 0);
dev_dbg(&dev->udev->dev, "get video info returned: %d, %s\n",
ret, print_buf);
}
#endif
mutex_unlock(&dev->usbc_mutex);
if (!vidinf->width || !vidinf->height || !vidinf->fps) {
kfree(vidinf);
vidinf = NULL;
}
err:
return vidinf;
}
int get_input_lines_info(struct hdpvr_device *dev)
{
#ifdef HDPVR_DEBUG
char print_buf[9];
#endif
int ret, lines;
mutex_lock(&dev->usbc_mutex);
ret = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
0x81, 0x80 | 0x38,
0x1800, 0x0003,
dev->usbc_buf, 3,
1000);
#ifdef HDPVR_DEBUG
if (hdpvr_debug & MSG_INFO) {
hex_dump_to_buffer(dev->usbc_buf, 3, 16, 1, print_buf,
sizeof(print_buf), 0);
dev_dbg(&dev->udev->dev,
"get input lines info returned: %d, %s\n", ret,
print_buf);
}
#endif
lines = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
mutex_unlock(&dev->usbc_mutex);
return lines;
}
int hdpvr_set_bitrate(struct hdpvr_device *dev)
{
int ret;
mutex_lock(&dev->usbc_mutex);
memset(dev->usbc_buf, 0, 4);
dev->usbc_buf[0] = dev->options.bitrate;
dev->usbc_buf[2] = dev->options.peak_bitrate;
ret = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
0x01, 0x38, CTRL_BITRATE_VALUE,
CTRL_DEFAULT_INDEX, dev->usbc_buf, 4, 1000);
mutex_unlock(&dev->usbc_mutex);
return ret;
}
int hdpvr_set_audio(struct hdpvr_device *dev, u8 input,
enum v4l2_mpeg_audio_encoding codec)
{
int ret = 0;
if (dev->flags & HDPVR_FLAG_AC3_CAP) {
mutex_lock(&dev->usbc_mutex);
memset(dev->usbc_buf, 0, 2);
dev->usbc_buf[0] = input;
if (codec == V4L2_MPEG_AUDIO_ENCODING_AAC)
dev->usbc_buf[1] = 0;
else if (codec == V4L2_MPEG_AUDIO_ENCODING_AC3)
dev->usbc_buf[1] = 1;
else {
mutex_unlock(&dev->usbc_mutex);
dev_err(&dev->udev->dev, "invalid audio codec %d\n",
codec);
ret = -EINVAL;
goto error;
}
ret = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
0x01, 0x38, CTRL_AUDIO_INPUT_VALUE,
CTRL_DEFAULT_INDEX, dev->usbc_buf, 2,
1000);
mutex_unlock(&dev->usbc_mutex);
if (ret == 2)
ret = 0;
} else
ret = hdpvr_config_call(dev, CTRL_AUDIO_INPUT_VALUE,
dev->options.audio_input+1);
error:
return ret;
}
int hdpvr_set_options(struct hdpvr_device *dev)
{
hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, dev->options.video_std);
hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE,
dev->options.video_input+1);
hdpvr_set_audio(dev, dev->options.audio_input+1,
dev->options.audio_codec);
hdpvr_set_bitrate(dev);
hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
dev->options.bitrate_mode);
hdpvr_config_call(dev, CTRL_GOP_MODE_VALUE, dev->options.gop_mode);
hdpvr_config_call(dev, CTRL_BRIGHTNESS, dev->options.brightness);
hdpvr_config_call(dev, CTRL_CONTRAST, dev->options.contrast);
hdpvr_config_call(dev, CTRL_HUE, dev->options.hue);
hdpvr_config_call(dev, CTRL_SATURATION, dev->options.saturation);
hdpvr_config_call(dev, CTRL_SHARPNESS, dev->options.sharpness);
return 0;
}

View File

@ -0,0 +1,439 @@
/*
* 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");

View File

@ -0,0 +1,145 @@
/*
* 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/i2c.h>
#include "hdpvr.h"
#define CTRL_READ_REQUEST 0xb8
#define CTRL_WRITE_REQUEST 0x38
#define REQTYPE_I2C_READ 0xb1
#define REQTYPE_I2C_WRITE 0xb0
#define REQTYPE_I2C_WRITE_STATT 0xd0
static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
char *data, int len)
{
int ret;
char *buf = kmalloc(len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
REQTYPE_I2C_READ, CTRL_READ_REQUEST,
0x100|addr, 0, buf, len, 1000);
if (ret == len) {
memcpy(data, buf, len);
ret = 0;
} else if (ret >= 0)
ret = -EIO;
kfree(buf);
return ret;
}
static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
char *data, int len)
{
int ret;
char *buf = kmalloc(len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
memcpy(buf, data, len);
ret = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
0x100|addr, 0, buf, len, 1000);
if (ret < 0)
goto error;
ret = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
0, 0, buf, 2, 1000);
if (ret == 2)
ret = 0;
else if (ret >= 0)
ret = -EIO;
error:
kfree(buf);
return ret;
}
static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
int num)
{
struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter);
int retval = 0, i, addr;
if (num <= 0)
return 0;
mutex_lock(&dev->i2c_mutex);
for (i = 0; i < num && !retval; i++) {
addr = msgs[i].addr << 1;
if (msgs[i].flags & I2C_M_RD)
retval = hdpvr_i2c_read(dev, addr, msgs[i].buf,
msgs[i].len);
else
retval = hdpvr_i2c_write(dev, addr, msgs[i].buf,
msgs[i].len);
}
mutex_unlock(&dev->i2c_mutex);
return retval ? retval : num;
}
static u32 hdpvr_functionality(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static struct i2c_algorithm hdpvr_algo = {
.master_xfer = hdpvr_transfer,
.functionality = hdpvr_functionality,
};
int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
{
struct i2c_adapter *i2c_adap;
int retval = -ENOMEM;
i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
if (i2c_adap == NULL)
goto error;
strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C",
sizeof(i2c_adap->name));
i2c_adap->algo = &hdpvr_algo;
i2c_adap->class = I2C_CLASS_TV_ANALOG;
i2c_adap->id = I2C_HW_B_HDPVR;
i2c_adap->owner = THIS_MODULE;
i2c_adap->dev.parent = &dev->udev->dev;
i2c_set_adapdata(i2c_adap, dev);
retval = i2c_add_adapter(i2c_adap);
if (!retval)
dev->i2c_adapter = i2c_adap;
else
kfree(i2c_adap);
error:
return retval;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,298 @@
/*
* 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);

View File

@ -88,6 +88,7 @@
#define I2C_HW_B_CX2341X 0x010020 /* Conexant CX2341X MPEG encoder cards */
#define I2C_HW_B_CX23885 0x010022 /* conexant 23885 based tv cards (bus1) */
#define I2C_HW_B_AU0828 0x010023 /* auvitek au0828 usb bridge */
#define I2C_HW_B_HDPVR 0x010025 /* Hauppauge HD PVR */
/* --- SGI adapters */
#define I2C_HW_SGI_VINO 0x160000