Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=ee820a648fb333034aa455e8e1479b89798a1281
Commit:     ee820a648fb333034aa455e8e1479b89798a1281
Parent:     db4836791dc578f0f6e9573468cffeee00fa7ebc
Author:     Oliver Endriss <[EMAIL PROTECTED]>
AuthorDate: Fri Apr 27 12:31:21 2007 -0300
Committer:  Mauro Carvalho Chehab <[EMAIL PROTECTED]>
CommitDate: Fri Apr 27 15:43:45 2007 -0300

    V4L/DVB (5334): Dvb-ttpci: Infrared remote control refactoring
    
    Infrared remote control support rewritten.
    Now each device provides its own event device, keymap, protocol,
    inversion and address setting.
    EVIOCGKEYCODE and EVIOCSKEYCODE ioctls are supported to read/modify
    a keymap. Keymaps may be loaded using
    - input tools (keyb etc.)
    - av7110_loadkeys (obsolete, for backward compatibility)
    New command line parameters:
    - ir_protocol:    select infrared protocol: 0 RC5, 1 RCMM (default)
    - ir_inversion:   signal inversion: 0 not inverted (default), 1 inverted
    - ir_device_mask: bitmask of infrared devices (default: accept all)
    Those parameters may be set anytime.
    
    Signed-off-by: Oliver Endriss <[EMAIL PROTECTED]>
    Signed-off-by: Mauro Carvalho Chehab <[EMAIL PROTECTED]>
---
 drivers/media/dvb/ttpci/av7110.c    |   13 +-
 drivers/media/dvb/ttpci/av7110.h    |   28 +++-
 drivers/media/dvb/ttpci/av7110_ir.c |  358 ++++++++++++++++++++++-------------
 3 files changed, 265 insertions(+), 134 deletions(-)

diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 29ed532..3cd8523 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -219,7 +219,10 @@ static void recover_arm(struct av7110 *av7110)
                av7110->recover(av7110);
 
        restart_feeds(av7110);
-       av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, av7110->ir_config);
+
+#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+       av7110_check_ir_config(av7110, true);
+#endif
 }
 
 static void av7110_arm_sync(struct av7110 *av7110)
@@ -250,6 +253,10 @@ static int arm_thread(void *data)
                if (!av7110->arm_ready)
                        continue;
 
+#if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
+               av7110_check_ir_config(av7110, false);
+#endif
+
                if (mutex_lock_interruptible(&av7110->dcomlock))
                        break;
                newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2);
@@ -667,8 +674,8 @@ static void gpioirq(unsigned long data)
                return;
 
        case DATA_IRCOMMAND:
-               if (av7110->ir_handler)
-                       av7110->ir_handler(av7110,
+               if (av7110->ir.ir_handler)
+                       av7110->ir.ir_handler(av7110,
                                swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 
4)));
                iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2);
                break;
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index b98bd45..115002b 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -5,6 +5,7 @@
 #include <linux/socket.h>
 #include <linux/netdevice.h>
 #include <linux/i2c.h>
+#include <linux/input.h>
 
 #include <linux/dvb/video.h>
 #include <linux/dvb/audio.h>
@@ -66,6 +67,27 @@ struct dvb_video_events {
 };
 
 
