xref: /haiku/src/add-ons/kernel/drivers/input/usb_hid/QuirkyDevices.cpp (revision 9f3bdf3d039430b5172c424def20ce5d9f7367d4)
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 
16 static status_t
17 sixaxis_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 
35 static status_t
36 sixaxis_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 
92 static status_t
93 elecom_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 
208 static status_t
209 xbox360_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 
248 usb_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 
276 int32 gQuirkyDeviceCount
277 	= sizeof(gQuirkyDevices) / sizeof(gQuirkyDevices[0]);
278