From 001dac87052903d6850c064737bab004bed94789 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 2 Apr 2013 19:58:34 +0200 Subject: [PATCH 1/3] HID: wiimote: use unique battery names Battery device names must be unique, otherwise registration fails if multiple Wii Remotes are connected. This breaks the sysfs API, but there is no known application that uses the Wii Remote battery that I know of so we should go ahead and apply this. Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina --- drivers/hid/hid-wiimote-core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index 0fb8ab93db68..f1c7a113b614 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -1160,6 +1160,7 @@ static void wiimote_destroy(struct wiimote_data *wdata) wiimote_leds_destroy(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); @@ -1216,9 +1217,14 @@ static int wiimote_hid_probe(struct hid_device *hdev, wdata->battery.properties = wiimote_battery_props; wdata->battery.num_properties = ARRAY_SIZE(wiimote_battery_props); wdata->battery.get_property = wiimote_battery_get_property; - wdata->battery.name = "wiimote_battery"; wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY; wdata->battery.use_for_apm = 0; + wdata->battery.name = kasprintf(GFP_KERNEL, "wiimote_battery_%s", + wdata->hdev->uniq); + if (!wdata->battery.name) { + ret = -ENOMEM; + goto err_battery_name; + } ret = power_supply_register(&wdata->hdev->dev, &wdata->battery); if (ret) { @@ -1254,6 +1260,8 @@ err_free: return ret; err_battery: + kfree(wdata->battery.name); +err_battery_name: input_unregister_device(wdata->input); wdata->input = NULL; err_input: From a33042fafdda4c4fb11981c2db95df86682e1083 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 2 Apr 2013 19:58:35 +0200 Subject: [PATCH 2/3] HID: wiimote: add 2nd generation Wii Remote IDs This adds the 2nd generation Wii Remote IDs. They have a different Bluetooth chipset (CSR instead of Broadcom) and are more restrictive in what they accept as input. Hence, you need up-to-date BlueZ and Bluetooth HIDP modules to use these devices. Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-wiimote-core.c | 2 ++ 3 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 512b01c04ea7..eb0309eae7b9 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1747,6 +1747,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) }, { } }; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c4388776f4e4..4905346b03f8 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -614,6 +614,7 @@ #define USB_VENDOR_ID_NINTENDO 0x057e #define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306 +#define USB_DEVICE_ID_NINTENDO_WIIMOTE2 0x0330 #define USB_VENDOR_ID_NOVATEK 0x0603 #define USB_DEVICE_ID_NOVATEK_PCT 0x0600 diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index f1c7a113b614..f7b521aa1b3d 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -1291,6 +1291,8 @@ static void wiimote_hid_remove(struct hid_device *hdev) static const struct hid_device_id wiimote_hid_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, + USB_DEVICE_ID_NINTENDO_WIIMOTE2) }, { } }; MODULE_DEVICE_TABLE(hid, wiimote_hid_devices); From 2d44e3d26891e9530e29395f5a86b751c2f69ee8 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 2 Apr 2013 19:58:36 +0200 Subject: [PATCH 3/3] HID: wiimote: parse reduced status reports It turns out the Wii accepts any status reports from clients reduced to "BB BB" key data only, as long as the report actually includes key data at the first two bytes. The official devices don't send these reduced reports, but of course, 3rd party devices make great use of this feature. Hence, add parsers for these reduced reports for every matching report. Also change the logic how we find handlers. There is no reason to call multiple handlers on a single report, but instead find the best handler and call it only once. Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina --- drivers/hid/hid-wiimote-core.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index f7b521aa1b3d..e5ee1f20bbd9 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c @@ -789,12 +789,20 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir, input_report_abs(wdata->ir, yid, y); } -static void handler_status(struct wiimote_data *wdata, const __u8 *payload) +/* reduced status report with "BB BB" key data only */ +static void handler_status_K(struct wiimote_data *wdata, + const __u8 *payload) { handler_keys(wdata, payload); /* on status reports the drm is reset so we need to resend the drm */ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); +} + +/* extended status report with "BB BB LF 00 00 VV" data */ +static void handler_status(struct wiimote_data *wdata, const __u8 *payload) +{ + handler_status_K(wdata, payload); wiiext_event(wdata, payload[2] & 0x02); @@ -804,6 +812,12 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload) } } +/* reduced generic report with "BB BB" key data only */ +static void handler_generic_K(struct wiimote_data *wdata, const __u8 *payload) +{ + handler_keys(wdata, payload); +} + static void handler_data(struct wiimote_data *wdata, const __u8 *payload) { __u16 offset = payload[3] << 8 | payload[4]; @@ -947,16 +961,26 @@ struct wiiproto_handler { static struct wiiproto_handler handlers[] = { { .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status }, + { .id = WIIPROTO_REQ_STATUS, .size = 2, .func = handler_status_K }, { .id = WIIPROTO_REQ_DATA, .size = 21, .func = handler_data }, + { .id = WIIPROTO_REQ_DATA, .size = 2, .func = handler_generic_K }, { .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return }, + { .id = WIIPROTO_REQ_RETURN, .size = 2, .func = handler_generic_K }, { .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys }, { .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA }, + { .id = WIIPROTO_REQ_DRM_KA, .size = 2, .func = handler_generic_K }, { .id = WIIPROTO_REQ_DRM_KE, .size = 10, .func = handler_drm_KE }, + { .id = WIIPROTO_REQ_DRM_KE, .size = 2, .func = handler_generic_K }, { .id = WIIPROTO_REQ_DRM_KAI, .size = 17, .func = handler_drm_KAI }, + { .id = WIIPROTO_REQ_DRM_KAI, .size = 2, .func = handler_generic_K }, { .id = WIIPROTO_REQ_DRM_KEE, .size = 21, .func = handler_drm_KEE }, + { .id = WIIPROTO_REQ_DRM_KEE, .size = 2, .func = handler_generic_K }, { .id = WIIPROTO_REQ_DRM_KAE, .size = 21, .func = handler_drm_KAE }, + { .id = WIIPROTO_REQ_DRM_KAE, .size = 2, .func = handler_generic_K }, { .id = WIIPROTO_REQ_DRM_KIE, .size = 21, .func = handler_drm_KIE }, + { .id = WIIPROTO_REQ_DRM_KIE, .size = 2, .func = handler_generic_K }, { .id = WIIPROTO_REQ_DRM_KAIE, .size = 21, .func = handler_drm_KAIE }, + { .id = WIIPROTO_REQ_DRM_KAIE, .size = 2, .func = handler_generic_K }, { .id = WIIPROTO_REQ_DRM_E, .size = 21, .func = handler_drm_E }, { .id = WIIPROTO_REQ_DRM_SKAI1, .size = 21, .func = handler_drm_SKAI1 }, { .id = WIIPROTO_REQ_DRM_SKAI2, .size = 21, .func = handler_drm_SKAI2 }, @@ -970,7 +994,6 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report, struct wiiproto_handler *h; int i; unsigned long flags; - bool handled = false; if (size < 1) return -EINVAL; @@ -981,11 +1004,11 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report, h = &handlers[i]; if (h->id == raw_data[0] && h->size < size) { h->func(wdata, &raw_data[1]); - handled = true; + break; } } - if (!handled) + if (!handlers[i].id) hid_warn(hdev, "Unhandled report %hhu size %d\n", raw_data[0], size);