+struct av7110;
+
+/* infrared remote control */
+struct infrared {
+       u16     key_map[256];
+       struct input_dev        *input_dev;
+       char                    input_phys[32];
+       struct timer_list       keyup_timer;
+       struct tasklet_struct   ir_tasklet;
+       void                    (*ir_handler)(struct av7110 *av7110, u32 ircom);
+       u32                     ir_command;
+       u32                     ir_config;
+       u32                     device_mask;
+       u8                      protocol;
+       u8                      inversion;
+       u16                     last_key;
+       u16                     last_toggle;
+       u8                      delay_timer_finished;
+};
+
+
 /* place to store all the necessary device information */
 struct av7110 {
 
@@ -227,10 +249,7 @@ struct av7110 {
        u16                     wssMode;
        u16                     wssData;
 
-       u32                     ir_config;
-       u32                     ir_command;
-       void                    (*ir_handler)(struct av7110 *av7110, u32 ircom);
-       struct tasklet_struct   ir_tasklet;
+       struct infrared         ir;
 
        /* firmware stuff */
        unsigned char *bin_fw;
@@ -268,6 +287,7 @@ struct av7110 {
 extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
                       u16 subpid, u16 pcrpid);
 
+extern int av7110_check_ir_config(struct av7110 *av7110, int force);
 extern int av7110_ir_init(struct av7110 *av7110);
 extern void av7110_ir_exit(struct av7110 *av7110);
 
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c 
b/drivers/media/dvb/ttpci/av7110_ir.c
index f59465b..921ff19 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -1,8 +1,31 @@
+/*
+ * Driver for the remote control of SAA7146 based AV7110 cards
+ *
+ * Copyright (C) 1999-2003 Holger Waechtler <[EMAIL PROTECTED]>
+ * Copyright (C) 2003-2007 Oliver Endriss <[EMAIL PROTECTED]>
+ *
+ * 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 the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/input.h>
 #include <linux/proc_fs.h>
 #include <linux/kernel.h>
 #include <asm/bitops.h>
@@ -10,18 +33,37 @@
 #include "av7110.h"
 #include "av7110_hw.h"
 
-#define UP_TIMEOUT (HZ*7/25)
 
-/* enable ir debugging by or'ing debug with 16 */
+#define AV_CNT         4
+
+#define IR_RC5         0
+#define IR_RCMM                1
+#define IR_RC5_EXT     2 /* internal only */
+
+#define IR_ALL         0xffffffff
+
+#define UP_TIMEOUT     (HZ*7/25)
+
+
+/* Note: enable ir debugging by or'ing debug with 16 */
+
+static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM};
+module_param_array(ir_protocol, int, NULL, 0644);
+MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)");
+
+static int ir_inversion[AV_CNT];
+module_param_array(ir_inversion, int, NULL, 0644);
+MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted 
(default), 1 inverted");
+
+static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL };
+module_param_array(ir_device_mask, uint, NULL, 0644);
+MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = 
device 0..31 (default: all)");
 
-static int av_cnt;
-static struct av7110 *av_list[4];
-static struct input_dev *input_dev;
-static char input_phys[32];
 
-static u8 delay_timer_finished;
+static int av_cnt;
+static struct av7110 *av_list[AV_CNT];
 
