V4L/DVB: ir-core: centralize sysfs raw decoder enabling/disabling
authorDavid Härdeman <david@hardeman.nu>
Sun, 13 Jun 2010 20:29:31 +0000 (17:29 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 2 Aug 2010 17:54:27 +0000 (14:54 -0300)
With the current logic, each raw decoder needs to add a copy of the exact
same sysfs code. This is both unnecessary and also means that (re)loading
an IR driver after raw decoder modules have been loaded won't work as
expected.

This patch moves that logic into ir-raw-event and adds a single sysfs
file per device.

Reading that file returns something like:

"rc5 [rc6] nec jvc [sony]"

(with enabled protocols in [] brackets)

Writing either "+protocol" or "-protocol" to that file will
enable or disable the according protocol decoder.

An additional benefit is that the disabling of a decoder will be
remembered across module removal/insertion so a previously
disabled decoder won't suddenly be activated again. The default
setting is to enable all decoders.

This is also necessary for the next patch which moves even more decoder
state into the central raw decoding structs.

Signed-off-by: David Härdeman <david@hardeman.nu>
Acked-by: Jarod Wilson <jarod@redhat.com>
Tested-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/IR/ir-core-priv.h
drivers/media/IR/ir-jvc-decoder.c
drivers/media/IR/ir-nec-decoder.c
drivers/media/IR/ir-raw-event.c
drivers/media/IR/ir-rc5-decoder.c
drivers/media/IR/ir-rc6-decoder.c
drivers/media/IR/ir-sony-decoder.c
drivers/media/IR/ir-sysfs.c

index 9a5e65a..5111dc2 100644 (file)
@@ -22,6 +22,7 @@
 struct ir_raw_handler {
        struct list_head list;
 
+       u64 protocols; /* which are handled by this handler */
        int (*decode)(struct input_dev *input_dev, struct ir_raw_event event);
        int (*raw_register)(struct input_dev *input_dev);
        int (*raw_unregister)(struct input_dev *input_dev);
@@ -33,6 +34,7 @@ struct ir_raw_event_ctrl {
        ktime_t                         last_event;     /* when last event occurred */
        enum raw_event_type             last_type;      /* last event type */
        struct input_dev                *input_dev;     /* pointer to the parent input_dev */
+       u64                             enabled_protocols; /* enabled raw protocol decoders */
 };
 
 /* macros for IR decoders */
@@ -74,6 +76,7 @@ void ir_unregister_class(struct input_dev *input_dev);
 /*
  * Routines from ir-raw-event.c to be used internally and by decoders
  */
+u64 ir_raw_get_allowed_protocols(void);
 int ir_raw_event_register(struct input_dev *input_dev);
 void ir_raw_event_unregister(struct input_dev *input_dev);
 int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
index b02e801..b1f9358 100644 (file)
@@ -41,7 +41,6 @@ enum jvc_state {
 struct decoder_data {
        struct list_head        list;
        struct ir_input_dev     *ir_dev;
-       int                     enabled:1;
 
        /* State machine control */
        enum jvc_state          state;
@@ -72,53 +71,6 @@ static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
        return data;
 }
 
-static ssize_t store_enabled(struct device *d,
-                            struct device_attribute *mattr,
-                            const char *buf,
-                            size_t len)
-{
-       unsigned long value;
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (strict_strtoul(buf, 10, &value) || value > 1)
-               return -EINVAL;
-
-       data->enabled = value;
-
-       return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-                            struct device_attribute *mattr, char *buf)
-{
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (data->enabled)
-               return sprintf(buf, "1\n");
-       else
-       return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-       &dev_attr_enabled.attr,
-       NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-       .name   = "jvc_decoder",
-       .attrs  = decoder_attributes,
-};
-
 /**
  * ir_jvc_decode() - Decode one JVC pulse or space
  * @input_dev: the struct input_dev descriptor of the device
@@ -135,7 +87,7 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!data)
                return -EINVAL;
 
-       if (!data->enabled)
+       if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC))
                return 0;
 
        if (IS_RESET(ev)) {
@@ -253,22 +205,12 @@ static int ir_jvc_register(struct input_dev *input_dev)
 {
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
        struct decoder_data *data;
-       u64 ir_type = ir_dev->rc_tab.ir_type;
-       int rc;
-
-       rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-       if (rc < 0)
-               return rc;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+       if (!data)
                return -ENOMEM;
-       }
 
        data->ir_dev = ir_dev;
-       if (ir_type == IR_TYPE_JVC || ir_type == IR_TYPE_UNKNOWN)
-               data->enabled = 1;
 
        spin_lock(&decoder_lock);
        list_add_tail(&data->list, &decoder_list);
@@ -286,8 +228,6 @@ static int ir_jvc_unregister(struct input_dev *input_dev)
        if (!data)
                return 0;
 
-       sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
        spin_lock(&decoder_lock);
        list_del(&data->list);
        spin_unlock(&decoder_lock);
@@ -296,6 +236,7 @@ static int ir_jvc_unregister(struct input_dev *input_dev)
 }
 
 static struct ir_raw_handler jvc_handler = {
+       .protocols      = IR_TYPE_JVC,
        .decode         = ir_jvc_decode,
        .raw_register   = ir_jvc_register,
        .raw_unregister = ir_jvc_unregister,
index 6059a1f..db62c65 100644 (file)
@@ -43,7 +43,6 @@ enum nec_state {
 struct decoder_data {
        struct list_head        list;
        struct ir_input_dev     *ir_dev;
-       int                     enabled:1;
 
        /* State machine control */
        enum nec_state          state;
@@ -71,53 +70,6 @@ static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
        return data;
 }
 
-static ssize_t store_enabled(struct device *d,
-                            struct device_attribute *mattr,
-                            const char *buf,
-                            size_t len)
-{
-       unsigned long value;
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (strict_strtoul(buf, 10, &value) || value > 1)
-               return -EINVAL;
-
-       data->enabled = value;
-
-       return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-                            struct device_attribute *mattr, char *buf)
-{
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (data->enabled)
-               return sprintf(buf, "1\n");
-       else
-       return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-       &dev_attr_enabled.attr,
-       NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-       .name   = "nec_decoder",
-       .attrs  = decoder_attributes,
-};
-
 /**
  * ir_nec_decode() - Decode one NEC pulse or space
  * @input_dev: the struct input_dev descriptor of the device
@@ -136,7 +88,7 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!data)
                return -EINVAL;
 
-       if (!data->enabled)
+       if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC))
                return 0;
 
        if (IS_RESET(ev)) {
@@ -260,22 +212,12 @@ static int ir_nec_register(struct input_dev *input_dev)
 {
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
        struct decoder_data *data;
-       u64 ir_type = ir_dev->rc_tab.ir_type;
-       int rc;
-
-       rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-       if (rc < 0)
-               return rc;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+       if (!data)
                return -ENOMEM;
-       }
 
        data->ir_dev = ir_dev;
-       if (ir_type == IR_TYPE_NEC || ir_type == IR_TYPE_UNKNOWN)
-               data->enabled = 1;
 
        spin_lock(&decoder_lock);
        list_add_tail(&data->list, &decoder_list);
@@ -293,8 +235,6 @@ static int ir_nec_unregister(struct input_dev *input_dev)
        if (!data)
                return 0;
 
-       sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
        spin_lock(&decoder_lock);
        list_del(&data->list);
        spin_unlock(&decoder_lock);
@@ -303,6 +243,7 @@ static int ir_nec_unregister(struct input_dev *input_dev)
 }
 
 static struct ir_raw_handler nec_handler = {
+       .protocols      = IR_TYPE_NEC,
        .decode         = ir_nec_decode,
        .raw_register   = ir_nec_register,
        .raw_unregister = ir_nec_unregister,
index d3bd3f9..fb3336c 100644 (file)
@@ -21,8 +21,9 @@
 #define MAX_IR_EVENT_SIZE      512
 
 /* Used to handle IR raw handler extensions */
-static LIST_HEAD(ir_raw_handler_list);
 static DEFINE_SPINLOCK(ir_raw_handler_lock);
+static LIST_HEAD(ir_raw_handler_list);
+static u64 available_protocols;
 
 /**
  * RUN_DECODER()       - runs an operation on all IR decoders
@@ -64,52 +65,6 @@ static void ir_raw_event_work(struct work_struct *work)
                RUN_DECODER(decode, raw->input_dev, ev);
 }
 
-int ir_raw_event_register(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir = input_get_drvdata(input_dev);
-       int rc;
-
-       ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
-       if (!ir->raw)
-               return -ENOMEM;
-
-       ir->raw->input_dev = input_dev;
-       INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
-
-       rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
-                        GFP_KERNEL);
-       if (rc < 0) {
-               kfree(ir->raw);
-               ir->raw = NULL;
-               return rc;
-       }
-
-       rc = RUN_DECODER(raw_register, input_dev);
-       if (rc < 0) {
-               kfifo_free(&ir->raw->kfifo);
-               kfree(ir->raw);
-               ir->raw = NULL;
-               return rc;
-       }
-
-       return rc;
-}
-
-void ir_raw_event_unregister(struct input_dev *input_dev)
-{
-       struct ir_input_dev *ir = input_get_drvdata(input_dev);
-
-       if (!ir->raw)
-               return;
-
-       cancel_work_sync(&ir->raw->rx_work);
-       RUN_DECODER(raw_unregister, input_dev);
-
-       kfifo_free(&ir->raw->kfifo);
-       kfree(ir->raw);
-       ir->raw = NULL;
-}
-
 /**
  * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
  * @input_dev: the struct input_dev device descriptor
@@ -203,6 +158,66 @@ void ir_raw_event_handle(struct input_dev *input_dev)
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
+/* used internally by the sysfs interface */
+u64
+ir_raw_get_allowed_protocols()
+{
+       u64 protocols;
+       spin_lock(&ir_raw_handler_lock);
+       protocols = available_protocols;
+       spin_unlock(&ir_raw_handler_lock);
+       return protocols;
+}
+
+/*
+ * Used to (un)register raw event clients
+ */
+int ir_raw_event_register(struct input_dev *input_dev)
+{
+       struct ir_input_dev *ir = input_get_drvdata(input_dev);
+       int rc;
+
+       ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
+       if (!ir->raw)
+               return -ENOMEM;
+
+       ir->raw->input_dev = input_dev;
+       INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
+       ir->raw->enabled_protocols = ~0;
+       rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
+                        GFP_KERNEL);
+       if (rc < 0) {
+               kfree(ir->raw);
+               ir->raw = NULL;
+               return rc;
+       }
+
+       rc = RUN_DECODER(raw_register, input_dev);
+       if (rc < 0) {
+               kfifo_free(&ir->raw->kfifo);
+               kfree(ir->raw);
+               ir->raw = NULL;
+               return rc;
+       }
+
+       return rc;
+}
+
+void ir_raw_event_unregister(struct input_dev *input_dev)
+{
+       struct ir_input_dev *ir = input_get_drvdata(input_dev);
+
+       if (!ir->raw)
+               return;
+
+       cancel_work_sync(&ir->raw->rx_work);
+       RUN_DECODER(raw_unregister, input_dev);
+
+       kfifo_free(&ir->raw->kfifo);
+       kfree(ir->raw);
+       ir->raw = NULL;
+}
+
 /*
  * Extension interface - used to register the IR decoders
  */
@@ -211,7 +226,9 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
 {
        spin_lock(&ir_raw_handler_lock);
        list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
+       available_protocols |= ir_raw_handler->protocols;
        spin_unlock(&ir_raw_handler_lock);
+
        return 0;
 }
 EXPORT_SYMBOL(ir_raw_handler_register);
@@ -220,6 +237,7 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
 {
        spin_lock(&ir_raw_handler_lock);
        list_del(&ir_raw_handler->list);
+       available_protocols &= ~ir_raw_handler->protocols;
        spin_unlock(&ir_raw_handler_lock);
 }
 EXPORT_SYMBOL(ir_raw_handler_unregister);
index 4aa797b..bdfa404 100644 (file)
@@ -45,7 +45,6 @@ enum rc5_state {
 struct decoder_data {
        struct list_head        list;
        struct ir_input_dev     *ir_dev;
-       int                     enabled:1;
 
        /* State machine control */
        enum rc5_state          state;
@@ -76,53 +75,6 @@ static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
        return data;
 }
 
-static ssize_t store_enabled(struct device *d,
-                            struct device_attribute *mattr,
-                            const char *buf,
-                            size_t len)
-{
-       unsigned long value;
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (strict_strtoul(buf, 10, &value) || value > 1)
-               return -EINVAL;
-
-       data->enabled = value;
-
-       return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-                            struct device_attribute *mattr, char *buf)
-{
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (data->enabled)
-               return sprintf(buf, "1\n");
-       else
-       return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-       &dev_attr_enabled.attr,
-       NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-       .name   = "rc5_decoder",
-       .attrs  = decoder_attributes,
-};
-
 /**
  * ir_rc5_decode() - Decode one RC-5 pulse or space
  * @input_dev: the struct input_dev descriptor of the device
@@ -141,8 +93,8 @@ static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!data)
                return -EINVAL;
 
-       if (!data->enabled)
-               return 0;
+        if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5))
+                return 0;
 
        if (IS_RESET(ev)) {
                data->state = STATE_INACTIVE;
@@ -256,22 +208,12 @@ static int ir_rc5_register(struct input_dev *input_dev)
 {
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
        struct decoder_data *data;
-       u64 ir_type = ir_dev->rc_tab.ir_type;
-       int rc;
-
-       rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-       if (rc < 0)
-               return rc;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+       if (!data)
                return -ENOMEM;
-       }
 
        data->ir_dev = ir_dev;
-       if (ir_type == IR_TYPE_RC5 || ir_type == IR_TYPE_UNKNOWN)
-               data->enabled = 1;
 
        spin_lock(&decoder_lock);
        list_add_tail(&data->list, &decoder_list);
@@ -289,8 +231,6 @@ static int ir_rc5_unregister(struct input_dev *input_dev)
        if (!data)
                return 0;
 
-       sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
        spin_lock(&decoder_lock);
        list_del(&data->list);
        spin_unlock(&decoder_lock);
@@ -299,6 +239,7 @@ static int ir_rc5_unregister(struct input_dev *input_dev)
 }
 
 static struct ir_raw_handler rc5_handler = {
+       .protocols      = IR_TYPE_RC5,
        .decode         = ir_rc5_decode,
        .raw_register   = ir_rc5_register,
        .raw_unregister = ir_rc5_unregister,
index 9f61da2..2ebd4ea 100644 (file)
@@ -61,7 +61,6 @@ enum rc6_state {
 struct decoder_data {
        struct list_head        list;
        struct ir_input_dev     *ir_dev;
-       int                     enabled:1;
 
        /* State machine control */
        enum rc6_state          state;
@@ -93,53 +92,6 @@ static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
        return data;
 }
 
-static ssize_t store_enabled(struct device *d,
-                            struct device_attribute *mattr,
-                            const char *buf,
-                            size_t len)
-{
-       unsigned long value;
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (strict_strtoul(buf, 10, &value) || value > 1)
-               return -EINVAL;
-
-       data->enabled = value;
-
-       return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-                            struct device_attribute *mattr, char *buf)
-{
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (data->enabled)
-               return sprintf(buf, "1\n");
-       else
-       return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-       &dev_attr_enabled.attr,
-       NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-       .name   = "rc6_decoder",
-       .attrs  = decoder_attributes,
-};
-
 static enum rc6_mode rc6_mode(struct decoder_data *data) {
        switch (data->header & RC6_MODE_MASK) {
        case 0:
@@ -171,7 +123,7 @@ static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!data)
                return -EINVAL;
 
-       if (!data->enabled)
+       if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6))
                return 0;
 
        if (IS_RESET(ev)) {
@@ -352,22 +304,12 @@ static int ir_rc6_register(struct input_dev *input_dev)
 {
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
        struct decoder_data *data;
-       u64 ir_type = ir_dev->rc_tab.ir_type;
-       int rc;
-
-       rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-       if (rc < 0)
-               return rc;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+       if (!data)
                return -ENOMEM;
-       }
 
        data->ir_dev = ir_dev;
-       if (ir_type == IR_TYPE_RC6 || ir_type == IR_TYPE_UNKNOWN)
-               data->enabled = 1;
 
        spin_lock(&decoder_lock);
        list_add_tail(&data->list, &decoder_list);
@@ -385,8 +327,6 @@ static int ir_rc6_unregister(struct input_dev *input_dev)
        if (!data)
                return 0;
 
-       sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
        spin_lock(&decoder_lock);
        list_del(&data->list);
        spin_unlock(&decoder_lock);
@@ -395,6 +335,7 @@ static int ir_rc6_unregister(struct input_dev *input_dev)
 }
 
 static struct ir_raw_handler rc6_handler = {
+       .protocols      = IR_TYPE_RC6,
        .decode         = ir_rc6_decode,
        .raw_register   = ir_rc6_register,
        .raw_unregister = ir_rc6_unregister,
index 219075f..e15db33 100644 (file)
@@ -38,7 +38,6 @@ enum sony_state {
 struct decoder_data {
        struct list_head        list;
        struct ir_input_dev     *ir_dev;
-       int                     enabled:1;
 
        /* State machine control */
        enum sony_state         state;
@@ -66,53 +65,6 @@ static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
        return data;
 }
 
-static ssize_t store_enabled(struct device *d,
-                            struct device_attribute *mattr,
-                            const char *buf,
-                            size_t len)
-{
-       unsigned long value;
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (strict_strtoul(buf, 10, &value) || value > 1)
-               return -EINVAL;
-
-       data->enabled = value;
-
-       return len;
-}
-
-static ssize_t show_enabled(struct device *d,
-                            struct device_attribute *mattr, char *buf)
-{
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       struct decoder_data *data = get_decoder_data(ir_dev);
-
-       if (!data)
-               return -EINVAL;
-
-       if (data->enabled)
-               return sprintf(buf, "1\n");
-       else
-       return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
-       &dev_attr_enabled.attr,
-       NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
-       .name   = "sony_decoder",
-       .attrs  = decoder_attributes,
-};
-
 /**
  * ir_sony_decode() - Decode one Sony pulse or space
  * @input_dev: the struct input_dev descriptor of the device
@@ -131,7 +83,7 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
        if (!data)
                return -EINVAL;
 
-       if (!data->enabled)
+       if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY))
                return 0;
 
        if (IS_RESET(ev)) {
@@ -245,22 +197,12 @@ static int ir_sony_register(struct input_dev *input_dev)
 {
        struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
        struct decoder_data *data;
-       u64 ir_type = ir_dev->rc_tab.ir_type;
-       int rc;
-
-       rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-       if (rc < 0)
-               return rc;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
+       if (!data)
                return -ENOMEM;
-       }
 
        data->ir_dev = ir_dev;
-       if (ir_type == IR_TYPE_SONY || ir_type == IR_TYPE_UNKNOWN)
-               data->enabled = 1;
 
        spin_lock(&decoder_lock);
        list_add_tail(&data->list, &decoder_list);
@@ -278,8 +220,6 @@ static int ir_sony_unregister(struct input_dev *input_dev)
        if (!data)
                return 0;
 
-       sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
        spin_lock(&decoder_lock);
        list_del(&data->list);
        spin_unlock(&decoder_lock);
@@ -288,6 +228,7 @@ static int ir_sony_unregister(struct input_dev *input_dev)
 }
 
 static struct ir_raw_handler sony_handler = {
+       .protocols      = IR_TYPE_SONY,
        .decode         = ir_sony_decode,
        .raw_register   = ir_sony_register,
        .raw_unregister = ir_sony_unregister,
index 2098dd1..005621d 100644 (file)
@@ -34,122 +34,178 @@ static struct class ir_input_class = {
 };
 
 /**
- * show_protocol() - shows the current IR protocol
+ * show_protocols() - shows the current IR protocol(s)
  * @d:         the device descriptor
  * @mattr:     the device attribute struct (unused)
  * @buf:       a pointer to the output buffer
  *
- * This routine is a callback routine for input read the IR protocol type.
- * it is trigged by reading /sys/class/rc/rc?/current_protocol.
- * It returns the protocol name, as understood by the driver.
+ * 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 returns the protocol names of supported protocols.
+ * Enabled protocols are printed in brackets.
  */
-static ssize_t show_protocol(struct device *d,
-                            struct device_attribute *mattr, char *buf)
+static ssize_t show_protocols(struct device *d,
+                             struct device_attribute *mattr, char *buf)
 {
-       char *s;
        struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       u64 ir_type = ir_dev->rc_tab.ir_type;
-
-       IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type);
-
-       /* FIXME: doesn't support multiple protocols at the same time */
-       if (ir_type == IR_TYPE_UNKNOWN)
-               s = "Unknown";
-       else if (ir_type == IR_TYPE_RC5)
-               s = "rc-5";
-       else if (ir_type == IR_TYPE_NEC)
-               s = "nec";
-       else if (ir_type == IR_TYPE_RC6)
-               s = "rc6";
-       else if (ir_type == IR_TYPE_JVC)
-               s = "jvc";
-       else if (ir_type == IR_TYPE_SONY)
-               s = "sony";
-       else
-               s = "other";
+       u64 allowed, enabled;
+       char *tmp = buf;
+
+       if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
+               enabled = ir_dev->rc_tab.ir_type;
+               allowed = ir_dev->props->allowed_protos;
+       } else {
+               enabled = ir_dev->raw->enabled_protocols;
+               allowed = ir_raw_get_allowed_protocols();
+       }
 
-       return sprintf(buf, "%s\n", s);
+       IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
+                  (long long)allowed,
+                  (long long)enabled);
+
+       if (allowed & enabled & IR_TYPE_UNKNOWN)
+               tmp += sprintf(tmp, "[unknown] ");
+       else if (allowed & IR_TYPE_UNKNOWN)
+               tmp += sprintf(tmp, "unknown ");
+
+       if (allowed & enabled & IR_TYPE_RC5)
+               tmp += sprintf(tmp, "[rc5] ");
+       else if (allowed & IR_TYPE_RC5)
+               tmp += sprintf(tmp, "rc5 ");
+
+       if (allowed & enabled & IR_TYPE_NEC)
+               tmp += sprintf(tmp, "[nec] ");
+       else if (allowed & IR_TYPE_NEC)
+               tmp += sprintf(tmp, "nec ");
+
+       if (allowed & enabled & IR_TYPE_RC6)
+               tmp += sprintf(tmp, "[rc6] ");
+       else if (allowed & IR_TYPE_RC6)
+               tmp += sprintf(tmp, "rc6 ");
+
+       if (allowed & enabled & IR_TYPE_JVC)
+               tmp += sprintf(tmp, "[jvc] ");
+       else if (allowed & IR_TYPE_JVC)
+               tmp += sprintf(tmp, "jvc ");
+
+       if (allowed & enabled & IR_TYPE_SONY)
+               tmp += sprintf(tmp, "[sony] ");
+       else if (allowed & IR_TYPE_SONY)
+               tmp += sprintf(tmp, "sony ");
+
+       if (tmp != buf)
+               tmp--;
+       *tmp = '\n';
+       return tmp + 1 - buf;
 }
 
 /**
- * store_protocol() - shows the current IR protocol
+ * store_protocols() - changes the current IR protocol(s)
  * @d:         the device descriptor
  * @mattr:     the device attribute struct (unused)
  * @buf:       a pointer to the input buffer
  * @len:       length of the input buffer
  *
  * This routine is a callback routine for changing the IR protocol type.
- * it is trigged by reading /sys/class/rc/rc?/current_protocol.
- * It changes the IR the protocol name, if the IR type is recognized
- * by the driver.
- * If an unknown protocol name is used, returns -EINVAL.
+ * 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 enable only "proto".
+ * Returns -EINVAL if an invalid protocol combination or unknown protocol name
+ * is used, otherwise @len.
  */
-static ssize_t store_protocol(struct device *d,
-                             struct device_attribute *mattr,
-                             const char *data,
-                             size_t len)
+static ssize_t store_protocols(struct device *d,
+                              struct device_attribute *mattr,
+                              const char *data,
+                              size_t len)
 {
        struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-       u64 ir_type = 0;
-       int rc = -EINVAL;
+       bool enable, disable;
+       const char *tmp;
+       u64 type;
+       u64 mask;
+       int rc;
        unsigned long flags;
-       char *buf;
-
-       while ((buf = strsep((char **) &data, " \n")) != NULL) {
-               if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5"))
-                       ir_type |= IR_TYPE_RC5;
-               if (!strcasecmp(buf, "nec"))
-                       ir_type |= IR_TYPE_NEC;
-               if (!strcasecmp(buf, "jvc"))
-                       ir_type |= IR_TYPE_JVC;
-               if (!strcasecmp(buf, "sony"))
-                       ir_type |= IR_TYPE_SONY;
+
+       tmp = skip_spaces(data);
+
+       if (*tmp == '+') {
+               enable = true;
+               disable = false;
+               tmp++;
+       } else if (*tmp == '-') {
+               enable = false;
+               disable = true;
+               tmp++;
+       } else {
+               enable = false;
+               disable = false;
        }
 
-       if (!ir_type) {
+       if (!strncasecmp(tmp, "unknown", 7)) {
+               tmp += 7;
+               mask = IR_TYPE_UNKNOWN;
+       } else if (!strncasecmp(tmp, "rc5", 3)) {
+               tmp += 3;
+               mask = IR_TYPE_RC5;
+       } else if (!strncasecmp(tmp, "nec", 3)) {
+               tmp += 3;
+               mask = IR_TYPE_NEC;
+       } else if (!strncasecmp(tmp, "rc6", 3)) {
+               tmp += 3;
+               mask = IR_TYPE_RC6;
+       } else if (!strncasecmp(tmp, "jvc", 3)) {
+               tmp += 3;
+               mask = IR_TYPE_JVC;
+       } else if (!strncasecmp(tmp, "sony", 4)) {
+               tmp += 4;
+               mask = IR_TYPE_SONY;
+       } else {
                IR_dprintk(1, "Unknown protocol\n");
                return -EINVAL;
        }
 
-       if (ir_dev->props && ir_dev->props->change_protocol)
-               rc = ir_dev->props->change_protocol(ir_dev->props->priv,
-                                                   ir_type);
-
-       if (rc < 0) {
-               IR_dprintk(1, "Error setting protocol to %lld\n",
-                          (long long)ir_type);
+       tmp = skip_spaces(tmp);
+       if (*tmp != '\0') {
+               IR_dprintk(1, "Invalid trailing characters\n");
                return -EINVAL;
        }
 
-       spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
-       ir_dev->rc_tab.ir_type = ir_type;
-       spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
+       if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
+               type = ir_dev->rc_tab.ir_type;
+       else
+               type = ir_dev->raw->enabled_protocols;
 
-       IR_dprintk(1, "Current protocol(s) is(are) %lld\n",
-                  (long long)ir_type);
+       if (enable)
+               type |= mask;
+       else if (disable)
+               type &= ~mask;
+       else
+               type = mask;
 
-       return len;
-}
+       if (ir_dev->props && ir_dev->props->change_protocol) {
+               rc = ir_dev->props->change_protocol(ir_dev->props->priv,
+                                                   type);
+               if (rc < 0) {
+                       IR_dprintk(1, "Error setting protocols to 0x%llx\n",
+                                  (long long)type);
+                       return -EINVAL;
+               }
+       }
 
-static ssize_t show_supported_protocols(struct device *d,
-                            struct device_attribute *mattr, char *buf)
-{
-       char *orgbuf = buf;
-       struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+       if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
+               spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
+               ir_dev->rc_tab.ir_type = type;
+               spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
+       } else {
+               ir_dev->raw->enabled_protocols = type;
+       }
 
-       /* FIXME: doesn't support multiple protocols at the same time */
-       if (ir_dev->props->allowed_protos == IR_TYPE_UNKNOWN)
-               buf += sprintf(buf, "unknown ");
-       if (ir_dev->props->allowed_protos & IR_TYPE_RC5)
-               buf += sprintf(buf, "rc-5 ");
-       if (ir_dev->props->allowed_protos & IR_TYPE_NEC)
-               buf += sprintf(buf, "nec ");
-       if (buf == orgbuf)
-               buf += sprintf(buf, "other ");
 
-       buf += sprintf(buf - 1, "\n");
+       IR_dprintk(1, "Current protocol(s): 0x%llx\n",
+                  (long long)type);
 
-       return buf - orgbuf;
+       return len;
 }
 
 #define ADD_HOTPLUG_VAR(fmt, val...)                                   \
@@ -159,7 +215,7 @@ static ssize_t show_supported_protocols(struct device *d,
                        return err;                                     \
        } while (0)
 
-static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env)
+static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 {
        struct ir_input_dev *ir_dev = dev_get_drvdata(device);
 
@@ -174,34 +230,26 @@ static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 /*
  * Static device attribute struct with the sysfs attributes for IR's
  */
-static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR,
-                  show_protocol, store_protocol);
-
-static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR,
-                  show_supported_protocols, NULL);
+static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR,
+                  show_protocols, store_protocols);
 
