Tested with device "Terratec Cinergy 200 USB". Signed-off-by: Frank Schäfer <fschaefer.oss@xxxxxxxxxxxxxx> --- drivers/media/usb/em28xx/em28xx-cards.c | 9 +- drivers/media/usb/em28xx/em28xx-i2c.c | 1 + drivers/media/usb/em28xx/em28xx-input.c | 142 +++++++++++++++++-------------- 3 Dateien geändert, 83 Zeilen hinzugefügt(+), 69 Zeilen entfernt(-) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 40c3e45..3b226b1 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -488,6 +488,7 @@ struct em28xx_board em28xx_boards[] = { .name = "Terratec Cinergy 250 USB", .tuner_type = TUNER_LG_PAL_NEW_TAPC, .has_ir_i2c = 1, + .ir_codes = RC_MAP_EM_TERRATEC, .tda9887_conf = TDA9887_PRESENT, .decoder = EM28XX_SAA711X, .input = { { @@ -508,6 +509,7 @@ struct em28xx_board em28xx_boards[] = { .name = "Pinnacle PCTV USB 2", .tuner_type = TUNER_LG_PAL_NEW_TAPC, .has_ir_i2c = 1, + .ir_codes = RC_MAP_PINNACLE_GREY, .tda9887_conf = TDA9887_PRESENT, .decoder = EM28XX_SAA711X, .input = { { @@ -533,6 +535,7 @@ struct em28xx_board em28xx_boards[] = { .decoder = EM28XX_TVP5150, .has_msp34xx = 1, .has_ir_i2c = 1, + .ir_codes = RC_MAP_HAUPPAUGE, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, @@ -629,6 +632,7 @@ struct em28xx_board em28xx_boards[] = { .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .has_ir_i2c = 1, + .ir_codes = RC_MAP_WINFAST_USBII_DELUXE, .tvaudio_addr = 0x58, .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT2_ACTIVE | @@ -1222,6 +1226,7 @@ struct em28xx_board em28xx_boards[] = { .name = "Terratec Cinergy 200 USB", .is_em2800 = 1, .has_ir_i2c = 1, + .ir_codes = RC_MAP_EM_TERRATEC, .tuner_type = TUNER_LG_TALN, .tda9887_conf = TDA9887_PRESENT, .decoder = EM28XX_SAA711X, @@ -2912,7 +2917,7 @@ static void request_module_async(struct work_struct *work) if (dev->board.has_dvb) request_module("em28xx-dvb"); - if (dev->board.ir_codes && !disable_ir) + if ((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir) request_module("em28xx-rc"); #endif /* CONFIG_MODULES */ } @@ -2935,8 +2940,6 @@ static void flush_request_modules(struct em28xx *dev) */ void em28xx_release_resources(struct em28xx *dev) { - /*FIXME: I2C IR should be disconnected */ - em28xx_release_analog_resources(dev); em28xx_i2c_unregister(dev); diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 44533e4..39c5a3e 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -470,6 +470,7 @@ static struct i2c_client em28xx_client_template = { static char *i2c_devs[128] = { [0x4a >> 1] = "saa7113h", [0x52 >> 1] = "drxk", + [0x3e >> 1] = "remote IR sensor", [0x60 >> 1] = "remote IR sensor", [0x8e >> 1] = "remote IR sensor", [0x86 >> 1] = "tda9887", diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 3598221..631e252 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -5,6 +5,7 @@ Markus Rechberger <mrechberger@xxxxxxxxx> Mauro Carvalho Chehab <mchehab@xxxxxxxxxxxxx> Sascha Sommer <saschasommer@xxxxxxxxxx> + Copyright (C) 2012 Frank Schäfer <fschaefer.oss@xxxxxxxxxxxxxx> 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 @@ -34,6 +35,8 @@ #define EM28XX_SBUTTON_QUERY_INTERVAL 500 #define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20 +#define EM28XX_RC_QUERY_INTERVAL 100 + static unsigned int ir_debug; module_param(ir_debug, int, 0644); MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); @@ -67,13 +70,14 @@ struct em28xx_IR { char name[32]; char phys[32]; - /* poll external decoder */ int polling; struct delayed_work work; unsigned int full_code:1; unsigned int last_readcount; u64 rc_type; + struct i2c_client *i2c_dev; /* external i2c IR receiver/decoder */ + int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); }; @@ -452,7 +456,7 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type) } } -static void em28xx_register_i2c_ir(struct em28xx *dev) +static int em28xx_register_i2c_ir(struct em28xx *dev, struct rc_dev *rc_dev) { /* Leadtek winfast tv USBII deluxe can find a non working IR-device */ /* at address 0x18, so if that address is needed for another board in */ @@ -470,30 +474,46 @@ static void em28xx_register_i2c_ir(struct em28xx *dev) switch (dev->model) { case EM2800_BOARD_TERRATEC_CINERGY_200: case EM2820_BOARD_TERRATEC_CINERGY_250: - dev->init_data.ir_codes = RC_MAP_EM_TERRATEC; - dev->init_data.get_key = em28xx_get_key_terratec; dev->init_data.name = "i2c IR (EM28XX Terratec)"; + dev->init_data.type = RC_BIT_OTHER; + dev->init_data.get_key = em28xx_get_key_terratec; break; case EM2820_BOARD_PINNACLE_USB_2: - dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY; - dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey; dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; + dev->init_data.type = RC_BIT_OTHER; + dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey; break; case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: - dev->init_data.ir_codes = RC_MAP_HAUPPAUGE; - dev->init_data.get_key = em28xx_get_key_em_haup; dev->init_data.name = "i2c IR (EM2840 Hauppauge)"; + dev->init_data.type = RC_BIT_RC5; + dev->init_data.get_key = em28xx_get_key_em_haup; break; case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE: - dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE; - dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe; dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)"; + dev->init_data.type = RC_BIT_OTHER; + dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe; break; } - if (dev->init_data.name) + if (dev->init_data.name && dev->board.ir_codes) { + dev->init_data.ir_codes = dev->board.ir_codes; + dev->init_data.polling_interval = EM28XX_RC_QUERY_INTERVAL; + dev->init_data.rc_dev = rc_dev; info.platform_data = &dev->init_data; - i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL); + } else { + em28xx_warn("Unknown i2c remote control device.\n"); + em28xx_warn("If the remote control doesn't work properly, please contact <linux-media@xxxxxxxxxxxxxxx>\n"); + } + + dev->ir->i2c_dev = i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL); + if (NULL == dev->ir->i2c_dev) + return -ENODEV; + +#if defined(CONFIG_MODULES) && defined(MODULE) + request_module("ir-kbd-i2c"); +#endif + + return 0; } /********************************************************** @@ -590,7 +610,7 @@ static int em28xx_ir_init(struct em28xx *dev) int err = -ENOMEM; u64 rc_type; - if (dev->board.ir_codes == NULL) { + if (dev->board.ir_codes == NULL && !dev->board.has_ir_i2c) { /* No remote control support */ em28xx_warn("Remote control support is not available for " "this card.\n"); @@ -607,68 +627,56 @@ static int em28xx_ir_init(struct em28xx *dev) dev->ir = ir; ir->rc = rc; - /* - * em2874 supports more protocols. For now, let's just announce - * the two protocols that were already tested - */ - rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC; - rc->priv = ir; - rc->change_protocol = em28xx_ir_change_protocol; - rc->open = em28xx_ir_start; - rc->close = em28xx_ir_stop; - - switch (dev->chip_id) { - case CHIP_ID_EM2860: - case CHIP_ID_EM2883: - rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC; - break; - case CHIP_ID_EM2884: - case CHIP_ID_EM2874: - case CHIP_ID_EM28174: - rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC | RC_BIT_RC6_0; - break; - default: - err = -ENODEV; - goto error; - } - - /* By default, keep protocol field untouched */ - rc_type = RC_BIT_UNKNOWN; - err = em28xx_ir_change_protocol(rc, &rc_type); - if (err) - goto error; - - /* This is how often we ask the chip for IR information */ - ir->polling = 100; /* ms */ - - /* init input device */ - snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", - dev->name); - + snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", dev->name); usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); + ir->polling = EM28XX_RC_QUERY_INTERVAL; - rc->input_name = ir->name; - rc->input_phys = ir->phys; - rc->input_id.bustype = BUS_USB; rc->input_id.version = 1; rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); rc->dev.parent = &dev->udev->dev; - rc->map_name = dev->board.ir_codes; rc->driver_name = MODULE_NAME; - /* all done */ - err = rc_register_device(rc); - if (err) - goto error; - - em28xx_register_i2c_ir(dev); + if (dev->board.has_ir_i2c) { + err = em28xx_register_i2c_ir(dev, rc); + if (err < 0) + goto error; + } else { + switch (dev->chip_id) { + case CHIP_ID_EM2860: + case CHIP_ID_EM2883: + rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC; + break; + case CHIP_ID_EM2884: + case CHIP_ID_EM2874: + case CHIP_ID_EM28174: + rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC | RC_BIT_RC6_0; + break; + default: + err = -ENODEV; + goto error; + } + rc->priv = ir; + rc->change_protocol = em28xx_ir_change_protocol; + rc->open = em28xx_ir_start; + rc->close = em28xx_ir_stop; + rc->input_name = ir->name; + rc->input_phys = ir->phys; + rc->input_id.bustype = BUS_USB; + rc->map_name = dev->board.ir_codes; + + /* By default, keep protocol field untouched */ + rc_type = RC_BIT_UNKNOWN; + err = em28xx_ir_change_protocol(rc, &rc_type); + if (err) + goto error; + + err = rc_register_device(rc); + if (err < 0) + goto error; + } -#if defined(CONFIG_MODULES) && defined(MODULE) - if (dev->board.has_ir_i2c) - request_module("ir-kbd-i2c"); -#endif if (dev->board.has_snapshot_button) em28xx_register_snapshot_button(dev); @@ -691,7 +699,9 @@ static int em28xx_ir_fini(struct em28xx *dev) if (!ir) return 0; - if (ir->rc) + if (ir->i2c_dev) + i2c_unregister_device(ir->i2c_dev); + else if (ir->rc) rc_unregister_device(ir->rc); /* done */ -- 1.7.10.4 -- 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