Let card drivers probe for IR receiver devices and instantiate them if
found. Ultimately it would be better if we could stop probing
completely, but I suspect this won't be possible for all card types.

There's certainly room for cleanups. For example, some drivers are
sharing I2C adapter IDs, so they also had to share the list of I2C
addresses being probed for an IR receiver. Now that each driver
explicitly says which addresses should be probed, maybe some addresses
can be dropped from some drivers.

Also, the special cases in saa7134-i2c should probably be handled on a
per-board basis. This would be more efficient and less risky than always
probing extra addresses on all boards. I'll give it a try later.

Signed-off-by: Jean Delvare <kh...@linux-fr.org>
Cc: Mauro Carvalho Chehab <mche...@infradead.org>
Cc: Hans Verkuil <hverk...@xs4all.nl>
Cc: Andy Walls <awa...@radix.net>
Cc: Mike Isely <is...@pobox.com>
---
 linux/drivers/media/video/bt8xx/bttv-i2c.c        |   21 ++
 linux/drivers/media/video/cx231xx/cx231xx-cards.c |   11 -
 linux/drivers/media/video/cx231xx/cx231xx-i2c.c   |    3 
 linux/drivers/media/video/cx231xx/cx231xx.h       |    1 
 linux/drivers/media/video/cx23885/cx23885-i2c.c   |   12 +
 linux/drivers/media/video/cx88/cx88-i2c.c         |   13 +
 linux/drivers/media/video/em28xx/em28xx-cards.c   |   20 +-
 linux/drivers/media/video/em28xx/em28xx-i2c.c     |    3 
 linux/drivers/media/video/em28xx/em28xx-input.c   |    6 
 linux/drivers/media/video/em28xx/em28xx.h         |    1 
 linux/drivers/media/video/ir-kbd-i2c.c            |  200 +++------------------
 linux/drivers/media/video/ivtv/ivtv-i2c.c         |   31 ++-
 linux/drivers/media/video/saa7134/saa7134-i2c.c   |    3 
 linux/drivers/media/video/saa7134/saa7134-input.c |   86 +++++++--
 linux/drivers/media/video/saa7134/saa7134.h       |    1 
 linux/include/media/ir-kbd-i2c.h                  |    2 
 16 files changed, 220 insertions(+), 194 deletions(-)

--- v4l-dvb.orig/linux/drivers/media/video/bt8xx/bttv-i2c.c     2009-05-12 
10:19:13.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/bt8xx/bttv-i2c.c  2009-05-12 
11:24:19.000000000 +0200
@@ -405,6 +405,27 @@ int __devinit init_bttv_i2c(struct bttv
        }
        if (0 == btv->i2c_rc && i2c_scan)
                do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
+
+       /* Instantiate the IR receiver device, if present */
+       if (0 == btv->i2c_rc) {
+               struct i2c_board_info info;
+               /* The external IR receiver is at i2c address 0x34 (0x35 for
+                  reads).  Future Hauppauge cards will have an internal
+                  receiver at 0x30 (0x31 for reads).  In theory, both can be
+                  fitted, and Hauppauge suggest an external overrides an
+                  internal.
+
+                  That's why we probe 0x1a (~0x34) first. CB
+               */
+               const unsigned short addr_list[] = {
+                       0x1a, 0x18, 0x4b, 0x64, 0x30,
+                       I2C_CLIENT_END
+               };
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list);
+       }
        return btv->i2c_rc;
 }
 
--- v4l-dvb.orig/linux/drivers/media/video/cx231xx/cx231xx-cards.c      
2009-05-12 10:19:13.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/cx231xx/cx231xx-cards.c   2009-05-12 
11:24:19.000000000 +0200
@@ -282,13 +282,16 @@ static void cx231xx_config_tuner(struct
 }
 
 /* ----------------------------------------------------------------------- */
