--- zzzz-none-000/linux-3.10.107/drivers/media/rc/rc-main.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/media/rc/rc-main.c 2021-02-04 17:41:59.000000000 +0000 @@ -1,6 +1,6 @@ /* rc-main.c - Remote Controller core module * - * Copyright (C) 2009-2010 by Mauro Carvalho Chehab + * Copyright (C) 2009-2010 by Mauro Carvalho Chehab * * 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 @@ -16,7 +16,9 @@ #include #include #include +#include #include +#include #include #include #include "rc-core-priv.h" @@ -24,6 +26,7 @@ /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */ #define IR_TAB_MIN_SIZE 256 #define IR_TAB_MAX_SIZE 8192 +#define RC_DEV_MAX 256 /* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */ #define IR_KEYPRESS_TIMEOUT 250 @@ -31,6 +34,10 @@ /* Used to keep track of known keymaps */ static LIST_HEAD(rc_map_list); static DEFINE_SPINLOCK(rc_map_lock); +static struct led_trigger *led_feedback; + +/* Used to keep track of rc devices */ +static DEFINE_IDA(rc_ida); static struct rc_map_list *seek_rc_map(const char *name) { @@ -56,7 +63,7 @@ map = seek_rc_map(name); #ifdef MODULE if (!map) { - int rc = request_module(name); + int rc = request_module("%s", name); if (rc < 0) { printk(KERN_ERR "Couldn't load IR keymap %s\n", name); return NULL; @@ -279,8 +286,8 @@ * IR tables from other remotes. So, we support specifying a mask to * indicate the valid bits of the scancodes. */ - if (dev->scanmask) - scancode &= dev->scanmask; + if (dev->scancode_mask) + scancode &= dev->scancode_mask; /* First check if we already have a mapping for this ir command */ for (i = 0; i < rc_map->len; i++) { @@ -535,6 +542,7 @@ IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode); input_report_key(dev->input_dev, dev->last_keycode, 0); + led_trigger_event(led_feedback, LED_OFF); if (sync) input_sync(dev->input_dev); dev->keypressed = false; @@ -616,6 +624,7 @@ /** * ir_do_keydown() - internal function to process a keypress * @dev: the struct rc_dev descriptor of the device + * @protocol: the protocol of the keypress * @scancode: the scancode of the keypress * @keycode: the keycode of the keypress * @toggle: the toggle value of the keypress @@ -623,12 +632,13 @@ * This function is used internally to register a keypress, it must be * called with keylock held. */ -static void ir_do_keydown(struct rc_dev *dev, int scancode, - u32 keycode, u8 toggle) +static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol, + u32 scancode, u32 keycode, u8 toggle) { - bool new_event = !dev->keypressed || - dev->last_scancode != scancode || - dev->last_toggle != toggle; + bool new_event = (!dev->keypressed || + dev->last_protocol != protocol || + dev->last_scancode != scancode || + dev->last_toggle != toggle); if (new_event && dev->keypressed) ir_do_keyup(dev, false); @@ -638,14 +648,17 @@ if (new_event && keycode != KEY_RESERVED) { /* Register a keypress */ dev->keypressed = true; + dev->last_protocol = protocol; dev->last_scancode = scancode; dev->last_toggle = toggle; dev->last_keycode = keycode; IR_dprintk(1, "%s: key down event, " - "key 0x%04x, scancode 0x%04x\n", - dev->input_name, keycode, scancode); + "key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", + dev->input_name, keycode, protocol, scancode); input_report_key(dev->input_dev, keycode, 1); + + led_trigger_event(led_feedback, LED_FULL); } input_sync(dev->input_dev); @@ -654,20 +667,21 @@ /** * rc_keydown() - generates input event for a key press * @dev: the struct rc_dev descriptor of the device - * @scancode: the scancode that we're seeking + * @protocol: the protocol for the keypress + * @scancode: the scancode for the keypress * @toggle: the toggle value (protocol dependent, if the protocol doesn't * support toggle values, this should be set to zero) * * This routine is used to signal that a key has been pressed on the * remote control. */ -void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle) +void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle) { unsigned long flags; u32 keycode = rc_g_keycode_from_table(dev, scancode); spin_lock_irqsave(&dev->keylock, flags); - ir_do_keydown(dev, scancode, keycode, toggle); + ir_do_keydown(dev, protocol, scancode, keycode, toggle); if (dev->keypressed) { dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT); @@ -681,37 +695,70 @@ * rc_keydown_notimeout() - generates input event for a key press without * an automatic keyup event at a later time * @dev: the struct rc_dev descriptor of the device - * @scancode: the scancode that we're seeking + * @protocol: the protocol for the keypress + * @scancode: the scancode for the keypress * @toggle: the toggle value (protocol dependent, if the protocol doesn't * support toggle values, this should be set to zero) * * This routine is used to signal that a key has been pressed on the * remote control. The driver must manually call rc_keyup() at a later stage. */ -void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle) +void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol, + u32 scancode, u8 toggle) { unsigned long flags; u32 keycode = rc_g_keycode_from_table(dev, scancode); spin_lock_irqsave(&dev->keylock, flags); - ir_do_keydown(dev, scancode, keycode, toggle); + ir_do_keydown(dev, protocol, scancode, keycode, toggle); spin_unlock_irqrestore(&dev->keylock, flags); } EXPORT_SYMBOL_GPL(rc_keydown_notimeout); +int rc_open(struct rc_dev *rdev) +{ + int rval = 0; + + if (!rdev) + return -EINVAL; + + mutex_lock(&rdev->lock); + if (!rdev->users++ && rdev->open != NULL) + rval = rdev->open(rdev); + + if (rval) + rdev->users--; + + mutex_unlock(&rdev->lock); + + return rval; +} +EXPORT_SYMBOL_GPL(rc_open); + static int ir_open(struct input_dev *idev) { struct rc_dev *rdev = input_get_drvdata(idev); - return rdev->open(rdev); + return rc_open(rdev); } +void rc_close(struct rc_dev *rdev) +{ + if (rdev) { + mutex_lock(&rdev->lock); + + if (!--rdev->users && rdev->close != NULL) + rdev->close(rdev); + + mutex_unlock(&rdev->lock); + } +} +EXPORT_SYMBOL_GPL(rc_close); + static void ir_close(struct input_dev *idev) { struct rc_dev *rdev = input_get_drvdata(idev); - - if (rdev) - rdev->close(rdev); + rc_close(rdev); } /* class for /sys/class/rc */ @@ -751,18 +798,61 @@ RC_BIT_SONY20, "sony" }, { RC_BIT_RC5_SZ, "rc-5-sz" }, { RC_BIT_SANYO, "sanyo" }, + { RC_BIT_SHARP, "sharp" }, { RC_BIT_MCE_KBD, "mce_kbd" }, - { RC_BIT_LIRC, "lirc" }, + { RC_BIT_XMP, "xmp" }, }; /** - * show_protocols() - shows the current IR protocol(s) + * struct rc_filter_attribute - Device attribute relating to a filter type. + * @attr: Device attribute. + * @type: Filter type. + * @mask: false for filter value, true for filter mask. + */ +struct rc_filter_attribute { + struct device_attribute attr; + enum rc_filter_type type; + bool mask; +}; +#define to_rc_filter_attr(a) container_of(a, struct rc_filter_attribute, attr) + +#define RC_PROTO_ATTR(_name, _mode, _show, _store, _type) \ + struct rc_filter_attribute dev_attr_##_name = { \ + .attr = __ATTR(_name, _mode, _show, _store), \ + .type = (_type), \ + } +#define RC_FILTER_ATTR(_name, _mode, _show, _store, _type, _mask) \ + struct rc_filter_attribute dev_attr_##_name = { \ + .attr = __ATTR(_name, _mode, _show, _store), \ + .type = (_type), \ + .mask = (_mask), \ + } + +static bool lirc_is_present(void) +{ +#if defined(CONFIG_LIRC_MODULE) + struct module *lirc; + + mutex_lock(&module_mutex); + lirc = find_module("lirc_dev"); + mutex_unlock(&module_mutex); + + return lirc ? true : false; +#elif defined(CONFIG_LIRC) + return true; +#else + return false; +#endif +} + +/** + * show_protocols() - shows the current/wakeup IR protocol(s) * @device: the device descriptor - * @mattr: the device attribute struct (unused) + * @mattr: the device attribute struct * @buf: a pointer to the output buffer * * This routine is a callback routine for input read the IR protocol type(s). - * it is trigged by reading /sys/class/rc/rc?/protocols. + * it is trigged by reading /sys/class/rc/rc?/[wakeup_]protocols. * It returns the protocol names of supported protocols. * Enabled protocols are printed in brackets. * @@ -773,6 +863,7 @@ struct device_attribute *mattr, char *buf) { struct rc_dev *dev = to_rc_dev(device); + struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr); u64 allowed, enabled; char *tmp = buf; int i; @@ -783,19 +874,20 @@ mutex_lock(&dev->lock); - enabled = dev->enabled_protocols; - if (dev->driver_type == RC_DRIVER_SCANCODE) - allowed = dev->allowed_protos; - else if (dev->raw) - allowed = ir_raw_get_allowed_protocols(); - else { - mutex_unlock(&dev->lock); - return -ENODEV; + if (fattr->type == RC_FILTER_NORMAL) { + enabled = dev->enabled_protocols; + allowed = dev->allowed_protocols; + if (dev->raw && !allowed) + allowed = ir_raw_get_allowed_protocols(); + } else { + enabled = dev->enabled_wakeup_protocols; + allowed = dev->allowed_wakeup_protocols; } - IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", - (long long)allowed, - (long long)enabled); + mutex_unlock(&dev->lock); + + IR_dprintk(1, "%s: allowed - 0x%llx, enabled - 0x%llx\n", + __func__, (long long)allowed, (long long)enabled); for (i = 0; i < ARRAY_SIZE(proto_names); i++) { if (allowed & enabled & proto_names[i].type) @@ -807,61 +899,36 @@ allowed &= ~proto_names[i].type; } + if (dev->driver_type == RC_DRIVER_IR_RAW && lirc_is_present()) + tmp += sprintf(tmp, "[lirc] "); + if (tmp != buf) tmp--; *tmp = '\n'; - mutex_unlock(&dev->lock); - return tmp + 1 - buf; } /** - * store_protocols() - changes the current IR protocol(s) - * @device: the device descriptor - * @mattr: the device attribute struct (unused) - * @buf: a pointer to the input buffer - * @len: length of the input buffer + * parse_protocol_change() - parses a protocol change request + * @protocols: pointer to the bitmask of current protocols + * @buf: pointer to the buffer with a list of changes * - * This routine is for changing the IR protocol type. - * It is trigged by writing to /sys/class/rc/rc?/protocols. - * Writing "+proto" will add a protocol to the list of enabled protocols. - * Writing "-proto" will remove a protocol from the list of enabled protocols. + * Writing "+proto" will add a protocol to the protocol mask. + * Writing "-proto" will remove a protocol from protocol mask. * Writing "proto" will enable only "proto". * Writing "none" will disable all protocols. - * Returns -EINVAL if an invalid protocol combination or unknown protocol name - * is used, otherwise @len. - * - * dev->lock is taken to guard against races between device - * registration, store_protocols and show_protocols. + * Returns the number of changes performed or a negative error code. */ -static ssize_t store_protocols(struct device *device, - struct device_attribute *mattr, - const char *data, - size_t len) +static int parse_protocol_change(u64 *protocols, const char *buf) { - struct rc_dev *dev = to_rc_dev(device); - bool enable, disable; const char *tmp; - u64 type; + unsigned count = 0; + bool enable, disable; u64 mask; - int rc, i, count = 0; - ssize_t ret; - - /* Device is being removed */ - if (!dev) - return -EINVAL; - - mutex_lock(&dev->lock); - - if (dev->driver_type != RC_DRIVER_SCANCODE && !dev->raw) { - IR_dprintk(1, "Protocol switching not supported\n"); - ret = -EINVAL; - goto out; - } - type = dev->enabled_protocols; + int i; - while ((tmp = strsep((char **) &data, " \n")) != NULL) { + while ((tmp = strsep((char **)&buf, " \n")) != NULL) { if (!*tmp) break; @@ -886,46 +953,251 @@ } if (i == ARRAY_SIZE(proto_names)) { - IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); - ret = -EINVAL; - goto out; + if (!strcasecmp(tmp, "lirc")) + mask = 0; + else { + IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); + return -EINVAL; + } } count++; if (enable) - type |= mask; + *protocols |= mask; else if (disable) - type &= ~mask; + *protocols &= ~mask; else - type = mask; + *protocols = mask; } if (!count) { IR_dprintk(1, "Protocol not specified\n"); - ret = -EINVAL; + return -EINVAL; + } + + return count; +} + +/** + * store_protocols() - changes the current/wakeup IR protocol(s) + * @device: the device descriptor + * @mattr: the device attribute struct + * @buf: a pointer to the input buffer + * @len: length of the input buffer + * + * This routine is for changing the IR protocol type. + * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]protocols. + * See parse_protocol_change() for the valid commands. + * Returns @len on success or a negative error code. + * + * dev->lock is taken to guard against races between device + * registration, store_protocols and show_protocols. + */ +static ssize_t store_protocols(struct device *device, + struct device_attribute *mattr, + const char *buf, size_t len) +{ + struct rc_dev *dev = to_rc_dev(device); + struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr); + u64 *current_protocols; + int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); + struct rc_scancode_filter *filter; + int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); + u64 old_protocols, new_protocols; + ssize_t rc; + + /* Device is being removed */ + if (!dev) + return -EINVAL; + + if (fattr->type == RC_FILTER_NORMAL) { + IR_dprintk(1, "Normal protocol change requested\n"); + current_protocols = &dev->enabled_protocols; + change_protocol = dev->change_protocol; + filter = &dev->scancode_filter; + set_filter = dev->s_filter; + } else { + IR_dprintk(1, "Wakeup protocol change requested\n"); + current_protocols = &dev->enabled_wakeup_protocols; + change_protocol = dev->change_wakeup_protocol; + filter = &dev->scancode_wakeup_filter; + set_filter = dev->s_wakeup_filter; + } + + if (!change_protocol) { + IR_dprintk(1, "Protocol switching not supported\n"); + return -EINVAL; + } + + mutex_lock(&dev->lock); + + old_protocols = *current_protocols; + new_protocols = old_protocols; + rc = parse_protocol_change(&new_protocols, buf); + if (rc < 0) + goto out; + + rc = change_protocol(dev, &new_protocols); + if (rc < 0) { + IR_dprintk(1, "Error setting protocols to 0x%llx\n", + (long long)new_protocols); goto out; } - if (dev->change_protocol) { - rc = dev->change_protocol(dev, &type); + if (new_protocols != old_protocols) { + *current_protocols = new_protocols; + IR_dprintk(1, "Protocols changed to 0x%llx\n", + (long long)new_protocols); + } + + /* + * If a protocol change was attempted the filter may need updating, even + * if the actual protocol mask hasn't changed (since the driver may have + * cleared the filter). + * Try setting the same filter with the new protocol (if any). + * Fall back to clearing the filter. + */ + if (set_filter && filter->mask) { + if (new_protocols) + rc = set_filter(dev, filter); + else + rc = -1; + if (rc < 0) { - IR_dprintk(1, "Error setting protocols to 0x%llx\n", - (long long)type); - ret = -EINVAL; - goto out; + filter->data = 0; + filter->mask = 0; + set_filter(dev, filter); } } - dev->enabled_protocols = type; - IR_dprintk(1, "Current protocol(s): 0x%llx\n", - (long long)type); - - ret = len; + rc = len; out: mutex_unlock(&dev->lock); - return ret; + return rc; +} + +/** + * show_filter() - shows the current scancode filter value or mask + * @device: the device descriptor + * @attr: the device attribute struct + * @buf: a pointer to the output buffer + * + * This routine is a callback routine to read a scancode filter value or mask. + * It is trigged by reading /sys/class/rc/rc?/[wakeup_]filter[_mask]. + * It prints the current scancode filter value or mask of the appropriate filter + * type in hexadecimal into @buf and returns the size of the buffer. + * + * Bits of the filter value corresponding to set bits in the filter mask are + * compared against input scancodes and non-matching scancodes are discarded. + * + * dev->lock is taken to guard against races between device registration, + * store_filter and show_filter. + */ +static ssize_t show_filter(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct rc_dev *dev = to_rc_dev(device); + struct rc_filter_attribute *fattr = to_rc_filter_attr(attr); + struct rc_scancode_filter *filter; + u32 val; + + /* Device is being removed */ + if (!dev) + return -EINVAL; + + if (fattr->type == RC_FILTER_NORMAL) + filter = &dev->scancode_filter; + else + filter = &dev->scancode_wakeup_filter; + + mutex_lock(&dev->lock); + if (fattr->mask) + val = filter->mask; + else + val = filter->data; + mutex_unlock(&dev->lock); + + return sprintf(buf, "%#x\n", val); +} + +/** + * store_filter() - changes the scancode filter value + * @device: the device descriptor + * @attr: the device attribute struct + * @buf: a pointer to the input buffer + * @len: length of the input buffer + * + * This routine is for changing a scancode filter value or mask. + * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]filter[_mask]. + * Returns -EINVAL if an invalid filter value for the current protocol was + * specified or if scancode filtering is not supported by the driver, otherwise + * returns @len. + * + * Bits of the filter value corresponding to set bits in the filter mask are + * compared against input scancodes and non-matching scancodes are discarded. + * + * dev->lock is taken to guard against races between device registration, + * store_filter and show_filter. + */ +static ssize_t store_filter(struct device *device, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct rc_dev *dev = to_rc_dev(device); + struct rc_filter_attribute *fattr = to_rc_filter_attr(attr); + struct rc_scancode_filter new_filter, *filter; + int ret; + unsigned long val; + int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); + u64 *enabled_protocols; + + /* Device is being removed */ + if (!dev) + return -EINVAL; + + ret = kstrtoul(buf, 0, &val); + if (ret < 0) + return ret; + + if (fattr->type == RC_FILTER_NORMAL) { + set_filter = dev->s_filter; + enabled_protocols = &dev->enabled_protocols; + filter = &dev->scancode_filter; + } else { + set_filter = dev->s_wakeup_filter; + enabled_protocols = &dev->enabled_wakeup_protocols; + filter = &dev->scancode_wakeup_filter; + } + + if (!set_filter) + return -EINVAL; + + mutex_lock(&dev->lock); + + new_filter = *filter; + if (fattr->mask) + new_filter.mask = val; + else + new_filter.data = val; + + if (!*enabled_protocols && val) { + /* refuse to set a filter unless a protocol is enabled */ + ret = -EINVAL; + goto unlock; + } + + ret = set_filter(dev, &new_filter); + if (ret < 0) + goto unlock; + + *filter = new_filter; + +unlock: + mutex_unlock(&dev->lock); + return (ret < 0) ? ret : len; } static void rc_dev_release(struct device *device) @@ -954,25 +1226,58 @@ /* * Static device attribute struct with the sysfs attributes for IR's */ -static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR, - show_protocols, store_protocols); +static RC_PROTO_ATTR(protocols, S_IRUGO | S_IWUSR, + show_protocols, store_protocols, RC_FILTER_NORMAL); +static RC_PROTO_ATTR(wakeup_protocols, S_IRUGO | S_IWUSR, + show_protocols, store_protocols, RC_FILTER_WAKEUP); +static RC_FILTER_ATTR(filter, S_IRUGO|S_IWUSR, + show_filter, store_filter, RC_FILTER_NORMAL, false); +static RC_FILTER_ATTR(filter_mask, S_IRUGO|S_IWUSR, + show_filter, store_filter, RC_FILTER_NORMAL, true); +static RC_FILTER_ATTR(wakeup_filter, S_IRUGO|S_IWUSR, + show_filter, store_filter, RC_FILTER_WAKEUP, false); +static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR, + show_filter, store_filter, RC_FILTER_WAKEUP, true); -static struct attribute *rc_dev_attrs[] = { - &dev_attr_protocols.attr, +static struct attribute *rc_dev_protocol_attrs[] = { + &dev_attr_protocols.attr.attr, NULL, }; -static struct attribute_group rc_dev_attr_grp = { - .attrs = rc_dev_attrs, +static struct attribute_group rc_dev_protocol_attr_grp = { + .attrs = rc_dev_protocol_attrs, }; -static const struct attribute_group *rc_dev_attr_groups[] = { - &rc_dev_attr_grp, - NULL +static struct attribute *rc_dev_wakeup_protocol_attrs[] = { + &dev_attr_wakeup_protocols.attr.attr, + NULL, +}; + +static struct attribute_group rc_dev_wakeup_protocol_attr_grp = { + .attrs = rc_dev_wakeup_protocol_attrs, +}; + +static struct attribute *rc_dev_filter_attrs[] = { + &dev_attr_filter.attr.attr, + &dev_attr_filter_mask.attr.attr, + NULL, +}; + +static struct attribute_group rc_dev_filter_attr_grp = { + .attrs = rc_dev_filter_attrs, +}; + +static struct attribute *rc_dev_wakeup_filter_attrs[] = { + &dev_attr_wakeup_filter.attr.attr, + &dev_attr_wakeup_filter_mask.attr.attr, + NULL, +}; + +static struct attribute_group rc_dev_wakeup_filter_attr_grp = { + .attrs = rc_dev_wakeup_filter_attrs, }; static struct device_type rc_dev_type = { - .groups = rc_dev_attr_groups, .release = rc_dev_release, .uevent = rc_dev_uevent, }; @@ -1014,8 +1319,7 @@ if (!dev) return; - if (dev->input_dev) - input_free_device(dev->input_dev); + input_free_device(dev->input_dev); put_device(&dev->dev); @@ -1027,9 +1331,10 @@ int rc_register_device(struct rc_dev *dev) { static bool raw_init = false; /* raw decoders loaded? */ - static atomic_t devno = ATOMIC_INIT(0); struct rc_map *rc_map; const char *path; + int attr = 0; + int minor; int rc; if (!dev || !dev->map_name) @@ -1050,6 +1355,24 @@ if (dev->close) dev->input_dev->close = ir_close; + minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL); + if (minor < 0) + return minor; + + dev->minor = minor; + dev_set_name(&dev->dev, "rc%u", dev->minor); + dev_set_drvdata(&dev->dev, dev); + + dev->dev.groups = dev->sysfs_groups; + dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp; + if (dev->s_filter) + dev->sysfs_groups[attr++] = &rc_dev_filter_attr_grp; + if (dev->s_wakeup_filter) + dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp; + if (dev->change_wakeup_protocol) + dev->sysfs_groups[attr++] = &rc_dev_wakeup_protocol_attr_grp; + dev->sysfs_groups[attr++] = NULL; + /* * Take the lock here, as the device sysfs node will appear * when device_add() is called, which may trigger an ir-keytable udev @@ -1058,9 +1381,6 @@ */ mutex_lock(&dev->lock); - dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1); - dev_set_name(&dev->dev, "rc%ld", dev->devno); - dev_set_drvdata(&dev->dev, dev); rc = device_add(&dev->dev); if (rc) goto out_unlock; @@ -1073,7 +1393,14 @@ memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id)); dev->input_dev->phys = dev->input_phys; dev->input_dev->name = dev->input_name; + + /* input_register_device can call ir_open, so unlock mutex here */ + mutex_unlock(&dev->lock); + rc = input_register_device(dev->input_dev); + + mutex_lock(&dev->lock); + if (rc) goto out_table; @@ -1106,13 +1433,16 @@ ir_raw_init(); raw_init = true; } + /* calls ir_register_device so unlock mutex here*/ + mutex_unlock(&dev->lock); rc = ir_raw_event_register(dev); + mutex_lock(&dev->lock); if (rc < 0) goto out_input; } if (dev->change_protocol) { - u64 rc_type = (1 << rc_map->rc_type); + u64 rc_type = (1ll << rc_map->rc_type); rc = dev->change_protocol(dev, &rc_type); if (rc < 0) goto out_raw; @@ -1121,8 +1451,8 @@ mutex_unlock(&dev->lock); - IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n", - dev->devno, + IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n", + dev->minor, dev->driver_name ? dev->driver_name : "unknown", rc_map->name ? rc_map->name : "unknown", dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked"); @@ -1141,6 +1471,7 @@ device_del(&dev->dev); out_unlock: mutex_unlock(&dev->lock); + ida_simple_remove(&rc_ida, minor); return rc; } EXPORT_SYMBOL_GPL(rc_register_device); @@ -1164,6 +1495,8 @@ device_del(&dev->dev); + ida_simple_remove(&rc_ida, dev->minor); + rc_free_device(dev); } @@ -1181,6 +1514,7 @@ return rc; } + led_trigger_register_simple("rc-feedback", &led_feedback); rc_map_register(&empty_map); return 0; @@ -1189,6 +1523,7 @@ static void __exit rc_core_exit(void) { class_unregister(&rc_class); + led_trigger_unregister_simple(led_feedback); rc_map_unregister(&empty_map); } @@ -1199,5 +1534,5 @@ EXPORT_SYMBOL_GPL(rc_core_debug); module_param_named(debug, rc_core_debug, int, 0644); -MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL");