diff options
author | David Herrmann <dh.herrmann@googlemail.com> | 2011-09-06 07:50:30 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2011-09-07 07:25:16 -0400 |
commit | f363e4f6ab71168cbdaadeef974b515512b41636 (patch) | |
tree | ca8a6a0e7347ea850d329e5c30a97dad038379a5 | |
parent | efcf91887419ec37ca564073a9fe30db49fe6c7c (diff) |
HID: wiimote: Add IR input device
The IR cam of the wiimote reports 4 trackable lights as absolute values. Since
we can turn the IR cam on and off, we register a separate input device so we can
react on open/close callbacks to save wiimote battery power when IR cam is not
needed.
The cam can be in four states: off, basic, extended and full
The DRM chooser automatically selects a proper DRM that includes all required IR
data so no information is lost.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | drivers/hid/hid-wiimote.c | 71 |
1 files changed, 67 insertions, 4 deletions
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c index de9aadf9218d..4cdaaf6e0307 100644 --- a/drivers/hid/hid-wiimote.c +++ b/drivers/hid/hid-wiimote.c | |||
@@ -38,6 +38,7 @@ struct wiimote_data { | |||
38 | struct input_dev *input; | 38 | struct input_dev *input; |
39 | struct led_classdev *leds[4]; | 39 | struct led_classdev *leds[4]; |
40 | struct input_dev *accel; | 40 | struct input_dev *accel; |
41 | struct input_dev *ir; | ||
41 | 42 | ||
42 | spinlock_t qlock; | 43 | spinlock_t qlock; |
43 | __u8 head; | 44 | __u8 head; |
@@ -54,8 +55,13 @@ struct wiimote_data { | |||
54 | #define WIIPROTO_FLAG_LED4 0x08 | 55 | #define WIIPROTO_FLAG_LED4 0x08 |
55 | #define WIIPROTO_FLAG_RUMBLE 0x10 | 56 | #define WIIPROTO_FLAG_RUMBLE 0x10 |
56 | #define WIIPROTO_FLAG_ACCEL 0x20 | 57 | #define WIIPROTO_FLAG_ACCEL 0x20 |
58 | #define WIIPROTO_FLAG_IR_BASIC 0x40 | ||
59 | #define WIIPROTO_FLAG_IR_EXT 0x80 | ||
60 | #define WIIPROTO_FLAG_IR_FULL 0xc0 /* IR_BASIC | IR_EXT */ | ||
57 | #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ | 61 | #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ |
58 | WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) | 62 | WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) |
63 | #define WIIPROTO_FLAGS_IR (WIIPROTO_FLAG_IR_BASIC | WIIPROTO_FLAG_IR_EXT | \ | ||
64 | WIIPROTO_FLAG_IR_FULL) | ||
59 | 65 | ||
60 | /* return flag for led \num */ | 66 | /* return flag for led \num */ |
61 | #define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1)) | 67 | #define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1)) |
@@ -71,6 +77,7 @@ enum wiiproto_reqs { | |||
71 | WIIPROTO_REQ_DRM_KA = 0x31, | 77 | WIIPROTO_REQ_DRM_KA = 0x31, |
72 | WIIPROTO_REQ_DRM_KAI = 0x33, | 78 | WIIPROTO_REQ_DRM_KAI = 0x33, |
73 | WIIPROTO_REQ_DRM_KAE = 0x35, | 79 | WIIPROTO_REQ_DRM_KAE = 0x35, |
80 | WIIPROTO_REQ_DRM_KIE = 0x36, | ||
74 | WIIPROTO_REQ_DRM_KAIE = 0x37, | 81 | WIIPROTO_REQ_DRM_KAIE = 0x37, |
75 | WIIPROTO_REQ_DRM_SKAI1 = 0x3e, | 82 | WIIPROTO_REQ_DRM_SKAI1 = 0x3e, |
76 | WIIPROTO_REQ_DRM_SKAI2 = 0x3f, | 83 | WIIPROTO_REQ_DRM_SKAI2 = 0x3f, |
@@ -248,10 +255,23 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds) | |||
248 | */ | 255 | */ |
249 | static __u8 select_drm(struct wiimote_data *wdata) | 256 | static __u8 select_drm(struct wiimote_data *wdata) |
250 | { | 257 | { |
251 | if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) | 258 | __u8 ir = wdata->state.flags & WIIPROTO_FLAGS_IR; |
252 | return WIIPROTO_REQ_DRM_KA; | 259 | |
253 | else | 260 | if (ir == WIIPROTO_FLAG_IR_BASIC) { |
254 | return WIIPROTO_REQ_DRM_K; | 261 | if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) |
262 | return WIIPROTO_REQ_DRM_KAIE; | ||
263 | else | ||
264 | return WIIPROTO_REQ_DRM_KIE; | ||
265 | } else if (ir == WIIPROTO_FLAG_IR_EXT) { | ||
266 | return WIIPROTO_REQ_DRM_KAI; | ||
267 | } else if (ir == WIIPROTO_FLAG_IR_FULL) { | ||
268 | return WIIPROTO_REQ_DRM_SKAI1; | ||
269 | } else { | ||
270 | if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) | ||
271 | return WIIPROTO_REQ_DRM_KA; | ||
272 | else | ||
273 | return WIIPROTO_REQ_DRM_K; | ||
274 | } | ||
255 | } | 275 | } |
256 | 276 | ||
257 | static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm) | 277 | static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm) |
@@ -681,6 +701,36 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev) | |||
681 | input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4); | 701 | input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4); |
682 | input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4); | 702 | input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4); |
683 | 703 | ||
704 | wdata->ir = input_allocate_device(); | ||
705 | if (!wdata->ir) | ||
706 | goto err_ir; | ||
707 | |||
708 | input_set_drvdata(wdata->ir, wdata); | ||
709 | wdata->ir->dev.parent = &wdata->hdev->dev; | ||
710 | wdata->ir->id.bustype = wdata->hdev->bus; | ||
711 | wdata->ir->id.vendor = wdata->hdev->vendor; | ||
712 | wdata->ir->id.product = wdata->hdev->product; | ||
713 | wdata->ir->id.version = wdata->hdev->version; | ||
714 | wdata->ir->name = WIIMOTE_NAME " IR"; | ||
715 | |||
716 | set_bit(EV_ABS, wdata->ir->evbit); | ||
717 | set_bit(ABS_HAT0X, wdata->ir->absbit); | ||
718 | set_bit(ABS_HAT0Y, wdata->ir->absbit); | ||
719 | set_bit(ABS_HAT1X, wdata->ir->absbit); | ||
720 | set_bit(ABS_HAT1Y, wdata->ir->absbit); | ||
721 | set_bit(ABS_HAT2X, wdata->ir->absbit); | ||
722 | set_bit(ABS_HAT2Y, wdata->ir->absbit); | ||
723 | set_bit(ABS_HAT3X, wdata->ir->absbit); | ||
724 | set_bit(ABS_HAT3Y, wdata->ir->absbit); | ||
725 | input_set_abs_params(wdata->ir, ABS_HAT0X, 0, 1023, 2, 4); | ||
726 | input_set_abs_params(wdata->ir, ABS_HAT0Y, 0, 767, 2, 4); | ||
727 | input_set_abs_params(wdata->ir, ABS_HAT1X, 0, 1023, 2, 4); | ||
728 | input_set_abs_params(wdata->ir, ABS_HAT1Y, 0, 767, 2, 4); | ||
729 | input_set_abs_params(wdata->ir, ABS_HAT2X, 0, 1023, 2, 4); | ||
730 | input_set_abs_params(wdata->ir, ABS_HAT2Y, 0, 767, 2, 4); | ||
731 | input_set_abs_params(wdata->ir, ABS_HAT3X, 0, 1023, 2, 4); | ||
732 | input_set_abs_params(wdata->ir, ABS_HAT3Y, 0, 767, 2, 4); | ||
733 | |||
684 | spin_lock_init(&wdata->qlock); | 734 | spin_lock_init(&wdata->qlock); |
685 | INIT_WORK(&wdata->worker, wiimote_worker); | 735 | INIT_WORK(&wdata->worker, wiimote_worker); |
686 | 736 | ||
@@ -688,6 +738,8 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev) | |||
688 | 738 | ||
689 | return wdata; | 739 | return wdata; |
690 | 740 | ||
741 | err_ir: | ||
742 | input_free_device(wdata->accel); | ||
691 | err_input: | 743 | err_input: |
692 | input_free_device(wdata->input); | 744 | input_free_device(wdata->input); |
693 | err: | 745 | err: |
@@ -700,6 +752,7 @@ static void wiimote_destroy(struct wiimote_data *wdata) | |||
700 | wiimote_leds_destroy(wdata); | 752 | wiimote_leds_destroy(wdata); |
701 | 753 | ||
702 | input_unregister_device(wdata->accel); | 754 | input_unregister_device(wdata->accel); |
755 | input_unregister_device(wdata->ir); | ||
703 | input_unregister_device(wdata->input); | 756 | input_unregister_device(wdata->input); |
704 | cancel_work_sync(&wdata->worker); | 757 | cancel_work_sync(&wdata->worker); |
705 | hid_hw_stop(wdata->hdev); | 758 | hid_hw_stop(wdata->hdev); |
@@ -737,6 +790,12 @@ static int wiimote_hid_probe(struct hid_device *hdev, | |||
737 | goto err_stop; | 790 | goto err_stop; |
738 | } | 791 | } |
739 | 792 | ||
793 | ret = input_register_device(wdata->ir); | ||
794 | if (ret) { | ||
795 | hid_err(hdev, "Cannot register input device\n"); | ||
796 | goto err_ir; | ||
797 | } | ||
798 | |||
740 | ret = input_register_device(wdata->input); | 799 | ret = input_register_device(wdata->input); |
741 | if (ret) { | 800 | if (ret) { |
742 | hid_err(hdev, "Cannot register input device\n"); | 801 | hid_err(hdev, "Cannot register input device\n"); |
@@ -761,11 +820,15 @@ err_free: | |||
761 | return ret; | 820 | return ret; |
762 | 821 | ||
763 | err_input: | 822 | err_input: |
823 | input_unregister_device(wdata->ir); | ||
824 | wdata->ir = NULL; | ||
825 | err_ir: | ||
764 | input_unregister_device(wdata->accel); | 826 | input_unregister_device(wdata->accel); |
765 | wdata->accel = NULL; | 827 | wdata->accel = NULL; |
766 | err_stop: | 828 | err_stop: |
767 | hid_hw_stop(hdev); | 829 | hid_hw_stop(hdev); |
768 | err: | 830 | err: |
831 | input_free_device(wdata->ir); | ||
769 | input_free_device(wdata->accel); | 832 | input_free_device(wdata->accel); |
770 | input_free_device(wdata->input); | 833 | input_free_device(wdata->input); |
771 | kfree(wdata); | 834 | kfree(wdata); |