-void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir)
+void cx231xx_register_i2c_ir(struct cx231xx *dev)
 {
-       if (disable_ir) {
-               ir->get_key = NULL;
+       if (disable_ir)
                return;
-       }
 
+       /* REVISIT: instantiate IR device */
+}
+
+void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir)
+{
        /* detect & configure */
        switch (dev->model) {
 
--- v4l-dvb.orig/linux/drivers/media/video/cx231xx/cx231xx-i2c.c        
2009-05-12 10:19:13.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/cx231xx/cx231xx-i2c.c     2009-05-12 
11:24:19.000000000 +0200
@@ -540,6 +540,9 @@ int cx231xx_i2c_register(struct cx231xx_
        if (0 == bus->i2c_rc) {
                if (i2c_scan)
                        cx231xx_do_i2c_scan(dev, &bus->i2c_client);
+
+               /* Instantiate the IR receiver device, if present */
+               cx231xx_register_i2c_ir(dev);
        } else
                cx231xx_warn("%s: i2c bus %d register FAILED\n",
                             dev->name, bus->nr);
--- v4l-dvb.orig/linux/drivers/media/video/cx231xx/cx231xx.h    2009-05-12 
10:19:13.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/cx231xx/cx231xx.h 2009-05-12 
11:24:19.000000000 +0200
@@ -747,6 +747,7 @@ extern void cx231xx_card_setup(struct cx
 extern struct cx231xx_board cx231xx_boards[];
 extern struct usb_device_id cx231xx_id_table[];
 extern const unsigned int cx231xx_bcount;
+void cx231xx_register_i2c_ir(struct cx231xx *dev);
 void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir);
 int cx231xx_tuner_callback(void *ptr, int component, int command, int arg);
 
--- v4l-dvb.orig/linux/drivers/media/video/cx23885/cx23885-i2c.c        
2009-05-12 10:19:13.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/cx23885/cx23885-i2c.c     2009-05-12 
11:24:19.000000000 +0200
@@ -364,6 +364,18 @@ int cx23885_i2c_register(struct cx23885_
                printk(KERN_WARNING "%s: i2c bus %d register FAILED\n",
                        dev->name, bus->nr);
 
+       /* Instantiate the IR receiver device, if present */
+       if (0 == bus->i2c_rc) {
+               struct i2c_board_info info;
+               const unsigned short addr_list[] = {
+                       0x6b, I2C_CLIENT_END
+               };
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               i2c_new_probed_device(&bus->i2c_adap, &info, addr_list);
+       }
+
        return bus->i2c_rc;
 }
 
--- v4l-dvb.orig/linux/drivers/media/video/cx88/cx88-i2c.c      2009-05-12 
10:19:13.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/cx88/cx88-i2c.c   2009-05-12 
11:24:19.000000000 +0200
@@ -186,6 +186,19 @@ int cx88_i2c_init(struct cx88_core *core
                        do_i2c_scan(core->name,&core->i2c_client);
        } else
                printk("%s: i2c register FAILED\n", core->name);
+
+       /* Instantiate the IR receiver device, if present */
+       if (0 == core->i2c_rc) {
+               struct i2c_board_info info;
+               const unsigned short addr_list[] = {
+                       0x18, 0x6b, 0x71,
+                       I2C_CLIENT_END
+               };
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               i2c_new_probed_device(&core->i2c_adap, &info, addr_list);
+       }
        return core->i2c_rc;
 }
 
--- v4l-dvb.orig/linux/drivers/media/video/em28xx/em28xx-cards.c        
2009-05-12 11:14:20.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/em28xx/em28xx-cards.c     2009-05-12 
11:24:19.000000000 +0200
@@ -1931,13 +1931,23 @@ static int em28xx_hint_board(struct em28
 }
 
 /* ----------------------------------------------------------------------- */
-void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
+void em28xx_register_i2c_ir(struct em28xx *dev)
 {
-       if (disable_ir) {
-               ir->get_key = NULL;
-               return ;
-       }
+       struct i2c_board_info info;
+       const unsigned short addr_list[] = {
+                0x30, 0x47, I2C_CLIENT_END
+       };
+
+       if (disable_ir)
+               return;
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+       i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
+}
 
+void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
+{
        /* detect & configure */
        switch (dev->model) {
        case (EM2800_BOARD_UNKNOWN):
--- v4l-dvb.orig/linux/drivers/media/video/em28xx/em28xx-i2c.c  2009-05-12 
10:19:13.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/em28xx/em28xx-i2c.c       2009-05-12 
11:24:19.000000000 +0200
@@ -581,6 +581,9 @@ int em28xx_i2c_register(struct em28xx *d
        if (i2c_scan)
                em28xx_do_i2c_scan(dev);
 
+       /* Instantiate the IR receiver device, if present */
+       em28xx_register_i2c_ir(dev);
+
        return 0;
 }
 
--- v4l-dvb.orig/linux/drivers/media/video/em28xx/em28xx-input.c        
2009-05-12 11:14:20.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/em28xx/em28xx-input.c     2009-05-12 
11:24:19.000000000 +0200
@@ -86,7 +86,7 @@ int em28xx_get_key_terratec(struct IR_i2
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c, &b, 1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -115,7 +115,7 @@ int em28xx_get_key_em_haup(struct IR_i2c
        unsigned char code;
 
        /* poll IR chip */
-       if (2 != i2c_master_recv(&ir->c, buf, 2))
+       if (2 != i2c_master_recv(ir->c, buf, 2))
                return -EIO;
 
        /* Does eliminate repeated parity code */
@@ -153,7 +153,7 @@ int em28xx_get_key_pinnacle_usb_grey(str
 
        /* poll IR chip */
 
-       if (3 != i2c_master_recv(&ir->c, buf, 3)) {
+       if (3 != i2c_master_recv(ir->c, buf, 3)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
--- v4l-dvb.orig/linux/drivers/media/video/em28xx/em28xx.h      2009-05-12 
10:19:13.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/em28xx/em28xx.h   2009-05-12 
11:24:19.000000000 +0200
@@ -649,6 +649,7 @@ extern void em28xx_card_setup(struct em2
 extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
 extern const unsigned int em28xx_bcount;
+void em28xx_register_i2c_ir(struct em28xx *dev);
 void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 void em28xx_release_resources(struct em28xx *dev);
--- v4l-dvb.orig/linux/drivers/media/video/ir-kbd-i2c.c 2009-05-12 
11:14:20.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/ir-kbd-i2c.c      2009-05-12 
11:24:19.000000000 +0200
@@ -75,7 +75,7 @@ static int get_key_haup_common(struct IR
        int start, range, toggle, dev, code, ircode;
 
        /* poll IR chip */
-       if (size != i2c_master_recv(&ir->c,buf,size))
+       if (size != i2c_master_recv(ir->c, buf, size))
                return -EIO;
 
        /* split rc5 data block ... */
@@ -138,7 +138,7 @@ static int get_key_pixelview(struct IR_i
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                dprintk(1,"read error\n");
                return -EIO;
        }
@@ -152,7 +152,7 @@ static int get_key_pv951(struct IR_i2c *
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                dprintk(1,"read error\n");
                return -EIO;
        }
@@ -172,7 +172,7 @@ static int get_key_fusionhdtv(struct IR_
        unsigned char buf[4];
 
        /* poll IR chip */
-       if (4 != i2c_master_recv(&ir->c,buf,4)) {
+       if (4 != i2c_master_recv(ir->c, buf, 4)) {
                dprintk(1,"read error\n");
                return -EIO;
        }
@@ -196,7 +196,7 @@ static int get_key_knc1(struct IR_i2c *i
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                dprintk(1,"read error\n");
                return -EIO;
        }
@@ -223,12 +223,12 @@ static int get_key_avermedia_cardbus(str
                                     u32 *ir_key, u32 *ir_raw)
 {
        unsigned char subaddr, key, keygroup;
-       struct i2c_msg msg[] = { { .addr = ir->c.addr, .flags = 0,
+       struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0,
                                   .buf = &subaddr, .len = 1},
-                                { .addr = ir->c.addr, .flags = I2C_M_RD,
+                                { .addr = ir->c->addr, .flags = I2C_M_RD,
                                  .buf = &key, .len = 1} };
        subaddr = 0x0d;
-       if (2 != i2c_transfer(ir->c.adapter, msg, 2)) {
+       if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
                dprintk(1, "read error\n");
                return -EIO;
        }
@@ -238,7 +238,7 @@ static int get_key_avermedia_cardbus(str
 
        subaddr = 0x0b;
        msg[1].buf = &keygroup;
-       if (2 != i2c_transfer(ir->c.adapter, msg, 2)) {
+       if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
                dprintk(1, "read error\n");
                return -EIO;
        }
@@ -295,7 +295,7 @@ static void ir_work(struct work_struct *
 
        /* MSI t...@nywhere Plus requires more frequent polling
           otherwise it will miss some keypresses */
-       if (ir->c.adapter->id == I2C_HW_SAA7134 && ir->c.addr == 0x30)
+       if (ir->c->adapter->id == I2C_HW_SAA7134 && ir->c->addr == 0x30)
                polling_interval = 50;
 
        ir_key_poll(ir);
@@ -304,34 +304,15 @@ static void ir_work(struct work_struct *
 
 /* ----------------------------------------------------------------------- */
 
-static int ir_attach(struct i2c_adapter *adap, int addr,
-                     unsigned short flags, int kind);
-static int ir_detach(struct i2c_client *client);
-static int ir_probe(struct i2c_adapter *adap);
-
-static struct i2c_driver driver = {
-       .driver = {
-               .name   = "ir-kbd-i2c",
-       },
-       .id             = I2C_DRIVERID_INFRARED,
-       .attach_adapter = ir_probe,
-       .detach_client  = ir_detach,
-};
-
-static struct i2c_client client_template =
-{
-       .name = "unset",
-       .driver = &driver
-};
-
-static int ir_attach(struct i2c_adapter *adap, int addr,
-                    unsigned short flags, int kind)
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        IR_KEYTAB_TYPE *ir_codes = NULL;
        char *name;
        int ir_type;
        struct IR_i2c *ir;
        struct input_dev *input_dev;
+       struct i2c_adapter *adap = client->adapter;
+       unsigned short addr = client->addr;
        int err;
 
        ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL);
@@ -341,14 +322,9 @@ static int ir_attach(struct i2c_adapter
                goto err_out_free;
        }
 
-       ir->c = client_template;
+       ir->c = client;
        ir->input = input_dev;
-
-       ir->c.adapter = adap;
-       ir->c.addr    = addr;
-       snprintf(ir->c.name, sizeof(ir->c.name), "ir-kbd");
-
-       i2c_set_clientdata(&ir->c, ir);
+       i2c_set_clientdata(client, ir);
 
        switch(addr) {
        case 0x64:
@@ -423,24 +399,9 @@ static int ir_attach(struct i2c_adapter
        snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name);
        ir->ir_codes = ir_codes;
 
-       /* register i2c device
-        * At device register, IR codes may be changed to be
-        * board dependent.
-        */
-       err = i2c_attach_client(&ir->c);
-       if (err)
-               goto err_out_free;
-
-       /* If IR not supported or disabled, unregisters driver */
-       if (ir->get_key == NULL) {
-               err = -ENODEV;
-               goto err_out_detach;
-       }
-
-       /* Phys addr can only be set after attaching (for ir->c.dev) */
        snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
-                dev_name(&ir->c.adapter->dev),
-                dev_name(&ir->c.dev));
+                dev_name(&adap->dev),
+                dev_name(&client->dev));
 
        /* init + register input device */
        ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes);
@@ -450,7 +411,7 @@ static int ir_attach(struct i2c_adapter
 
        err = input_register_device(ir->input);
        if (err)
-               goto err_out_detach;
+               goto err_out_free;
 
        printk(DEVNAME ": %s detected at %s [%s]\n",
               ir->input->name, ir->input->phys, adap->name);
@@ -465,135 +426,42 @@ static int ir_attach(struct i2c_adapter
 
        return 0;
 
- err_out_detach:
-       i2c_detach_client(&ir->c);
  err_out_free:
        input_free_device(input_dev);
        kfree(ir);
        return err;
 }
 
-static int ir_detach(struct i2c_client *client)
+static int ir_remove(struct i2c_client *client)
 {
        struct IR_i2c *ir = i2c_get_clientdata(client);
 
        /* kill outstanding polls */
        cancel_delayed_work_sync(&ir->work);
 
-       /* unregister devices */
+       /* unregister device */
        input_unregister_device(ir->input);
-       i2c_detach_client(&ir->c);
 
        /* free memory */
        kfree(ir);
        return 0;
 }
 
-static int ir_probe(struct i2c_adapter *adap)
-{
-
-       /* The external IR receiver is at i2c address 0x34 (0x35 for
-          reads).  Future Hauppauge cards will have an internal
-          receiver at 0x30 (0x31 for reads).  In theory, both can be
-          fitted, and Hauppauge suggest an external overrides an
-          internal.
-
-          That's why we probe 0x1a (~0x34) first. CB
-       */
-
-       static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
-       static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 };
-       static const int probe_em28XX[] = { 0x30, 0x47, -1 };
-       static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
-       static const int probe_cx23885[] = { 0x6b, -1 };
-       const int *probe;
-       struct i2c_msg msg = {
-               .flags = I2C_M_RD,
-               .len = 0,
-               .buf = NULL,
-       };
-       int i, rc;
-
-       switch (adap->id) {
-       case I2C_HW_B_BT848:
-               probe = probe_bttv;
-               break;
-       case I2C_HW_B_CX2341X:
-               probe = probe_bttv;
-               break;
-       case I2C_HW_SAA7134:
-               probe = probe_saa7134;
-               break;
-       case I2C_HW_B_EM28XX:
-               probe = probe_em28XX;
-               break;
-       case I2C_HW_B_CX2388x:
-               probe = probe_cx88;
-               break;
-       case I2C_HW_B_CX23885:
-               probe = probe_cx23885;
-               break;
-       default:
-               return 0;
-       }
-
-       for (i = 0; -1 != probe[i]; i++) {
-               msg.addr = probe[i];
-               rc = i2c_transfer(adap, &msg, 1);
-               dprintk(1,"probe 0x%02x @ %s: %s\n",
-                       probe[i], adap->name,
-                       (1 == rc) ? "yes" : "no");
-               if (1 == rc) {
-                       ir_attach(adap, probe[i], 0, 0);
-                       return 0;
-               }
-       }
-
-       /* Special case for MSI t...@nywhere Plus remote */
-       if (adap->id == I2C_HW_SAA7134) {
-               u8 temp;
-
-               /* MSI t...@nywhere Plus controller doesn't seem to
-                  respond to probes unless we read something from
-                  an existing device. Weird... */
-
-               msg.addr = 0x50;
-               rc = i2c_transfer(adap, &msg, 1);
-                       dprintk(1, "probe 0x%02x @ %s: %s\n",
-                       msg.addr, adap->name,
-                       (1 == rc) ? "yes" : "no");
-
-               /* Now do the probe. The controller does not respond
-                  to 0-byte reads, so we use a 1-byte read instead. */
-               msg.addr = 0x30;
-               msg.len = 1;
-               msg.buf = &temp;
-               rc = i2c_transfer(adap, &msg, 1);
-               dprintk(1, "probe 0x%02x @ %s: %s\n",
-                       msg.addr, adap->name,
-                       (1 == rc) ? "yes" : "no");
-               if (1 == rc)
-                       ir_attach(adap, msg.addr, 0, 0);
-       }
-
-       /* Special case for AVerMedia Cardbus remote */
-       if (adap->id == I2C_HW_SAA7134) {
-               unsigned char subaddr, data;
-               struct i2c_msg msg[] = { { .addr = 0x40, .flags = 0,
-                                          .buf = &subaddr, .len = 1},
-                                        { .addr = 0x40, .flags = I2C_M_RD,
-                                          .buf = &data, .len = 1} };
-               subaddr = 0x0d;
-               rc = i2c_transfer(adap, msg, 2);
-               dprintk(1, "probe 0x%02x/0x%02x @ %s: %s\n",
-                       msg[0].addr, subaddr, adap->name,
-                       (2 == rc) ? "yes" : "no");
-               if (2 == rc)
-                       ir_attach(adap, msg[0].addr, 0, 0);
-       }
+static const struct i2c_device_id ir_kbd_id[] = {
+       /* Generic entry for any IR receiver */
+       { "ir_video", 0 },
+       /* IR device specific entries could be added here */
+       { }
+};
 
-       return 0;
-}
+static struct i2c_driver driver = {
+       .driver = {
+               .name   = "ir-kbd-i2c",
+       },
+       .probe          = ir_probe,
+       .remove         = ir_remove,
+       .id_table       = ir_kbd_id,
+};
 
 /* ----------------------------------------------------------------------- */
 
--- v4l-dvb.orig/linux/drivers/media/video/ivtv/ivtv-i2c.c      2009-05-12 
10:19:13.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/ivtv/ivtv-i2c.c   2009-05-12 
11:24:19.000000000 +0200
@@ -592,9 +592,11 @@ static struct i2c_client ivtv_i2c_client
        .name = "ivtv internal",
 };
 
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter + instantiate IR receiver */
 int init_ivtv_i2c(struct ivtv *itv)
 {
+       int retval;
+
        IVTV_DEBUG_I2C("i2c init\n");
 
        /* Sanity checks for the I2C hardware arrays. They must be the
@@ -634,9 +636,32 @@ int init_ivtv_i2c(struct ivtv *itv)
        ivtv_setsda(itv, 1);
 
        if (itv->options.newi2c > 0)
-               return i2c_add_adapter(&itv->i2c_adap);
+               retval = i2c_add_adapter(&itv->i2c_adap);
        else
-               return i2c_bit_add_bus(&itv->i2c_adap);
+               retval = i2c_bit_add_bus(&itv->i2c_adap);
+
+       /* Instantiate the IR receiver device, if present */
+       if (retval == 0) {
+               struct i2c_board_info info;
+               /* The external IR receiver is at i2c address 0x34 (0x35 for
+                  reads).  Future Hauppauge cards will have an internal
+                  receiver at 0x30 (0x31 for reads).  In theory, both can be
+                  fitted, and Hauppauge suggest an external overrides an
+                  internal.
+
+                  That's why we probe 0x1a (~0x34) first. CB
+               */
+               const unsigned short addr_list[] = {
+                       0x1a, 0x18, 0x64, 0x30,
+                       I2C_CLIENT_END
+               };
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               i2c_new_probed_device(&itv->i2c_adap, &info, addr_list);
+       }
+
+       return retval;
 }
 
 void exit_ivtv_i2c(struct ivtv *itv)
--- v4l-dvb.orig/linux/drivers/media/video/saa7134/saa7134-i2c.c        
2009-05-12 10:19:13.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/saa7134/saa7134-i2c.c     2009-05-12 
11:24:19.000000000 +0200
@@ -444,6 +444,9 @@ int saa7134_i2c_register(struct saa7134_
        saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata));
        if (i2c_scan)
                do_i2c_scan(dev->name,&dev->i2c_client);
+
+       /* Instantiate the IR receiver device, if present */
+       saa7134_probe_i2c_ir(dev);
        return 0;
 }
 
--- v4l-dvb.orig/linux/drivers/media/video/saa7134/saa7134-input.c      
2009-05-12 11:14:20.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/saa7134/saa7134-input.c   2009-05-12 
11:24:19.000000000 +0200
@@ -134,10 +134,10 @@ static int get_key_msi_tvanywhere_plus(s
        int gpio;
 
        /* <dev> is needed to access GPIO. Used by the saa_readl macro. */
-       struct saa7134_dev *dev = ir->c.adapter->algo_data;
+       struct saa7134_dev *dev = ir->c->adapter->algo_data;
        if (dev == NULL) {
                dprintk("get_key_msi_tvanywhere_plus: "
-                       "gir->c.adapter->algo_data is NULL!\n");
+                       "gir->c->adapter->algo_data is NULL!\n");
                return -EIO;
        }
 
@@ -156,7 +156,7 @@ static int get_key_msi_tvanywhere_plus(s
 
        /* GPIO says there is a button press. Get it. */
 
-       if (1 != i2c_master_recv(&ir->c, &b, 1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -179,7 +179,7 @@ static int get_key_purpletv(struct IR_i2
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -202,7 +202,7 @@ static int get_key_hvr1110(struct IR_i2c
        unsigned char buf[5], cod4, code3, code4;
 
        /* poll IR chip */
-       if (5 != i2c_master_recv(&ir->c,buf,5))
+       if (5 != i2c_master_recv(ir->c, buf, 5))
                return -EIO;
 
        cod4    = buf[4];
@@ -224,7 +224,7 @@ static int get_key_beholdm6xx(struct IR_
        unsigned char data[12];
        u32 gpio;
 
-       struct saa7134_dev *dev = ir->c.adapter->algo_data;
+       struct saa7134_dev *dev = ir->c->adapter->algo_data;
 
        /* rising SAA7134_GPIO_GPRESCAN reads the status */
        saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
@@ -235,9 +235,9 @@ static int get_key_beholdm6xx(struct IR_
        if (0x400000 & ~gpio)
                return 0; /* No button press */
 
-       ir->c.addr = 0x5a >> 1;
+       ir->c->addr = 0x5a >> 1;
 
-       if (12 != i2c_master_recv(&ir->c, data, 12)) {
+       if (12 != i2c_master_recv(ir->c, data, 12)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -267,7 +267,7 @@ static int get_key_pinnacle(struct IR_i2
        unsigned int start = 0,parity = 0,code = 0;
 
        /* poll IR chip */
-       if (4 != i2c_master_recv(&ir->c, b, 4)) {
+       if (4 != i2c_master_recv(ir->c, b, 4)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -686,14 +686,76 @@ void saa7134_input_fini(struct saa7134_d
        dev->remote = NULL;
 }
 
-void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
 {
+       struct i2c_board_info info;
+       const unsigned short addr_list[] = {
+               0x7a, 0x47, 0x71, 0x2d,
+               I2C_CLIENT_END
+       };
+
+       const unsigned short addr_list_msi[] = {
+               0x30, I2C_CLIENT_END
+       };
+       struct i2c_msg msg_msi = {
+               .addr = 0x50,
+               .flags = I2C_M_RD,
+               .len = 0,
+               .buf = NULL,
+       };
+
+       unsigned char subaddr, data;
+       struct i2c_msg msg_avermedia[] = { {
+               .addr = 0x40,
+               .flags = 0,
+               .len = 1,
+               .buf = &subaddr,
+       }, {
+               .addr = 0x40,
+               .flags = I2C_M_RD,
+               .len = 1,
+               .buf = &data,
+       } };
+
+       struct i2c_client *client;
+       int rc;
+
        if (disable_ir) {
-               dprintk("Found supported i2c remote, but IR has been 
disabled\n");
-               ir->get_key=NULL;
+               dprintk("IR has been disabled, not probing for i2c remote\n");
+               return;
+       }
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+       client = i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
+       if (client)
                return;
+
+       /* MSI t...@nywhere Plus controller doesn't seem to
+          respond to probes unless we read something from
+          an existing device. Weird... */
+       rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+       dprintk(KERN_DEBUG "probe 0x%02x @ %s: %s\n",
+               msg_msi.addr, dev->i2c_adap.name,
+               (1 == rc) ? "yes" : "no");
+       client = i2c_new_probed_device(&dev->i2c_adap, &info, addr_list_msi);
+       if (client)
+               return;
+
+       /* Special case for AVerMedia Cardbus remote */
+       subaddr = 0x0d;
+       rc = i2c_transfer(&dev->i2c_adap, msg_avermedia, 2);
+       dprintk(KERN_DEBUG "probe 0x%02x/0x%02x @ %s: %s\n",
+               msg_avermedia[0].addr, subaddr, dev->i2c_adap.name,
+               (2 == rc) ? "yes" : "no");
+       if (2 == rc) {
+               info.addr = msg_avermedia[0].addr;
+               i2c_new_device(&dev->i2c_adap, &info);
        }
+}
 
+void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
+{
        switch (dev->board) {
        case SAA7134_BOARD_PINNACLE_PCTV_110i:
        case SAA7134_BOARD_PINNACLE_PCTV_310i:
--- v4l-dvb.orig/linux/drivers/media/video/saa7134/saa7134.h    2009-05-12 
10:19:32.000000000 +0200
+++ v4l-dvb/linux/drivers/media/video/saa7134/saa7134.h 2009-05-12 
11:24:19.000000000 +0200
@@ -804,6 +804,7 @@ void saa7134_irq_oss_done(struct saa7134
 int  saa7134_input_init1(struct saa7134_dev *dev);
 void saa7134_input_fini(struct saa7134_dev *dev);
 void saa7134_input_irq(struct saa7134_dev *dev);
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
 void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir);
 void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir);
 void saa7134_ir_stop(struct saa7134_dev *dev);
--- v4l-dvb.orig/linux/include/media/ir-kbd-i2c.h       2009-05-12 
11:14:20.000000000 +0200
+++ v4l-dvb/linux/include/media/ir-kbd-i2c.h    2009-05-12 11:24:19.000000000 
+0200
@@ -7,7 +7,7 @@ struct IR_i2c;
 
 struct IR_i2c {
        IR_KEYTAB_TYPE         *ir_codes;
-       struct i2c_client      c;
+       struct i2c_client      *c;
        struct input_dev       *input;
        struct ir_input_state  ir;
 

-- 
Jean Delvare
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to