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
93elecom_build_descriptor(HIDWriter &writer)
94{
95	uint8 patchedDescriptor[] = {
96		0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
97		0x09, 0x02, // Usage (Mouse)
98		0xA1, 0x01, // Collection (Application)
99		0x09, 0x01, // Usage (Pointer)
100		0xA1, 0x00, // Collection (Physical)
101		0x85, 0x01, // Report ID (1)
102		0x95, 0x06, // Report Count (6) (is 5 in the original descriptor)
103		0x75, 0x01, // Report Size (1)
104		0x05, 0x09, // Usage Page (Button)
105		0x19, 0x01, // Usage Minimum (0x01)
106		0x29, 0x06, // Usage Maximum (0x06) (is 5 in the original descriptor)
107		0x15, 0x00, // Logical Minimum (0)
108		0x25, 0x01, // Logical Maximum (1)
109		0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
110		0x95, 0x01, // Report Count (1)
111		0x75, 0x02, // Report Size (2) (is 3 in the original descriptor)
112		0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
113		0x75, 0x10, // Report Size (16)
114		0x95, 0x02, // Report Count (2)
115		0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
116		0x09, 0x30, // Usage (X)
117		0x09, 0x31, // Usage (Y)
118		0x16, 0x00, 0x80,  // Logical Minimum (-32768)
119		0x26, 0xFF, 0x7F,  // Logical Maximum (32767)
120		0x81, 0x06,  // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
121		0xC0,        // End Collection
122		0xA1, 0x00,  // Collection (Physical)
123		0x95, 0x01,  // Report Count (1)
124		0x75, 0x08,  // Report Size (8)
125		0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
126		0x09, 0x38,  // Usage (Wheel)
127		0x15, 0x81,  // Logical Minimum (-127)
128		0x25, 0x7F,  // Logical Maximum (127)
129		0x81, 0x06,  // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
130		0xC0,        // End Collection
131		0xA1, 0x00,  // Collection (Physical)
132		0x95, 0x01,  // Report Count (1)
133		0x75, 0x08,  // Report Size (8)
134		0x05, 0x0C,  // Usage Page (Consumer)
135		0x0A, 0x38, 0x02,  // Usage (AC Pan)
136		0x15, 0x81,  // Logical Minimum (-127)
137		0x25, 0x7F,  // Logical Maximum (127)
138		0x81, 0x06,  // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
139		0xC0,        // End Collection
140		0xC0,        // End Collection
141		0x06, 0x01, 0xFF,  // Usage Page (Vendor Defined 0xFF01)
142		0x09, 0x00,  // Usage (0x00)
143		0xA1, 0x01,  // Collection (Application)
144		0x85, 0x02,  // Report ID (2)
145		0x09, 0x00,  // Usage (0x00)
146		0x15, 0x00,  // Logical Minimum (0)
147		0x26, 0xFF, 0x00,  // Logical Maximum (255)
148		0x75, 0x08,  // Report Size (8)
149		0x95, 0x07,  // Report Count (7)
150		0x81, 0x02,  // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
151		0xC0,        // End Collection
152		0x05, 0x0C,  // Usage Page (Consumer)
153		0x09, 0x01,  // Usage (Consumer Control)
154		0xA1, 0x01,  // Collection (Application)
155		0x85, 0x05,  // Report ID (5)
156		0x19, 0x00,  // Usage Minimum (Unassigned)
157		0x2A, 0x3C, 0x02,  // Usage Maximum (AC Format)
158		0x15, 0x00,  // Logical Minimum (0)
159		0x26, 0x3C, 0x02,  // Logical Maximum (572)
160		0x95, 0x01,  // Report Count (1)
161		0x75, 0x10,  // Report Size (16)
162		0x81, 0x00,  // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
163		0xC0,        // End Collection
164		0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
165		0x09, 0x80,  // Usage (Sys Control)
166		0xA1, 0x01,  // Collection (Application)
167		0x85, 0x03,  // Report ID (3)
168		0x19, 0x81,  // Usage Minimum (Sys Power Down)
169		0x29, 0x83,  // Usage Maximum (Sys Wake Up)
170		0x15, 0x00,  // Logical Minimum (0)
171		0x25, 0x01,  // Logical Maximum (1)
172		0x75, 0x01,  // Report Size (1)
173		0x95, 0x03,  // Report Count (3)
174		0x81, 0x02,  // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
175		0x95, 0x05,  // Report Count (5)
176		0x81, 0x01,  // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
177		0xC0,        // End Collection
178		0x06, 0xBC, 0xFF,  // Usage Page (Vendor Defined 0xFFBC)
179		0x09, 0x88,  // Usage (0x88)
180		0xA1, 0x01,  // Collection (Application)
181		0x85, 0x04,  // Report ID (4)
182		0x95, 0x01,  // Report Count (1)
183		0x75, 0x08,  // Report Size (8)
184		0x15, 0x00,  // Logical Minimum (0)
185		0x26, 0xFF, 0x00,  // Logical Maximum (255)
186		0x19, 0x00,  // Usage Minimum (0x00)
187		0x2A, 0xFF, 0x00,  // Usage Maximum (0xFF)
188		0x81, 0x00,  // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
189		0xC0,        // End Collection
190		0x06, 0x02, 0xFF,  // Usage Page (Vendor Defined 0xFF02)
191		0x09, 0x02,  // Usage (0x02)
192		0xA1, 0x01,  // Collection (Application)
193		0x85, 0x06,  // Report ID (6)
194		0x09, 0x02,  // Usage (0x02)
195		0x15, 0x00,  // Logical Minimum (0)
196		0x26, 0xFF, 0x00,  // Logical Maximum (255)
197		0x75, 0x08,  // Report Size (8)
198		0x95, 0x07,  // Report Count (7)
199		0xB1, 0x02,
200			// Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position, Non-volatile)
201		0xC0,        // End Collection
202	};
203
204	return writer.Write(&patchedDescriptor, sizeof(patchedDescriptor));
205}
206
207
208static status_t
209xbox360_build_descriptor(HIDWriter &writer)
210{
211	writer.BeginCollection(COLLECTION_APPLICATION,
212		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_JOYSTICK);
213
214	main_item_data_converter converter;
215	converter.flat_data = 0; // defaults
216	converter.main_data.array_variable = 1;
217	converter.main_data.no_preferred = 1;
218
219	// unknown / padding / byte count
220	writer.DefineInputPadding(2, 8);
221
222	// dpad / buttons
223	writer.DefineInputData(11, 1, converter.main_data, 0, 1,
224		B_HID_USAGE_PAGE_BUTTON, 1);
225	writer.DefineInputPadding(1, 1);
226	writer.DefineInputData(4, 1, converter.main_data, 0, 1,
227		B_HID_USAGE_PAGE_BUTTON, 12);
228
229	// triggers
230	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
231		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Z);
232	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
233		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_RZ);
234
235	// sticks
236	writer.DefineInputData(2, 16, converter.main_data, -32768, 32767,
237		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
238	writer.DefineInputData(2, 16, converter.main_data, -32768, 32767,
239		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
240
241	// unknown / padding
242	writer.DefineInputPadding(6, 8);
243
244	return writer.EndCollection();
245}
246
247
248usb_hid_quirky_device gQuirkyDevices[] = {
249	{
250		// The Sony SIXAXIS controller (PS3) needs a GET_REPORT to become
251		// operational which we do in sixaxis_init. Also the normal report
252		// descriptor doesn't contain items for the motion sensing data
253		// and pressure sensitive buttons, so we constrcut a new report
254		// descriptor that includes those extra items.
255		0x054c, 0x0268, USB_INTERFACE_CLASS_HID, 0, 0,
256		sixaxis_init, sixaxis_build_descriptor
257	},
258
259	{
260		// Elecom trackball which has 6 buttons, and includes them in the report, but not in the
261		// report descriptor. Construct a report descriptor including all 6 buttons.
262		0x056e, 0x00fd, USB_INTERFACE_CLASS_HID, 0, 0,
263		NULL, elecom_build_descriptor
264	},
265
266	{
267		// XBOX 360 controllers aren't really HID (marked vendor specific).
268		// They therefore don't provide a HID/report descriptor either. The
269		// input stream is HID-like enough though. We therefore claim support
270		// and build a report descriptor of our own.
271		0, 0, 0xff /* vendor specific */, 0x5d /* XBOX controller */, 0x01,
272		NULL, xbox360_build_descriptor
273	}
274};
275
276int32 gQuirkyDeviceCount
277	= sizeof(gQuirkyDevices) / sizeof(gQuirkyDevices[0]);
278