diff options
Diffstat (limited to 'drivers/media/IR/ir-sysfs.c')
-rw-r--r-- | drivers/media/IR/ir-sysfs.c | 202 |
1 files changed, 146 insertions, 56 deletions
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c index e14e6c486b52..d7da63e16c92 100644 --- a/drivers/media/IR/ir-sysfs.c +++ b/drivers/media/IR/ir-sysfs.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* ir-register.c - handle IR scancode->keycode tables | 1 | /* ir-sysfs.c - sysfs interface for RC devices (/sys/class/rc) |
2 | * | 2 | * |
3 | * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com> | 3 | * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -15,15 +15,23 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/input.h> | 16 | #include <linux/input.h> |
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <media/ir-core.h> | 18 | #include "ir-core-priv.h" |
19 | 19 | ||
20 | #define IRRCV_NUM_DEVICES 256 | 20 | #define IRRCV_NUM_DEVICES 256 |
21 | 21 | ||
22 | /* bit array to represent IR sysfs device number */ | 22 | /* bit array to represent IR sysfs device number */ |
23 | static unsigned long ir_core_dev_number; | 23 | static unsigned long ir_core_dev_number; |
24 | 24 | ||
25 | /* class for /sys/class/irrcv */ | 25 | /* class for /sys/class/rc */ |
26 | static struct class *ir_input_class; | 26 | static char *ir_devnode(struct device *dev, mode_t *mode) |
27 | { | ||
28 | return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev)); | ||
29 | } | ||
30 | |||
31 | static struct class ir_input_class = { | ||
32 | .name = "rc", | ||
33 | .devnode = ir_devnode, | ||
34 | }; | ||
27 | 35 | ||
28 | /** | 36 | /** |
29 | * show_protocol() - shows the current IR protocol | 37 | * show_protocol() - shows the current IR protocol |
@@ -32,7 +40,7 @@ static struct class *ir_input_class; | |||
32 | * @buf: a pointer to the output buffer | 40 | * @buf: a pointer to the output buffer |
33 | * | 41 | * |
34 | * This routine is a callback routine for input read the IR protocol type. | 42 | * This routine is a callback routine for input read the IR protocol type. |
35 | * it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol. | 43 | * it is trigged by reading /sys/class/rc/rc?/current_protocol. |
36 | * It returns the protocol name, as understood by the driver. | 44 | * It returns the protocol name, as understood by the driver. |
37 | */ | 45 | */ |
38 | static ssize_t show_protocol(struct device *d, | 46 | static ssize_t show_protocol(struct device *d, |
@@ -48,13 +56,17 @@ static ssize_t show_protocol(struct device *d, | |||
48 | if (ir_type == IR_TYPE_UNKNOWN) | 56 | if (ir_type == IR_TYPE_UNKNOWN) |
49 | s = "Unknown"; | 57 | s = "Unknown"; |
50 | else if (ir_type == IR_TYPE_RC5) | 58 | else if (ir_type == IR_TYPE_RC5) |
51 | s = "RC-5"; | 59 | s = "rc-5"; |
52 | else if (ir_type == IR_TYPE_PD) | ||
53 | s = "Pulse/distance"; | ||
54 | else if (ir_type == IR_TYPE_NEC) | 60 | else if (ir_type == IR_TYPE_NEC) |
55 | s = "NEC"; | 61 | s = "nec"; |
62 | else if (ir_type == IR_TYPE_RC6) | ||
63 | s = "rc6"; | ||
64 | else if (ir_type == IR_TYPE_JVC) | ||
65 | s = "jvc"; | ||
66 | else if (ir_type == IR_TYPE_SONY) | ||
67 | s = "sony"; | ||
56 | else | 68 | else |
57 | s = "Other"; | 69 | s = "other"; |
58 | 70 | ||
59 | return sprintf(buf, "%s\n", s); | 71 | return sprintf(buf, "%s\n", s); |
60 | } | 72 | } |
@@ -67,7 +79,7 @@ static ssize_t show_protocol(struct device *d, | |||
67 | * @len: length of the input buffer | 79 | * @len: length of the input buffer |
68 | * | 80 | * |
69 | * This routine is a callback routine for changing the IR protocol type. | 81 | * This routine is a callback routine for changing the IR protocol type. |
70 | * it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol. | 82 | * it is trigged by reading /sys/class/rc/rc?/current_protocol. |
71 | * It changes the IR the protocol name, if the IR type is recognized | 83 | * It changes the IR the protocol name, if the IR type is recognized |
72 | * by the driver. | 84 | * by the driver. |
73 | * If an unknown protocol name is used, returns -EINVAL. | 85 | * If an unknown protocol name is used, returns -EINVAL. |
@@ -78,23 +90,24 @@ static ssize_t store_protocol(struct device *d, | |||
78 | size_t len) | 90 | size_t len) |
79 | { | 91 | { |
80 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); | 92 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); |
81 | u64 ir_type = IR_TYPE_UNKNOWN; | 93 | u64 ir_type = 0; |
82 | int rc = -EINVAL; | 94 | int rc = -EINVAL; |
83 | unsigned long flags; | 95 | unsigned long flags; |
84 | char *buf; | 96 | char *buf; |
85 | 97 | ||
86 | buf = strsep((char **) &data, "\n"); | 98 | while ((buf = strsep((char **) &data, " \n")) != NULL) { |
87 | 99 | if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5")) | |
88 | if (!strcasecmp(buf, "rc-5")) | 100 | ir_type |= IR_TYPE_RC5; |
89 | ir_type = IR_TYPE_RC5; | 101 | if (!strcasecmp(buf, "nec")) |
90 | else if (!strcasecmp(buf, "pd")) | 102 | ir_type |= IR_TYPE_NEC; |
91 | ir_type = IR_TYPE_PD; | 103 | if (!strcasecmp(buf, "jvc")) |
92 | else if (!strcasecmp(buf, "nec")) | 104 | ir_type |= IR_TYPE_JVC; |
93 | ir_type = IR_TYPE_NEC; | 105 | if (!strcasecmp(buf, "sony")) |
106 | ir_type |= IR_TYPE_SONY; | ||
107 | } | ||
94 | 108 | ||
95 | if (ir_type == IR_TYPE_UNKNOWN) { | 109 | if (!ir_type) { |
96 | IR_dprintk(1, "Error setting protocol to %lld\n", | 110 | IR_dprintk(1, "Unknown protocol\n"); |
97 | (long long)ir_type); | ||
98 | return -EINVAL; | 111 | return -EINVAL; |
99 | } | 112 | } |
100 | 113 | ||
@@ -112,25 +125,87 @@ static ssize_t store_protocol(struct device *d, | |||
112 | ir_dev->rc_tab.ir_type = ir_type; | 125 | ir_dev->rc_tab.ir_type = ir_type; |
113 | spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); | 126 | spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); |
114 | 127 | ||
115 | IR_dprintk(1, "Current protocol is %lld\n", | 128 | IR_dprintk(1, "Current protocol(s) is(are) %lld\n", |
116 | (long long)ir_type); | 129 | (long long)ir_type); |
117 | 130 | ||
118 | return len; | 131 | return len; |
119 | } | 132 | } |
120 | 133 | ||
134 | static ssize_t show_supported_protocols(struct device *d, | ||
135 | struct device_attribute *mattr, char *buf) | ||
136 | { | ||
137 | char *orgbuf = buf; | ||
138 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); | ||
139 | |||
140 | /* FIXME: doesn't support multiple protocols at the same time */ | ||
141 | if (ir_dev->props->allowed_protos == IR_TYPE_UNKNOWN) | ||
142 | buf += sprintf(buf, "unknown "); | ||
143 | if (ir_dev->props->allowed_protos & IR_TYPE_RC5) | ||
144 | buf += sprintf(buf, "rc-5 "); | ||
145 | if (ir_dev->props->allowed_protos & IR_TYPE_NEC) | ||
146 | buf += sprintf(buf, "nec "); | ||
147 | if (buf == orgbuf) | ||
148 | buf += sprintf(buf, "other "); | ||
149 | |||
150 | buf += sprintf(buf - 1, "\n"); | ||
151 | |||
152 | return buf - orgbuf; | ||
153 | } | ||
154 | |||
155 | #define ADD_HOTPLUG_VAR(fmt, val...) \ | ||
156 | do { \ | ||
157 | int err = add_uevent_var(env, fmt, val); \ | ||
158 | if (err) \ | ||
159 | return err; \ | ||
160 | } while (0) | ||
161 | |||
162 | static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env) | ||
163 | { | ||
164 | struct ir_input_dev *ir_dev = dev_get_drvdata(device); | ||
165 | |||
166 | if (ir_dev->rc_tab.name) | ||
167 | ADD_HOTPLUG_VAR("NAME=%s", ir_dev->rc_tab.name); | ||
168 | if (ir_dev->driver_name) | ||
169 | ADD_HOTPLUG_VAR("DRV_NAME=%s", ir_dev->driver_name); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
121 | /* | 174 | /* |
122 | * Static device attribute struct with the sysfs attributes for IR's | 175 | * Static device attribute struct with the sysfs attributes for IR's |
123 | */ | 176 | */ |
124 | static DEVICE_ATTR(current_protocol, S_IRUGO | S_IWUSR, | 177 | static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR, |
125 | show_protocol, store_protocol); | 178 | show_protocol, store_protocol); |
126 | 179 | ||
127 | static struct attribute *ir_dev_attrs[] = { | 180 | static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR, |
128 | &dev_attr_current_protocol.attr, | 181 | show_supported_protocols, NULL); |
182 | |||
183 | static struct attribute *ir_hw_dev_attrs[] = { | ||
184 | &dev_attr_protocol.attr, | ||
185 | &dev_attr_supported_protocols.attr, | ||
129 | NULL, | 186 | NULL, |
130 | }; | 187 | }; |
131 | 188 | ||
189 | static struct attribute_group ir_hw_dev_attr_grp = { | ||
190 | .attrs = ir_hw_dev_attrs, | ||
191 | }; | ||
192 | |||
193 | static const struct attribute_group *ir_hw_dev_attr_groups[] = { | ||
194 | &ir_hw_dev_attr_grp, | ||
195 | NULL | ||
196 | }; | ||
197 | |||
198 | static struct device_type rc_dev_type = { | ||
199 | .groups = ir_hw_dev_attr_groups, | ||
200 | .uevent = ir_dev_uevent, | ||
201 | }; | ||
202 | |||
203 | static struct device_type ir_raw_dev_type = { | ||
204 | .uevent = ir_dev_uevent, | ||
205 | }; | ||
206 | |||
132 | /** | 207 | /** |
133 | * ir_register_class() - creates the sysfs for /sys/class/irrcv/irrcv? | 208 | * ir_register_class() - creates the sysfs for /sys/class/rc/rc? |
134 | * @input_dev: the struct input_dev descriptor of the device | 209 | * @input_dev: the struct input_dev descriptor of the device |
135 | * | 210 | * |
136 | * This routine is used to register the syfs code for IR class | 211 | * This routine is used to register the syfs code for IR class |
@@ -138,8 +213,7 @@ static struct attribute *ir_dev_attrs[] = { | |||
138 | int ir_register_class(struct input_dev *input_dev) | 213 | int ir_register_class(struct input_dev *input_dev) |
139 | { | 214 | { |
140 | int rc; | 215 | int rc; |
141 | struct kobject *kobj; | 216 | const char *path; |
142 | |||
143 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); | 217 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); |
144 | int devno = find_first_zero_bit(&ir_core_dev_number, | 218 | int devno = find_first_zero_bit(&ir_core_dev_number, |
145 | IRRCV_NUM_DEVICES); | 219 | IRRCV_NUM_DEVICES); |
@@ -147,19 +221,36 @@ int ir_register_class(struct input_dev *input_dev) | |||
147 | if (unlikely(devno < 0)) | 221 | if (unlikely(devno < 0)) |
148 | return devno; | 222 | return devno; |
149 | 223 | ||
150 | ir_dev->attr.attrs = ir_dev_attrs; | 224 | if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) |
151 | ir_dev->class_dev = device_create(ir_input_class, NULL, | 225 | ir_dev->dev.type = &rc_dev_type; |
152 | input_dev->dev.devt, ir_dev, | 226 | else |
153 | "irrcv%d", devno); | 227 | ir_dev->dev.type = &ir_raw_dev_type; |
154 | kobj = &ir_dev->class_dev->kobj; | 228 | |
155 | 229 | ir_dev->dev.class = &ir_input_class; | |
156 | printk(KERN_WARNING "Creating IR device %s\n", kobject_name(kobj)); | 230 | ir_dev->dev.parent = input_dev->dev.parent; |
157 | rc = sysfs_create_group(kobj, &ir_dev->attr); | 231 | dev_set_name(&ir_dev->dev, "rc%d", devno); |
158 | if (unlikely(rc < 0)) { | 232 | dev_set_drvdata(&ir_dev->dev, ir_dev); |
159 | device_destroy(ir_input_class, input_dev->dev.devt); | 233 | rc = device_register(&ir_dev->dev); |
160 | return -ENOMEM; | 234 | if (rc) |
235 | return rc; | ||
236 | |||
237 | |||
238 | input_dev->dev.parent = &ir_dev->dev; | ||
239 | rc = input_register_device(input_dev); | ||
240 | if (rc < 0) { | ||
241 | device_del(&ir_dev->dev); | ||
242 | return rc; | ||
161 | } | 243 | } |
162 | 244 | ||
245 | __module_get(THIS_MODULE); | ||
246 | |||
247 | path = kobject_get_path(&ir_dev->dev.kobj, GFP_KERNEL); | ||
248 | printk(KERN_INFO "%s: %s as %s\n", | ||
249 | dev_name(&ir_dev->dev), | ||
250 | input_dev->name ? input_dev->name : "Unspecified device", | ||
251 | path ? path : "N/A"); | ||
252 | kfree(path); | ||
253 | |||
163 | ir_dev->devno = devno; | 254 | ir_dev->devno = devno; |
164 | set_bit(devno, &ir_core_dev_number); | 255 | set_bit(devno, &ir_core_dev_number); |
165 | 256 | ||
@@ -168,7 +259,7 @@ int ir_register_class(struct input_dev *input_dev) | |||
168 | 259 | ||
169 | /** | 260 | /** |
170 | * ir_unregister_class() - removes the sysfs for sysfs for | 261 | * ir_unregister_class() - removes the sysfs for sysfs for |
171 | * /sys/class/irrcv/irrcv? | 262 | * /sys/class/rc/rc? |
172 | * @input_dev: the struct input_dev descriptor of the device | 263 | * @input_dev: the struct input_dev descriptor of the device |
173 | * | 264 | * |
174 | * This routine is used to unregister the syfs code for IR class | 265 | * This routine is used to unregister the syfs code for IR class |
@@ -176,36 +267,35 @@ int ir_register_class(struct input_dev *input_dev) | |||
176 | void ir_unregister_class(struct input_dev *input_dev) | 267 | void ir_unregister_class(struct input_dev *input_dev) |
177 | { | 268 | { |
178 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); | 269 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); |
179 | struct kobject *kobj; | ||
180 | 270 | ||
181 | clear_bit(ir_dev->devno, &ir_core_dev_number); | 271 | clear_bit(ir_dev->devno, &ir_core_dev_number); |
272 | input_unregister_device(input_dev); | ||
273 | device_del(&ir_dev->dev); | ||
182 | 274 | ||
183 | kobj = &ir_dev->class_dev->kobj; | 275 | module_put(THIS_MODULE); |
184 | |||
185 | sysfs_remove_group(kobj, &ir_dev->attr); | ||
186 | device_destroy(ir_input_class, input_dev->dev.devt); | ||
187 | |||
188 | kfree(ir_dev->attr.name); | ||
189 | } | 276 | } |
190 | 277 | ||
191 | /* | 278 | /* |
192 | * Init/exit code for the module. Basically, creates/removes /sys/class/irrcv | 279 | * Init/exit code for the module. Basically, creates/removes /sys/class/rc |
193 | */ | 280 | */ |
194 | 281 | ||
195 | static int __init ir_core_init(void) | 282 | static int __init ir_core_init(void) |
196 | { | 283 | { |
197 | ir_input_class = class_create(THIS_MODULE, "irrcv"); | 284 | int rc = class_register(&ir_input_class); |
198 | if (IS_ERR(ir_input_class)) { | 285 | if (rc) { |
199 | printk(KERN_ERR "ir_core: unable to register irrcv class\n"); | 286 | printk(KERN_ERR "ir_core: unable to register rc class\n"); |
200 | return PTR_ERR(ir_input_class); | 287 | return rc; |
201 | } | 288 | } |
202 | 289 | ||
290 | /* Initialize/load the decoders/keymap code that will be used */ | ||
291 | ir_raw_init(); | ||
292 | |||
203 | return 0; | 293 | return 0; |
204 | } | 294 | } |
205 | 295 | ||
206 | static void __exit ir_core_exit(void) | 296 | static void __exit ir_core_exit(void) |
207 | { | 297 | { |
208 | class_destroy(ir_input_class); | 298 | class_unregister(&ir_input_class); |
209 | } | 299 | } |
210 | 300 | ||
211 | module_init(ir_core_init); | 301 | module_init(ir_core_init); |