HID: wiimote: convert KEYS and RUMBLE to modules
authorDavid Herrmann <dh.herrmann@gmail.com>
Sun, 5 May 2013 21:12:52 +0000 (23:12 +0200)
committerJiri Kosina <jkosina@suse.cz>
Mon, 3 Jun 2013 09:07:01 +0000 (11:07 +0200)
This introduces the first sub-device modules by converting the KEYS and
RUMBLE sub-devices into wiimote modules. Both must be converted at once
because they depend on the built-in shared input device.

This mostly moves code from wiimote-core to wiimote-modules and doesn't
change any semantics or ABI.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-wiimote-core.c
drivers/hid/hid-wiimote-modules.c
drivers/hid/hid-wiimote.h

index 275428b31509177583cea0cbfd55fcbb91de9d52..6ada226067078a326824fb412412daab8ae8e3f1 100644 (file)
 #include "hid-ids.h"
 #include "hid-wiimote.h"
 
-enum wiiproto_keys {
-       WIIPROTO_KEY_LEFT,
-       WIIPROTO_KEY_RIGHT,
-       WIIPROTO_KEY_UP,
-       WIIPROTO_KEY_DOWN,
-       WIIPROTO_KEY_PLUS,
-       WIIPROTO_KEY_MINUS,
-       WIIPROTO_KEY_ONE,
-       WIIPROTO_KEY_TWO,
-       WIIPROTO_KEY_A,
-       WIIPROTO_KEY_B,
-       WIIPROTO_KEY_HOME,
-       WIIPROTO_KEY_COUNT
-};
-
-static __u16 wiiproto_keymap[] = {
-       KEY_LEFT,       /* WIIPROTO_KEY_LEFT */
-       KEY_RIGHT,      /* WIIPROTO_KEY_RIGHT */
-       KEY_UP,         /* WIIPROTO_KEY_UP */
-       KEY_DOWN,       /* WIIPROTO_KEY_DOWN */
-       KEY_NEXT,       /* WIIPROTO_KEY_PLUS */
-       KEY_PREVIOUS,   /* WIIPROTO_KEY_MINUS */
-       BTN_1,          /* WIIPROTO_KEY_ONE */
-       BTN_2,          /* WIIPROTO_KEY_TWO */
-       BTN_A,          /* WIIPROTO_KEY_A */
-       BTN_B,          /* WIIPROTO_KEY_B */
-       BTN_MODE,       /* WIIPROTO_KEY_HOME */
-};
-
 static enum power_supply_property wiimote_battery_props[] = {
        POWER_SUPPLY_PROP_CAPACITY,
        POWER_SUPPLY_PROP_SCOPE,
@@ -166,7 +137,7 @@ static inline void wiiproto_keep_rumble(struct wiimote_data *wdata, __u8 *cmd1)
                *cmd1 |= 0x01;
 }
 
-static void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble)
+void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble)
 {
        __u8 cmd[2];
 
@@ -654,31 +625,6 @@ static void wiimote_leds_set(struct led_classdev *led_dev,
        }
 }
 
-static int wiimote_ff_play(struct input_dev *dev, void *data,
-                                                       struct ff_effect *eff)
-{
-       struct wiimote_data *wdata = input_get_drvdata(dev);
-       __u8 value;
-       unsigned long flags;
-
-       /*
-        * The wiimote supports only a single rumble motor so if any magnitude
-        * is set to non-zero then we start the rumble motor. If both are set to
-        * zero, we stop the rumble motor.
-        */
-
-       if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
-               value = 1;
-       else
-               value = 0;
-
-       spin_lock_irqsave(&wdata->state.lock, flags);
-       wiiproto_req_rumble(wdata, value);
-       spin_unlock_irqrestore(&wdata->state.lock, flags);
-
-       return 0;
-}
-
 static int wiimote_accel_open(struct input_dev *dev)
 {
        struct wiimote_data *wdata = input_get_drvdata(dev);
@@ -725,12 +671,18 @@ static const __u8 * const wiimote_devtype_mods[WIIMOTE_DEV_NUM] = {
                WIIMOD_NULL,
        },
        [WIIMOTE_DEV_GENERIC] = (const __u8[]){
+               WIIMOD_KEYS,
+               WIIMOD_RUMBLE,
                WIIMOD_NULL,
        },
        [WIIMOTE_DEV_GEN10] = (const __u8[]){
+               WIIMOD_KEYS,
+               WIIMOD_RUMBLE,
                WIIMOD_NULL,
        },
        [WIIMOTE_DEV_GEN20] = (const __u8[]){
+               WIIMOD_KEYS,
+               WIIMOD_RUMBLE,
                WIIMOD_NULL,
        },
 };
