diff options
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; |