-static u16 key_map [256] = {
+static u16 default_key_map [256] = {
        KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7,
        KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO,
        KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -45,141 +87,187 @@ static u16 key_map [256] = {
 };
 
 
-static void av7110_emit_keyup(unsigned long data)
+/* key-up timer */
+static void av7110_emit_keyup(unsigned long parm)
 {
-       if (!data || !test_bit(data, input_dev->key))
+       struct infrared *ir = (struct infrared *) parm;
+
+       if (!ir || !test_bit(ir->last_key, ir->input_dev->key))
                return;
 
-       input_report_key(input_dev, data, 0);
-       input_sync(input_dev);
+       input_report_key(ir->input_dev, ir->last_key, 0);
+       input_sync(ir->input_dev);
 }
 
 
-static struct timer_list keyup_timer = { .function = av7110_emit_keyup };
-
-
+/* tasklet */
 static void av7110_emit_key(unsigned long parm)
 {
-       struct av7110 *av7110 = (struct av7110 *) parm;
-       u32 ir_config = av7110->ir_config;
-       u32 ircom = av7110->ir_command;
+       struct infrared *ir = (struct infrared *) parm;
+       u32 ircom = ir->ir_command;
        u8 data;
        u8 addr;
-       static u16 old_toggle = 0;
-       u16 new_toggle;
+       u16 toggle;
        u16 keycode;
 
        /* extract device address and data */
-       switch (ir_config & 0x0003) {
-       case 0: /* RC5: 5 bits device address, 6 bits data */
+       switch (ir->protocol) {
+       case IR_RC5: /* RC5: 5 bits device address, 6 bits data */
                data = ircom & 0x3f;
                addr = (ircom >> 6) & 0x1f;
+               toggle = ircom & 0x0800;
                break;
 
-       case 1: /* RCMM: 8(?) bits device address, 8(?) bits data */
+       case IR_RCMM: /* RCMM: ? bits device address, ? bits data */
                data = ircom & 0xff;
-               addr = (ircom >> 8) & 0xff;
+               addr = (ircom >> 8) & 0x1f;
+               toggle = ircom & 0x8000;
                break;
 
-       case 2: /* extended RC5: 5 bits device address, 7 bits data */
+       case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */
                data = ircom & 0x3f;
                addr = (ircom >> 6) & 0x1f;
                /* invert 7th data bit for backward compatibility with RC5 
keymaps */
                if (!(ircom & 0x1000))
                        data |= 0x40;
+               toggle = ircom & 0x0800;
                break;
 
        default:
-               printk("invalid ir_config %x\n", ir_config);
+               printk("%s invalid protocol %x\n", __FUNCTION__, ir->protocol);
                return;
        }
 
-       keycode = key_map[data];
+       keycode = ir->key_map[data];
 
-       dprintk(16, "code %08x -> addr %i data 0x%02x -> keycode %i\n",
-               ircom, addr, data, keycode);
+       dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n",
+               __FUNCTION__, ircom, addr, data, keycode);
 
-       /* check device address (if selected) */
-       if (ir_config & 0x4000)
-               if (addr != ((ir_config >> 16) & 0xff))
-                       return;
+       /* check device address */
+       if (!(ir->device_mask & (1 << addr)))
+               return;
 
        if (!keycode) {
-               printk ("%s: unknown key 0x%02x!!\n", __FUNCTION__, data);
+               printk ("%s: code %08x -> addr %i data 0x%02x -> unknown 
key!\n",
+                       __FUNCTION__, ircom, addr, data);
                return;
        }
 
-       if ((ir_config & 0x0003) == 1)
-               new_toggle = 0; /* RCMM */
-       else
-               new_toggle = (ircom & 0x800); /* RC5, extended RC5 */
-
-       if (timer_pending(&keyup_timer)) {
-               del_timer(&keyup_timer);
-               if (keyup_timer.data != keycode || new_toggle != old_toggle) {
-                       delay_timer_finished = 0;
-                       input_event(input_dev, EV_KEY, keyup_timer.data, 0);
-                       input_event(input_dev, EV_KEY, keycode, 1);
-                       input_sync(input_dev);
-               } else if (delay_timer_finished) {
-                       input_event(input_dev, EV_KEY, keycode, 2);
-                       input_sync(input_dev);
+       if (timer_pending(&ir->keyup_timer)) {
+               del_timer(&ir->keyup_timer);
+               if (ir->last_key != keycode || toggle != ir->last_toggle) {
+                       ir->delay_timer_finished = 0;
+                       input_event(ir->input_dev, EV_KEY, ir->last_key, 0);
+                       input_event(ir->input_dev, EV_KEY, keycode, 1);
+                       input_sync(ir->input_dev);
+               } else if (ir->delay_timer_finished) {
+                       input_event(ir->input_dev, EV_KEY, keycode, 2);
+                       input_sync(ir->input_dev);
                }
        } else {
-               delay_timer_finished = 0;
-               input_event(input_dev, EV_KEY, keycode, 1);
-               input_sync(input_dev);
+               ir->delay_timer_finished = 0;
+               input_event(ir->input_dev, EV_KEY, keycode, 1);
+               input_sync(ir->input_dev);
        }
 
-       keyup_timer.expires = jiffies + UP_TIMEOUT;
-       keyup_timer.data = keycode;
+       ir->last_key = keycode;
+       ir->last_toggle = toggle;
 
-       add_timer(&keyup_timer);
+       ir->keyup_timer.expires = jiffies + UP_TIMEOUT;
+       add_timer(&ir->keyup_timer);
 
-       old_toggle = new_toggle;
 }
 
-static void input_register_keys(void)
+
+/* register with input layer */
+static void input_register_keys(struct infrared *ir)
 {
        int i;
 
-       memset(input_dev->keybit, 0, sizeof(input_dev->keybit));
+       set_bit(EV_KEY, ir->input_dev->evbit);
+       set_bit(EV_REP, ir->input_dev->evbit);
 
-       for (i = 0; i < ARRAY_SIZE(key_map); i++) {
-               if (key_map[i] > KEY_MAX)
-                       key_map[i] = 0;
-               else if (key_map[i] > KEY_RESERVED)
-                       set_bit(key_map[i], input_dev->keybit);
+       memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit));
+
+       for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) {
+               if (ir->key_map[i] > KEY_MAX)
+                       ir->key_map[i] = 0;
+               else if (ir->key_map[i] > KEY_RESERVED)
+                       set_bit(ir->key_map[i], ir->input_dev->keybit);
        }
+
+       ir->input_dev->keycode = ir->key_map;
+       ir->input_dev->keycodesize = sizeof(ir->key_map[0]);
+       ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
 }
 
 
-static void input_repeat_key(unsigned long data)
+/* called by the input driver after rep[REP_DELAY] ms */
+static void input_repeat_key(unsigned long parm)
 {
-       /* called by the input driver after rep[REP_DELAY] ms */
-       delay_timer_finished = 1;
+       struct infrared *ir = (struct infrared *) parm;
+
+       ir->delay_timer_finished = 1;
 }
 
 
-static int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config)
+/* check for configuration changes */
+int av7110_check_ir_config(struct av7110 *av7110, int force)
 {
-       int ret = 0;
+       int i;
+       int modified = force;
+       int ret = -ENODEV;
 
-       dprintk(4, "%p\n", av7110);
-       if (av7110) {
-               ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, 
ir_config);
-               av7110->ir_config = ir_config;
+       for (i = 0; i < av_cnt; i++)
+               if (av7110 == av_list[i])
+                       break;
+
+       if (i < av_cnt && av7110) {
+               if ((av7110->ir.protocol & 1) != ir_protocol[i] ||
+                   av7110->ir.inversion != ir_inversion[i])
+                       modified = true;
+
+               if (modified) {
+                       /* protocol */
+                       if (ir_protocol[i]) {
+                               ir_protocol[i] = 1;
+                               av7110->ir.protocol = IR_RCMM;
+                               av7110->ir.ir_config = 0x0001;
+                       } else if (FW_VERSION(av7110->arm_app) >= 0x2620) {
+                               av7110->ir.protocol = IR_RC5_EXT;
+                               av7110->ir.ir_config = 0x0002;
+                       } else {
+                               av7110->ir.protocol = IR_RC5;
+                               av7110->ir.ir_config = 0x0000;
+                       }
+                       /* inversion */
+                       if (ir_inversion[i]) {
+                               ir_inversion[i] = 1;
+                               av7110->ir.ir_config |= 0x8000;
+                       }
+                       av7110->ir.inversion = ir_inversion[i];
+                       /* update ARM */
+                       ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1,
+                                               av7110->ir.ir_config);
+               } else
+                       ret = 0;
+
+               /* address */
+               if (av7110->ir.device_mask != ir_device_mask[i])
+                       av7110->ir.device_mask = ir_device_mask[i];
        }
+
        return ret;
 }
 
 
