提交 324b04ba 编写于 作者: J Jarod Wilson 提交者: Mauro Carvalho Chehab

[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: NJarod Wilson <jarod@redhat.com>
Acked-by: NAndy Walls <awalls@md.metrocast.net>
Signed-off-by: NMauro Carvalho Chehab <mchehab@redhat.com>
上级 706c57d8
hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o
hdpvr-$(CONFIG_I2C) += hdpvr-i2c.o
obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o
......
...@@ -378,19 +378,17 @@ static int hdpvr_probe(struct usb_interface *interface, ...@@ -378,19 +378,17 @@ static int hdpvr_probe(struct usb_interface *interface,
goto error; goto error;
} }
#ifdef CONFIG_I2C #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
/* until i2c is working properly */ retval = hdpvr_register_i2c_adapter(dev);
retval = 0; /* hdpvr_register_i2c_adapter(dev); */
if (retval < 0) { if (retval < 0) {
v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n"); v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n");
goto error; goto error;
} }
/* until i2c is working properly */ retval = hdpvr_register_i2c_ir(dev);
retval = 0; /* hdpvr_register_i2c_ir(dev); */
if (retval < 0) if (retval < 0)
v4l2_err(&dev->v4l2_dev, "registering i2c IR devices failed\n"); v4l2_err(&dev->v4l2_dev, "registering i2c IR devices failed\n");
#endif /* CONFIG_I2C */ #endif
/* let the user know what node this device is now attached to */ /* let the user know what node this device is now attached to */
v4l2_info(&dev->v4l2_dev, "device now attached to %s\n", v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
* *
*/ */
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -28,55 +30,31 @@ ...@@ -28,55 +30,31 @@
#define Z8F0811_IR_TX_I2C_ADDR 0x70 #define Z8F0811_IR_TX_I2C_ADDR 0x70
#define Z8F0811_IR_RX_I2C_ADDR 0x71 #define Z8F0811_IR_RX_I2C_ADDR 0x71
static const u8 ir_i2c_addrs[] = {
Z8F0811_IR_TX_I2C_ADDR,
Z8F0811_IR_RX_I2C_ADDR,
};
static const char * const ir_devicenames[] = { static struct i2c_board_info hdpvr_i2c_board_info = {
"ir_tx_z8f0811_hdpvr", I2C_BOARD_INFO("ir_tx_z8f0811_hdpvr", Z8F0811_IR_TX_I2C_ADDR),
"ir_rx_z8f0811_hdpvr", I2C_BOARD_INFO("ir_rx_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR),
}; };
static int hdpvr_new_i2c_ir(struct hdpvr_device *dev, struct i2c_adapter *adap, int hdpvr_register_i2c_ir(struct hdpvr_device *dev)
const char *type, u8 addr)
{ {
struct i2c_board_info info; struct i2c_client *c;
struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data; struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data;
unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, type, I2C_NAME_SIZE);
/* Our default information for ir-kbd-i2c.c to use */ /* Our default information for ir-kbd-i2c.c to use */
switch (addr) { init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
case Z8F0811_IR_RX_I2C_ADDR: init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW; init_data->type = RC_TYPE_RC5;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; init_data->name = "HD PVR";
init_data->type = RC_TYPE_RC5; hdpvr_i2c_board_info.platform_data = init_data;
init_data->name = "HD PVR";
info.platform_data = init_data;
break;
}
return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
-1 : 0;
}
int hdpvr_register_i2c_ir(struct hdpvr_device *dev) c = i2c_new_device(&dev->i2c_adapter, &hdpvr_i2c_board_info);
{
int i;
int ret = 0;
for (i = 0; i < ARRAY_SIZE(ir_i2c_addrs); i++) return (c == NULL) ? -ENODEV : 0;
ret += hdpvr_new_i2c_ir(dev, dev->i2c_adapter,
ir_devicenames[i], ir_i2c_addrs[i]);
return ret;
} }
static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr, static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus,
char *data, int len) unsigned char addr, char *data, int len)
{ {
int ret; int ret;
char *buf = kmalloc(len, GFP_KERNEL); char *buf = kmalloc(len, GFP_KERNEL);
...@@ -86,7 +64,7 @@ static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr, ...@@ -86,7 +64,7 @@ static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
ret = usb_control_msg(dev->udev, ret = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0), usb_rcvctrlpipe(dev->udev, 0),
REQTYPE_I2C_READ, CTRL_READ_REQUEST, REQTYPE_I2C_READ, CTRL_READ_REQUEST,
0x100|addr, 0, buf, len, 1000); (bus << 8) | addr, 0, buf, len, 1000);
if (ret == len) { if (ret == len) {
memcpy(data, buf, len); memcpy(data, buf, len);
...@@ -99,8 +77,8 @@ static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr, ...@@ -99,8 +77,8 @@ static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
return ret; return ret;
} }
static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr, static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus,
char *data, int len) unsigned char addr, char *data, int len)
{ {
int ret; int ret;
char *buf = kmalloc(len, GFP_KERNEL); char *buf = kmalloc(len, GFP_KERNEL);
...@@ -111,7 +89,7 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr, ...@@ -111,7 +89,7 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
ret = usb_control_msg(dev->udev, ret = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0), usb_sndctrlpipe(dev->udev, 0),
REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
0x100|addr, 0, buf, len, 1000); (bus << 8) | addr, 0, buf, len, 1000);
if (ret < 0) if (ret < 0)
goto error; goto error;
...@@ -121,7 +99,7 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr, ...@@ -121,7 +99,7 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST, REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
0, 0, buf, 2, 1000); 0, 0, buf, 2, 1000);
if (ret == 2) if ((ret == 2) && (buf[1] == (len - 1)))
ret = 0; ret = 0;
else if (ret >= 0) else if (ret >= 0)
ret = -EIO; ret = -EIO;
...@@ -146,10 +124,10 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, ...@@ -146,10 +124,10 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
addr = msgs[i].addr << 1; addr = msgs[i].addr << 1;
if (msgs[i].flags & I2C_M_RD) if (msgs[i].flags & I2C_M_RD)
retval = hdpvr_i2c_read(dev, addr, msgs[i].buf, retval = hdpvr_i2c_read(dev, 1, addr, msgs[i].buf,
msgs[i].len); msgs[i].len);
else else
retval = hdpvr_i2c_write(dev, addr, msgs[i].buf, retval = hdpvr_i2c_write(dev, 1, addr, msgs[i].buf,
msgs[i].len); msgs[i].len);
} }
...@@ -168,30 +146,47 @@ static struct i2c_algorithm hdpvr_algo = { ...@@ -168,30 +146,47 @@ static struct i2c_algorithm hdpvr_algo = {
.functionality = hdpvr_functionality, .functionality = hdpvr_functionality,
}; };
static struct i2c_adapter hdpvr_i2c_adapter_template = {
.name = "Hauppage HD PVR I2C",
.owner = THIS_MODULE,
.algo = &hdpvr_algo,
};
static int hdpvr_activate_ir(struct hdpvr_device *dev)
{
char buffer[8];
mutex_lock(&dev->i2c_mutex);
hdpvr_i2c_read(dev, 0, 0x54, buffer, 1);
buffer[0] = 0;
buffer[1] = 0x8;
hdpvr_i2c_write(dev, 1, 0x54, buffer, 2);
buffer[1] = 0x18;
hdpvr_i2c_write(dev, 1, 0x54, buffer, 2);
mutex_unlock(&dev->i2c_mutex);
return 0;
}
int hdpvr_register_i2c_adapter(struct hdpvr_device *dev) int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
{ {
struct i2c_adapter *i2c_adap;
int retval = -ENOMEM; int retval = -ENOMEM;
i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); hdpvr_activate_ir(dev);
if (i2c_adap == NULL)
goto error;
strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C", memcpy(&dev->i2c_adapter, &hdpvr_i2c_adapter_template,
sizeof(i2c_adap->name)); sizeof(struct i2c_adapter));
i2c_adap->algo = &hdpvr_algo; dev->i2c_adapter.dev.parent = &dev->udev->dev;
i2c_adap->owner = THIS_MODULE;
i2c_adap->dev.parent = &dev->udev->dev;
i2c_set_adapdata(i2c_adap, dev); i2c_set_adapdata(&dev->i2c_adapter, dev);
retval = i2c_add_adapter(i2c_adap); retval = i2c_add_adapter(&dev->i2c_adapter);
if (!retval)
dev->i2c_adapter = i2c_adap;
else
kfree(i2c_adap);
error:
return retval; return retval;
} }
#endif
...@@ -1220,12 +1220,9 @@ static void hdpvr_device_release(struct video_device *vdev) ...@@ -1220,12 +1220,9 @@ static void hdpvr_device_release(struct video_device *vdev)
v4l2_device_unregister(&dev->v4l2_dev); v4l2_device_unregister(&dev->v4l2_dev);
/* deregister I2C adapter */ /* deregister I2C adapter */
#ifdef CONFIG_I2C #if defined(CONFIG_I2C) || (CONFIG_I2C_MODULE)
mutex_lock(&dev->i2c_mutex); mutex_lock(&dev->i2c_mutex);
if (dev->i2c_adapter) i2c_del_adapter(&dev->i2c_adapter);
i2c_del_adapter(dev->i2c_adapter);
kfree(dev->i2c_adapter);
dev->i2c_adapter = NULL;
mutex_unlock(&dev->i2c_mutex); mutex_unlock(&dev->i2c_mutex);
#endif /* CONFIG_I2C */ #endif /* CONFIG_I2C */
......
...@@ -106,7 +106,7 @@ struct hdpvr_device { ...@@ -106,7 +106,7 @@ struct hdpvr_device {
struct work_struct worker; struct work_struct worker;
/* I2C adapter */ /* I2C adapter */
struct i2c_adapter *i2c_adapter; struct i2c_adapter i2c_adapter;
/* I2C lock */ /* I2C lock */
struct mutex i2c_mutex; struct mutex i2c_mutex;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册