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