From patchwork Thu Dec 27 23:02:45 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Frank_Sch=C3=A4fer?= X-Patchwork-Id: 1913821 Return-Path: X-Original-To: patchwork-linux-media@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 93F3A3FF0F for ; Thu, 27 Dec 2012 23:02:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752191Ab2L0XCn (ORCPT ); Thu, 27 Dec 2012 18:02:43 -0500 Received: from mail-ea0-f173.google.com ([209.85.215.173]:46828 "EHLO mail-ea0-f173.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751593Ab2L0XCl (ORCPT ); Thu, 27 Dec 2012 18:02:41 -0500 Received: by mail-ea0-f173.google.com with SMTP id i13so3993564eaa.4 for ; Thu, 27 Dec 2012 15:02:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:mime-version:content-type:content-transfer-encoding; bh=SxoYmUyWBEr7Nb1ITepRgqn1FDak7aHOD8tTFazttOM=; b=Mo6n11bAYsc/w6hVr/Y20d5kVskH3U6ugwdMWmPquYqvxhx9ffYdd802yb4TqOdZa2 MhUHeRfN/J0MheftiGyFSL7uvVMhvFrX/Yrz3+7jrjitQd8rnHnQ42HcT/8CLZfoCsgx 4DGJq1S29N9RCH3rJyZ0XVZU5JGuiCFlc+haxWf7f51EV3krbWhpWKOAQ07MhXY68jIx wy+F6mkCLa9Sxa1HSEbMA7bE5zsjj9VsnOC/IZ4XbFKOGsX82lytQWBabR+vMaDFGjU9 x+l1Vdp6fFvZnFHErZr2JSlP+PVVxcqgJFeS9IYhIbs6SPjvWJghxMLHY93S5Q9H+PfI 12eA== X-Received: by 10.14.207.6 with SMTP id m6mr80779450eeo.10.1356649359428; Thu, 27 Dec 2012 15:02:39 -0800 (PST) Received: from Athlon64X2-5000.site (ip-37-24-90-62.unitymediagroup.de. [37.24.90.62]) by mx.google.com with ESMTPS id q44sm62258729eep.5.2012.12.27.15.02.37 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 27 Dec 2012 15:02:38 -0800 (PST) From: =?UTF-8?q?Frank=20Sch=C3=A4fer?= To: mchehab@redhat.com Cc: linux-media@vger.kernel.org, =?UTF-8?q?Frank=20Sch=C3=A4fer?= Subject: [PATCH 3/6] em28xx: make remote controls of devices with external IR IC working again Date: Fri, 28 Dec 2012 00:02:45 +0100 Message-Id: <1356649368-5426-4-git-send-email-fschaefer.oss@googlemail.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1356649368-5426-1-git-send-email-fschaefer.oss@googlemail.com> References: <1356649368-5426-1-git-send-email-fschaefer.oss@googlemail.com> MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Tested with device "Terratec Cinergy 200 USB". Signed-off-by: Frank Schäfer --- 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 Mauro Carvalho Chehab Sascha Sommer + Copyright (C) 2012 Frank Schäfer 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 \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 */