aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-04-02 13:58:36 -0400
committerJiri Kosina <jkosina@suse.cz>2013-04-04 03:38:43 -0400
commit2d44e3d26891e9530e29395f5a86b751c2f69ee8 (patch)
tree6f172c6332daf6c456dcefd61821ae6071c6194a
parenta33042fafdda4c4fb11981c2db95df86682e1083 (diff)
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 <dh.herrmann@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hid-wiimote-core.c31
1 files 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,
789 input_report_abs(wdata->ir, yid, y); 789 input_report_abs(wdata->ir, yid, y);
790} 790}
791 791
792static void handler_status(struct wiimote_data *wdata, const __u8 *payload) 792/* reduced status report with "BB BB" key data only */
793static void handler_status_K(struct wiimote_data *wdata,
794 const __u8 *payload)
793{ 795{
794 handler_keys(wdata, payload); 796 handler_keys(wdata, payload);
795 797
796 /* on status reports the drm is reset so we need to resend the drm */ 798 /* on status reports the drm is reset so we need to resend the drm */
797 wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 799 wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
800}
801
802/* extended status report with "BB BB LF 00 00 VV" data */
803static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
804{
805 handler_status_K(wdata, payload);
798 806
799 wiiext_event(wdata, payload[2] & 0x02); 807 wiiext_event(wdata, payload[2] & 0x02);
800 808
@@ -804,6 +812,12 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
804 } 812 }
805} 813}
806 814
815/* reduced generic report with "BB BB" key data only */
816static void handler_generic_K(struct wiimote_data *wdata, const __u8 *payload)
817{
818 handler_keys(wdata, payload);
819}
820
807static void handler_data(struct wiimote_data *wdata, const __u8 *payload) 821static void handler_data(struct wiimote_data *wdata, const __u8 *payload)
808{ 822{
809 __u16 offset = payload[3] << 8 | payload[4]; 823 __u16 offset = payload[3] << 8 | payload[4];
@@ -947,16 +961,26 @@ struct wiiproto_handler {
947 961
948static struct wiiproto_handler handlers[] = { 962static struct wiiproto_handler handlers[] = {
949 { .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status }, 963 { .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status },
964 { .id = WIIPROTO_REQ_STATUS, .size = 2, .func = handler_status_K },
950 { .id = WIIPROTO_REQ_DATA, .size = 21, .func = handler_data }, 965 { .id = WIIPROTO_REQ_DATA, .size = 21, .func = handler_data },
966 { .id = WIIPROTO_REQ_DATA, .size = 2, .func = handler_generic_K },
951 { .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return }, 967 { .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return },
968 { .id = WIIPROTO_REQ_RETURN, .size = 2, .func = handler_generic_K },
952 { .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys }, 969 { .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
953 { .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA }, 970 { .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA },
971 { .id = WIIPROTO_REQ_DRM_KA, .size = 2, .func = handler_generic_K },
954 { .id = WIIPROTO_REQ_DRM_KE, .size = 10, .func = handler_drm_KE }, 972 { .id = WIIPROTO_REQ_DRM_KE, .size = 10, .func = handler_drm_KE },
973 { .id = WIIPROTO_REQ_DRM_KE, .size = 2, .func = handler_generic_K },
955 { .id = WIIPROTO_REQ_DRM_KAI, .size = 17, .func = handler_drm_KAI }, 974 { .id = WIIPROTO_REQ_DRM_KAI, .size = 17, .func = handler_drm_KAI },
975 { .id = WIIPROTO_REQ_DRM_KAI, .size = 2, .func = handler_generic_K },
956 { .id = WIIPROTO_REQ_DRM_KEE, .size = 21, .func = handler_drm_KEE }, 976 { .id = WIIPROTO_REQ_DRM_KEE, .size = 21, .func = handler_drm_KEE },
977 { .id = WIIPROTO_REQ_DRM_KEE, .size = 2, .func = handler_generic_K },
957 { .id = WIIPROTO_REQ_DRM_KAE, .size = 21, .func = handler_drm_KAE }, 978 { .id = WIIPROTO_REQ_DRM_KAE, .size = 21, .func = handler_drm_KAE },
979 { .id = WIIPROTO_REQ_DRM_KAE, .size = 2, .func = handler_generic_K },
958 { .id = WIIPROTO_REQ_DRM_KIE, .size = 21, .func = handler_drm_KIE }, 980 { .id = WIIPROTO_REQ_DRM_KIE, .size = 21, .func = handler_drm_KIE },
981 { .id = WIIPROTO_REQ_DRM_KIE, .size = 2, .func = handler_generic_K },
959 { .id = WIIPROTO_REQ_DRM_KAIE, .size = 21, .func = handler_drm_KAIE }, 982 { .id = WIIPROTO_REQ_DRM_KAIE, .size = 21, .func = handler_drm_KAIE },
983 { .id = WIIPROTO_REQ_DRM_KAIE, .size = 2, .func = handler_generic_K },
960 { .id = WIIPROTO_REQ_DRM_E, .size = 21, .func = handler_drm_E }, 984 { .id = WIIPROTO_REQ_DRM_E, .size = 21, .func = handler_drm_E },
961 { .id = WIIPROTO_REQ_DRM_SKAI1, .size = 21, .func = handler_drm_SKAI1 }, 985 { .id = WIIPROTO_REQ_DRM_SKAI1, .size = 21, .func = handler_drm_SKAI1 },
962 { .id = WIIPROTO_REQ_DRM_SKAI2, .size = 21, .func = handler_drm_SKAI2 }, 986 { .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,
970 struct wiiproto_handler *h; 994 struct wiiproto_handler *h;
971 int i; 995 int i;
972 unsigned long flags; 996 unsigned long flags;
973 bool handled = false;
974 997
975 if (size < 1) 998 if (size < 1)
976 return -EINVAL; 999 return -EINVAL;
@@ -981,11 +1004,11 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
981 h = &handlers[i]; 1004 h = &handlers[i];
982 if (h->id == raw_data[0] && h->size < size) { 1005 if (h->id == raw_data[0] && h->size < size) {
983 h->func(wdata, &raw_data[1]); 1006 h->func(wdata, &raw_data[1]);
984 handled = true; 1007 break;
985 } 1008 }
986 } 1009 }
987 1010
988 if (!handled) 1011 if (!handlers[i].id)
989 hid_warn(hdev, "Unhandled report %hhu size %d\n", raw_data[0], 1012 hid_warn(hdev, "Unhandled report %hhu size %d\n", raw_data[0],
990 size); 1013 size);
991 1014