diff options
author | David Herrmann <dh.herrmann@googlemail.com> | 2011-07-05 07:45:19 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2011-07-11 08:30:24 -0400 |
commit | 3c1c2fce64fdfa2f0c0ff4fffb3bb171ea6361ca (patch) | |
tree | 58ba2f4c42cf84fbe23e0d7661c7c232ecf5c8de /drivers/hid | |
parent | 32a0d9a522b577d0efa6ce793a6ac0516c5e3627 (diff) |
HID: wiimote: Add sysfs support to wiimote driver
Add sysfs files for each led of the wiimote. Writing 1 to the file
enables the led and 0 disables the led.
We do not need memory barriers when checking wdata->ready since we use
a spinlock directly after it.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-wiimote.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c index f9a3bcb6b240..a594383ce03d 100644 --- a/drivers/hid/hid-wiimote.c +++ b/drivers/hid/hid-wiimote.c | |||
@@ -87,6 +87,9 @@ static __u16 wiiproto_keymap[] = { | |||
87 | BTN_MODE, /* WIIPROTO_KEY_HOME */ | 87 | BTN_MODE, /* WIIPROTO_KEY_HOME */ |
88 | }; | 88 | }; |
89 | 89 | ||
90 | #define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \ | ||
91 | dev)) | ||
92 | |||
90 | static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer, | 93 | static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer, |
91 | size_t count) | 94 | size_t count) |
92 | { | 95 | { |
@@ -189,6 +192,55 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds) | |||
189 | wiimote_queue(wdata, cmd, sizeof(cmd)); | 192 | wiimote_queue(wdata, cmd, sizeof(cmd)); |
190 | } | 193 | } |
191 | 194 | ||
195 | #define wiifs_led_show_set(num) \ | ||
196 | static ssize_t wiifs_led_show_##num(struct device *dev, \ | ||
197 | struct device_attribute *attr, char *buf) \ | ||
198 | { \ | ||
199 | struct wiimote_data *wdata = dev_to_wii(dev); \ | ||
200 | unsigned long flags; \ | ||
201 | int state; \ | ||
202 | \ | ||
203 | if (!atomic_read(&wdata->ready)) \ | ||
204 | return -EBUSY; \ | ||
205 | \ | ||
206 | spin_lock_irqsave(&wdata->state.lock, flags); \ | ||
207 | state = !!(wdata->state.flags & WIIPROTO_FLAG_LED##num); \ | ||
208 | spin_unlock_irqrestore(&wdata->state.lock, flags); \ | ||
209 | \ | ||
210 | return sprintf(buf, "%d\n", state); \ | ||
211 | } \ | ||
212 | static ssize_t wiifs_led_set_##num(struct device *dev, \ | ||
213 | struct device_attribute *attr, const char *buf, size_t count) \ | ||
214 | { \ | ||
215 | struct wiimote_data *wdata = dev_to_wii(dev); \ | ||
216 | int tmp = simple_strtoul(buf, NULL, 10); \ | ||
217 | unsigned long flags; \ | ||
218 | __u8 state; \ | ||
219 | \ | ||
220 | if (!atomic_read(&wdata->ready)) \ | ||
221 | return -EBUSY; \ | ||
222 | \ | ||
223 | spin_lock_irqsave(&wdata->state.lock, flags); \ | ||
224 | \ | ||
225 | state = wdata->state.flags; \ | ||
226 | \ | ||
227 | if (tmp) \ | ||
228 | wiiproto_req_leds(wdata, state | WIIPROTO_FLAG_LED##num);\ | ||
229 | else \ | ||
230 | wiiproto_req_leds(wdata, state & ~WIIPROTO_FLAG_LED##num);\ | ||
231 | \ | ||
232 | spin_unlock_irqrestore(&wdata->state.lock, flags); \ | ||
233 | \ | ||
234 | return count; \ | ||
235 | } \ | ||
236 | static DEVICE_ATTR(led##num, S_IRUGO | S_IWUSR, wiifs_led_show_##num, \ | ||
237 | wiifs_led_set_##num) | ||
238 | |||
239 | wiifs_led_show_set(1); | ||
240 | wiifs_led_show_set(2); | ||
241 | wiifs_led_show_set(3); | ||
242 | wiifs_led_show_set(4); | ||
243 | |||
192 | static int wiimote_input_event(struct input_dev *dev, unsigned int type, | 244 | static int wiimote_input_event(struct input_dev *dev, unsigned int type, |
193 | unsigned int code, int value) | 245 | unsigned int code, int value) |
194 | { | 246 | { |
@@ -325,6 +377,19 @@ static int wiimote_hid_probe(struct hid_device *hdev, | |||
325 | return -ENOMEM; | 377 | return -ENOMEM; |
326 | } | 378 | } |
327 | 379 | ||
380 | ret = device_create_file(&hdev->dev, &dev_attr_led1); | ||
381 | if (ret) | ||
382 | goto err; | ||
383 | ret = device_create_file(&hdev->dev, &dev_attr_led2); | ||
384 | if (ret) | ||
385 | goto err; | ||
386 | ret = device_create_file(&hdev->dev, &dev_attr_led3); | ||
387 | if (ret) | ||
388 | goto err; | ||
389 | ret = device_create_file(&hdev->dev, &dev_attr_led4); | ||
390 | if (ret) | ||
391 | goto err; | ||
392 | |||
328 | ret = hid_parse(hdev); | 393 | ret = hid_parse(hdev); |
329 | if (ret) { | 394 | if (ret) { |
330 | hid_err(hdev, "HID parse failed\n"); | 395 | hid_err(hdev, "HID parse failed\n"); |
@@ -359,6 +424,10 @@ err_stop: | |||
359 | hid_hw_stop(hdev); | 424 | hid_hw_stop(hdev); |
360 | err: | 425 | err: |
361 | input_free_device(wdata->input); | 426 | input_free_device(wdata->input); |
427 | device_remove_file(&hdev->dev, &dev_attr_led1); | ||
428 | device_remove_file(&hdev->dev, &dev_attr_led2); | ||
429 | device_remove_file(&hdev->dev, &dev_attr_led3); | ||
430 | device_remove_file(&hdev->dev, &dev_attr_led4); | ||
362 | wiimote_destroy(wdata); | 431 | wiimote_destroy(wdata); |
363 | return ret; | 432 | return ret; |
364 | } | 433 | } |
@@ -369,6 +438,11 @@ static void wiimote_hid_remove(struct hid_device *hdev) | |||
369 | 438 | ||
370 | hid_info(hdev, "Device removed\n"); | 439 | hid_info(hdev, "Device removed\n"); |
371 | 440 | ||
441 | device_remove_file(&hdev->dev, &dev_attr_led1); | ||
442 | device_remove_file(&hdev->dev, &dev_attr_led2); | ||
443 | device_remove_file(&hdev->dev, &dev_attr_led3); | ||
444 | device_remove_file(&hdev->dev, &dev_attr_led4); | ||
445 | |||
372 | hid_hw_stop(hdev); | 446 | hid_hw_stop(hdev); |
373 | input_unregister_device(wdata->input); | 447 | input_unregister_device(wdata->input); |
374 | 448 | ||