+/* /proc/av7110_ir interface */
 static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
                                unsigned long count, void *data)
 {
        char *page;
-       int size = 4 + 256 * sizeof(u16);
        u32 ir_config;
+       int size = sizeof ir_config + sizeof av_list[0]->ir.key_map;
        int i;
 
        if (count < size)
@@ -194,71 +282,86 @@ static int av7110_ir_write_proc(struct file *file, const 
char __user *buffer,
                return -EFAULT;
        }
 
-       memcpy(&ir_config, page, 4);
-       memcpy(&key_map, page + 4, 256 * sizeof(u16));
+       memcpy(&ir_config, page, sizeof ir_config);
+
+       for (i = 0; i < av_cnt; i++) {
+               /* keymap */
+               memcpy(av_list[i]->ir.key_map, page + sizeof ir_config,
+                       sizeof(av_list[i]->ir.key_map));
+               /* protocol, inversion, address */
+               ir_protocol[i] = ir_config & 0x0001;
+               ir_inversion[i] = ir_config & 0x8000 ? 1 : 0;
+               if (ir_config & 0x4000)
+                       ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f);
+               else
+                       ir_device_mask[i] = IR_ALL;
+               /* update configuration */
+               av7110_check_ir_config(av_list[i], false);
+               input_register_keys(&av_list[i]->ir);
+       }
        vfree(page);
-       if (FW_VERSION(av_list[0]->arm_app) >= 0x2620 && !(ir_config & 0x0001))
-               ir_config |= 0x0002; /* enable extended RC5 */
-       for (i = 0; i < av_cnt; i++)
-               av7110_setup_irc_config(av_list[i], ir_config);
-       input_register_keys();
        return count;
 }
 
 
