1/*
2 * Copyright 2011 Michael Lotz <mmlr@mlotz.ch>
3 * Distributed under the terms of the MIT license.
4 */
5
6
7#include "QuirkyDevices.h"
8
9#include "HIDWriter.h"
10
11#include <string.h>
12
13#include <usb/USB_hid.h>
14
15
16static status_t
17sixaxis_init(usb_device device, const usb_configuration_info *config,
18	size_t interfaceIndex)
19{
20	TRACE_ALWAYS("found SIXAXIS controller, putting it in operational mode\n");
21
22	// an extra get_report is required for the SIXAXIS to become operational
23	uint8 dummy[18];
24	status_t result = gUSBModule->send_request(device, USB_REQTYPE_INTERFACE_IN
25			| USB_REQTYPE_CLASS, B_USB_REQUEST_HID_GET_REPORT, 0x03f2 /* ? */,
26		interfaceIndex, sizeof(dummy), dummy, NULL);
27	if (result != B_OK) {
28		TRACE_ALWAYS("failed to set operational mode: %s\n", strerror(result));
29	}
30
31	return result;
32}
33
34
35static status_t
36sixaxis_build_descriptor(HIDWriter &writer)
37{
38	writer.BeginCollection(COLLECTION_APPLICATION,
39		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_JOYSTICK);
40
41	main_item_data_converter converter;
42	converter.flat_data = 0; // defaults
43	converter.main_data.array_variable = 1;
44	converter.main_data.no_preferred = 1;
45
46	writer.SetReportID(1);
47
48	// unknown / padding
49	writer.DefineInputPadding(1, 8);
50
51	// digital button state on/off
52	writer.DefineInputData(19, 1, converter.main_data, 0, 1,
53		B_HID_USAGE_PAGE_BUTTON, 1);
54
55	// padding to 32 bit boundary
56	writer.DefineInputPadding(13, 1);
57
58	// left analog stick
59	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
60		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
61	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
62		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Y);
63
64	// right analog stick
65	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
66		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
67	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
68		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Y);
69
70	// unknown / padding
71	writer.DefineInputPadding(4, 8);
72
73	// pressure sensitive button states
74	writer.DefineInputData(12, 8, converter.main_data, 0, 255,
75		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_VNO, B_HID_UID_GD_VNO);
76
77	// unknown / padding / operation mode / battery status / connection ...
78	writer.DefineInputPadding(15, 8);
79
80	// accelerometer x, y and z
81	writer.DefineInputData(3, 16, converter.main_data, 0, UINT16_MAX,
82		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_VX);
83
84	// gyroscope
85	writer.DefineInputData(1, 16, converter.main_data, 0, UINT16_MAX,
86		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_VBRZ);
87
88	return writer.EndCollection();
89}
90
91
92static status_t
93xbox360_build_descriptor(HIDWriter &writer)
94{
95	writer.BeginCollection(COLLECTION_APPLICATION,
96		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_JOYSTICK);
97
98	main_item_data_converter converter;
99	converter.flat_data = 0; // defaults
100	converter.main_data.array_variable = 1;
101	converter.main_data.no_preferred = 1;
102
103	// unknown / padding / byte count
104	writer.DefineInputPadding(2, 8);
105
106	// dpad / buttons
107	writer.DefineInputData(11, 1, converter.main_data, 0, 1,
108		B_HID_USAGE_PAGE_BUTTON, 1);
109	writer.DefineInputPadding(1, 1);
110	writer.DefineInputData(4, 1, converter.main_data, 0, 1,
111		B_HID_USAGE_PAGE_BUTTON, 12);
112
113	// triggers
114	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
115		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Z);
116	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
117		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_RZ);
118
119	// sticks
120	writer.DefineInputData(2, 16, converter.main_data, -32768, 32767,
121		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
122	writer.DefineInputData(2, 16, converter.main_data, -32768, 32767,
123		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
124
125	// unknown / padding
126	writer.DefineInputPadding(6, 8);
127
128	return writer.EndCollection();
129}
130
131
132usb_hid_quirky_device gQuirkyDevices[] = {
133	{
134		// The Sony SIXAXIS controller (PS3) needs a GET_REPORT to become
135		// operational which we do in sixaxis_init. Also the normal report
136		// descriptor doesn't contain items for the motion sensing data
137		// and pressure sensitive buttons, so we constrcut a new report
138		// descriptor that includes those extra items.
139		0x054c, 0x0268, USB_INTERFACE_CLASS_HID, 0, 0,
140		sixaxis_init, sixaxis_build_descriptor
141	},
142
143	{
144		// XBOX 360 controllers aren't really HID (marked vendor specific).
145		// They therefore don't provide a HID/report descriptor either. The
146		// input stream is HID-like enough though. We therefore claim support
147		// and build a report descriptor of our own.
148		0, 0, 0xff /* vendor specific */, 0x5d /* XBOX controller */, 0x01,
149		NULL, xbox360_build_descriptor
150	}
151};
152
153int32 gQuirkyDeviceCount
154	= sizeof(gQuirkyDevices) / sizeof(gQuirkyDevices[0]);
155