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%08lx; length: %lu\n", result, 99 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%08lx; length: %lu\n", result, 127 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 fInterruptPipe = interface->endpoint[i].handle; 174 break; 175 } 176 } 177 178 if (fInterruptPipe == 0) { 179 TRACE_ALWAYS("didn't find a suitable interrupt pipe\n"); 180 return; 181 } 182 183 fTransferBufferSize = fParser.MaxReportSize(); 184 if (fTransferBufferSize == 0) { 185 TRACE_ALWAYS("report claims a report size of 0\n"); 186 return; 187 } 188 189 // We pad the allocation size so that we can always read 32 bits at a time 190 // (as done in HIDReportItem) without the need for an additional boundary 191 // check. We don't increase the transfer buffer size though as to not expose 192 // this implementation detail onto the device when scheduling transfers. 193 fTransferBuffer = (uint8 *)malloc(fTransferBufferSize + 3); 194 if (fTransferBuffer == NULL) { 195 TRACE_ALWAYS("failed to allocate transfer buffer\n"); 196 fStatus = B_NO_MEMORY; 197 return; 198 } 199 200 if (quirkyIndex >= 0) { 201 quirky_init_function quirkyInit 202 = gQuirkyDevices[quirkyIndex].init_function; 203 204 if (quirkyInit != NULL) { 205 fStatus = quirkyInit(device, config, interfaceIndex); 206 if (fStatus != B_OK) 207 return; 208 } 209 } 210 211 ProtocolHandler::AddHandlers(*this, fProtocolHandlerList, 212 fProtocolHandlerCount); 213 fStatus = B_OK; 214 } 215 216 217 HIDDevice::~HIDDevice() 218 { 219 ProtocolHandler *handler = fProtocolHandlerList; 220 while (handler != NULL) { 221 ProtocolHandler *next = handler->NextHandler(); 222 delete handler; 223 handler = next; 224 } 225 226 free(fTransferBuffer); 227 } 228 229 230 void 231 HIDDevice::SetParentCookie(int32 cookie) 232 { 233 fParentCookie = cookie; 234 } 235 236 237 status_t 238 HIDDevice::Open(ProtocolHandler *handler, uint32 flags) 239 { 240 atomic_add(&fOpenCount, 1); 241 return B_OK; 242 } 243 244 245 status_t 246 HIDDevice::Close(ProtocolHandler *handler) 247 { 248 atomic_add(&fOpenCount, -1); 249 return B_OK; 250 } 251 252 253 void 254 HIDDevice::Removed() 255 { 256 fRemoved = true; 257 gUSBModule->cancel_queued_transfers(fInterruptPipe); 258 } 259 260 261 status_t 262 HIDDevice::MaybeScheduleTransfer() 263 { 264 if (fRemoved) 265 return B_ERROR; 266 267 if (atomic_set(&fTransferScheduled, 1) != 0) { 268 // someone else already caused a transfer to be scheduled 269 return B_OK; 270 } 271 272 TRACE("scheduling interrupt transfer of %lu bytes\n", fTransferBufferSize); 273 status_t result = gUSBModule->queue_interrupt(fInterruptPipe, 274 fTransferBuffer, fTransferBufferSize, _TransferCallback, this); 275 if (result != B_OK) { 276 TRACE_ALWAYS("failed to schedule interrupt transfer 0x%08lx\n", result); 277 return result; 278 } 279 280 return B_OK; 281 } 282 283 284 status_t 285 HIDDevice::SendReport(HIDReport *report) 286 { 287 size_t actualLength; 288 return gUSBModule->send_request(fDevice, 289 USB_REQTYPE_INTERFACE_OUT | USB_REQTYPE_CLASS, 290 B_USB_REQUEST_HID_SET_REPORT, 0x200 | report->ID(), fInterfaceIndex, 291 report->ReportSize(), report->CurrentReport(), &actualLength); 292 } 293 294 295 ProtocolHandler * 296 HIDDevice::ProtocolHandlerAt(uint32 index) const 297 { 298 ProtocolHandler *handler = fProtocolHandlerList; 299 while (handler != NULL) { 300 if (index == 0) 301 return handler; 302 303 handler = handler->NextHandler(); 304 index--; 305 } 306 307 return NULL; 308 } 309 310 311 void 312 HIDDevice::_TransferCallback(void *cookie, status_t status, void *data, 313 size_t actualLength) 314 { 315 HIDDevice *device = (HIDDevice *)cookie; 316 if (status == B_DEV_STALLED && !device->fRemoved) { 317 // try clearing stalls right away, the report listeners will resubmit 318 gUSBModule->clear_feature(device->fInterruptPipe, 319 USB_FEATURE_ENDPOINT_HALT); 320 } 321 322 atomic_set(&device->fTransferScheduled, 0); 323 device->fParser.SetReport(status, device->fTransferBuffer, actualLength); 324 } 325