+/* interrupt handler */
 static void ir_handler(struct av7110 *av7110, u32 ircom)
 {
-       dprintk(4, "ircommand = %08x\n", ircom);
-       av7110->ir_command = ircom;
-       tasklet_schedule(&av7110->ir_tasklet);
+       dprintk(4, "ir command = %08x\n", ircom);
+       av7110->ir.ir_command = ircom;
+       tasklet_schedule(&av7110->ir.ir_tasklet);
 }
 
 
 int __devinit av7110_ir_init(struct av7110 *av7110)
 {
+       struct input_dev *input_dev;
        static struct proc_dir_entry *e;
        int err;
 
        if (av_cnt >= ARRAY_SIZE(av_list))
                return -ENOSPC;
 
-       av7110_setup_irc_config(av7110, 0x0001);
+       av7110_check_ir_config(av7110, true);
        av_list[av_cnt++] = av7110;
 
-       if (av_cnt == 1) {
-               init_timer(&keyup_timer);
-               keyup_timer.data = 0;
-
-               input_dev = input_allocate_device();
-               if (!input_dev)
-                       return -ENOMEM;
-
-               snprintf(input_phys, sizeof(input_phys),
-                       "pci-%s/ir0", pci_name(av7110->dev->pci));
-
-               input_dev->name = "DVB on-card IR receiver";
-
-               input_dev->phys = input_phys;
-               input_dev->id.bustype = BUS_PCI;
-               input_dev->id.version = 1;
-               if (av7110->dev->pci->subsystem_vendor) {
-                       input_dev->id.vendor = 
av7110->dev->pci->subsystem_vendor;
-                       input_dev->id.product = 
av7110->dev->pci->subsystem_device;
-               } else {
-                       input_dev->id.vendor = av7110->dev->pci->vendor;
-                       input_dev->id.product = av7110->dev->pci->device;
-               }
-               input_dev->cdev.dev = &av7110->dev->pci->dev;
-               set_bit(EV_KEY, input_dev->evbit);
-               set_bit(EV_REP, input_dev->evbit);
-               input_register_keys();
-               err = input_register_device(input_dev);
-               if (err) {
-                       input_free_device(input_dev);
-                       return err;
-               }
-               input_dev->timer.function = input_repeat_key;
+       init_timer(&av7110->ir.keyup_timer);
+       av7110->ir.keyup_timer.function = av7110_emit_keyup;
+       av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir;
+
+       input_dev = input_allocate_device();
+       if (!input_dev)
+               return -ENOMEM;
+
+       av7110->ir.input_dev = input_dev;
+       snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys),
+               "pci-%s/ir0", pci_name(av7110->dev->pci));
 
+       input_dev->name = "DVB on-card IR receiver";
+
+       input_dev->phys = av7110->ir.input_phys;
+       input_dev->id.bustype = BUS_PCI;
+       input_dev->id.version = 2;
+       if (av7110->dev->pci->subsystem_vendor) {
+               input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
+               input_dev->id.product = av7110->dev->pci->subsystem_device;
+       } else {
+               input_dev->id.vendor = av7110->dev->pci->vendor;
+               input_dev->id.product = av7110->dev->pci->device;
+       }
+       input_dev->cdev.dev = &av7110->dev->pci->dev;
+       /* initial keymap */
+       memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
+       input_register_keys(&av7110->ir);
+       err = input_register_device(input_dev);
+       if (err) {
+               input_free_device(input_dev);
+               return err;
+       }
+       input_dev->timer.function = input_repeat_key;
+       input_dev->timer.data = (unsigned long) &av7110->ir;
+
+       if (av_cnt == 1) {
                e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, 
NULL);
                if (e) {
                        e->write_proc = av7110_ir_write_proc;
@@ -266,8 +369,8 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
                }
        }
 
-       tasklet_init(&av7110->ir_tasklet, av7110_emit_key, (unsigned long) 
av7110);
-       av7110->ir_handler = ir_handler;
+       tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) 
&av7110->ir);
+       av7110->ir.ir_handler = ir_handler;
 
        return 0;
 }
@@ -280,8 +383,10 @@ void __devexit av7110_ir_exit(struct av7110 *av7110)
        if (av_cnt == 0)
                return;
 
-       av7110->ir_handler = NULL;
-       tasklet_kill(&av7110->ir_tasklet);
+       del_timer_sync(&av7110->ir.keyup_timer);
+       av7110->ir.ir_handler = NULL;
+       tasklet_kill(&av7110->ir.ir_tasklet);
+
        for (i = 0; i < av_cnt; i++)
                if (av_list[i] == av7110) {
                        av_list[i] = av_list[av_cnt-1];
@@ -289,14 +394,13 @@ void __devexit av7110_ir_exit(struct av7110 *av7110)
                        break;
                }
 
-       if (av_cnt == 1) {
-               del_timer_sync(&keyup_timer);
+       if (av_cnt == 1)
                remove_proc_entry("av7110_ir", NULL);
-               input_unregister_device(input_dev);
-       }
+
+       input_unregister_device(av7110->ir.input_dev);
 
        av_cnt--;
 }
 
-//MODULE_AUTHOR("Holger Waechtler <[EMAIL PROTECTED]>");
+//MODULE_AUTHOR("Holger Waechtler <[EMAIL PROTECTED]>, Oliver Endriss <[EMAIL 
PROTECTED]>");
 //MODULE_LICENSE("GPL");
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to