ir-kbd-i2c, lirc_zilog: Allow bridge drivers to pass an IR trasnceiver mutex to I2C IR modules
Subsystems (2)
RFC PATCH 1/1 ir-kbd-i2c, lirc_zilog: Allow bridge drivers to pass an IR trasnceiver mutex to I2C IR modules
The following patch allows bridge drivers, with an I2C IR Tx/Rx transceiver, to pass a mutex for serializing access to a single I2C IR chip between separate IR Tx and Rx modules.
The change modifies struct IR_i2c_init_data and struct IR_i2c to add
struct mutex *transceiver_lock
that ir-kbd-i2c and lirc_zilog will use, if provided by the bridge driver. The changes to ir-kbd-i2c.[ch] and lirc_zilog.c provide the functional change in the patch.
This patch also modifies cx18, ivtv, and hdpvr (sans Jarrod's recent patches) to provide a transceiver_lock mutex to ir-kbd-i2c and lirc_zilog.
I skimmed all the other modules that use IR_i2c_init_data. They all appear to zero-fill the init_data properly before handing the data over to ir-kbd-i2c.c.
I did find that pvrusb2 IR Rx for address 0x71 was broken, due to my recommendation to remove automatic config for address 0x71 from ir-kbd-i2c.c. I'll fix that in another patch, if someone with a pvrusb2 device doesn't beat me to it.
So without further ado...
drivers/media/video/cx18/cx18-driver.c +1 -0
@@ -701,6 +701,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)mutex_init (&cx->serialize_lock);mutex_init (&cx->gpio_lock); +mutex_init (&cx->ir_transceiver_lock);mutex_init (&cx->epu2apu_mb_lock);mutex_init (&cx->epu2cpu_mb_lock);
drivers/media/video/cx18/cx18-driver.h +1 -0
@@ -626,6 +626,7 @@ struct cx18 {struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2 ];struct IR_i2c_init_data ir_i2c_init_data; +struct mutex ir_transceiver_lock;/* gpio */ u32 gpio_dir;
drivers/media/video/cx18/cx18-i2c.c +2 -0
@@ -96,10 +96,12 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,/* Our default information for ir-kbd-i2c.c to use */ switch (hw) {case CX18_HW_Z8F0811_IR_RX_HAUP : +case CX18_HW_Z8F0811_IR_TX_HAUP : init_data->ir_codes =RC_MAP_HAUPPAUGE_NEW ; init_data->internal_get_key_func =IR_KBD_GET_KEY_HAUP_XVR ; init_data->type =RC_TYPE_RC5 ; init_data->name = cx->card_name; + init_data->transceiver_lock = &cx->ir_transceiver_lock; info.platform_data = init_data;break ; }
drivers/media/video/hdpvr/hdpvr-core.c +1 -0
@@ -304,6 +304,7 @@ static int hdpvr_probe(struct usb_interface *interface,mutex_init (&dev->io_mutex);mutex_init (&dev->i2c_mutex); +mutex_init (&dev->ir_transceiver_mutex);mutex_init (&dev->usbc_mutex); dev->usbc_buf =kmalloc (64 ,GFP_KERNEL );if (!dev->usbc_buf) {
drivers/media/video/hdpvr/hdpvr-i2c.c +3 -1
@@ -48,13 +48,15 @@ static int hdpvr_new_i2c_ir(struct hdpvr_device *dev, struct i2c_adapter *adap,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 and lirc_zilog.c to use */ switch (addr) {case Z8F0811_IR_RX_I2C_ADDR : +case Z8F0811_IR_TX_I2C_ADDR : init_data->ir_codes =RC_MAP_HAUPPAUGE_NEW ; init_data->internal_get_key_func =IR_KBD_GET_KEY_HAUP_XVR ; init_data->type =RC_TYPE_RC5 ; init_data->name ="HD PVR" ; + init_data->transceiver_lock = &dev->ir_transceiver_mutex; info.platform_data = init_data;break ; }
drivers/media/video/hdpvr/hdpvr.h +1 -0
@@ -112,6 +112,7 @@ struct hdpvr_device {/* For passing data to ir-kbd-i2c */ struct IR_i2c_init_data ir_i2c_init_data; +struct mutex ir_transceiver_mutex;/* usb control transfer buffer and lock */ struct mutex usbc_mutex;
drivers/media/video/ir-kbd-i2c.c +10 -0
@@ -245,7 +245,15 @@ static void ir_key_poll(struct IR_i2c *ir)int rc;dprintk (2 ,"ir_poll_key\n" ); + +if (ir->transceiver_lock) +mutex_lock (ir->transceiver_lock); + rc = ir->get_key (ir, &ir_key, &ir_raw); + +if (ir->transceiver_lock) +mutex_unlock (ir->transceiver_lock); +if (rc <0 ) {dprintk (2 ,"error\n" );return ;
@@ -362,6 +370,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->get_key = get_key_avermedia_cardbus;break ; } + + ir->transceiver_lock = init_data->transceiver_lock; }if (!rc) {
drivers/media/video/ivtv/ivtv-driver.c +1 -0
@@ -713,6 +713,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) itv->dec_mbox.max_mbox =1 ;/* the decoder has 2 mailboxes (0-1) */ mutex_init (&itv->serialize_lock); +mutex_init (&itv->ir_transceiver_lock);mutex_init (&itv->i2c_bus_lock);mutex_init (&itv->udma.lock);
drivers/media/video/ivtv/ivtv-driver.h +1 -0
@@ -699,6 +699,7 @@ struct ivtv {struct mutex i2c_bus_lock;/* lock i2c bus */ struct IR_i2c_init_data ir_i2c_init_data; +struct mutex ir_transceiver_lock;/* Program Index information */ u32 pgm_info_offset;/* start of pgm info in encoder memory */
drivers/media/video/ivtv/ivtv-i2c.c +15 -0
@@ -184,7 +184,21 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)if (hw &IVTV_HW_IR_TX_ANY ) {if (itv->hw_flags &IVTV_HW_IR_TX_ANY )return -1 ; + +/* Our default information for lirc_zilog.c to use */ +switch (hw) { +case IVTV_HW_Z8F0811_IR_TX_HAUP : +/* Default to grey remote */ + init_data->ir_codes =RC_MAP_HAUPPAUGE_NEW ; + init_data->internal_get_key_func = +IR_KBD_GET_KEY_HAUP_XVR ; + init_data->type =RC_TYPE_RC5 ; + init_data->name = itv->card_name; + init_data->transceiver_lock = &itv->ir_transceiver_lock; +break ; + }memset (&info,0 ,sizeof (struct i2c_board_info )); + info.platform_data = init_data;strlcpy (info.type, type,I2C_NAME_SIZE );return i2c_new_probed_device (adap, &info, addr_list,NULL ) ==NULL ?-1 :0 ;
@@ -217,6 +231,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) init_data->internal_get_key_func =IR_KBD_GET_KEY_HAUP_XVR ; init_data->type =RC_TYPE_RC5 ; init_data->name = itv->card_name; + init_data->transceiver_lock = &itv->ir_transceiver_lock;break ;case IVTV_HW_I2C_IR_RX_ADAPTEC : init_data->get_key = get_key_adaptec;
drivers/staging/lirc/lirc_zilog.c +26 -17
150 lines not on this page · raw message
include/media/ir-kbd-i2c.h +3 -0
@@ -21,6 +21,7 @@ struct IR_i2c {char name[32 ];char phys[32 ];int (*get_key)(struct IR_i2c *,u32 *,u32 *); +struct mutex *transceiver_lock; };enum ir_kbd_get_key_fn {
@@ -48,5 +49,7 @@ struct IR_i2c_init_data {enum ir_kbd_get_key_fn internal_get_key_func;struct rc_dev *rc_dev; + + struct mutex *transceiver_lock; };#endif
Jarod/Andy,
For now, I'm marking all those ir-kbd-i2c/lirc_zilog patches as "RFC" at patchwork, as I'm not sure if they're ok, and because there are a few revisions of them and I'm afraid to apply some wrong version.
Please, after finishing and testing, send me a patch series or, preferably, a git pull with those stuff.
Thanks!
Mauro
Em 16-01-2011 01:49, Andy Walls escreveu:
Quoted 396 lines
The following patch allows bridge drivers, with an I2C IR Tx/Rx transceiver, to pass a mutex for serializing access to a single I2C IR chip between separate IR Tx and Rx modules.
The change modifies struct
IR_i2c_init_dataand structIR_i2cto addstruct mutex
*transceiver_lockthat ir-kbd-i2c and
lirc_zilogwill use, if provided by the bridge driver. The changes to ir-kbd-i2c.[ch] andlirc_zilog.cprovide the functional change in the patch.This patch also modifies cx18, ivtv, and hdpvr (sans Jarrod's recent patches) to provide a
transceiver_lockmutex to ir-kbd-i2c andlirc_zilog.I skimmed all the other modules that use
IR_i2c_init_data. They all appear to zero-fill theinit_dataproperly before handing the data over toir-kbd-i2c.c.I did find that pvrusb2 IR Rx for address
0x71was broken, due to my recommendation to remove automatic config for address0x71fromir-kbd-i2c.c. I'll fix that in another patch, if someone with a pvrusb2 device doesn't beat me to it.So without further ado...
drivers/media/video/cx18/cx18-driver.c +1
-0@@ -701,6 +701,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)mutex_init (&cx->serialize_lock);mutex_init (&cx->gpio_lock); +mutex_init (&cx->ir_transceiver_lock);mutex_init (&cx->epu2apu_mb_lock);mutex_init (&cx->epu2cpu_mb_lock);drivers/media/video/cx18/cx18-driver.h +1
-0@@ -626,6 +626,7 @@ struct cx18 {struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2 ];struct IR_i2c_init_data ir_i2c_init_data; +struct mutex ir_transceiver_lock;/* gpio */ u32 gpio_dir;drivers/media/video/cx18/cx18-i2c.c +2
-0@@ -96,10 +96,12 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,/* Our default information for ir-kbd-i2c.c to use */ switch (hw) {case CX18_HW_Z8F0811_IR_RX_HAUP : +case CX18_HW_Z8F0811_IR_TX_HAUP : init_data->ir_codes =RC_MAP_HAUPPAUGE_NEW ; init_data->internal_get_key_func =IR_KBD_GET_KEY_HAUP_XVR ; init_data->type =RC_TYPE_RC5 ; init_data->name = cx->card_name; + init_data->transceiver_lock = &cx->ir_transceiver_lock; info.platform_data = init_data;break ; }drivers/media/video/hdpvr/hdpvr-core.c +1
-0@@ -304,6 +304,7 @@ static int hdpvr_probe(struct usb_interface *interface,mutex_init (&dev->io_mutex);mutex_init (&dev->i2c_mutex); +mutex_init (&dev->ir_transceiver_mutex);mutex_init (&dev->usbc_mutex); dev->usbc_buf =kmalloc (64 ,GFP_KERNEL );if (!dev->usbc_buf) {drivers/media/video/hdpvr/hdpvr-i2c.c +3
-1@@ -48,13 +48,15 @@ static int hdpvr_new_i2c_ir(struct hdpvr_device *dev, struct i2c_adapter *adap,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 and lirc_zilog.c to use */ switch (addr) {case Z8F0811_IR_RX_I2C_ADDR : +case Z8F0811_IR_TX_I2C_ADDR : init_data->ir_codes =RC_MAP_HAUPPAUGE_NEW ; init_data->internal_get_key_func =IR_KBD_GET_KEY_HAUP_XVR ; init_data->type =RC_TYPE_RC5 ; init_data->name ="HD PVR" ; + init_data->transceiver_lock = &dev->ir_transceiver_mutex; info.platform_data = init_data;break ; }drivers/media/video/hdpvr/hdpvr.h +1
-0@@ -112,6 +112,7 @@ struct hdpvr_device {/* For passing data to ir-kbd-i2c */ struct IR_i2c_init_data ir_i2c_init_data; +struct mutex ir_transceiver_mutex;/* usb control transfer buffer and lock */ struct mutex usbc_mutex;drivers/media/video/ir-kbd-i2c.c +10
-0@@ -245,7 +245,15 @@ static void ir_key_poll(struct IR_i2c *ir)int rc;dprintk (2 ,"ir_poll_key\n" ); + +if (ir->transceiver_lock) +mutex_lock (ir->transceiver_lock); + rc = ir->get_key (ir, &ir_key, &ir_raw); + +if (ir->transceiver_lock) +mutex_unlock (ir->transceiver_lock); +if (rc <0 ) {dprintk (2 ,"error\n" );return ;@@ -362,6 +370,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->get_key = get_key_avermedia_cardbus;break ; } + + ir->transceiver_lock = init_data->transceiver_lock; }if (!rc) {drivers/media/video/ivtv/ivtv-driver.c +1
-0@@ -713,6 +713,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) itv->dec_mbox.max_mbox =1 ;/* the decoder has 2 mailboxes (0-1) */ mutex_init (&itv->serialize_lock); +mutex_init (&itv->ir_transceiver_lock);mutex_init (&itv->i2c_bus_lock);mutex_init (&itv->udma.lock);drivers/media/video/ivtv/ivtv-driver.h +1
-0@@ -699,6 +699,7 @@ struct ivtv {struct mutex i2c_bus_lock;/* lock i2c bus */ struct IR_i2c_init_data ir_i2c_init_data; +struct mutex ir_transceiver_lock;/* Program Index information */ u32 pgm_info_offset;/* start of pgm info in encoder memory */ drivers/media/video/ivtv/ivtv-i2c.c +15
-0@@ -184,7 +184,21 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)if (hw &IVTV_HW_IR_TX_ANY ) {if (itv->hw_flags &IVTV_HW_IR_TX_ANY )return -1 ; + +/* Our default information for lirc_zilog.c to use */ +switch (hw) { +case IVTV_HW_Z8F0811_IR_TX_HAUP : +/* Default to grey remote */ + init_data->ir_codes =RC_MAP_HAUPPAUGE_NEW ; + init_data->internal_get_key_func = +IR_KBD_GET_KEY_HAUP_XVR ; + init_data->type =RC_TYPE_RC5 ; + init_data->name = itv->card_name; + init_data->transceiver_lock = &itv->ir_transceiver_lock; +break ; + }memset (&info,0 ,sizeof (struct i2c_board_info )); + info.platform_data = init_data;strlcpy (info.type, type,I2C_NAME_SIZE );return i2c_new_probed_device (adap, &info, addr_list,NULL ) ==NULL ?-1 :0 ;@@ -217,6 +231,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) init_data->internal_get_key_func =IR_KBD_GET_KEY_HAUP_XVR ; init_data->type =RC_TYPE_RC5 ; init_data->name = itv->card_name; + init_data->transceiver_lock = &itv->ir_transceiver_lock;break ;case IVTV_HW_I2C_IR_RX_ADAPTEC : init_data->get_key = get_key_adaptec;drivers/staging/lirc/lirc_zilog.c +26
-17@@ -59,6 +59,7 @@#include <media/lirc_dev.h> #include <media/lirc.h> +#include <media/ir-kbd-i2c.h> struct IR_rx {/* RX device */ @@ -89,6 +90,7 @@ struct IR {struct lirc_driver l;struct mutex ir_lock; +struct mutex *xcvr_lock;int open;struct i2c_adapter *adapter;@@ -175,10 +177,10 @@ static int add_to_buf(struct IR *ir)* Lock i2c bus for the duration. RX/TX chips interfere so * this is worth it */ -mutex_lock (&ir->ir_lock); +mutex_lock (ir->xcvr_lock);if (kthread_should_stop ()) { -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);return -ENODATA ; }@@ -190,7 +192,7 @@ static int add_to_buf(struct IR *ir)if (ret !=1 ) {zilog_error ("i2c_master_send failed with %d\n" , ret);if (failures >=3 ) { -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);zilog_error ("unable to read from the IR chip " "after 3 resets, giving up\n" );return ret;@@ -202,23 +204,23 @@ static int add_to_buf(struct IR *ir)set_current_state (TASK_UNINTERRUPTIBLE );if (kthread_should_stop ()) { -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);return -ENODATA ; }schedule_timeout ((100 *HZ +999 ) /1000 ); ir->tx->need_boot =1 ; ++failures; -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);continue ; }if (kthread_should_stop ()) { -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);return -ENODATA ; } ret =i2c_master_recv (rx->c, keybuf,sizeof (keybuf)); -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);if (ret !=sizeof (keybuf)) {zilog_error ("i2c_master_recv failed with %d -- " "keeping last read buffer\n" , ret);@@ -920,7 +922,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,return -EINVAL ;/* Lock i2c bus for the duration */ -mutex_lock (&ir->ir_lock); +mutex_lock (ir->xcvr_lock);/* Send each keypress */ for (i =0 ; i < n;) {@@ -928,7 +930,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,int command;if (copy_from_user (&command, buf + i,sizeof (command))) { -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);return -EFAULT ; }@@ -944,7 +946,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, ret =send_code (tx, (unsigned )command >>16 , (unsigned )command &0xFFFF );if (ret == -EPROTO ) { -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);return ret; } }@@ -961,7 +963,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,if (failures >=3 ) {zilog_error ("unable to send to the IR chip " "after 3 resets, giving up\n" ); -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);return ret; }set_current_state (TASK_UNINTERRUPTIBLE );@@ -973,7 +975,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, }/* Release i2c bus */ -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);/* All looks good */ return n;@@ -1079,15 +1081,15 @@ static int open(struct inode *node, struct file *filep)return -ENODEV ;/* increment in use count */ -mutex_lock (&ir->ir_lock); +mutex_lock (ir->xcvr_lock); ++ir->open; ret =set_use_inc (ir);if (ret !=0 ) { --ir->open; -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);return ret; } -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);/* stash our IR struct */ filep->private_data = ir;@@ -1106,10 +1108,10 @@ static int close(struct inode *node, struct file *filep) }/* decrement in use count */ -mutex_lock (&ir->ir_lock); +mutex_lock (ir->xcvr_lock); --ir->open;set_use_dec (ir); -mutex_unlock (&ir->ir_lock); +mutex_unlock (ir->xcvr_lock);return 0 ; }@@ -1251,6 +1253,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) {struct IR *ir;struct i2c_adapter *adap = client->adapter; +const struct IR_i2c_init_data *init_data = client->dev.platform_data;int ret;bool tx_probe = false;@@ -1288,6 +1291,12 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->adapter = adap;mutex_init (&ir->ir_lock); +/* Use bridge driver's transceiver lock, if provided */ +if (init_data !=NULL ) + ir->xcvr_lock = init_data->transceiver_lock; +if (ir->xcvr_lock ==NULL ) + ir->xcvr_lock = &ir->ir_lock; +/* set lirc_dev stuff */ memcpy (&ir->l, &lirc_template,sizeof (struct lirc_driver )); ir->l.minor = minor;/* module option */ include/media/ir-kbd-i2c.h +3
-1@@ -21,6 +21,7 @@ struct IR_i2c {char name[32 ];char phys[32 ];int (*get_key)(struct IR_i2c *,u32 *,u32 *); +struct mutex *transceiver_lock; };enum ir_kbd_get_key_fn {@@ -48,5 +49,7 @@ struct IR_i2c_init_data {enum ir_kbd_get_key_fn internal_get_key_func;struct rc_dev *rc_dev; + + struct mutex *transceiver_lock; };#endif --To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 5 lines · Mauro Carvalho Chehab
Jarod/Andy,
For now, I'm marking all those ir-kbd-i2c/lirc_zilog patches as "RFC" at patchwork, as I'm not sure if they're ok, and because there are a few revisions of them and I'm afraid to apply some wrong version.
And that's just fine. :)
That particular RFC was to get mostly Jean's opinion on adding fields to struct IR_i2c_init_data and struct IR_i2c and code to ir-kbd-i2c.
Quoted 2 lines
Please, after finishing and testing, send me a patch series or, preferably, a git pull with those stuff.
I just sent a [GIT PATCHES for 2.6.38], which is my pull request. It fixes one minor regression in ir-kbd-i2c.c. The rest of the patches are limited to lirc_zilog and do not modify any bridge drivers. The lirc_zilog changes were tested by me using my HVR-1600.
Jarrod will have to ask you to pull any hdpvr fixes, when he feels they are ready.
Note my pull request does *not* include the patches in the subject [RFC PATCH], so no worries about pulling those in. :) I'll submit a pull for those when they are correct and ready.
Regards,
Andy