@@ -933,29 +885,17 @@ static void wiimote_init_worker(struct work_struct *work)
 
 static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
 {
-       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_LEFT],
-                                                       !!(payload[0] & 0x01));
-       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_RIGHT],
-                                                       !!(payload[0] & 0x02));
-       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_DOWN],
-                                                       !!(payload[0] & 0x04));
-       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_UP],
-                                                       !!(payload[0] & 0x08));
-       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_PLUS],
-                                                       !!(payload[0] & 0x10));
-       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_TWO],
-                                                       !!(payload[1] & 0x01));
-       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_ONE],
-                                                       !!(payload[1] & 0x02));
-       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_B],
-                                                       !!(payload[1] & 0x04));
-       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_A],
-                                                       !!(payload[1] & 0x08));
-       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_MINUS],
-                                                       !!(payload[1] & 0x10));
-       input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_HOME],
-                                                       !!(payload[1] & 0x80));
-       input_sync(wdata->input);
+       const __u8 *iter, *mods;
+       const struct wiimod_ops *ops;
+
+       mods = wiimote_devtype_mods[wdata->state.devtype];
+       for (iter = mods; *iter != WIIMOD_NULL; ++iter) {
+               ops = wiimod_table[*iter];
+               if (ops->in_keys) {
+                       ops->in_keys(wdata, payload);
+                       break;
+               }
+       }
 }
 
 static void handler_accel(struct wiimote_data *wdata, const __u8 *payload)
@@ -1319,38 +1259,17 @@ err:
 static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 {
        struct wiimote_data *wdata;
-       int i;
 
        wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
        if (!wdata)
                return NULL;
 
-       wdata->input = input_allocate_device();
-       if (!wdata->input)
-               goto err;
-
        wdata->hdev = hdev;
        hid_set_drvdata(hdev, wdata);
 
-       input_set_drvdata(wdata->input, wdata);
-       wdata->input->dev.parent = &wdata->hdev->dev;
-       wdata->input->id.bustype = wdata->hdev->bus;
-       wdata->input->id.vendor = wdata->hdev->vendor;
-       wdata->input->id.product = wdata->hdev->product;
-       wdata->input->id.version = wdata->hdev->version;
-       wdata->input->name = WIIMOTE_NAME;
-
-       set_bit(EV_KEY, wdata->input->evbit);
-       for (i = 0; i < WIIPROTO_KEY_COUNT; ++i)
-               set_bit(wiiproto_keymap[i], wdata->input->keybit);
-
-       set_bit(FF_RUMBLE, wdata->input->ffbit);
-       if (input_ff_create_memless(wdata->input, NULL, wiimote_ff_play))
-               goto err_input;
-
        wdata->accel = input_allocate_device();
        if (!wdata->accel)
-               goto err_input;
+               goto err;
 
        input_set_drvdata(wdata->accel, wdata);
        wdata->accel->open = wiimote_accel_open;
@@ -1417,8 +1336,6 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
 
 err_ir:
        input_free_device(wdata->accel);
-err_input:
-       input_free_device(wdata->input);
 err:
        kfree(wdata);
        return NULL;
@@ -1430,13 +1347,12 @@ static void wiimote_destroy(struct wiimote_data *wdata)
        wiiext_deinit(wdata);
        wiimote_leds_destroy(wdata);
 
+       cancel_work_sync(&wdata->init_worker);
        wiimote_modules_unload(wdata);
        power_supply_unregister(&wdata->battery);
        kfree(wdata->battery.name);
        input_unregister_device(wdata->accel);
        input_unregister_device(wdata->ir);
-       input_unregister_device(wdata->input);
-       cancel_work_sync(&wdata->init_worker);
        cancel_work_sync(&wdata->queue.worker);
        hid_hw_close(wdata->hdev);
        hid_hw_stop(wdata->hdev);
@@ -1488,12 +1404,6 @@ static int wiimote_hid_probe(struct hid_device *hdev,
                goto err_ir;
        }
 
-       ret = input_register_device(wdata->input);
-       if (ret) {
-               hid_err(hdev, "Cannot register input device\n");
-               goto err_input;
-       }
-
        wdata->battery.properties = wiimote_battery_props;
        wdata->battery.num_properties = ARRAY_SIZE(wiimote_battery_props);
        wdata->battery.get_property = wiimote_battery_get_property;
@@ -1545,9 +1455,6 @@ err_free:
 err_battery:
        kfree(wdata->battery.name);
 err_battery_name:
-       input_unregister_device(wdata->input);
-       wdata->input = NULL;
-err_input:
        input_unregister_device(wdata->ir);
        wdata->ir = NULL;
 err_ir:
@@ -1560,7 +1467,6 @@ err_stop:
 err:
        input_free_device(wdata->ir);
        input_free_device(wdata->accel);
-       input_free_device(wdata->input);
        kfree(wdata);
        return ret;
 }