-static struct attribute *ir_hw_dev_attrs[] = {
-       &dev_attr_protocol.attr,
-       &dev_attr_supported_protocols.attr,
+static struct attribute *rc_dev_attrs[] = {
+       &dev_attr_protocols.attr,
        NULL,
 };
 
-static struct attribute_group ir_hw_dev_attr_grp = {
-       .attrs  = ir_hw_dev_attrs,
+static struct attribute_group rc_dev_attr_grp = {
+       .attrs  = rc_dev_attrs,
 };
 
-static const struct attribute_group *ir_hw_dev_attr_groups[] = {
-       &ir_hw_dev_attr_grp,
+static const struct attribute_group *rc_dev_attr_groups[] = {
+       &rc_dev_attr_grp,
        NULL
 };
 
 static struct device_type rc_dev_type = {
-       .groups         = ir_hw_dev_attr_groups,
-       .uevent         = ir_dev_uevent,
-};
-
-static struct device_type ir_raw_dev_type = {
-       .uevent         = ir_dev_uevent,
+       .groups         = rc_dev_attr_groups,
+       .uevent         = rc_dev_uevent,
 };
 
 /**
@@ -221,11 +269,7 @@ int ir_register_class(struct input_dev *input_dev)
        if (unlikely(devno < 0))
                return devno;
 
-       if (ir_dev->props) {
-               if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
-                       ir_dev->dev.type = &rc_dev_type;
-       } else
-               ir_dev->dev.type = &ir_raw_dev_type;
+       ir_dev->dev.type = &rc_dev_type;
 
        ir_dev->dev.class = &ir_input_class;
        ir_dev->dev.parent = input_dev->dev.parent;