diff options
| -rw-r--r-- | drivers/hid/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/hid/hid-wiimote.c | 165 |
2 files changed, 107 insertions, 59 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 306b15f39c9c..1130a8987125 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig | |||
| @@ -589,6 +589,7 @@ config HID_WACOM_POWER_SUPPLY | |||
| 589 | config HID_WIIMOTE | 589 | config HID_WIIMOTE |
| 590 | tristate "Nintendo Wii Remote support" | 590 | tristate "Nintendo Wii Remote support" |
| 591 | depends on BT_HIDP | 591 | depends on BT_HIDP |
| 592 | depends on LEDS_CLASS | ||
| 592 | ---help--- | 593 | ---help--- |
| 593 | Support for the Nintendo Wii Remote bluetooth device. | 594 | Support for the Nintendo Wii Remote bluetooth device. |
| 594 | 595 | ||
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 | ||