index 5dcdd234f29cf5f379a09ba2eb7e7b0216ec2dfa..616f24024f77c94b55f02af9ef100b33038f6179 100644 (file)
 #include <linux/spinlock.h>
 #include "hid-wiimote.h"
 
+/*
+ * Keys
+ * The initial Wii Remote provided a bunch of buttons that are reported as
+ * part of the core protocol. Many later devices dropped these and report
+ * invalid data in the core button reports. Load this only on devices which
+ * correctly send button reports.
+ * It uses the shared input device.
+ */
+
+static const __u16 wiimod_keys_map[] = {
+       KEY_LEFT,       /* WIIPROTO_KEY_LEFT */
+       KEY_RIGHT,      /* WIIPROTO_KEY_RIGHT */
+       KEY_UP,         /* WIIPROTO_KEY_UP */
+       KEY_DOWN,       /* WIIPROTO_KEY_DOWN */
+       KEY_NEXT,       /* WIIPROTO_KEY_PLUS */
+       KEY_PREVIOUS,   /* WIIPROTO_KEY_MINUS */
+       BTN_1,          /* WIIPROTO_KEY_ONE */
+       BTN_2,          /* WIIPROTO_KEY_TWO */
+       BTN_A,          /* WIIPROTO_KEY_A */
+       BTN_B,          /* WIIPROTO_KEY_B */
+       BTN_MODE,       /* WIIPROTO_KEY_HOME */
+};
+
+static void wiimod_keys_in_keys(struct wiimote_data *wdata, const __u8 *keys)
+{
+       input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_LEFT],
+                                                       !!(keys[0] & 0x01));
+       input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_RIGHT],
+                                                       !!(keys[0] & 0x02));
+       input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_DOWN],
+                                                       !!(keys[0] & 0x04));
+       input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_UP],
+                                                       !!(keys[0] & 0x08));
+       input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_PLUS],
+                                                       !!(keys[0] & 0x10));
+       input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_TWO],
+                                                       !!(keys[1] & 0x01));
+       input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_ONE],
+                                                       !!(keys[1] & 0x02));
+       input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_B],
+                                                       !!(keys[1] & 0x04));
+       input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_A],
+                                                       !!(keys[1] & 0x08));
+       input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_MINUS],
+                                                       !!(keys[1] & 0x10));
+       input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_HOME],
+                                                       !!(keys[1] & 0x80));
+       input_sync(wdata->input);
+}
+
+static int wiimod_keys_probe(const struct wiimod_ops *ops,
+                            struct wiimote_data *wdata)
+{
+       unsigned int i;
+
+       set_bit(EV_KEY, wdata->input->evbit);
+       for (i = 0; i < WIIPROTO_KEY_COUNT; ++i)
+               set_bit(wiimod_keys_map[i], wdata->input->keybit);
+
+       return 0;
+}
+
+static const struct wiimod_ops wiimod_keys = {
+       .flags = WIIMOD_FLAG_INPUT,
+       .arg = 0,
+       .probe = wiimod_keys_probe,
+       .remove = NULL,
+       .in_keys = wiimod_keys_in_keys,
+};
+
+/*
+ * Rumble
+ * Nearly all devices provide a rumble feature. A small motor for
+ * force-feedback effects. We provide an FF_RUMBLE memless ff device on the
+ * shared input device if this module is loaded.
+ * The rumble motor is controlled via a flag on almost every output report so
+ * the wiimote core handles the rumble flag. But if a device doesn't provide
+ * the rumble motor, this flag shouldn't be set.
+ */
+
+static int wiimod_rumble_play(struct input_dev *dev, void *data,
+                             struct ff_effect *eff)
+{
+       struct wiimote_data *wdata = input_get_drvdata(dev);
+       __u8 value;
+       unsigned long flags;
+
+       /*
+        * The wiimote supports only a single rumble motor so if any magnitude
+        * is set to non-zero then we start the rumble motor. If both are set to
+        * zero, we stop the rumble motor.
+        */
+
+       if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
+               value = 1;
+       else
+               value = 0;
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+       wiiproto_req_rumble(wdata, value);
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+       return 0;
+}
+
+static int wiimod_rumble_probe(const struct wiimod_ops *ops,
+                              struct wiimote_data *wdata)
+{
+       set_bit(FF_RUMBLE, wdata->input->ffbit);
+       if (input_ff_create_memless(wdata->input, NULL, wiimod_rumble_play))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void wiimod_rumble_remove(const struct wiimod_ops *ops,
+                                struct wiimote_data *wdata)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+       wiiproto_req_rumble(wdata, 0);
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static const struct wiimod_ops wiimod_rumble = {
+       .flags = WIIMOD_FLAG_INPUT,
+       .arg = 0,
+       .probe = wiimod_rumble_probe,
+       .remove = wiimod_rumble_remove,
+};
+
 /* module table */
 
 const struct wiimod_ops *wiimod_table[WIIMOD_NUM] = {
+       [WIIMOD_KEYS] = &wiimod_keys,
+       [WIIMOD_RUMBLE] = &wiimod_rumble,
 };
index 3c94e3c657c6e128c532185c9d6cad33087d2738..93c48fbef7a589900b8ed19c46990b839061801b 100644 (file)
 /* return flag for led \num */
 #define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1))
 
+enum wiiproto_keys {
+       WIIPROTO_KEY_LEFT,
+       WIIPROTO_KEY_RIGHT,
+       WIIPROTO_KEY_UP,
+       WIIPROTO_KEY_DOWN,
+       WIIPROTO_KEY_PLUS,
+       WIIPROTO_KEY_MINUS,
+       WIIPROTO_KEY_ONE,
+       WIIPROTO_KEY_TWO,
+       WIIPROTO_KEY_A,
+       WIIPROTO_KEY_B,
+       WIIPROTO_KEY_HOME,
+       WIIPROTO_KEY_COUNT
+};
+
 enum wiimote_devtype {
        WIIMOTE_DEV_PENDING,
        WIIMOTE_DEV_UNKNOWN,
@@ -111,6 +126,8 @@ struct wiimote_data {
 /* wiimote modules */
 
 enum wiimod_module {
+       WIIMOD_KEYS,
+       WIIMOD_RUMBLE,
        WIIMOD_NUM,
        WIIMOD_NULL = WIIMOD_NUM,
 };
@@ -166,6 +183,7 @@ enum wiiproto_reqs {
                                                                        dev))
 
 extern void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm);
+extern void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble);
 extern int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
                                                const __u8 *wmem, __u8 size);
 extern ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset,