diff options
author | David Härdeman <david@hardeman.nu> | 2010-06-13 16:29:31 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-08-02 13:54:27 -0400 |
commit | 667c9ebe97f7e5f1e48e7eb321644c6fb1668de5 (patch) | |
tree | 11dae4e3d480960fe697964776222b16ee0ecce8 /drivers/media/IR/ir-sysfs.c | |
parent | 0dc50942d6f23989ffb3024aa2271941ec44aea8 (diff) |
V4L/DVB: ir-core: centralize sysfs raw decoder enabling/disabling
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>
Diffstat (limited to 'drivers/media/IR/ir-sysfs.c')
-rw-r--r-- | drivers/media/IR/ir-sysfs.c | 252 |
1 files changed, 148 insertions, 104 deletions
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c index 2098dd1488e0..005621d067f0 100644 --- a/drivers/media/IR/ir-sysfs.c +++ b/drivers/media/IR/ir-sysfs.c | |||
@@ -34,122 +34,178 @@ static struct class ir_input_class = { | |||
34 | }; | 34 | }; |
35 | 35 | ||
36 | /** | 36 | /** |
37 | * show_protocol() - shows the current IR protocol | 37 | * show_protocols() - shows the current IR protocol(s) |
38 | * @d: the device descriptor | 38 | * @d: the device descriptor |
39 | * @mattr: the device attribute struct (unused) | 39 | * @mattr: the device attribute struct (unused) |
40 | * @buf: a pointer to the output buffer | 40 | * @buf: a pointer to the output buffer |
41 | * | 41 | * |
42 | * 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(s). |
43 | * it is trigged by reading /sys/class/rc/rc?/current_protocol. | 43 | * it is trigged by reading /sys/class/rc/rc?/protocols. |
44 | * It returns the protocol name, as understood by the driver. | 44 | * It returns the protocol names of supported protocols. |
45 | * Enabled protocols are printed in brackets. | ||
45 | */ | 46 | */ |
46 | static ssize_t show_protocol(struct device *d, | 47 | static ssize_t show_protocols(struct device *d, |
47 | struct device_attribute *mattr, char *buf) | 48 | struct device_attribute *mattr, char *buf) |
48 | { | 49 | { |
49 | char *s; | ||
50 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); | 50 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); |
51 | u64 ir_type = ir_dev->rc_tab.ir_type; | 51 | u64 allowed, enabled; |
52 | 52 | char *tmp = buf; | |
53 | IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type); | 53 | |
54 | 54 | if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { | |
55 | /* FIXME: doesn't support multiple protocols at the same time */ | 55 | enabled = ir_dev->rc_tab.ir_type; |
56 | if (ir_type == IR_TYPE_UNKNOWN) | 56 | allowed = ir_dev->props->allowed_protos; |
57 | s = "Unknown"; | 57 | } else { |
58 | else if (ir_type == IR_TYPE_RC5) | 58 | enabled = ir_dev->raw->enabled_protocols; |
59 | s = "rc-5"; | 59 | allowed = ir_raw_get_allowed_protocols(); |
60 | else if (ir_type == IR_TYPE_NEC) | 60 | } |
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"; | ||
68 | else | ||
69 | s = "other"; | ||
70 | 61 | ||
71 | return sprintf(buf, "%s\n", s); | 62 | IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", |
63 | (long long)allowed, | ||
64 | (long long)enabled); | ||
65 | |||
66 | if (allowed & enabled & IR_TYPE_UNKNOWN) | ||
67 | tmp += sprintf(tmp, "[unknown] "); | ||
68 | else if (allowed & IR_TYPE_UNKNOWN) | ||
69 | tmp += sprintf(tmp, "unknown "); | ||
70 | |||
71 | if (allowed & enabled & IR_TYPE_RC5) | ||
72 | tmp += sprintf(tmp, "[rc5] "); | ||
73 | else if (allowed & IR_TYPE_RC5) | ||
74 | tmp += sprintf(tmp, "rc5 "); | ||
75 | |||
76 | if (allowed & enabled & IR_TYPE_NEC) | ||
77 | tmp += sprintf(tmp, "[nec] "); | ||
78 | else if (allowed & IR_TYPE_NEC) | ||
79 | tmp += sprintf(tmp, "nec "); | ||
80 | |||
81 | if (allowed & enabled & IR_TYPE_RC6) | ||
82 | tmp += sprintf(tmp, "[rc6] "); | ||
83 | else if (allowed & IR_TYPE_RC6) | ||
84 | tmp += sprintf(tmp, "rc6 "); | ||
85 | |||
86 | if (allowed & enabled & IR_TYPE_JVC) | ||
87 | tmp += sprintf(tmp, "[jvc] "); | ||
88 | else if (allowed & IR_TYPE_JVC) | ||
89 | tmp += sprintf(tmp, "jvc "); | ||
90 | |||
91 | if (allowed & enabled & IR_TYPE_SONY) | ||
92 | tmp += sprintf(tmp, "[sony] "); | ||
93 | else if (allowed & IR_TYPE_SONY) | ||
94 | tmp += sprintf(tmp, "sony "); | ||
95 | |||
96 | if (tmp != buf) | ||
97 | tmp--; | ||
98 | *tmp = '\n'; | ||
99 | return tmp + 1 - buf; | ||
72 | } | 100 | } |
73 | 101 | ||
74 | /** | 102 | /** |
75 | * store_protocol() - shows the current IR protocol | 103 | * store_protocols() - changes the current IR protocol(s) |
76 | * @d: the device descriptor | 104 | * @d: the device descriptor |
77 | * @mattr: the device attribute struct (unused) | 105 | * @mattr: the device attribute struct (unused) |
78 | * @buf: a pointer to the input buffer | 106 | * @buf: a pointer to the input buffer |
79 | * @len: length of the input buffer | 107 | * @len: length of the input buffer |
80 | * | 108 | * |
81 | * This routine is a callback routine for changing the IR protocol type. | 109 | * This routine is a callback routine for changing the IR protocol type. |
82 | * it is trigged by reading /sys/class/rc/rc?/current_protocol. | 110 | * It is trigged by writing to /sys/class/rc/rc?/protocols. |
83 | * It changes the IR the protocol name, if the IR type is recognized | 111 | * Writing "+proto" will add a protocol to the list of enabled protocols. |
84 | * by the driver. | 112 | * Writing "-proto" will remove a protocol from the list of enabled protocols. |
85 | * If an unknown protocol name is used, returns -EINVAL. | 113 | * Writing "proto" will enable only "proto". |
114 | * Returns -EINVAL if an invalid protocol combination or unknown protocol name | ||
115 | * is used, otherwise @len. | ||
86 | */ | 116 | */ |
87 | static ssize_t store_protocol(struct device *d, | 117 | static ssize_t store_protocols(struct device *d, |
88 | struct device_attribute *mattr, | 118 | struct device_attribute *mattr, |
89 | const char *data, | 119 | const char *data, |
90 | size_t len) | 120 | size_t len) |
91 | { | 121 | { |
92 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); | 122 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); |
93 | u64 ir_type = 0; | 123 | bool enable, disable; |
94 | int rc = -EINVAL; | 124 | const char *tmp; |
125 | u64 type; | ||
126 | u64 mask; | ||
127 | int rc; | ||
95 | unsigned long flags; | 128 | unsigned long flags; |
96 | char *buf; | 129 | |
97 | 130 | tmp = skip_spaces(data); | |
98 | while ((buf = strsep((char **) &data, " \n")) != NULL) { | 131 | |
99 | if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5")) | 132 | if (*tmp == '+') { |
100 | ir_type |= IR_TYPE_RC5; | 133 | enable = true; |
101 | if (!strcasecmp(buf, "nec")) | 134 | disable = false; |
102 | ir_type |= IR_TYPE_NEC; | 135 | tmp++; |
103 | if (!strcasecmp(buf, "jvc")) | 136 | } else if (*tmp == '-') { |
104 | ir_type |= IR_TYPE_JVC; | 137 | enable = false; |
105 | if (!strcasecmp(buf, "sony")) | 138 | disable = true; |
106 | ir_type |= IR_TYPE_SONY; | 139 | tmp++; |
140 | } else { | ||
141 | enable = false; | ||
142 | disable = false; | ||
107 | } | 143 | } |
108 | 144 | ||
109 | if (!ir_type) { | 145 | if (!strncasecmp(tmp, "unknown", 7)) { |
146 | tmp += 7; | ||
147 | mask = IR_TYPE_UNKNOWN; | ||
148 | } else if (!strncasecmp(tmp, "rc5", 3)) { | ||
149 | tmp += 3; | ||
150 | mask = IR_TYPE_RC5; | ||
151 | } else if (!strncasecmp(tmp, "nec", 3)) { | ||
152 | tmp += 3; | ||
153 | mask = IR_TYPE_NEC; | ||
154 | } else if (!strncasecmp(tmp, "rc6", 3)) { | ||
155 | tmp += 3; | ||
156 | mask = IR_TYPE_RC6; | ||
157 | } else if (!strncasecmp(tmp, "jvc", 3)) { | ||
158 | tmp += 3; | ||
159 | mask = IR_TYPE_JVC; | ||
160 | } else if (!strncasecmp(tmp, "sony", 4)) { | ||
161 | tmp += 4; | ||
162 | mask = IR_TYPE_SONY; | ||
163 | } else { | ||
110 | IR_dprintk(1, "Unknown protocol\n"); | 164 | IR_dprintk(1, "Unknown protocol\n"); |
111 | return -EINVAL; | 165 | return -EINVAL; |
112 | } | 166 | } |
113 | 167 | ||
114 | if (ir_dev->props && ir_dev->props->change_protocol) | 168 | tmp = skip_spaces(tmp); |
115 | rc = ir_dev->props->change_protocol(ir_dev->props->priv, | 169 | if (*tmp != '\0') { |
116 | ir_type); | 170 | IR_dprintk(1, "Invalid trailing characters\n"); |
117 | |||
118 | if (rc < 0) { | ||
119 | IR_dprintk(1, "Error setting protocol to %lld\n", | ||
120 | (long long)ir_type); | ||
121 | return -EINVAL; | 171 | return -EINVAL; |
122 | } | 172 | } |
123 | 173 | ||
124 | spin_lock_irqsave(&ir_dev->rc_tab.lock, flags); | 174 | if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) |
125 | ir_dev->rc_tab.ir_type = ir_type; | 175 | type = ir_dev->rc_tab.ir_type; |
126 | spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); | 176 | else |
177 | type = ir_dev->raw->enabled_protocols; | ||
127 | 178 | ||
128 | IR_dprintk(1, "Current protocol(s) is(are) %lld\n", | 179 | if (enable) |
129 | (long long)ir_type); | 180 | type |= mask; |
181 | else if (disable) | ||
182 | type &= ~mask; | ||
183 | else | ||
184 | type = mask; | ||
130 | 185 | ||
131 | return len; | 186 | if (ir_dev->props && ir_dev->props->change_protocol) { |
132 | } | 187 | rc = ir_dev->props->change_protocol(ir_dev->props->priv, |
188 | type); | ||
189 | if (rc < 0) { | ||
190 | IR_dprintk(1, "Error setting protocols to 0x%llx\n", | ||
191 | (long long)type); | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | } | ||
133 | 195 | ||
134 | static ssize_t show_supported_protocols(struct device *d, | 196 | if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { |
135 | struct device_attribute *mattr, char *buf) | 197 | spin_lock_irqsave(&ir_dev->rc_tab.lock, flags); |
136 | { | 198 | ir_dev->rc_tab.ir_type = type; |
137 | char *orgbuf = buf; | 199 | spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); |
138 | struct ir_input_dev *ir_dev = dev_get_drvdata(d); | 200 | } else { |
201 | ir_dev->raw->enabled_protocols = type; | ||
202 | } | ||
139 | 203 | ||
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 | 204 | ||
150 | buf += sprintf(buf - 1, "\n"); | 205 | IR_dprintk(1, "Current protocol(s): 0x%llx\n", |
206 | (long long)type); | ||
151 | 207 | ||
152 | return buf - orgbuf; | 208 | return len; |
153 | } | 209 | } |
154 | 210 | ||
155 | #define ADD_HOTPLUG_VAR(fmt, val...) \ | 211 | #define ADD_HOTPLUG_VAR(fmt, val...) \ |
@@ -159,7 +215,7 @@ static ssize_t show_supported_protocols(struct device *d, | |||
159 | return err; \ | 215 | return err; \ |
160 | } while (0) | 216 | } while (0) |
161 | 217 | ||
162 | static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env) | 218 | static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) |
163 | { | 219 | { |
164 | struct ir_input_dev *ir_dev = dev_get_drvdata(device); | 220 | struct ir_input_dev *ir_dev = dev_get_drvdata(device); |
165 | 221 | ||
@@ -174,34 +230,26 @@ static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env) | |||
174 | /* | 230 | /* |
175 | * Static device attribute struct with the sysfs attributes for IR's | 231 | * Static device attribute struct with the sysfs attributes for IR's |
176 | */ | 232 | */ |
177 | static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR, | 233 | static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR, |
178 | show_protocol, store_protocol); | 234 | show_protocols, store_protocols); |
179 | |||
180 | static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR, | ||
181 | show_supported_protocols, NULL); | ||
182 | 235 | ||
183 | static struct attribute *ir_hw_dev_attrs[] = { | 236 | static struct attribute *rc_dev_attrs[] = { |
184 | &dev_attr_protocol.attr, | 237 | &dev_attr_protocols.attr, |
185 | &dev_attr_supported_protocols.attr, | ||
186 | NULL, | 238 | NULL, |
187 | }; | 239 | }; |
188 | 240 | ||
189 | static struct attribute_group ir_hw_dev_attr_grp = { | 241 | static struct attribute_group rc_dev_attr_grp = { |
190 | .attrs = ir_hw_dev_attrs, | 242 | .attrs = rc_dev_attrs, |
191 | }; | 243 | }; |
192 | 244 | ||
193 | static const struct attribute_group *ir_hw_dev_attr_groups[] = { | 245 | static const struct attribute_group *rc_dev_attr_groups[] = { |
194 | &ir_hw_dev_attr_grp, | 246 | &rc_dev_attr_grp, |
195 | NULL | 247 | NULL |
196 | }; | 248 | }; |
197 | 249 | ||
198 | static struct device_type rc_dev_type = { | 250 | static struct device_type rc_dev_type = { |
199 | .groups = ir_hw_dev_attr_groups, | 251 | .groups = rc_dev_attr_groups, |
200 | .uevent = ir_dev_uevent, | 252 | .uevent = rc_dev_uevent, |
201 | }; | ||
202 | |||
203 | static struct device_type ir_raw_dev_type = { | ||
204 | .uevent = ir_dev_uevent, | ||
205 | }; | 253 | }; |
206 | 254 | ||
207 | /** | 255 | /** |
@@ -221,11 +269,7 @@ int ir_register_class(struct input_dev *input_dev) | |||
221 | if (unlikely(devno < 0)) | 269 | if (unlikely(devno < 0)) |
222 | return devno; | 270 | return devno; |
223 | 271 | ||
224 | if (ir_dev->props) { | 272 | ir_dev->dev.type = &rc_dev_type; |
225 | if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) | ||
226 | ir_dev->dev.type = &rc_dev_type; | ||
227 | } else | ||
228 | ir_dev->dev.type = &ir_raw_dev_type; | ||
229 | 273 | ||
230 | ir_dev->dev.class = &ir_input_class; | 274 | ir_dev->dev.class = &ir_input_class; |
231 | ir_dev->dev.parent = input_dev->dev.parent; | 275 | ir_dev->dev.parent = input_dev->dev.parent; |