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: > 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... > > > diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c > index 676e5be..da1ef93 100644 > --- a/drivers/media/video/cx18/cx18-driver.c > +++ b/drivers/media/video/cx18/cx18-driver.c > @@ -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); > > diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h > index f6f3e50..82dc747 100644 > --- a/drivers/media/video/cx18/cx18-driver.h > +++ b/drivers/media/video/cx18/cx18-driver.h > @@ -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; > diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c > index c330fb9..7782de1 100644 > --- a/drivers/media/video/cx18/cx18-i2c.c > +++ b/drivers/media/video/cx18/cx18-i2c.c > @@ -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; > } > diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c > index f7d1ee5..df4a02a 100644 > --- a/drivers/media/video/hdpvr/hdpvr-core.c > +++ b/drivers/media/video/hdpvr/hdpvr-core.c > @@ -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) { > diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c > index 24966aa..b1e68b8 100644 > --- a/drivers/media/video/hdpvr/hdpvr-i2c.c > +++ b/drivers/media/video/hdpvr/hdpvr-i2c.c > @@ -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; > } > diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h > index 37f1e4c..00c8563 100644 > --- a/drivers/media/video/hdpvr/hdpvr.h > +++ b/drivers/media/video/hdpvr/hdpvr.h > @@ -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; > diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c > index c87b6bc..6714e1e 100644 > --- a/drivers/media/video/ir-kbd-i2c.c > +++ b/drivers/media/video/ir-kbd-i2c.c > @@ -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) { > diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c > index 3994642..ea2afeb 100644 > --- a/drivers/media/video/ivtv/ivtv-driver.c > +++ b/drivers/media/video/ivtv/ivtv-driver.c > @@ -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); > > diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h > index 04bacdb..2c8d7c1 100644 > --- a/drivers/media/video/ivtv/ivtv-driver.h > +++ b/drivers/media/video/ivtv/ivtv-driver.h > @@ -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 */ > diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c > index e103b8f..4233b48 100644 > --- a/drivers/media/video/ivtv/ivtv-i2c.c > +++ b/drivers/media/video/ivtv/ivtv-i2c.c > @@ -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; > diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c > index 18fae54..8185581 100644 > --- a/drivers/staging/lirc/lirc_zilog.c > +++ b/drivers/staging/lirc/lirc_zilog.c > @@ -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 */ > diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h > index 768aa77..5893fd8 100644 > --- a/include/media/ir-kbd-i2c.h > +++ b/include/media/ir-kbd-i2c.h > @@ -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 majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html