1 /* 2 * Copyright 2008-2011, Michael Lotz <mmlr@mlotz.ch> 3 * Distributed under the terms of the MIT license. 4 */ 5 6 7 //! Driver for USB Human Interface Devices. 8 9 10 #include "Driver.h" 11 #include "HIDDevice.h" 12 #include "HIDReport.h" 13 #include "HIDWriter.h" 14 #include "ProtocolHandler.h" 15 #include "QuirkyDevices.h" 16 17 #include <usb/USB_hid.h> 18 19 #include <stdlib.h> 20 #include <stdio.h> 21 #include <string.h> 22 #include <unistd.h> 23 #include <new> 24 25 26 HIDDevice::HIDDevice(usb_device device, const usb_configuration_info *config, 27 size_t interfaceIndex, int32 quirkyIndex) 28 : fStatus(B_NO_INIT), 29 fDevice(device), 30 fInterfaceIndex(interfaceIndex), 31 fTransferScheduled(0), 32 fTransferBufferSize(0), 33 fTransferBuffer(NULL), 34 fParentCookie(-1), 35 fOpenCount(0), 36 fRemoved(false), 37 fParser(this), 38 fProtocolHandlerCount(0), 39 fProtocolHandlerList(NULL) 40 { 41 uint8 *reportDescriptor = NULL; 42 size_t descriptorLength = 0; 43 44 const usb_device_descriptor *deviceDescriptor 45 = gUSBModule->get_device_descriptor(device); 46 47 HIDWriter descriptorWriter; 48 bool hasFixedDescriptor = false; 49 if (quirkyIndex >= 0) { 50 quirky_build_descriptor quirkyBuildDescriptor 51 = gQuirkyDevices[quirkyIndex].build_descriptor; 52 53 if (quirkyBuildDescriptor != NULL 54 && quirkyBuildDescriptor(descriptorWriter) == B_OK) { 55 56 reportDescriptor = (uint8 *)descriptorWriter.Buffer(); 57 descriptorLength = descriptorWriter.BufferLength(); 58 hasFixedDescriptor = true; 59 } 60 } 61 62 if (!hasFixedDescriptor) { 63 // Conforming device, find the HID descriptor and get the report 64 // descriptor from the device. 65 usb_hid_descriptor *hidDescriptor = NULL; 66 67 const usb_interface_info *interfaceInfo 68 = config->interface[interfaceIndex].active; 69 for (size_t i = 0; i < interfaceInfo->generic_count; i++) { 70 const usb_generic_descriptor &generic 71 = interfaceInfo->generic[i]->generic; 72 if (generic.descriptor_type == B_USB_HID_DESCRIPTOR_HID) { 73 hidDescriptor = (usb_hid_descriptor *)&generic; 74 descriptorLength 75 = hidDescriptor->descriptor_info[0].descriptor_length; 76 break; 77 } 78 } 79 80 if (hidDescriptor == NULL) { 81 TRACE_ALWAYS("didn't find a HID descriptor in the configuration, " 82 "trying to retrieve manually\n"); 83 84 descriptorLength = sizeof(usb_hid_descriptor); 85 hidDescriptor = (usb_hid_descriptor *)malloc(descriptorLength); 86 if (hidDescriptor == NULL) { 87 TRACE_ALWAYS("failed to allocate buffer for hid descriptor\n"); 88 fStatus = B_NO_MEMORY; 89 return; 90 } 91 92 status_t result = gUSBModule->send_request(device, 93 USB_REQTYPE_INTERFACE_IN | USB_REQTYPE_STANDARD, 94 USB_REQUEST_GET_DESCRIPTOR, 95 B_USB_HID_DESCRIPTOR_HID << 8, interfaceIndex, descriptorLength, 96 hidDescriptor, &descriptorLength); 97 98 TRACE("get hid descriptor: result: 0x%08" B_PRIx32 "; length: %lu" 99 "\n", result, descriptorLength); 100 if (result == B_OK) { 101 descriptorLength 102 = hidDescriptor->descriptor_info[0].descriptor_length; 103 } else { 104 descriptorLength = 256; /* XXX */ 105 TRACE_ALWAYS("failed to get HID descriptor, trying with a " 106 "fallback report descriptor length of %lu\n", 107 descriptorLength); 108 } 109 110 free(hidDescriptor); 111 } 112 113 reportDescriptor = (uint8 *)malloc(descriptorLength); 114 if (reportDescriptor == NULL) { 115 TRACE_ALWAYS("failed to allocate buffer for report descriptor\n"); 116 fStatus = B_NO_MEMORY; 117 return; 118 } 119 120 status_t result = gUSBModule->send_request(device, 121 USB_REQTYPE_INTERFACE_IN | USB_REQTYPE_STANDARD, 122 USB_REQUEST_GET_DESCRIPTOR, 123 B_USB_HID_DESCRIPTOR_REPORT << 8, interfaceIndex, descriptorLength, 124 reportDescriptor, &descriptorLength); 125 126 TRACE("get report descriptor: result: 0x%08" B_PRIx32 "; length: %" 127 B_PRIuSIZE "\n", result, descriptorLength); 128 if (result != B_OK) { 129 TRACE_ALWAYS("failed tot get report descriptor\n"); 130 free(reportDescriptor); 131 return; 132 } 133 } else { 134 TRACE_ALWAYS("found quirky device, using patched descriptor\n"); 135 } 136 137 #if 1 138 // save report descriptor for troubleshooting 139 char outputFile[128]; 140 sprintf(outputFile, "/tmp/usb_hid_report_descriptor_%04x_%04x_%lu.bin", 141 deviceDescriptor->vendor_id, deviceDescriptor->product_id, 142 interfaceIndex); 143 int fd = open(outputFile, O_WRONLY | O_CREAT | O_TRUNC, 0644); 144 if (fd >= 0) { 145 write(fd, reportDescriptor, descriptorLength); 146 close(fd); 147 } 148 #endif 149 150 status_t result = fParser.ParseReportDescriptor(reportDescriptor, 151 descriptorLength); 152 if (!hasFixedDescriptor) 153 free(reportDescriptor); 154 155 if (result != B_OK) { 156 TRACE_ALWAYS("parsing the report descriptor failed\n"); 157 fStatus = result; 158 return; 159 } 160 161 #if 0 162 for (uint32 i = 0; i < fParser.CountReports(HID_REPORT_TYPE_ANY); i++) 163 fParser.ReportAt(HID_REPORT_TYPE_ANY, i)->PrintToStream(); 164 #endif 165 166 // find the interrupt in pipe 167 usb_interface_info *interface = config->interface[interfaceIndex].active; 168 for (size_t i = 0; i < interface->endpoint_count; i++) { 169 usb_endpoint_descriptor *descriptor = interface->endpoint[i].descr; 170 if ((descriptor->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) 171 && (descriptor->attributes & USB_ENDPOINT_ATTR_MASK) 172 == USB_ENDPOINT_ATTR_INTERRUPT) { 173 fEndpointAddress = descriptor->endpoint_address; 174 fInterruptPipe = interface->endpoint[i].handle; 175 break; 176 } 177 } 178 179 if (fInterruptPipe == 0) { 180 TRACE_ALWAYS("didn't find a suitable interrupt pipe\n"); 181 return; 182 } 183 184 fTransferBufferSize = fParser.MaxReportSize(HID_REPORT_TYPE_INPUT); 185 if (fTransferBufferSize == 0) { 186 TRACE_ALWAYS("report claims a report size of 0\n"); 187 return; 188 } 189 190 // We pad the allocation size so that we can always read 32 bits at a time 191 // (as done in HIDReportItem) without the need for an additional boundary 192 // check. We don't increase the transfer buffer size though as to not expose 193 // this implementation detail onto the device when scheduling transfers. 194 fTransferBuffer = (uint8 *)malloc(fTransferBufferSize + 3); 195 if (fTransferBuffer == NULL) { 196 TRACE_ALWAYS("failed to allocate transfer buffer\n"); 197 fStatus = B_NO_MEMORY; 198 return; 199 } 200 201 if (quirkyIndex >= 0) { 202 quirky_init_function quirkyInit 203 = gQuirkyDevices[quirkyIndex].init_function; 204 205 if (quirkyInit != NULL) { 206 fStatus = quirkyInit(device, config, interfaceIndex); 207 if (fStatus != B_OK) 208 return; 209 } 210 } 211 212 ProtocolHandler::AddHandlers(*this, fProtocolHandlerList, 213 fProtocolHandlerCount); 214 fStatus = B_OK; 215 } 216 217 218 HIDDevice::~HIDDevice() 219 { 220 ProtocolHandler *handler = fProtocolHandlerList; 221 while (handler != NULL) { 222 ProtocolHandler *next = handler->NextHandler(); 223 delete handler; 224 handler = next; 225 } 226 227 free(fTransferBuffer); 228 } 229 230 231 void 232 HIDDevice::SetParentCookie(int32 cookie) 233 { 234 fParentCookie = cookie; 235 } 236 237 238 status_t 239 HIDDevice::Open(ProtocolHandler *handler, uint32 flags) 240 { 241 atomic_add(&fOpenCount, 1); 242 return B_OK; 243 } 244 245 246 status_t 247 HIDDevice::Close(ProtocolHandler *handler) 248 { 249 atomic_add(&fOpenCount, -1); 250 gUSBModule->cancel_queued_transfers(fInterruptPipe); 251 // This will wake up any listeners. Whether they should close or retry 252 // is handeled internally by the handlers. 253 return B_OK; 254 } 255 256 257 void 258 HIDDevice::Removed() 259 { 260 fRemoved = true; 261 gUSBModule->cancel_queued_transfers(fInterruptPipe); 262 } 263 264 265 status_t 266 HIDDevice::MaybeScheduleTransfer(HIDReport*) 267 { 268 if (fRemoved) 269 return ENODEV; 270 271 if (atomic_get_and_set(&fTransferScheduled, 1) != 0) { 272 // someone else already caused a transfer to be scheduled 273 return B_OK; 274 } 275 276 TRACE("scheduling interrupt transfer of %lu bytes\n", fTransferBufferSize); 277 status_t result = gUSBModule->queue_interrupt(fInterruptPipe, 278 fTransferBuffer, fTransferBufferSize, _TransferCallback, this); 279 if (result != B_OK) { 280 TRACE_ALWAYS("failed to schedule interrupt transfer 0x%08" B_PRIx32 281 "\n", result); 282 return result; 283 } 284 285 return B_OK; 286 } 287 288 289 status_t 290 HIDDevice::SendReport(HIDReport *report) 291 { 292 size_t actualLength; 293 return gUSBModule->send_request(fDevice, 294 USB_REQTYPE_INTERFACE_OUT | USB_REQTYPE_CLASS, 295 B_USB_REQUEST_HID_SET_REPORT, 0x200 | report->ID(), fInterfaceIndex, 296 report->ReportSize(), report->CurrentReport(), &actualLength); 297 } 298 299 300 ProtocolHandler * 301 HIDDevice::ProtocolHandlerAt(uint32 index) const 302 { 303 ProtocolHandler *handler = fProtocolHandlerList; 304 while (handler != NULL) { 305 if (index == 0) 306 return handler; 307 308 handler = handler->NextHandler(); 309 index--; 310 } 311 312 return NULL; 313 } 314 315 316 void 317 HIDDevice::_UnstallCallback(void *cookie, status_t status, void *data, 318 size_t actualLength) 319 { 320 HIDDevice *device = (HIDDevice *)cookie; 321 if (status != B_OK) { 322 TRACE_ALWAYS("Unable to unstall device: %s\n", strerror(status)); 323 } 324 325 // Now report the original failure, since we're ready to retry 326 _TransferCallback(cookie, B_ERROR, device->fTransferBuffer, 0); 327 } 328 329 330 void 331 HIDDevice::_TransferCallback(void *cookie, status_t status, void *data, 332 size_t actualLength) 333 { 334 HIDDevice *device = (HIDDevice *)cookie; 335 if (status == B_DEV_STALLED && !device->fRemoved) { 336 // try clearing stalls right away, the report listeners will resubmit 337 gUSBModule->queue_request(device->fDevice, 338 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT, 339 USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 340 device->fEndpointAddress, 0, NULL, _UnstallCallback, device); 341 return; 342 } 343 344 atomic_set(&device->fTransferScheduled, 0); 345 device->fParser.SetReport(status, device->fTransferBuffer, actualLength); 346 } 347