aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-05-05 17:12:51 -0400
committerJiri Kosina <jkosina@suse.cz>2013-06-03 05:07:00 -0400
commit27f06942142e7a17757b5de1dc4f128c179b7c13 (patch)
treea494da599d33a444d530314221e2738f1f0a39cf /drivers/hid
parentd758b1f0c527aedc5e83a565a0737d9ac21ea46a (diff)
HID: wiimote: add sub-device module infrastructure
To avoid loading all sub-device drivers for every Wii Remote, even though the required hardware might not be available, we introduce a module layer. The module layer specifies which sub-devices are available on each device-type. After device detection, we only load the modules for the detected device. If module loading fails, we unload everything and mark the device as WIIMOTE_DEV_UNKNOWN. As long as a device is marked as "unknown", no sub-devices will be used and the device is considered unsupported. All the different sub-devices, including KEYS, RUMBLE, BATTERY, LEDS, ACCELEROMETER, IR and more will be ported in follow-up patches to the new module layer. Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/Makefile2
-rw-r--r--drivers/hid/hid-wiimote-core.c124
-rw-r--r--drivers/hid/hid-wiimote-modules.c45
-rw-r--r--drivers/hid/hid-wiimote.h27
4 files changed, 194 insertions, 4 deletions
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 2065694f57ab..2c2222684043 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -28,7 +28,7 @@ ifdef CONFIG_LOGIWHEELS_FF
28 hid-logitech-y += hid-lg4ff.o 28 hid-logitech-y += hid-lg4ff.o
29endif 29endif
30 30
31hid-wiimote-y := hid-wiimote-core.o 31hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o
32ifdef CONFIG_HID_WIIMOTE_EXT 32ifdef CONFIG_HID_WIIMOTE_EXT
33 hid-wiimote-y += hid-wiimote-ext.o 33 hid-wiimote-y += hid-wiimote-ext.o
34endif 34endif
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index a025d2104d3c..275428b31509 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -715,6 +715,124 @@ static void wiimote_ir_close(struct input_dev *dev)
715 wiimote_init_ir(wdata, 0); 715 wiimote_init_ir(wdata, 0);
716} 716}
717 717
718/* device module handling */
719
720static const __u8 * const wiimote_devtype_mods[WIIMOTE_DEV_NUM] = {
721 [WIIMOTE_DEV_PENDING] = (const __u8[]){
722 WIIMOD_NULL,
723 },
724 [WIIMOTE_DEV_UNKNOWN] = (const __u8[]){
725 WIIMOD_NULL,
726 },
727 [WIIMOTE_DEV_GENERIC] = (const __u8[]){
728 WIIMOD_NULL,
729 },
730 [WIIMOTE_DEV_GEN10] = (const __u8[]){
731 WIIMOD_NULL,
732 },
733 [WIIMOTE_DEV_GEN20] = (const __u8[]){
734 WIIMOD_NULL,
735 },
736};
737
738static void wiimote_modules_load(struct wiimote_data *wdata,
739 unsigned int devtype)
740{
741 bool need_input = false;
742 const __u8 *mods, *iter;
743 const struct wiimod_ops *ops;
744 int ret;
745
746 mods = wiimote_devtype_mods[devtype];
747
748 for (iter = mods; *iter != WIIMOD_NULL; ++iter) {
749 if (wiimod_table[*iter]->flags & WIIMOD_FLAG_INPUT) {
750 need_input = true;
751 break;
752 }
753 }
754
755 if (need_input) {
756 wdata->input = input_allocate_device();
757 if (!wdata->input)
758 return;
759
760 input_set_drvdata(wdata->input, wdata);
761 wdata->input->dev.parent = &wdata->hdev->dev;
762 wdata->input->id.bustype = wdata->hdev->bus;
763 wdata->input->id.vendor = wdata->hdev->vendor;
764 wdata->input->id.product = wdata->hdev->product;
765 wdata->input->id.version = wdata->hdev->version;
766 wdata->input->name = WIIMOTE_NAME;
767 }
768
769 for (iter = mods; *iter != WIIMOD_NULL; ++iter) {
770 ops = wiimod_table[*iter];
771 if (!ops->probe)
772 continue;
773
774 ret = ops->probe(ops, wdata);
775 if (ret)
776 goto error;
777 }
778
779 if (wdata->input) {
780 ret = input_register_device(wdata->input);
781 if (ret)
782 goto error;
783 }
784
785 spin_lock_irq(&wdata->state.lock);
786 wdata->state.devtype = devtype;
787 spin_unlock_irq(&wdata->state.lock);
788 return;
789
790error:
791 for ( ; iter-- != mods; ) {
792 ops = wiimod_table[*iter];
793 if (ops->remove)
794 ops->remove(ops, wdata);
795 }
796
797 if (wdata->input) {
798 input_free_device(wdata->input);
799 wdata->input = NULL;
800 }
801}
802
803static void wiimote_modules_unload(struct wiimote_data *wdata)
804{
805 const __u8 *mods, *iter;
806 const struct wiimod_ops *ops;
807 unsigned long flags;
808
809 mods = wiimote_devtype_mods[wdata->state.devtype];
810
811 spin_lock_irqsave(&wdata->state.lock, flags);
812 wdata->state.devtype = WIIMOTE_DEV_UNKNOWN;
813 spin_unlock_irqrestore(&wdata->state.lock, flags);
814
815 /* find end of list */
816 for (iter = mods; *iter != WIIMOD_NULL; ++iter)
817 /* empty */ ;
818
819 if (wdata->input) {
820 input_get_device(wdata->input);
821 input_unregister_device(wdata->input);
822 }
823
824 for ( ; iter-- != mods; ) {
825 ops = wiimod_table[*iter];
826 if (ops->remove)
827 ops->remove(ops, wdata);
828 }
829
830 if (wdata->input) {
831 input_put_device(wdata->input);
832 wdata->input = NULL;
833 }
834}
835
718/* device (re-)initialization and detection */ 836/* device (re-)initialization and detection */
719 837
720static const char *wiimote_devtype_names[WIIMOTE_DEV_NUM] = { 838static const char *wiimote_devtype_names[WIIMOTE_DEV_NUM] = {
@@ -766,9 +884,7 @@ done:
766 hid_info(wdata->hdev, "detected device: %s\n", 884 hid_info(wdata->hdev, "detected device: %s\n",
767 wiimote_devtype_names[devtype]); 885 wiimote_devtype_names[devtype]);
768 886
769 spin_lock_irq(&wdata->state.lock); 887 wiimote_modules_load(wdata, devtype);
770 wdata->state.devtype = devtype;
771 spin_unlock_irq(&wdata->state.lock);
772} 888}
773 889
774static void wiimote_init_detect(struct wiimote_data *wdata) 890static void wiimote_init_detect(struct wiimote_data *wdata)
@@ -780,6 +896,7 @@ static void wiimote_init_detect(struct wiimote_data *wdata)
780 wiimote_cmd_acquire_noint(wdata); 896 wiimote_cmd_acquire_noint(wdata);
781 897
782 spin_lock_irq(&wdata->state.lock); 898 spin_lock_irq(&wdata->state.lock);
899 wdata->state.devtype = WIIMOTE_DEV_UNKNOWN;
783 wiimote_cmd_set(wdata, WIIPROTO_REQ_SREQ, 0); 900 wiimote_cmd_set(wdata, WIIPROTO_REQ_SREQ, 0);
784 wiiproto_req_status(wdata); 901 wiiproto_req_status(wdata);
785 spin_unlock_irq(&wdata->state.lock); 902 spin_unlock_irq(&wdata->state.lock);
@@ -1313,6 +1430,7 @@ static void wiimote_destroy(struct wiimote_data *wdata)
1313 wiiext_deinit(wdata); 1430 wiiext_deinit(wdata);
1314 wiimote_leds_destroy(wdata); 1431 wiimote_leds_destroy(wdata);
1315 1432
1433 wiimote_modules_unload(wdata);
1316 power_supply_unregister(&wdata->battery); 1434 power_supply_unregister(&wdata->battery);
1317 kfree(wdata->battery.name); 1435 kfree(wdata->battery.name);
1318 input_unregister_device(wdata->accel); 1436 input_unregister_device(wdata->accel);
diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
new file mode 100644
index 000000000000..5dcdd234f29c
--- /dev/null
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -0,0 +1,45 @@
1/*
2 * Device Modules for Nintendo Wii / Wii U HID Driver
3 * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
4 */
5
6/*
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 */
12
13/*
14 * Wiimote Modules
15 * Nintendo devices provide different peripherals and many new devices lack
16 * initial features like the IR camera. Therefore, each peripheral device is
17 * implemented as an independent module and we probe on each device only the
18 * modules for the hardware that really is available.
19 *
20 * Module registration is sequential. Unregistration is done in reverse order.
21 * After device detection, the needed modules are loaded. Users can trigger
22 * re-detection which causes all modules to be unloaded and then reload the
23 * modules for the new detected device.
24 *
25 * wdata->input is a shared input device. It is always initialized prior to
26 * module registration. If at least one registered module is marked as
27 * WIIMOD_FLAG_INPUT, then the input device will get registered after all
28 * modules were registered.
29 * Please note that it is unregistered _before_ the "remove" callbacks are
30 * called. This guarantees that no input interaction is done, anymore. However,
31 * the wiimote core keeps a reference to the input device so it is freed only
32 * after all modules were removed. It is safe to send events to unregistered
33 * input devices.
34 */
35
36#include <linux/device.h>
37#include <linux/hid.h>
38#include <linux/input.h>
39#include <linux/spinlock.h>
40#include "hid-wiimote.h"
41
42/* module table */
43
44const struct wiimod_ops *wiimod_table[WIIMOD_NUM] = {
45};
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h
index 34417021606e..3c94e3c657c6 100644
--- a/drivers/hid/hid-wiimote.h
+++ b/drivers/hid/hid-wiimote.h
@@ -108,6 +108,33 @@ struct wiimote_data {
108 struct work_struct init_worker; 108 struct work_struct init_worker;
109}; 109};
110 110
111/* wiimote modules */
112
113enum wiimod_module {
114 WIIMOD_NUM,
115 WIIMOD_NULL = WIIMOD_NUM,
116};
117
118#define WIIMOD_FLAG_INPUT 0x0001
119
120struct wiimod_ops {
121 __u16 flags;
122 unsigned long arg;
123 int (*probe) (const struct wiimod_ops *ops,
124 struct wiimote_data *wdata);
125 void (*remove) (const struct wiimod_ops *ops,
126 struct wiimote_data *wdata);
127
128 void (*in_keys) (struct wiimote_data *wdata, const __u8 *keys);
129 void (*in_accel) (struct wiimote_data *wdata, const __u8 *accel);
130 void (*in_ir) (struct wiimote_data *wdata, const __u8 *ir, bool packed,
131 unsigned int id);
132};
133
134extern const struct wiimod_ops *wiimod_table[WIIMOD_NUM];
135
136/* wiimote requests */
137
111enum wiiproto_reqs { 138enum wiiproto_reqs {
112 WIIPROTO_REQ_NULL = 0x0, 139 WIIPROTO_REQ_NULL = 0x0,
113 WIIPROTO_REQ_RUMBLE = 0x10, 140 WIIPROTO_REQ_RUMBLE = 0x10,