* 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)
        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;
        if (tmp != buf)
                tmp--;
        *tmp = '\n';
+
+       mutex_unlock(&dev->lock);
+
        return tmp + 1 - buf;
 }
 
  * 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,
        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) {
                        }
                        if (i == ARRAY_SIZE(proto_names)) {
                                IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto out;
                        }
                        count++;
                }
 
        if (!count) {
                IR_dprintk(1, "Protocol not specified\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        if (dev->change_protocol) {
                if (rc < 0) {
                        IR_dprintk(1, "Error setting protocols to 0x%llx\n",
                                   (long long)type);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto out;
                }
        }
 
        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)
 
        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;
        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)
                if (rc < 0)
                        goto out_input;
        }
+       mutex_unlock(&dev->lock);
 
        if (dev->change_protocol) {
                rc = dev->change_protocol(dev, rc_map->rc_type);
        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);
 
  * @driver_name: name of the hardware driver which registered this device
  * @map_name: name of the default keymap
  * @rc_map: current scan/key table
+ * @lock: used to ensure we've filled in all protocol details before
+ *     anyone can call show_protocols or store_protocols
  * @devno: unique remote control device number
  * @raw: additional data for raw pulse/space devices
  * @input_dev: the input child device used to communicate events to userspace
- * @driver_type: specifies if protocol decoding is done in hardware or software 
+ * @driver_type: specifies if protocol decoding is done in hardware or software
  * @idle: used to keep track of RX state
  * @allowed_protos: bitmask with the supported RC_TYPE_* protocols
  * @scanmask: some hardware decoders are not capable of providing the full
        struct input_id                 input_id;
        char                            *driver_name;
        const char                      *map_name;
-       struct rc_map   rc_map;
+       struct rc_map                   rc_map;
+       struct mutex                    lock;
        unsigned long                   devno;
        struct ir_raw_event_ctrl        *raw;
        struct input_dev                *input_dev;