X-Git-Url: https://git.stricted.de/?a=blobdiff_plain;f=drivers%2Fmedia%2Frc%2Frc-main.c;h=f57cd5677ac27c4bee3ebbbbfda25997585d6f1b;hb=cd4ecf877a4d629c38571405fd649077c12dec50;hp=a2706648e3651f30468310fcb9213bd7af7c4658;hpb=cf73df1e2975ae8f88e573e5f593761339a65def;p=GitHub%2Fmt8127%2Fandroid_kernel_alcatel_ttab.git diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index a2706648e365..f57cd5677ac2 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -749,6 +749,9 @@ static struct { * it is trigged by reading /sys/class/rc/rc?/protocols. * It returns the protocol names of supported protocols. * Enabled protocols are printed in brackets. + * + * dev->lock is taken to guard against races between device + * registration, store_protocols and show_protocols. */ static ssize_t show_protocols(struct device *device, struct device_attribute *mattr, char *buf) @@ -762,6 +765,8 @@ static ssize_t show_protocols(struct device *device, if (!dev) return -EINVAL; + mutex_lock(&dev->lock); + if (dev->driver_type == RC_DRIVER_SCANCODE) { enabled = dev->rc_map.rc_type; allowed = dev->allowed_protos; @@ -784,6 +789,9 @@ static ssize_t show_protocols(struct device *device, if (tmp != buf) tmp--; *tmp = '\n'; + + mutex_unlock(&dev->lock); + return tmp + 1 - buf; } @@ -802,6 +810,9 @@ static ssize_t show_protocols(struct device *device, * 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. */ static ssize_t store_protocols(struct device *device, struct device_attribute *mattr, @@ -815,18 +826,22 @@ static ssize_t store_protocols(struct device *device, u64 mask; int rc, i, count = 0; unsigned long flags; + ssize_t ret; /* Device is being removed */ if (!dev) return -EINVAL; + mutex_lock(&dev->lock); + if (dev->driver_type == RC_DRIVER_SCANCODE) type = dev->rc_map.rc_type; else if (dev->raw) type = dev->raw->enabled_protocols; else { IR_dprintk(1, "Protocol switching not supported\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } while ((tmp = strsep((char **) &data, " \n")) != NULL) { @@ -860,7 +875,8 @@ static ssize_t store_protocols(struct device *device, } if (i == ARRAY_SIZE(proto_names)) { IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); - return -EINVAL; + ret = -EINVAL; + goto out; } count++; } @@ -875,7 +891,8 @@ static ssize_t store_protocols(struct device *device, if (!count) { IR_dprintk(1, "Protocol not specified\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } if (dev->change_protocol) { @@ -883,7 +900,8 @@ static ssize_t store_protocols(struct device *device, if (rc < 0) { IR_dprintk(1, "Error setting protocols to 0x%llx\n", (long long)type); - return -EINVAL; + ret = -EINVAL; + goto out; } } @@ -898,7 +916,11 @@ static ssize_t store_protocols(struct device *device, IR_dprintk(1, "Current protocol(s): 0x%llx\n", (long long)type); - return len; + ret = len; + +out: + mutex_unlock(&dev->lock); + return ret; } static void rc_dev_release(struct device *device) @@ -974,6 +996,7 @@ struct rc_dev *rc_allocate_device(void) spin_lock_init(&dev->rc_map.lock); spin_lock_init(&dev->keylock); + mutex_init(&dev->lock); setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev); dev->dev.type = &rc_dev_type; @@ -1019,12 +1042,21 @@ int rc_register_device(struct rc_dev *dev) if (dev->close) dev->input_dev->close = ir_close; + /* + * Take the lock here, as the device sysfs node will appear + * when device_add() is called, which may trigger an ir-keytable udev + * rule, which will in turn call show_protocols and access either + * dev->rc_map.rc_type or dev->raw->enabled_protocols before it has + * been initialized. + */ + 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) - return rc; + goto out_unlock; rc = ir_setkeytable(dev, rc_map); if (rc) @@ -1046,6 +1078,13 @@ int rc_register_device(struct rc_dev *dev) */ dev->input_dev->rep[REP_DELAY] = 500; + /* + * As a repeat event on protocols like RC-5 and NEC take as long as + * 110/114ms, using 33ms as a repeat period is not the right thing + * to do. + */ + dev->input_dev->rep[REP_PERIOD] = 125; + path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); printk(KERN_INFO "%s: %s as %s\n", dev_name(&dev->dev), @@ -1058,6 +1097,7 @@ int rc_register_device(struct rc_dev *dev) if (rc < 0) goto out_input; } + mutex_unlock(&dev->lock); if (dev->change_protocol) { rc = dev->change_protocol(dev, rc_map->rc_type); @@ -1083,6 +1123,8 @@ out_table: ir_free_table(&dev->rc_map); out_dev: device_del(&dev->dev); +out_unlock: + mutex_unlock(&dev->lock); return rc; } EXPORT_SYMBOL_GPL(rc_register_device);