V4L/DVB: ir-nec-decoder: Add sysfs node to enable/disable per irrcv
authorMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 26 Mar 2010 02:49:46 +0000 (23:49 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 18 May 2010 03:53:01 +0000 (00:53 -0300)
With the help of raw_register/raw_unregister, adds a sysfs group
associated with the decoder, inside the corresponding irrcv node.

Writing 1 to nec_decoder/enabled enables the decoder, while
writing 0 disables it.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/IR/ir-nec-decoder.c
drivers/media/IR/ir-raw-event.c

index cb57cc2877348aefb58052c46b8d40db8e91d5f2..83a9912722f4fc580d428921481f8538ed89b446 100644 (file)
 
 #define REPEAT_TIME    240 /* ms */
 
+/* Used to register nec_decoder clients */
+static LIST_HEAD(decoder_list);
+static spinlock_t decoder_lock;
+
+struct decoder_data {
+       struct list_head        list;
+       struct ir_input_dev     *ir_dev;
+       int                     enabled:1;
+};
+
+
+/**
+ * get_decoder_data()  - gets decoder data
+ * @input_dev: input device
+ *
+ * Returns the struct decoder_data that corresponds to a device
+ */
+
+static struct decoder_data *get_decoder_data(struct  ir_input_dev *ir_dev)
+{
+       struct decoder_data *data = NULL;
+
+       spin_lock(&decoder_lock);
+       list_for_each_entry(data, &decoder_list, list) {
+               if (data->ir_dev == ir_dev)
+                       break;
+       }
+       spin_unlock(&decoder_lock);
+       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,
+};
+
+
 /** is_repeat - Check if it is a NEC repeat event
  * @input_dev: the struct input_dev descriptor of the device
  * @pos:       the position of the first event
@@ -184,9 +263,15 @@ static int ir_nec_decode(struct input_dev *input_dev,
                         struct ir_raw_event *evs,
                         int len)
 {
+       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       struct decoder_data *data;
        int pos = 0;
        int rc = 0;
 
+       data = get_decoder_data(ir_dev);
+       if (!data || !data->enabled)
+               return 0;
+
        while (pos < len) {
                if (__ir_nec_decode(input_dev, evs, len, &pos) > 0)
                        rc++;
@@ -194,8 +279,54 @@ static int ir_nec_decode(struct input_dev *input_dev,
        return rc;
 }
 
+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;
+       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);
+               return -ENOMEM;
+       }
+
+       data->ir_dev = ir_dev;
+       data->enabled = 1;
+
+       spin_lock(&decoder_lock);
+       list_add_tail(&data->list, &decoder_list);
+       spin_unlock(&decoder_lock);
+
+       return 0;
+}
+
+static int ir_nec_unregister(struct input_dev *input_dev)
+{
+       struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+       static struct decoder_data *data;
+
+       data = get_decoder_data(ir_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);
+
+       return 0;
+}
+
 static struct ir_raw_handler nec_handler = {
-       .decode = ir_nec_decode,
+       .decode         = ir_nec_decode,
+       .raw_register   = ir_nec_register,
+       .raw_unregister = ir_nec_unregister,
 };
 
 static int __init ir_nec_decode_init(void)
index 11f23f4491b2e6c5c31de5b4977a3cd2349f4bd6..371d88e5a586dbcb02f182c02cf6fb43d761387c 100644 (file)
@@ -223,7 +223,7 @@ static void init_decoders(struct work_struct *work)
 void ir_raw_init(void)
 {
        spin_lock_init(&ir_raw_handler_lock);
-       
+
 #ifdef MODULE
        INIT_WORK(&wq_load, init_decoders);
        schedule_work(&wq_load);