2009-03-19 05:10:04 +08:00
|
|
|
/*
|
2009-03-20 06:00:35 +08:00
|
|
|
* Hauppauge HD PVR USB driver
|
2009-03-19 05:10:04 +08:00
|
|
|
*
|
|
|
|
* 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>
|
2011-07-27 07:09:06 +08:00
|
|
|
#include <linux/atomic.h>
|
2009-03-19 05:10:04 +08:00
|
|
|
#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");
|
|
|
|
|
2010-01-30 04:30:53 +08:00
|
|
|
static uint default_video_input = HDPVR_VIDEO_INPUTS;
|
2009-03-19 05:10:04 +08:00
|
|
|
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");
|
|
|
|
|
2010-01-30 04:30:53 +08:00
|
|
|
static uint default_audio_input = HDPVR_AUDIO_INPUTS;
|
2009-03-19 05:10:04 +08:00
|
|
|
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");
|
|
|
|
|
2012-01-13 07:02:20 +08:00
|
|
|
static bool boost_audio;
|
2009-03-19 05:10:04 +08:00
|
|
|
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) },
|
2010-02-03 22:51:23 +08:00
|
|
|
{ USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID3) },
|
2010-10-11 21:29:36 +08:00
|
|
|
{ USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID4) },
|
2009-03-19 05:10:04 +08:00
|
|
|
{ } /* 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) {
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_err(&dev->v4l2_dev, "Out of memory\n");
|
2009-07-31 07:00:44 +08:00
|
|
|
return retval;
|
2009-03-19 05:10:04 +08:00
|
|
|
}
|
|
|
|
#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) {
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_err(&dev->v4l2_dev,
|
|
|
|
"unexpected answer of status request, len %d\n", ret);
|
2009-07-31 07:00:44 +08:00
|
|
|
goto unlock;
|
2009-03-19 05:10:04 +08:00
|
|
|
}
|
|
|
|
#ifdef HDPVR_DEBUG
|
|
|
|
else {
|
|
|
|
hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf,
|
2009-12-13 19:41:12 +08:00
|
|
|
5*buf_size+1, 0);
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
|
|
|
|
"Status request returned, len %d: %s\n",
|
|
|
|
ret, print_buf);
|
2009-03-19 05:10:04 +08:00
|
|
|
}
|
|
|
|
#endif
|
2010-07-26 19:30:06 +08:00
|
|
|
|
2011-10-21 10:33:23 +08:00
|
|
|
dev->fw_ver = dev->usbc_buf[1];
|
|
|
|
|
2010-07-26 19:30:06 +08:00
|
|
|
v4l2_info(&dev->v4l2_dev, "firmware version 0x%x dated %s\n",
|
2011-10-21 10:33:23 +08:00
|
|
|
dev->fw_ver, &dev->usbc_buf[2]);
|
|
|
|
|
|
|
|
if (dev->fw_ver > 0x15) {
|
|
|
|
dev->options.brightness = 0x80;
|
|
|
|
dev->options.contrast = 0x40;
|
|
|
|
dev->options.hue = 0xf;
|
|
|
|
dev->options.saturation = 0x40;
|
|
|
|
dev->options.sharpness = 0x80;
|
|
|
|
}
|
2010-07-26 19:30:06 +08:00
|
|
|
|
2011-10-21 10:33:23 +08:00
|
|
|
switch (dev->fw_ver) {
|
2010-07-27 22:03:35 +08:00
|
|
|
case HDPVR_FIRMWARE_VERSION:
|
2009-03-19 05:10:04 +08:00
|
|
|
dev->flags &= ~HDPVR_FLAG_AC3_CAP;
|
2010-07-27 22:03:35 +08:00
|
|
|
break;
|
|
|
|
case HDPVR_FIRMWARE_VERSION_AC3:
|
|
|
|
case HDPVR_FIRMWARE_VERSION_0X12:
|
|
|
|
case HDPVR_FIRMWARE_VERSION_0X15:
|
2013-03-20 15:23:51 +08:00
|
|
|
case HDPVR_FIRMWARE_VERSION_0X1E:
|
2009-03-19 05:10:04 +08:00
|
|
|
dev->flags |= HDPVR_FLAG_AC3_CAP;
|
2010-07-27 22:03:35 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
v4l2_info(&dev->v4l2_dev, "untested firmware, the driver might"
|
|
|
|
" not work.\n");
|
2011-10-21 10:33:23 +08:00
|
|
|
if (dev->fw_ver >= HDPVR_FIRMWARE_VERSION_AC3)
|
2010-07-27 22:03:35 +08:00
|
|
|
dev->flags |= HDPVR_FLAG_AC3_CAP;
|
|
|
|
else
|
|
|
|
dev->flags &= ~HDPVR_FLAG_AC3_CAP;
|
2009-03-19 05:10:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
response = dev->usbc_buf+38;
|
|
|
|
#ifdef HDPVR_DEBUG
|
2009-12-13 19:41:12 +08:00
|
|
|
hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0);
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n",
|
|
|
|
print_buf);
|
2009-03-19 05:10:04 +08:00
|
|
|
#endif
|
|
|
|
challenge(response);
|
|
|
|
#ifdef HDPVR_DEBUG
|
2009-12-13 19:41:12 +08:00
|
|
|
hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0);
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n",
|
|
|
|
print_buf);
|
2013-02-25 05:49:43 +08:00
|
|
|
kfree(print_buf);
|
2009-03-19 05:10:04 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
msleep(100);
|
|
|
|
ret = usb_control_msg(dev->udev,
|
|
|
|
usb_sndctrlpipe(dev->udev, 0),
|
|
|
|
0xd1, 0x00 | request_type,
|
|
|
|
0x0000, 0x0000,
|
|
|
|
response, 8,
|
|
|
|
10000);
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
|
|
|
|
"magic request returned %d\n", ret);
|
2009-03-19 05:10:04 +08:00
|
|
|
|
|
|
|
retval = ret != 8;
|
2009-07-31 07:00:44 +08:00
|
|
|
unlock:
|
|
|
|
mutex_unlock(&dev->usbc_mutex);
|
2009-03-19 05:10:04 +08:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int hdpvr_device_init(struct hdpvr_device *dev)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
u8 *buf;
|
|
|
|
|
|
|
|
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);
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
|
|
|
|
"control request returned %d\n", ret);
|
2009-03-19 05:10:04 +08:00
|
|
|
mutex_unlock(&dev->usbc_mutex);
|
|
|
|
|
|
|
|
/* 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);
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
|
|
|
|
"control request returned %d\n", ret);
|
2009-03-19 05:10:04 +08:00
|
|
|
|
|
|
|
/* 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);
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
|
|
|
|
"control request returned %d\n", ret);
|
2009-03-19 05:10:04 +08:00
|
|
|
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,
|
2011-10-21 10:33:23 +08:00
|
|
|
/* original picture controls for firmware version <= 0x15 */
|
|
|
|
/* updated in device_authorization() for newer firmware */
|
2009-03-19 05:10:04 +08:00
|
|
|
.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;
|
2011-01-20 05:10:14 +08:00
|
|
|
struct i2c_client *client;
|
2009-03-19 05:10:04 +08:00
|
|
|
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) {
|
2012-04-26 05:48:49 +08:00
|
|
|
dev_err(&interface->dev, "Out of memory\n");
|
2009-03-19 05:10:04 +08:00
|
|
|
goto error;
|
|
|
|
}
|
2009-03-28 07:01:40 +08:00
|
|
|
|
2010-07-06 02:11:51 +08:00
|
|
|
dev->workqueue = 0;
|
|
|
|
|
2009-03-28 07:01:40 +08:00
|
|
|
/* register v4l2_device early so it can be used for printks */
|
|
|
|
if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
|
2012-04-26 05:48:49 +08:00
|
|
|
dev_err(&interface->dev, "v4l2_device_register failed\n");
|
2009-03-28 07:01:40 +08:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-03-19 05:10:04 +08:00
|
|
|
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) {
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_err(&dev->v4l2_dev, "Out of memory\n");
|
2009-03-19 05:10:04 +08:00
|
|
|
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;
|
|
|
|
|
2010-07-27 21:40:43 +08:00
|
|
|
if (default_audio_input < HDPVR_AUDIO_INPUTS) {
|
2009-03-19 05:10:04 +08:00
|
|
|
dev->options.audio_input = default_audio_input;
|
2010-07-27 21:40:43 +08:00
|
|
|
if (default_audio_input == HDPVR_SPDIF)
|
|
|
|
dev->options.audio_codec =
|
|
|
|
V4L2_MPEG_AUDIO_ENCODING_AC3;
|
|
|
|
}
|
2009-03-19 05:10:04 +08:00
|
|
|
|
|
|
|
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) {
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_err(&dev->v4l2_dev, "Could not find bulk-in endpoint\n");
|
2009-03-19 05:10:04 +08:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* init the device */
|
|
|
|
if (hdpvr_device_init(dev)) {
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_err(&dev->v4l2_dev, "device init failed\n");
|
2009-03-19 05:10:04 +08:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_lock(&dev->io_mutex);
|
|
|
|
if (hdpvr_alloc_buffers(dev, NUM_BUFFERS)) {
|
2009-07-31 07:00:44 +08:00
|
|
|
mutex_unlock(&dev->io_mutex);
|
2009-03-28 07:09:40 +08:00
|
|
|
v4l2_err(&dev->v4l2_dev,
|
|
|
|
"allocating transfer buffers failed\n");
|
2009-03-19 05:10:04 +08:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
mutex_unlock(&dev->io_mutex);
|
|
|
|
|
2013-01-20 06:41:29 +08:00
|
|
|
#if IS_ENABLED(CONFIG_I2C)
|
[media] hdpvr: enable IR part
A number of things going on here, but the end result is that the IR part
on the hdpvr gets enabled, and can be used with ir-kbd-i2c and/or
lirc_zilog.
First up, there are some conditional build fixes that come into play
whether i2c is built-in or modular. Second, we're swapping out
i2c_new_probed_device() for i2c_new_device(), as in my testing, probing
always fails, but we *know* that all hdpvr devices have a z8 chip at
0x70 and 0x71. Third, we're poking at an i2c address directly without a
client, and writing some magic bits to actually turn on this IR part
(this could use some improvement in the future). Fourth, some of the
i2c_adapter storage has been reworked, as the existing implementation
used to lead to an oops following i2c changes c. 2.6.31.
Earlier editions of this patch have been floating around the 'net for a
while, including being patched into Fedora kernels, and they *do* work.
This specific version isn't yet tested, beyond loading ir-kbd-i2c and
confirming that it does bind to the RX address of the hdpvr.
[mchehab@redhat.com: I2C_CLASS_TV_ANALOG is not defined. Fix compilation bug]
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Acked-by: Andy Walls <awalls@md.metrocast.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2011-01-15 03:25:21 +08:00
|
|
|
retval = hdpvr_register_i2c_adapter(dev);
|
2009-03-24 05:18:54 +08:00
|
|
|
if (retval < 0) {
|
2011-01-20 05:10:14 +08:00
|
|
|
v4l2_err(&dev->v4l2_dev, "i2c adapter register failed\n");
|
2009-03-24 05:18:54 +08:00
|
|
|
goto error;
|
|
|
|
}
|
2010-12-29 09:46:13 +08:00
|
|
|
|
2011-01-20 05:10:14 +08:00
|
|
|
client = hdpvr_register_ir_rx_i2c(dev);
|
|
|
|
if (!client) {
|
|
|
|
v4l2_err(&dev->v4l2_dev, "i2c IR RX device register failed\n");
|
2012-09-06 22:23:48 +08:00
|
|
|
retval = -ENODEV;
|
2011-01-20 05:10:14 +08:00
|
|
|
goto reg_fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
client = hdpvr_register_ir_tx_i2c(dev);
|
|
|
|
if (!client) {
|
|
|
|
v4l2_err(&dev->v4l2_dev, "i2c IR TX device register failed\n");
|
2012-09-06 22:23:48 +08:00
|
|
|
retval = -ENODEV;
|
2011-01-20 05:10:14 +08:00
|
|
|
goto reg_fail;
|
|
|
|
}
|
[media] hdpvr: enable IR part
A number of things going on here, but the end result is that the IR part
on the hdpvr gets enabled, and can be used with ir-kbd-i2c and/or
lirc_zilog.
First up, there are some conditional build fixes that come into play
whether i2c is built-in or modular. Second, we're swapping out
i2c_new_probed_device() for i2c_new_device(), as in my testing, probing
always fails, but we *know* that all hdpvr devices have a z8 chip at
0x70 and 0x71. Third, we're poking at an i2c address directly without a
client, and writing some magic bits to actually turn on this IR part
(this could use some improvement in the future). Fourth, some of the
i2c_adapter storage has been reworked, as the existing implementation
used to lead to an oops following i2c changes c. 2.6.31.
Earlier editions of this patch have been floating around the 'net for a
while, including being patched into Fedora kernels, and they *do* work.
This specific version isn't yet tested, beyond loading ir-kbd-i2c and
confirming that it does bind to the RX address of the hdpvr.
[mchehab@redhat.com: I2C_CLASS_TV_ANALOG is not defined. Fix compilation bug]
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Acked-by: Andy Walls <awalls@md.metrocast.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2011-01-15 03:25:21 +08:00
|
|
|
#endif
|
2009-03-19 05:10:04 +08:00
|
|
|
|
2013-03-19 20:34:58 +08:00
|
|
|
retval = hdpvr_register_videodev(dev, &interface->dev,
|
|
|
|
video_nr[atomic_inc_return(&dev_nr)]);
|
|
|
|
if (retval < 0) {
|
|
|
|
v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-03-19 05:10:04 +08:00
|
|
|
/* let the user know what node this device is now attached to */
|
2009-11-28 00:57:15 +08:00
|
|
|
v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
|
|
|
|
video_device_node_name(dev->video_dev));
|
2009-03-19 05:10:04 +08:00
|
|
|
return 0;
|
|
|
|
|
2011-01-20 05:10:14 +08:00
|
|
|
reg_fail:
|
2013-01-20 06:41:29 +08:00
|
|
|
#if IS_ENABLED(CONFIG_I2C)
|
2011-01-20 05:10:14 +08:00
|
|
|
i2c_del_adapter(&dev->i2c_adapter);
|
|
|
|
#endif
|
2009-03-19 05:10:04 +08:00
|
|
|
error:
|
|
|
|
if (dev) {
|
2010-07-06 02:11:51 +08:00
|
|
|
/* Destroy single thread */
|
|
|
|
if (dev->workqueue)
|
|
|
|
destroy_workqueue(dev->workqueue);
|
2009-03-19 05:10:04 +08:00
|
|
|
/* this frees allocated memory */
|
|
|
|
hdpvr_delete(dev);
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hdpvr_disconnect(struct usb_interface *interface)
|
|
|
|
{
|
2010-05-02 19:01:04 +08:00
|
|
|
struct hdpvr_device *dev = to_hdpvr_dev(usb_get_intfdata(interface));
|
2009-03-19 05:10:04 +08:00
|
|
|
|
2010-05-02 19:01:04 +08:00
|
|
|
v4l2_info(&dev->v4l2_dev, "device %s disconnected\n",
|
|
|
|
video_device_node_name(dev->video_dev));
|
2009-03-19 05:10:04 +08:00
|
|
|
/* prevent more I/O from starting and stop any ongoing */
|
|
|
|
mutex_lock(&dev->io_mutex);
|
|
|
|
dev->status = STATUS_DISCONNECTED;
|
|
|
|
wake_up_interruptible(&dev->wait_data);
|
|
|
|
wake_up_interruptible(&dev->wait_buffer);
|
2009-03-27 07:56:06 +08:00
|
|
|
mutex_unlock(&dev->io_mutex);
|
2010-05-02 19:01:04 +08:00
|
|
|
v4l2_device_disconnect(&dev->v4l2_dev);
|
2009-03-19 05:10:04 +08:00
|
|
|
msleep(100);
|
|
|
|
flush_workqueue(dev->workqueue);
|
2009-03-27 07:56:06 +08:00
|
|
|
mutex_lock(&dev->io_mutex);
|
2009-03-19 05:10:04 +08:00
|
|
|
hdpvr_cancel_queue(dev);
|
|
|
|
mutex_unlock(&dev->io_mutex);
|
2013-01-20 06:41:29 +08:00
|
|
|
#if IS_ENABLED(CONFIG_I2C)
|
2011-01-20 05:10:14 +08:00
|
|
|
i2c_del_adapter(&dev->i2c_adapter);
|
|
|
|
#endif
|
2010-05-02 19:01:04 +08:00
|
|
|
video_unregister_device(dev->video_dev);
|
2009-03-19 05:10:04 +08:00
|
|
|
atomic_dec(&dev_nr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct usb_driver hdpvr_usb_driver = {
|
|
|
|
.name = "hdpvr",
|
|
|
|
.probe = hdpvr_probe,
|
|
|
|
.disconnect = hdpvr_disconnect,
|
|
|
|
.id_table = hdpvr_table,
|
|
|
|
};
|
|
|
|
|
2011-11-19 01:46:12 +08:00
|
|
|
module_usb_driver(hdpvr_usb_driver);
|
2009-03-19 05:10:04 +08:00
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
[media] Stop using linux/version.h on most video drivers
All the modified drivers didn't have any version increment since
Jan, 1 2011. Several of them didn't have any version increment
for a long time, even having new features and important bug fixes
happening.
As we're now filling the QUERYCAP version with the current Kernel
Release, we don't need to maintain a per-driver version control
anymore. So, let's just use the default.
In order to preserve the Kernel module version history, a
KERNEL_VERSION() macro were added to all modified drivers, and
the extraver number were incremented.
I opted to preserve the per-driver version control to a few
pwc, pvrusb2, s2255, s5p-fimc and sh_vou.
A few drivers are still using the legacy way to handle ioctl's.
So, we can't do such change on them, otherwise, they'll break.
Those are: uvc, et61x251 and sn9c102.
The rationale is that the per-driver version control seems to be
actively maintained on those.
Yet, I think that the better for them would be to just use the
default version numbering, instead of doing that by themselves.
While here, removed a few uneeded include linux/version.h
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2011-06-25 01:45:49 +08:00
|
|
|
MODULE_VERSION("0.2.1");
|
2009-03-19 05:10:04 +08:00
|
|
|
MODULE_AUTHOR("Janne Grunau");
|
|
|
|
MODULE_DESCRIPTION("Hauppauge HD PVR driver");
|