Ticket #15051: HIDDevice.cpp

File HIDDevice.cpp, 9.2 KB (added by MelanieFox, 5 years ago)

hack in line 189

Line 
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
26HIDDevice::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 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();
185 if (fTransferBufferSize == 0) {
186 TRACE_ALWAYS("report claims a report size of 0\n");
187 return;
188 } else if ( fTransferBufferSize == 7 ) {
189 //XXX: Dirty Hack for my decus gaming mouse!
190 fTransferBufferSize = 8;
191 }
192
193 TRACE_ALWAYS("fTransferBufferSize = %d\n", fTransferBufferSize );
194
195 // We pad the allocation size so that we can always read 32 bits at a time
196 // (as done in HIDReportItem) without the need for an additional boundary
197 // check. We don't increase the transfer buffer size though as to not expose
198 // this implementation detail onto the device when scheduling transfers.
199 fTransferBuffer = (uint8 *)malloc(fTransferBufferSize + 3);
200 if (fTransferBuffer == NULL) {
201 TRACE_ALWAYS("failed to allocate transfer buffer\n");
202 fStatus = B_NO_MEMORY;
203 return;
204 }
205
206 if (quirkyIndex >= 0) {
207 quirky_init_function quirkyInit
208 = gQuirkyDevices[quirkyIndex].init_function;
209
210 if (quirkyInit != NULL) {
211 fStatus = quirkyInit(device, config, interfaceIndex);
212 if (fStatus != B_OK)
213 return;
214 }
215 }
216
217 ProtocolHandler::AddHandlers(*this, fProtocolHandlerList,
218 fProtocolHandlerCount);
219 fStatus = B_OK;
220}
221
222
223HIDDevice::~HIDDevice()
224{
225 ProtocolHandler *handler = fProtocolHandlerList;
226 while (handler != NULL) {
227 ProtocolHandler *next = handler->NextHandler();
228 delete handler;
229 handler = next;
230 }
231
232 free(fTransferBuffer);
233}
234
235
236void
237HIDDevice::SetParentCookie(int32 cookie)
238{
239 fParentCookie = cookie;
240}
241
242
243status_t
244HIDDevice::Open(ProtocolHandler *handler, uint32 flags)
245{
246 atomic_add(&fOpenCount, 1);
247 return B_OK;
248}
249
250
251status_t
252HIDDevice::Close(ProtocolHandler *handler)
253{
254 atomic_add(&fOpenCount, -1);
255 gUSBModule->cancel_queued_transfers(fInterruptPipe);
256 // This will wake up any listeners. Whether they should close or retry
257 // is handeled internally by the handlers.
258 return B_OK;
259}
260
261
262void
263HIDDevice::Removed()
264{
265 fRemoved = true;
266 gUSBModule->cancel_queued_transfers(fInterruptPipe);
267}
268
269
270status_t
271HIDDevice::MaybeScheduleTransfer()
272{
273 if (fRemoved)
274 return B_ERROR;
275
276 if (atomic_get_and_set(&fTransferScheduled, 1) != 0) {
277 // someone else already caused a transfer to be scheduled
278 return B_OK;
279 }
280
281 TRACE("scheduling interrupt transfer of %lu bytes\n", fTransferBufferSize);
282 status_t result = gUSBModule->queue_interrupt(fInterruptPipe,
283 fTransferBuffer, fTransferBufferSize, _TransferCallback, this);
284 if (result != B_OK) {
285 TRACE_ALWAYS("failed to schedule interrupt transfer 0x%08" B_PRIx32
286 "\n", result);
287 return result;
288 }
289
290 return B_OK;
291}
292
293
294status_t
295HIDDevice::SendReport(HIDReport *report)
296{
297 size_t actualLength;
298 return gUSBModule->send_request(fDevice,
299 USB_REQTYPE_INTERFACE_OUT | USB_REQTYPE_CLASS,
300 B_USB_REQUEST_HID_SET_REPORT, 0x200 | report->ID(), fInterfaceIndex,
301 report->ReportSize(), report->CurrentReport(), &actualLength);
302}
303
304
305ProtocolHandler *
306HIDDevice::ProtocolHandlerAt(uint32 index) const
307{
308 ProtocolHandler *handler = fProtocolHandlerList;
309 while (handler != NULL) {
310 if (index == 0)
311 return handler;
312
313 handler = handler->NextHandler();
314 index--;
315 }
316
317 return NULL;
318}
319
320
321void
322HIDDevice::_UnstallCallback(void *cookie, status_t status, void *data,
323 size_t actualLength)
324{
325 HIDDevice *device = (HIDDevice *)cookie;
326 if (status != B_OK) {
327 TRACE_ALWAYS("Unable to unstall device: %s\n", strerror(status));
328 }
329
330 // Now report the original failure, since we're ready to retry
331 _TransferCallback(cookie, B_ERROR, device->fTransferBuffer, 0);
332}
333
334
335void
336HIDDevice::_TransferCallback(void *cookie, status_t status, void *data,
337 size_t actualLength)
338{
339 HIDDevice *device = (HIDDevice *)cookie;
340 if (status == B_DEV_STALLED && !device->fRemoved) {
341 // try clearing stalls right away, the report listeners will resubmit
342 TRACE_ALWAYS("Trying to unstall device %u\n", device->fDevice );
343 gUSBModule->queue_request(device->fDevice,
344 USB_REQTYPE_STANDARD | USB_REQTYPE_ENDPOINT_OUT,
345 USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT,
346 device->fEndpointAddress, 0, NULL, _UnstallCallback, device);
347 return;
348 }
349
350 atomic_set(&device->fTransferScheduled, 0);
351 device->fParser.SetReport(status, device->fTransferBuffer, actualLength);
352}