diff options
author | David Herrmann <dh.herrmann@googlemail.com> | 2011-08-17 05:43:22 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2011-08-23 04:55:21 -0400 |
commit | 23a5a4a39eddbe515a832767a371cc54e82cc25e (patch) | |
tree | 749dfe3d46b6ae45af39d8df6026e511bdf5e2e5 /drivers/hid/hid-wiimote.c | |
parent | 26af17484a737aaa991a7ce578cb15809a582fbc (diff) |
HID: wiimote: Register led class devices
This registers 4 led devices to allow controlling the wiimote leds via standard
LED sysfs API. It removes the four sysfs attributes so we don't have two APIs
for one device.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-wiimote.c')
-rw-r--r-- | drivers/hid/hid-wiimote.c | 165 |
1 files changed, 106 insertions, 59 deletions
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c index d49f67c7a00c..29edd55d4bb0 100644 --- a/drivers/hid/hid-wiimote.c +++ b/drivers/hid/hid-wiimote.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/device.h> | 13 | #include <linux/device.h> |
14 | #include <linux/hid.h> | 14 | #include <linux/hid.h> |
15 | #include <linux/input.h> | 15 | #include <linux/input.h> |
16 | #include <linux/leds.h> | ||
16 | #include <linux/module.h> | 17 | #include <linux/module.h> |
17 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
18 | #include "hid-ids.h" | 19 | #include "hid-ids.h" |
@@ -34,6 +35,7 @@ struct wiimote_state { | |||
34 | struct wiimote_data { | 35 | struct wiimote_data { |
35 | struct hid_device *hdev; | 36 | struct hid_device *hdev; |
36 | struct input_dev *input; | 37 | struct input_dev *input; |
38 | struct led_classdev *leds[4]; | ||
37 | 39 | ||
38 | spinlock_t qlock; | 40 | spinlock_t qlock; |
39 | __u8 head; | 41 | __u8 head; |
@@ -51,6 +53,9 @@ struct wiimote_data { | |||
51 | #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ | 53 | #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ |
52 | WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) | 54 | WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) |
53 | 55 | ||
56 | /* return flag for led \num */ | ||
57 | #define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1)) | ||
58 | |||
54 | enum wiiproto_reqs { | 59 | enum wiiproto_reqs { |
55 | WIIPROTO_REQ_LED = 0x11, | 60 | WIIPROTO_REQ_LED = 0x11, |
56 | WIIPROTO_REQ_DRM_K = 0x30, | 61 | WIIPROTO_REQ_DRM_K = 0x30, |
@@ -85,9 +90,6 @@ static __u16 wiiproto_keymap[] = { | |||
85 | BTN_MODE, /* WIIPROTO_KEY_HOME */ | 90 | BTN_MODE, /* WIIPROTO_KEY_HOME */ |
86 | }; | 91 | }; |
87 | 92 | ||
88 | #define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \ | ||
89 | dev)) | ||
90 | |||
91 | 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, |
92 | size_t count) | 94 | size_t count) |
93 | { | 95 | { |
@@ -190,48 +192,53 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds) | |||
190 | wiimote_queue(wdata, cmd, sizeof(cmd)); | 192 | wiimote_queue(wdata, cmd, sizeof(cmd)); |
191 | } | 193 | } |
192 | 194 | ||
193 | #define wiifs_led_show_set(num) \ | 195 | static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev) |
194 | static ssize_t wiifs_led_show_##num(struct device *dev, \ | 196 | { |
195 | struct device_attribute *attr, char *buf) \ | 197 | struct wiimote_data *wdata; |
196 | { \ | 198 | struct device *dev = led_dev->dev->parent; |
197 | struct wiimote_data *wdata = dev_to_wii(dev); \ | 199 | int i; |
198 | unsigned long flags; \ | 200 | unsigned long flags; |
199 | int state; \ | 201 | bool value = false; |
200 | \ | 202 | |
201 | spin_lock_irqsave(&wdata->state.lock, flags); \ | 203 | wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev)); |
202 | state = !!(wdata->state.flags & WIIPROTO_FLAG_LED##num); \ | 204 | |
203 | spin_unlock_irqrestore(&wdata->state.lock, flags); \ | 205 | for (i = 0; i < 4; ++i) { |
204 | \ | 206 | if (wdata->leds[i] == led_dev) { |
205 | return sprintf(buf, "%d\n", state); \ | 207 | spin_lock_irqsave(&wdata->state.lock, flags); |
206 | } \ | 208 | value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1); |
207 | static ssize_t wiifs_led_set_##num(struct device *dev, \ | 209 | spin_unlock_irqrestore(&wdata->state.lock, flags); |
208 | struct device_attribute *attr, const char *buf, size_t count) \ | 210 | break; |
209 | { \ | 211 | } |
210 | struct wiimote_data *wdata = dev_to_wii(dev); \ | 212 | } |
211 | int tmp = simple_strtoul(buf, NULL, 10); \ | 213 | |
212 | unsigned long flags; \ | 214 | return value ? LED_FULL : LED_OFF; |
213 | __u8 state; \ | 215 | } |
214 | \ | 216 | |
215 | spin_lock_irqsave(&wdata->state.lock, flags); \ | 217 | static void wiimote_leds_set(struct led_classdev *led_dev, |
216 | \ | 218 | enum led_brightness value) |
217 | state = wdata->state.flags; \ | 219 | { |
218 | \ | 220 | struct wiimote_data *wdata; |
219 | if (tmp) \ | 221 | struct device *dev = led_dev->dev->parent; |
220 | wiiproto_req_leds(wdata, state | WIIPROTO_FLAG_LED##num);\ | 222 | int i; |
221 | else \ | 223 | unsigned long flags; |
222 | wiiproto_req_leds(wdata, state & ~WIIPROTO_FLAG_LED##num);\ | 224 | __u8 state, flag; |
223 | \ | 225 | |
224 | spin_unlock_irqrestore(&wdata->state.lock, flags); \ | 226 | wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev)); |
225 | \ | 227 | |
226 | return count; \ | 228 | for (i = 0; i < 4; ++i) { |
227 | } \ | 229 | if (wdata->leds[i] == led_dev) { |
228 | static DEVICE_ATTR(led##num, S_IRUGO | S_IWUSR, wiifs_led_show_##num, \ | 230 | flag = WIIPROTO_FLAG_LED(i + 1); |
229 | wiifs_led_set_##num) | 231 | spin_lock_irqsave(&wdata->state.lock, flags); |
230 | 232 | state = wdata->state.flags; | |
231 | wiifs_led_show_set(1); | 233 | if (value == LED_OFF) |
232 | wiifs_led_show_set(2); | 234 | wiiproto_req_leds(wdata, state & ~flag); |
233 | wiifs_led_show_set(3); | 235 | else |
234 | wiifs_led_show_set(4); | 236 | wiiproto_req_leds(wdata, state | flag); |
237 | spin_unlock_irqrestore(&wdata->state.lock, flags); | ||
238 | break; | ||
239 | } | ||
240 | } | ||
241 | } | ||
235 | 242 | ||
236 | static int wiimote_input_event(struct input_dev *dev, unsigned int type, | 243 | static int wiimote_input_event(struct input_dev *dev, unsigned int type, |
237 | unsigned int code, int value) | 244 | unsigned int code, int value) |
@@ -315,6 +322,58 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report, | |||
315 | return 0; | 322 | return 0; |
316 | } | 323 | } |
317 | 324 | ||
325 | static void wiimote_leds_destroy(struct wiimote_data *wdata) | ||
326 | { | ||
327 | int i; | ||
328 | struct led_classdev *led; | ||
329 | |||
330 | for (i = 0; i < 4; ++i) { | ||
331 | if (wdata->leds[i]) { | ||
332 | led = wdata->leds[i]; | ||
333 | wdata->leds[i] = NULL; | ||
334 | led_classdev_unregister(led); | ||
335 | kfree(led); | ||
336 | } | ||
337 | } | ||
338 | } | ||
339 | |||
340 | static int wiimote_leds_create(struct wiimote_data *wdata) | ||
341 | { | ||
342 | int i, ret; | ||
343 | struct device *dev = &wdata->hdev->dev; | ||
344 | size_t namesz = strlen(dev_name(dev)) + 9; | ||
345 | struct led_classdev *led; | ||
346 | char *name; | ||
347 | |||
348 | for (i = 0; i < 4; ++i) { | ||
349 | led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL); | ||
350 | if (!led) { | ||
351 | ret = -ENOMEM; | ||
352 | goto err; | ||
353 | } | ||
354 | name = (void*)&led[1]; | ||
355 | snprintf(name, namesz, "%s:blue:p%d", dev_name(dev), i); | ||
356 | led->name = name; | ||
357 | led->brightness = 0; | ||
358 | led->max_brightness = 1; | ||
359 | led->brightness_get = wiimote_leds_get; | ||
360 | led->brightness_set = wiimote_leds_set; | ||
361 | |||
362 | ret = led_classdev_register(dev, led); | ||
363 | if (ret) { | ||
364 | kfree(led); | ||
365 | goto err; | ||
366 | } | ||
367 | wdata->leds[i] = led; | ||
368 | } | ||
369 | |||
370 | return 0; | ||
371 | |||
372 | err: | ||
373 | wiimote_leds_destroy(wdata); | ||
374 | return ret; | ||
375 | } | ||
376 | |||
318 | static struct wiimote_data *wiimote_create(struct hid_device *hdev) | 377 | static struct wiimote_data *wiimote_create(struct hid_device *hdev) |
319 | { | 378 | { |
320 | struct wiimote_data *wdata; | 379 | struct wiimote_data *wdata; |
@@ -358,10 +417,7 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev) | |||
358 | 417 | ||
359 | static void wiimote_destroy(struct wiimote_data *wdata) | 418 | static void wiimote_destroy(struct wiimote_data *wdata) |
360 | { | 419 | { |
361 | device_remove_file(&wdata->hdev->dev, &dev_attr_led1); | 420 | wiimote_leds_destroy(wdata); |
362 | device_remove_file(&wdata->hdev->dev, &dev_attr_led2); | ||
363 | device_remove_file(&wdata->hdev->dev, &dev_attr_led3); | ||
364 | device_remove_file(&wdata->hdev->dev, &dev_attr_led4); | ||
365 | 421 | ||
366 | input_unregister_device(wdata->input); | 422 | input_unregister_device(wdata->input); |
367 | cancel_work_sync(&wdata->worker); | 423 | cancel_work_sync(&wdata->worker); |
@@ -400,16 +456,7 @@ static int wiimote_hid_probe(struct hid_device *hdev, | |||
400 | goto err_stop; | 456 | goto err_stop; |
401 | } | 457 | } |
402 | 458 | ||
403 | ret = device_create_file(&hdev->dev, &dev_attr_led1); | 459 | ret = wiimote_leds_create(wdata); |
404 | if (ret) | ||
405 | goto err_free; | ||
406 | ret = device_create_file(&hdev->dev, &dev_attr_led2); | ||
407 | if (ret) | ||
408 | goto err_free; | ||
409 | ret = device_create_file(&hdev->dev, &dev_attr_led3); | ||
410 | if (ret) | ||
411 | goto err_free; | ||
412 | ret = device_create_file(&hdev->dev, &dev_attr_led4); | ||
413 | if (ret) | 460 | if (ret) |
414 | goto err_free; | 461 | goto err_free; |
415 | 462 | ||