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
sixaxis_init(usb_device device,const usb_configuration_info * config,size_t interfaceIndex)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
sixaxis_build_descriptor(HIDWriter & writer)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
elecom_build_descriptor(HIDWriter & writer)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
xbox360_build_descriptor(HIDWriter & writer)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