From 8e1857f79521285ff4ecf2ab2a258191dd4aa0a8 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Mon, 27 Jul 2009 00:35:21 +0000 Subject: [PATCH] * Completely rework the USB HID driver to make use of the HID framework introduced earlier. * Reworked the previous device classes to make them ProtocolHandlers handling their respective input_server <-> driver protocol. * Implement setting report item data and building/sending reports based on that. * Remove the old HID parsing code. This enables us to use all HID devices as we now parse and use the HID descriptors/reports. Non-boot-porotocol devices should therefore work. The next step will be to implement a generic input/output framework in userland that can communicate with a generic protocol handler in usb_hid. This will then enable applications to make use of all the non-mapped HID stuff directly. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31790 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/drivers/usb/USB_hid.h | 127 ++++--- .../kernel/drivers/input/usb_hid/Driver.cpp | 138 ++++--- .../kernel/drivers/input/usb_hid/Driver.h | 3 - .../drivers/input/usb_hid/HIDDevice.cpp | 330 +++++----------- .../kernel/drivers/input/usb_hid/HIDDevice.h | 83 ++--- .../drivers/input/usb_hid/HIDParser.cpp | 8 +- .../drivers/input/usb_hid/HIDReport.cpp | 48 ++- .../kernel/drivers/input/usb_hid/HIDReport.h | 3 + .../drivers/input/usb_hid/HIDReportItem.cpp | 43 +++ .../drivers/input/usb_hid/HIDReportItem.h | 8 +- .../kernel/drivers/input/usb_hid/Jamfile | 27 +- .../drivers/input/usb_hid/KeyboardDevice.cpp | 295 ++++++++++----- .../drivers/input/usb_hid/KeyboardDevice.h | 45 ++- .../drivers/input/usb_hid/MouseDevice.cpp | 159 ++++---- .../drivers/input/usb_hid/MouseDevice.h | 36 +- .../drivers/input/usb_hid/ProtocolHandler.cpp | 141 +++++++ .../drivers/input/usb_hid/ProtocolHandler.h | 52 +++ .../kernel/drivers/input/usb_hid/hidparse.c | 352 ------------------ .../kernel/drivers/input/usb_hid/hidparse.h | 174 --------- .../kernel/drivers/input/usb_hid/kernel_cpp.h | 45 --- 20 files changed, 945 insertions(+), 1172 deletions(-) create mode 100644 src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.cpp create mode 100644 src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h delete mode 100644 src/add-ons/kernel/drivers/input/usb_hid/hidparse.c delete mode 100644 src/add-ons/kernel/drivers/input/usb_hid/hidparse.h diff --git a/headers/os/drivers/usb/USB_hid.h b/headers/os/drivers/usb/USB_hid.h index 913e812d7e..370e6fa190 100644 --- a/headers/os/drivers/usb/USB_hid.h +++ b/headers/os/drivers/usb/USB_hid.h @@ -17,13 +17,13 @@ // HID Interface Subclasses enum { - USB_HID_INTERFACE_NO_SUBCLASS = 0x00, // No Subclass + USB_HID_INTERFACE_NO_SUBCLASS = 0x00, // No Subclass USB_HID_INTERFACE_BOOT_SUBCLASS // Boot Interface Subclass }; // HID Class-Specific descriptor subtypes enum { - USB_HID_DESCRIPTOR_HID = 0x21, + USB_HID_DESCRIPTOR_HID = 0x21, USB_HID_DESCRIPTOR_REPORT, USB_HID_DESCRIPTOR_PHYSICAL }; @@ -34,7 +34,7 @@ enum { USB_REQUEST_HID_GET_IDLE, USB_REQUEST_HID_GET_PROTOCOL, - USB_REQUEST_HID_SET_REPORT = 0x09, + USB_REQUEST_HID_SET_REPORT = 0x09, USB_REQUEST_HID_SET_IDLE, USB_REQUEST_HID_SET_PROTOCOL }; @@ -55,67 +55,88 @@ typedef struct { /* Usage Pages/IDs */ enum { - USAGE_PAGE_GENERIC_DESKTOP = 0x1, - USAGE_PAGE_SIMULATION, - USAGE_PAGE_VR, - USAGE_PAGE_SPORT, - USAGE_PAGE_GAME, - USAGE_PAGE_GENERIC, - USAGE_PAGE_KEYBOARD, - USAGE_PAGE_LED, - USAGE_PAGE_BUTTON, - USAGE_PAGE_ORDINAL, - USAGE_PAGE_TELEPHONY, - USAGE_PAGE_CONSUMER, - USAGE_PAGE_DIGITIZER, - USAGE_PAGE_PID = 0xf, - USAGE_PAGE_UNICODE, - USAGE_PAGE_ALPHANUM_DISPLAY = 0x14, - USAGE_PAGE_MEDICAL = 0x40, - USAGE_PAGE_MICROSOFT = 0xff00 + HID_USAGE_PAGE_GENERIC_DESKTOP = 0x1, + HID_USAGE_PAGE_SIMULATION, + HID_USAGE_PAGE_VR, + HID_USAGE_PAGE_SPORT, + HID_USAGE_PAGE_GAME, + HID_USAGE_PAGE_GENERIC, + HID_USAGE_PAGE_KEYBOARD, + HID_USAGE_PAGE_LED, + HID_USAGE_PAGE_BUTTON, + HID_USAGE_PAGE_ORDINAL, + HID_USAGE_PAGE_TELEPHONY, + HID_USAGE_PAGE_CONSUMER, + HID_USAGE_PAGE_DIGITIZER, + HID_USAGE_PAGE_PID = 0xf, + HID_USAGE_PAGE_UNICODE, + HID_USAGE_PAGE_ALPHANUM_DISPLAY = 0x14, + HID_USAGE_PAGE_MEDICAL = 0x40, + HID_USAGE_PAGE_MICROSOFT = 0xff00 }; /* Page 1: Generic Desktop */ enum { - USAGE_ID_POINTER = 0x1, - USAGE_ID_MOUSE, - USAGE_ID_JOYSTICK = 0x4, - USAGE_ID_GAMEPAD, - USAGE_ID_KEYBOARD, - USAGE_ID_KEYPAD, - USAGE_ID_MULTIAXIS = 0x8, + HID_USAGE_ID_POINTER = 0x1, + HID_USAGE_ID_MOUSE, + HID_USAGE_ID_JOYSTICK = 0x4, + HID_USAGE_ID_GAMEPAD, + HID_USAGE_ID_KEYBOARD, + HID_USAGE_ID_KEYPAD, + HID_USAGE_ID_MULTIAXIS = 0x8, - USAGE_ID_X = 0x30, - USAGE_ID_Y, - USAGE_ID_Z, - USAGE_ID_RX, - USAGE_ID_RY, - USAGE_ID_RZ, - USAGE_ID_SLIDER, - USAGE_ID_DIAL, - USAGE_ID_WHEEL, - USAGE_ID_HAT_SWITCH, - USAGE_ID_COUNTED_BUFFER, - USAGE_ID_BYTE_COUNT, - USAGE_ID_MOTION_WAKEUP, - USAGE_ID_START, - USAGE_ID_SELECT, - USAGE_ID_VX = 0x40, - USAGE_ID_VY, - USAGE_ID_VZ, - USAGE_ID_VBRX, - USAGE_ID_VBRY, - USAGE_ID_VBRZ, - USAGE_ID_VNO, - USAGE_ID_FEATURE_NOTIFICATION + HID_USAGE_ID_X = 0x30, + HID_USAGE_ID_Y, + HID_USAGE_ID_Z, + HID_USAGE_ID_RX, + HID_USAGE_ID_RY, + HID_USAGE_ID_RZ, + HID_USAGE_ID_SLIDER, + HID_USAGE_ID_DIAL, + HID_USAGE_ID_WHEEL, + HID_USAGE_ID_HAT_SWITCH, + HID_USAGE_ID_COUNTED_BUFFER, + HID_USAGE_ID_BYTE_COUNT, + HID_USAGE_ID_MOTION_WAKEUP, + HID_USAGE_ID_START, + HID_USAGE_ID_SELECT, + HID_USAGE_ID_VX = 0x40, + HID_USAGE_ID_VY, + HID_USAGE_ID_VZ, + HID_USAGE_ID_VBRX, + HID_USAGE_ID_VBRY, + HID_USAGE_ID_VBRZ, + HID_USAGE_ID_VNO, + HID_USAGE_ID_FEATURE_NOTIFICATION }; /* Page 2: Simulation */ enum { - USAGE_ID_RUDDER = 0xBA, - USAGE_ID_THROTTLE = 0xBB, + HID_USAGE_ID_RUDDER = 0xba, + HID_USAGE_ID_THROTTLE = 0xbb, +}; + +/* Page 7: Keyboard */ + +enum { + HID_USAGE_ID_LEFT_CONTROL = 0xe0, + HID_USAGE_ID_LEFT_SHIFT, + HID_USAGE_ID_LEFT_ALT, + HID_USAGE_ID_LEFT_GUI, + HID_USAGE_ID_RIGHT_CONTROL, + HID_USAGE_ID_RIGHT_SHIFT, + HID_USAGE_ID_RIGHT_ALT, + HID_USAGE_ID_RIGHT_GUI +}; + +/* Page 8: LED */ + +enum { + HID_USAGE_ID_LED_NUM_LOCK = 0x01, + HID_USAGE_ID_LED_CAPS_LOCK, + HID_USAGE_ID_LED_SCROLL_LOCK }; #endif // _USB_HID_H diff --git a/src/add-ons/kernel/drivers/input/usb_hid/Driver.cpp b/src/add-ons/kernel/drivers/input/usb_hid/Driver.cpp index e1707550c6..231aaba7a2 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/Driver.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/Driver.cpp @@ -1,22 +1,18 @@ /* Driver for USB Human Interface Devices. - Copyright (C) 2008 Michael Lotz + Copyright (C) 2008-2009 Michael Lotz Distributed under the terms of the MIT license. - - Some parts of the code are based on the previous usb_hid driver which - was written by Jérôme Duval. */ + #include "DeviceList.h" #include "Driver.h" #include "HIDDevice.h" +#include "ProtocolHandler.h" -#ifdef HAIKU_TARGET_PLATFORM_HAIKU -#include // for mutex -#else -#include "BeOSCompatibility.h" // for pseudo mutex -#endif - +#include #include +#include +#include int32 api_version = B_CUR_DRIVER_API_VERSION; @@ -74,17 +70,43 @@ usb_hid_device_added(usb_device device, void **cookie) i, interfaceClass, interfaceSubclass, interface->descr->interface_protocol); - if (interfaceClass == USB_INTERFACE_CLASS_HID - && interfaceSubclass == USB_INTERFACE_SUBCLASS_HID_BOOT) { + if (interfaceClass == USB_INTERFACE_CLASS_HID) { mutex_lock(&sDriverLock); - HIDDevice *hidDevice = HIDDevice::MakeHIDDevice(device, config, i); + HIDDevice *hidDevice + = new(std::nothrow) HIDDevice(device, config, i); if (hidDevice != NULL && hidDevice->InitCheck() == B_OK) { hidDevice->SetParentCookie(parentCookie); - gDeviceList->AddDevice(hidDevice->Name(), hidDevice); - devicesFound = true; + + for (uint32 i = 0;; i++) { + ProtocolHandler *handler = hidDevice->ProtocolHandlerAt(i); + if (handler == NULL) + break; + + // As devices can be un- and replugged at will, we cannot + // simply rely on a device count. If there is just one + // keyboard, this does not mean that it uses the 0 name. + // There might have been two keyboards and the one using 0 + // might have been unplugged. So we just generate names + // until we find one that is not currently in use. + int32 index = 0; + char pathBuffer[128]; + const char *basePath = handler->BasePath(); + while (true) { + sprintf(pathBuffer, "%s%ld", basePath, index++); + if (gDeviceList->FindDevice(pathBuffer) == NULL) { + // this name is still free, use it + handler->SetPublishPath(strdup(pathBuffer)); + break; + } + } + + gDeviceList->AddDevice(handler->PublishPath(), handler); + devicesFound = true; + } } else delete hidDevice; + mutex_unlock(&sDriverLock); } } @@ -105,21 +127,32 @@ usb_hid_device_removed(void *cookie) TRACE("device_removed(%ld)\n", parentCookie); for (int32 i = 0; i < gDeviceList->CountDevices(); i++) { - HIDDevice *device = (HIDDevice *)gDeviceList->DeviceAt(i); - if (!device) + ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->DeviceAt(i); + if (!handler) continue; - if (device->ParentCookie() == parentCookie) { - // this device belongs to the one removed - if (device->IsOpen()) { - // the device will be deleted upon being freed - device->Removed(); - } else { - // remove the device and start over - gDeviceList->RemoveDevice(NULL, device); - i = -1; - } + HIDDevice *device = handler->Device(); + if (device->ParentCookie() != parentCookie) + continue; + + // this handler's device belongs to the one removed + if (device->IsOpen()) { + // the device and it's handlers will be deleted in the free hook + device->Removed(); + break; } + + // remove all the handlers + for (uint32 i = 0;; i++) { + handler = device->ProtocolHandlerAt(i); + if (handler == NULL) + break; + + gDeviceList->RemoveDevice(NULL, handler); + } + + delete device; + break; } mutex_unlock(&sDriverLock); @@ -136,14 +169,14 @@ usb_hid_open(const char *name, uint32 flags, void **cookie) TRACE("open(%s, %lu, %p)\n", name, flags, cookie); mutex_lock(&sDriverLock); - HIDDevice *device = (HIDDevice *)gDeviceList->FindDevice(name); - if (device == NULL) { + ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->FindDevice(name); + if (handler == NULL) { mutex_unlock(&sDriverLock); return B_ENTRY_NOT_FOUND; } - status_t result = device->Open(flags); - *cookie = device; + status_t result = handler->Open(flags); + *cookie = handler; mutex_unlock(&sDriverLock); return result; } @@ -152,9 +185,9 @@ usb_hid_open(const char *name, uint32 flags, void **cookie) static status_t usb_hid_read(void *cookie, off_t position, void *buffer, size_t *numBytes) { - TRACE("read(%p, %Ld, %p, %lu)\n", cookie, position, buffer, *numBytes); - HIDDevice *device = (HIDDevice *)cookie; - return device->Read((uint8 *)buffer, numBytes); + TRACE_ALWAYS("read on hid device\n"); + *numBytes = 0; + return B_ERROR; } @@ -162,9 +195,9 @@ static status_t usb_hid_write(void *cookie, off_t position, const void *buffer, size_t *numBytes) { - TRACE("write(%p, %Ld, %p, %lu)\n", cookie, position, buffer, *numBytes); - HIDDevice *device = (HIDDevice *)cookie; - return device->Write((const uint8 *)buffer, numBytes); + TRACE_ALWAYS("write on hid device\n"); + *numBytes = 0; + return B_ERROR; } @@ -172,8 +205,8 @@ static status_t usb_hid_control(void *cookie, uint32 op, void *buffer, size_t length) { TRACE("control(%p, %lu, %p, %lu)\n", cookie, op, buffer, length); - HIDDevice *device = (HIDDevice *)cookie; - return device->Control(op, buffer, length); + ProtocolHandler *handler = (ProtocolHandler *)cookie; + return handler->Control(op, buffer, length); } @@ -181,8 +214,8 @@ static status_t usb_hid_close(void *cookie) { TRACE("close(%p)\n", cookie); - HIDDevice *device = (HIDDevice *)cookie; - return device->Close(); + ProtocolHandler *handler = (ProtocolHandler *)cookie; + return handler->Close(); } @@ -190,18 +223,27 @@ static status_t usb_hid_free(void *cookie) { TRACE("free(%p)\n", cookie); - HIDDevice *device = (HIDDevice *)cookie; mutex_lock(&sDriverLock); - status_t status = device->Free(); - if (device->IsRemoved() - && gDeviceList->RemoveDevice(NULL, device) == B_OK) { - // the device is removed already but as it was open the removed hook - // has not deleted the object + + HIDDevice *device = ((ProtocolHandler *)cookie)->Device(); + if (device->IsOpen()) { + // another handler of this device is still open so we can't free it + } else if (device->IsRemoved()) { + // the parent device is removed already and none of its handlers are + // open anymore so we can free it here + for (uint32 i = 0;; i++) { + ProtocolHandler *handler = device->ProtocolHandlerAt(i); + if (handler == NULL) + break; + + gDeviceList->RemoveDevice(NULL, handler); + } + delete device; } mutex_unlock(&sDriverLock); - return status; + return B_OK; } diff --git a/src/add-ons/kernel/drivers/input/usb_hid/Driver.h b/src/add-ons/kernel/drivers/input/usb_hid/Driver.h index 2ca3e9f406..a362e699db 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/Driver.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/Driver.h @@ -21,9 +21,6 @@ #define USB_DEFAULT_CONFIGURATION 0 #define USB_VENDOR_WACOM 0x056a -#define USB_HID_DEVICE_TYPE_KEYBOARD 0x06090105 -#define USB_HID_DEVICE_TYPE_MOUSE 0x02090105 - extern usb_module_info *gUSBModule; extern DeviceList *gDeviceList; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp b/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp index 139082c704..9eba7ec2c5 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp @@ -1,78 +1,44 @@ /* - Driver for USB Human Interface Devices. - Copyright (C) 2008 Michael Lotz + Copyright (C) 2008-2009 Michael Lotz Distributed under the terms of the MIT license. */ #include "Driver.h" #include "HIDDevice.h" +#include "HIDReport.h" +#include "ProtocolHandler.h" + #include + +#include #include #include #include -// includes for the different device types -#include "KeyboardDevice.h" -#include "MouseDevice.h" - -HIDDevice::HIDDevice(usb_device device, usb_pipe interruptPipe, - size_t interfaceIndex, report_insn *instructions, size_t instructionCount, - size_t totalReportSize, size_t ringBufferSize) +HIDDevice::HIDDevice(usb_device device, const usb_configuration_info *config, + size_t interfaceIndex) : fStatus(B_NO_INIT), fDevice(device), - fInterruptPipe(interruptPipe), fInterfaceIndex(interfaceIndex), - fInstructions(instructions), - fInstructionCount(instructionCount), - fTotalReportSize(totalReportSize), - fTransferUnprocessed(false), - fTransferStatus(B_ERROR), - fTransferActualLength(0), + fTransferScheduled(0), + fTransferBufferSize(0), fTransferBuffer(NULL), - fTransferNotifySem(-1), - fName(NULL), fParentCookie(-1), - fOpen(false), + fOpenCount(0), fRemoved(false), - fRingBuffer(NULL) -{ - if (ringBufferSize > 0) - fRingBuffer = create_ring_buffer(ringBufferSize); - - fTransferBuffer = (uint8 *)malloc(fTotalReportSize); - if (fTransferBuffer == NULL) { - fStatus = B_NO_MEMORY; - return; - } - - fStatus = B_OK; -} - - -HIDDevice::~HIDDevice() -{ - if (fRingBuffer) { - delete_ring_buffer(fRingBuffer); - fRingBuffer = NULL; - } - - if (fTransferNotifySem >= 0) - delete_sem(fTransferNotifySem); - - free(fTransferBuffer); - free(fName); -} - - -HIDDevice * -HIDDevice::MakeHIDDevice(usb_device device, - const usb_configuration_info *config, size_t interfaceIndex) + fParser(this), + fProtocolHandlerCount(0), + fProtocolHandlers(NULL) { // read HID descriptor size_t descriptorLength = sizeof(usb_hid_descriptor); - usb_hid_descriptor *hidDescriptor = (usb_hid_descriptor *)malloc(descriptorLength); - if (hidDescriptor == NULL) - return NULL; + usb_hid_descriptor *hidDescriptor + = (usb_hid_descriptor *)malloc(descriptorLength); + if (hidDescriptor == NULL) { + TRACE_ALWAYS("failed to allocate buffer for hid descriptor\n"); + fStatus = B_NO_MEMORY; + return; + } status_t result = gUSBModule->send_request(device, USB_REQTYPE_INTERFACE_IN | USB_REQTYPE_STANDARD, @@ -80,7 +46,8 @@ HIDDevice::MakeHIDDevice(usb_device device, USB_HID_DESCRIPTOR_HID << 8, interfaceIndex, descriptorLength, hidDescriptor, &descriptorLength); - TRACE("get_hid_desc: result: 0x%08lx; length: %lu\n", result, descriptorLength); + TRACE("get hid descriptor: result: 0x%08lx; length: %lu\n", result, + descriptorLength); if (result == B_OK) descriptorLength = hidDescriptor->descriptor_info[0].descriptor_length; else @@ -88,8 +55,11 @@ HIDDevice::MakeHIDDevice(usb_device device, free(hidDescriptor); uint8 *reportDescriptor = (uint8 *)malloc(descriptorLength); - if (reportDescriptor == NULL) - return NULL; + if (reportDescriptor == NULL) { + TRACE_ALWAYS("failed to allocate buffer for report descriptor\n"); + fStatus = B_NO_MEMORY; + return; + } result = gUSBModule->send_request(device, USB_REQTYPE_INTERFACE_IN | USB_REQTYPE_STANDARD, @@ -97,10 +67,12 @@ HIDDevice::MakeHIDDevice(usb_device device, USB_HID_DESCRIPTOR_REPORT << 8, interfaceIndex, descriptorLength, reportDescriptor, &descriptorLength); - TRACE("get_hid_rep_desc: result: 0x%08lx; length: %lu\n", result, descriptorLength); + TRACE("get report descriptor: result: 0x%08lx; length: %lu\n", result, + descriptorLength); if (result != B_OK) { + TRACE_ALWAYS("failed tot get report descriptor\n"); free(reportDescriptor); - return NULL; + return; } #if 1 @@ -118,100 +90,57 @@ HIDDevice::MakeHIDDevice(usb_device device, } #endif - // decompose report descriptor - size_t itemCount = descriptorLength; - decomp_item *items = (decomp_item *)malloc(sizeof(decomp_item) * itemCount); - if (items == NULL) { - free(reportDescriptor); - return NULL; - } - - decompose_report_descriptor(reportDescriptor, descriptorLength, items, - &itemCount); - uint32 deviceType = *(uint32 *)reportDescriptor; + result = fParser.ParseReportDescriptor(reportDescriptor, descriptorLength); free(reportDescriptor); - - // parse report descriptor - size_t instructionCount = itemCount; - report_insn *instructions - = (report_insn *)malloc(sizeof(report_insn) * instructionCount); - if (instructions == NULL) { - free(items); - return NULL; + if (result != B_OK) { + TRACE_ALWAYS("parsing the report descriptor failed\n"); + fStatus = result; + return; } - int firstReportID = 0; - size_t totalReportSize = 0; - parse_report_descriptor(items, itemCount, instructions, - &instructionCount, &totalReportSize, &firstReportID); - free(items); - - report_insn *finalInstructions = (report_insn *)realloc(instructions, - sizeof(report_insn) * instructionCount); - if (finalInstructions == NULL) { - free(instructions); - return NULL; - } - - TRACE("%lu items, %lu instructions, %lu bytes\n", itemCount, - instructionCount, totalReportSize); - // find the interrupt in pipe - usb_pipe interruptPipe = 0; usb_interface_info *interface = config->interface[interfaceIndex].active; for (size_t i = 0; i < interface->endpoint_count; i++) { usb_endpoint_descriptor *descriptor = interface->endpoint[i].descr; if ((descriptor->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) - && (descriptor->attributes & USB_ENDPOINT_ATTR_MASK) == USB_ENDPOINT_ATTR_INTERRUPT) { - interruptPipe = interface->endpoint[i].handle; + && (descriptor->attributes & USB_ENDPOINT_ATTR_MASK) + == USB_ENDPOINT_ATTR_INTERRUPT) { + fInterruptPipe = interface->endpoint[i].handle; break; } } - if (interruptPipe == 0) { + if (fInterruptPipe == 0) { TRACE_ALWAYS("didn't find a suitable interrupt pipe\n"); - free(finalInstructions); - return NULL; + return; } - // determine device type and create the device object - HIDDevice *hidDevice = NULL; - if (deviceType == USB_HID_DEVICE_TYPE_KEYBOARD) { - hidDevice = new(std::nothrow) KeyboardDevice(device, interruptPipe, - interfaceIndex, finalInstructions, instructionCount, - totalReportSize); - } else if (deviceType == USB_HID_DEVICE_TYPE_MOUSE) { - hidDevice = new(std::nothrow) MouseDevice(device, interruptPipe, - interfaceIndex, finalInstructions, instructionCount, - totalReportSize); - } else - TRACE_ALWAYS("unsupported device type 0x%08lx\n", deviceType); + fTransferBufferSize = fParser.MaxReportSize(); + if (fTransferBufferSize == 0) { + TRACE_ALWAYS("report claims a report size of 0\n"); + return; + } - if (hidDevice == NULL) - free(finalInstructions); - return hidDevice; + fTransferBuffer = (uint8 *)malloc(fTransferBufferSize); + if (fTransferBuffer == NULL) { + TRACE_ALWAYS("failed to allocate transfer buffer\n"); + fStatus = B_NO_MEMORY; + return; + } + + ProtocolHandler::AddHandlers(this, &fProtocolHandlers, + &fProtocolHandlerCount); + fStatus = B_OK; } -void -HIDDevice::SetBaseName(const char *baseName) +HIDDevice::~HIDDevice() { - // As devices can be un- and replugged at will, we cannot simply rely on - // a device count. If there is just one keyboard, this does not mean that - // it uses the 0 name. There might have been two keyboards and the one - // using 0 might have been unplugged. So we just generate names until we - // find one that is not currently in use. - int32 index = 0; - char nameBuffer[128]; - while (true) { - sprintf(nameBuffer, "%s%ld", baseName, index++); - if (gDeviceList->FindDevice(nameBuffer) == NULL) { - // this name is still free, use it - free(fName); - fName = strdup(nameBuffer); - return; - } - } + for (uint32 i = 0; i < fProtocolHandlerCount; i++) + delete fProtocolHandlers[i]; + + free(fProtocolHandlers); + free(fTransferBuffer); } @@ -223,71 +152,21 @@ HIDDevice::SetParentCookie(int32 cookie) status_t -HIDDevice::Open(uint32 flags) +HIDDevice::Open(ProtocolHandler *handler, uint32 flags) { - if (fOpen) - return B_BUSY; - - if (fTransferNotifySem < 0) { - fTransferNotifySem = create_sem(0, "hid device transfer notify sem"); - if (fTransferNotifySem < 0) - return (status_t)fTransferNotifySem; - } - - fOpen = true; - + atomic_add(&fOpenCount, 1); return B_OK; } status_t -HIDDevice::Close() +HIDDevice::Close(ProtocolHandler *handler) { - fOpen = false; - // make threads waiting for a transfer bail out - if (fTransferNotifySem >= 0) { - gUSBModule->cancel_queued_transfers(fInterruptPipe); - delete_sem(fTransferNotifySem); - fTransferNotifySem = -1; - _SetTransferProcessed(); - } + atomic_add(&fOpenCount, -1); return B_OK; } -status_t -HIDDevice::Free() -{ - return B_OK; -} - - -status_t -HIDDevice::Read(uint8 *buffer, size_t *numBytes) -{ - TRACE_ALWAYS("read on hid device\n"); - *numBytes = 0; - return B_ERROR; -} - - -status_t -HIDDevice::Write(const uint8 *buffer, size_t *numBytes) -{ - TRACE_ALWAYS("write on hid device\n"); - *numBytes = 0; - return B_ERROR; -} - - -status_t -HIDDevice::Control(uint32 op, void *buffer, size_t length) -{ - TRACE_ALWAYS("control on base class\n"); - return B_ERROR; -} - - void HIDDevice::Removed() { @@ -296,62 +175,46 @@ HIDDevice::Removed() } -void -HIDDevice::_SetTransferProcessed() -{ - fTransferUnprocessed = false; -} - - -bool -HIDDevice::_IsTransferUnprocessed() -{ - return fTransferUnprocessed; -} - - status_t -HIDDevice::_ScheduleTransfer() +HIDDevice::MaybeScheduleTransfer() { - if (fTransferNotifySem < 0) - return B_ERROR; - if (fTransferUnprocessed) - return B_BUSY; if (fRemoved) return B_ERROR; + if (atomic_set(&fTransferScheduled, 1) != 0) { + // someone else already caused a transfer to be scheduled + return B_OK; + } + + TRACE("scheduling interrupt transfer of %lu bytes\n", fTransferBufferSize); status_t result = gUSBModule->queue_interrupt(fInterruptPipe, - fTransferBuffer, fTotalReportSize, _TransferCallback, this); - if (result < B_OK) { + fTransferBuffer, fTransferBufferSize, _TransferCallback, this); + if (result != B_OK) { TRACE_ALWAYS("failed to schedule interrupt transfer 0x%08lx\n", result); return result; } - fTransferUnprocessed = true; - return B_OK; -} - - -int32 -HIDDevice::_RingBufferReadable() -{ - return ring_buffer_readable(fRingBuffer); -} - - -status_t -HIDDevice::_RingBufferRead(void *buffer, size_t length) -{ - ring_buffer_user_read(fRingBuffer, (uint8 *)buffer, length); return B_OK; } status_t -HIDDevice::_RingBufferWrite(const void *buffer, size_t length) +HIDDevice::SendReport(HIDReport *report) { - ring_buffer_write(fRingBuffer, (const uint8 *)buffer, length); - return B_OK; + size_t actualLength; + return gUSBModule->send_request(fDevice, + USB_REQTYPE_INTERFACE_OUT | USB_REQTYPE_CLASS, + USB_REQUEST_HID_SET_REPORT, 0x200 | report->ID(), fInterfaceIndex, + report->ReportSize(), report->CurrentReport(), &actualLength); +} + + +ProtocolHandler * +HIDDevice::ProtocolHandlerAt(uint32 index) +{ + if (index >= fProtocolHandlerCount) + return NULL; + return fProtocolHandlers[index]; } @@ -360,7 +223,12 @@ HIDDevice::_TransferCallback(void *cookie, status_t status, void *data, size_t actualLength) { HIDDevice *device = (HIDDevice *)cookie; - device->fTransferStatus = status; - device->fTransferActualLength = actualLength; - release_sem_etc(device->fTransferNotifySem, 1, B_DO_NOT_RESCHEDULE); + if (status == B_DEV_STALLED && !device->fRemoved) { + // try clearing stalls right away, the report listeners will resubmit + gUSBModule->clear_feature(device->fInterruptPipe, + USB_FEATURE_ENDPOINT_HALT); + } + + atomic_set(&device->fTransferScheduled, 0); + device->fParser.SetReport(status, device->fTransferBuffer, actualLength); } diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.h b/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.h index 656b901dd4..b3aa051899 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.h @@ -3,85 +3,66 @@ Copyright (C) 2008 Michael Lotz Distributed under the terms of the MIT license. */ -#ifndef _USB_HID_DEVICE_H_ -#define _USB_HID_DEVICE_H_ +#ifndef USB_HID_DEVICE_H +#define USB_HID_DEVICE_H + +#include "HIDParser.h" -#include "hidparse.h" -#include "ring_buffer.h" #include +class ProtocolHandler; + class HIDDevice { public: HIDDevice(usb_device device, - usb_pipe interruptPipe, - size_t interfaceIndex, - report_insn *instructions, - size_t instructionCount, - size_t totalReportSize, - size_t ringBufferSize); -virtual ~HIDDevice(); - -static HIDDevice * MakeHIDDevice(usb_device device, const usb_configuration_info *config, size_t interfaceIndex); - - void SetBaseName(const char *baseName); - const char * Name() { return fName; }; + ~HIDDevice(); void SetParentCookie(int32 cookie); int32 ParentCookie() { return fParentCookie; }; status_t InitCheck() { return fStatus; }; -virtual status_t Open(uint32 flags); - bool IsOpen() { return fOpen; }; + bool IsOpen() { return fOpenCount > 0; }; + status_t Open(ProtocolHandler *handler, uint32 flags); + status_t Close(ProtocolHandler *handler); -virtual status_t Close(); -virtual status_t Free(); - -virtual status_t Read(uint8 *buffer, size_t *numBytes); -virtual status_t Write(const uint8 *buffer, size_t *numBytes); -virtual status_t Control(uint32 op, void *buffer, size_t length); - -virtual void Removed(); + void Removed(); bool IsRemoved() { return fRemoved; }; -protected: - void _SetTransferProcessed(); - bool _IsTransferUnprocessed(); - status_t _ScheduleTransfer(); + status_t MaybeScheduleTransfer(); - int32 _RingBufferReadable(); - status_t _RingBufferRead(void *buffer, size_t length); - status_t _RingBufferWrite(const void *buffer, - size_t length); + status_t SendReport(HIDReport *report); - status_t fStatus; - usb_device fDevice; - usb_pipe fInterruptPipe; - size_t fInterfaceIndex; - report_insn * fInstructions; - size_t fInstructionCount; - size_t fTotalReportSize; + HIDParser * Parser() { return &fParser; }; + ProtocolHandler * ProtocolHandlerAt(uint32 index); - // transfer data - bool fTransferUnprocessed; - status_t fTransferStatus; - size_t fTransferActualLength; - uint8 * fTransferBuffer; - sem_id fTransferNotifySem; + // only to be used for the kernel debugger information + usb_pipe InterruptPipe() { return fInterruptPipe; }; private: static void _TransferCallback(void *cookie, status_t status, void *data, size_t actualLength); - char * fName; + status_t fStatus; + usb_device fDevice; + usb_pipe fInterruptPipe; + size_t fInterfaceIndex; + + int32 fTransferScheduled; + size_t fTransferBufferSize; + uint8 * fTransferBuffer; + int32 fParentCookie; -volatile bool fOpen; + int32 fOpenCount; bool fRemoved; - struct ring_buffer * fRingBuffer; + HIDParser fParser; + + uint32 fProtocolHandlerCount; + ProtocolHandler ** fProtocolHandlers; }; -#endif // _USB_HID_DEVICE_H_ +#endif // USB_HID_DEVICE_H diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.cpp b/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.cpp index fcc65f0c06..26e27a1ae4 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.cpp @@ -438,6 +438,9 @@ HIDParser::MaxReportSize() maxSize = report->ReportSize(); } + if (fUsesReportIDs) + maxSize++; + return maxSize; } @@ -459,12 +462,13 @@ HIDParser::SetReport(status_t status, uint8 *report, size_t length) return; } - HIDReport *target = fReports[0]; + HIDReport *target = NULL; if (fUsesReportIDs) { target = FindReport(HID_REPORT_TYPE_INPUT, report[0]); report++; length--; - } + } else + target = FindReport(HID_REPORT_TYPE_INPUT, 0); if (target == NULL) { TRACE_ALWAYS("got report buffer but found no report to handle it\n"); diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.cpp b/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.cpp index c4f24dd4a5..950a70377d 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.cpp @@ -158,6 +158,33 @@ HIDReport::SetReport(status_t status, uint8 *report, size_t length) } +status_t +HIDReport::SendReport() +{ + size_t reportSize = ReportSize(); + uint8 *report = (uint8 *)malloc(reportSize); + if (report == NULL) + return B_NO_MEMORY; + + fCurrentReport = report; + memset(fCurrentReport, 0, reportSize); + + for (uint32 i = 0; i < fItemsUsed; i++) { + HIDReportItem *item = fItems[i]; + if (item == NULL) + continue; + + item->Insert(); + } + + status_t result = fParser->Device()->SendReport(this); + + fCurrentReport = NULL; + free(report); + return result; +} + + HIDReportItem * HIDReport::ItemAt(uint32 index) { @@ -167,13 +194,25 @@ HIDReport::ItemAt(uint32 index) } +HIDReportItem * +HIDReport::FindItem(uint16 usagePage, uint16 usageID) +{ + for (uint32 i = 0; i < fItemsUsed; i++) { + if (fItems[i]->UsagePage() == usagePage + && fItems[i]->UsageID() == usageID) + return fItems[i]; + } + + return NULL; +} + + status_t HIDReport::WaitForReport(bigtime_t timeout) { - while (atomic_or(&fBusyCount, 0) != 0) + while (atomic_get(&fBusyCount) != 0) snooze(1000); -#ifndef TEST_MODE ConditionVariableEntry conditionVariableEntry; fConditionVariable.Add(&conditionVariableEntry); status_t result = fParser->Device()->MaybeScheduleTransfer(); @@ -182,14 +221,13 @@ HIDReport::WaitForReport(bigtime_t timeout) return result; } - result = conditionVariableEntry.Wait(B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, - timeout); + result = conditionVariableEntry.Wait(B_RELATIVE_TIMEOUT, timeout); + TRACE("waiting for report returned with result: %s\n", strerror(result)); if (result != B_OK) return result; if (fReportStatus != B_OK) return fReportStatus; -#endif atomic_add(&fBusyCount, 1); return B_OK; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.h b/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.h index e760b9f607..48f9bd3026 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDReport.h @@ -39,8 +39,11 @@ public: size_t length); uint8 * CurrentReport() { return fCurrentReport; }; + status_t SendReport(); + uint32 CountItems() { return fItemsUsed; }; HIDReportItem * ItemAt(uint32 index); + HIDReportItem * FindItem(uint16 usagePage, uint16 usageID); status_t WaitForReport(bigtime_t timeout); void DoneProcessing(); diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.cpp b/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.cpp index 9341efbf46..6ce9a2d2c5 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.cpp @@ -39,6 +39,15 @@ HIDReportItem::UsagePage() } +uint16 +HIDReportItem::UsageID() +{ + usage_value value; + value.u.extended = fUsageMinimum; + return value.u.s.usage_id; +} + + status_t HIDReportItem::Extract() { @@ -67,6 +76,40 @@ HIDReportItem::Extract() } +status_t +HIDReportItem::Insert() +{ + uint8 *report = fReport->CurrentReport(); + if (report == NULL) + return B_NO_INIT; + + uint32 value; + memcpy(&value, report + fByteOffset, sizeof(uint32)); + value &= ~(fMask << fShift); + + if (fValid) + value |= (fData & fMask) << fShift; + + memcpy(report + fByteOffset, &value, sizeof(uint32)); + return B_OK; +} + + +status_t +HIDReportItem::SetData(uint32 data) +{ + fData = data; + + if (Signed()) { + fValid = (int32)fData >= (int32)fMinimum + && (int32)fData <= (int32)fMaximum; + } else + fValid = fData >= fMinimum && fData <= fMaximum; + + return fValid ? B_OK : B_BAD_VALUE; +} + + void HIDReportItem::PrintToStream(uint32 indentLevel) { diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.h b/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.h index b5ebfac3a1..ca9f489d9b 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.h @@ -23,13 +23,19 @@ public: bool Signed() { return fMinimum > fMaximum; }; uint16 UsagePage(); + uint16 UsageID(); + uint32 UsageMinimum() { return fUsageMinimum; }; uint32 UsageMaximum() { return fUsageMaximum; }; status_t Extract(); - bool Valid() { return fValid; }; + status_t Insert(); + + status_t SetData(uint32 data); uint32 Data() { return fData; }; + bool Valid() { return fValid; }; + void PrintToStream(uint32 indentLevel = 0); private: HIDReport * fReport; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/Jamfile b/src/add-ons/kernel/drivers/input/usb_hid/Jamfile index d090d8de8b..e877d9fb7a 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/Jamfile +++ b/src/add-ons/kernel/drivers/input/usb_hid/Jamfile @@ -1,17 +1,10 @@ SubDir HAIKU_TOP src add-ons kernel drivers input usb_hid ; -SetSubDirSupportedPlatformsBeOSCompatible ; - SubDirC++Flags -fno-rtti ; SubDirSysHdrs $(HAIKU_TOP) headers os drivers ; -UsePrivateHeaders [ FDirName kernel util ] input ; -UsePrivateHeaders kernel ; - -local buffer_impl = ; -if ! $(TARGET_PLATFORM_HAIKU_COMPATIBLE) { - buffer_impl = ring_buffer.cpp ; -} +UsePrivateHeaders [ FDirName kernel util ] input drivers ; +UsePrivateKernelHeaders ; KernelAddon usb_hid : DeviceList.cpp @@ -19,14 +12,10 @@ KernelAddon usb_hid : HIDDevice.cpp KeyboardDevice.cpp MouseDevice.cpp - hidparse.c - $(buffer_impl) + ProtocolHandler.cpp + + HIDCollection.cpp + HIDParser.cpp + HIDReport.cpp + HIDReportItem.cpp ; - -SEARCH on [ FGristFiles ring_buffer.cpp ] = [ FDirName $(HAIKU_TOP) src system kernel util ] ; - -Package haiku-inputkit-cvs : - usb_hid : - boot home config add-ons kernel drivers bin ; - -PackageDriverSymLink haiku-inputkit-cvs : input usb_hid ; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp index 3a481047b2..bd8bac480b 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp @@ -1,14 +1,8 @@ /* - * Copyright 2008 Michael Lotz + * Copyright 2008-2009 Michael Lotz * Distributed under the terms of the MIT license. */ -/*! Driver for USB Human Interface Devices. - Interpretation code based on the previous usb_hid driver which was written - by Jérôme Duval. -*/ - - #include #include @@ -18,6 +12,10 @@ #include "Driver.h" #include "KeyboardDevice.h" +#include "HIDDevice.h" +#include "HIDReport.h" +#include "HIDReportItem.h" + // input server private for raw_key_info, KB_READ, etc... #include "kb_mouse_driver.h" @@ -43,26 +41,81 @@ debug_get_keyboard_config(int argc, char **argv) // #pragma mark - -KeyboardDevice::KeyboardDevice(usb_device device, usb_pipe interruptPipe, - size_t interfaceIndex, report_insn *instructions, size_t instructionCount, - size_t totalReportSize) +KeyboardDevice::KeyboardDevice(HIDReport *inputReport, HIDReport *outputReport) : - HIDDevice(device, interruptPipe, interfaceIndex, instructions, - instructionCount, totalReportSize, 512), + ProtocolHandler(inputReport->Device(), "input/keyboard/usb/", 512), + fInputReport(inputReport), + fOutputReport(outputReport), fRepeatDelay(300000), fRepeatRate(35000), - fLastTransferBuffer(NULL) + fCurrentRepeatDelay(B_INFINITE_TIMEOUT), + fCurrentRepeatKey(0), + fKeyCount(0), + fModifierCount(0), + fLastModifiers(0), + fCurrentKeys(NULL), + fLastKeys(NULL) { - fCurrentRepeatDelay = B_INFINITE_TIMEOUT; - fCurrentRepeatKey = 0; + // find modifiers and keys + for (uint32 i = 0; i < inputReport->CountItems(); i++) { + HIDReportItem *item = inputReport->ItemAt(i); + if (!item->HasData()) + continue; - fLastTransferBuffer = (uint8 *)malloc(totalReportSize); - if (fLastTransferBuffer == NULL) { + if (item->UsagePage() == HID_USAGE_PAGE_KEYBOARD) { + TRACE("keyboard item with usage %lx\n", item->UsageMinimum()); + item->PrintToStream(); + + if (item->Array()) { + // normal keys handled as array items + if (fKeyCount < MAX_KEYS) + fKeys[fKeyCount++] = item; + } else { + if (item->UsageID() >= HID_USAGE_ID_LEFT_CONTROL + && item->UsageID() <= HID_USAGE_ID_RIGHT_GUI) { + // modifiers are generally implemented as bitmaps + if (fModifierCount < MAX_MODIFIERS) + fModifiers[fModifierCount++] = item; + } + } + } + } + + TRACE("keyboard device with %lu keys and %lu modifiers\n", fKeyCount, + fModifierCount); + + fLastKeys = (uint8 *)malloc(fKeyCount * 2); + fCurrentKeys = fLastKeys + fKeyCount; + if (fLastKeys == NULL) { fStatus = B_NO_MEMORY; return; } - SetBaseName("input/keyboard/usb/"); + // find leds if we have an output report + fLEDs[0] = fLEDs[1] = fLEDs[2] = NULL; + if (outputReport != NULL) { + for (uint32 i = 0; i < outputReport->CountItems(); i++) { + HIDReportItem *item = outputReport->ItemAt(i); + if (!item->HasData()) + continue; + + // the led item array is identity mapped with what we get from + // the input_server for the set-leds command + if (item->UsagePage() == HID_USAGE_PAGE_LED) { + switch (item->UsageID()) { + case HID_USAGE_ID_LED_NUM_LOCK: + fLEDs[0] = item; + break; + case HID_USAGE_ID_LED_CAPS_LOCK: + fLEDs[1] = item; + break; + case HID_USAGE_ID_LED_SCROLL_LOCK: + fLEDs[2] = item; + break; + } + } + } + } if (atomic_add(&sDebuggerCommandAdded, 1) == 0) { add_debugger_command("get_usb_keyboard_config", @@ -74,7 +127,7 @@ KeyboardDevice::KeyboardDevice(usb_device device, usb_pipe interruptPipe, KeyboardDevice::~KeyboardDevice() { - free(fLastTransferBuffer); + free(fLastKeys); if (atomic_add(&sDebuggerCommandAdded, -1) == 1) { remove_debugger_command("get_usb_keyboard_config", @@ -83,10 +136,62 @@ KeyboardDevice::~KeyboardDevice() } +ProtocolHandler * +KeyboardDevice::AddHandler(HIDDevice *device) +{ + HIDParser *parser = device->Parser(); + + // try to find the keyboard usage in any input report + HIDReport *input = NULL; + bool foundKeyboardUsage = false; + uint32 reportCount = parser->CountReports(HID_REPORT_TYPE_INPUT); + for (uint32 i = 0; i < reportCount; i++) { + input = parser->ReportAt(HID_REPORT_TYPE_INPUT, i); + + for (uint32 j = 0; j < input->CountItems(); j++) { + HIDReportItem *item = input->ItemAt(j); + if (item->UsagePage() == HID_USAGE_PAGE_KEYBOARD) { + // found at least one item with a keyboard usage + foundKeyboardUsage = true; + break; + } + } + + if (foundKeyboardUsage) + break; + } + + if (!foundKeyboardUsage) + return NULL; + + // try to find the led output report + HIDReport *output = NULL; + bool foundOutputReport = false; + reportCount = parser->CountReports(HID_REPORT_TYPE_OUTPUT); + for (uint32 i = 0; i < reportCount; i++) { + output = parser->ReportAt(HID_REPORT_TYPE_OUTPUT, i); + + for (uint32 j = 0; j < output->CountItems(); j++) { + HIDReportItem *item = output->ItemAt(j); + if (item->UsagePage() == HID_USAGE_PAGE_LED) { + foundOutputReport = true; + break; + } + } + + if (foundOutputReport) + break; + } + + return new(std::nothrow) KeyboardDevice(input, + foundOutputReport ? output : NULL); +} + + status_t KeyboardDevice::Open(uint32 flags) { - status_t status = HIDDevice::Open(flags); + status_t status = ProtocolHandler::Open(flags); if (status != B_OK) { TRACE_ALWAYS("keyboard device failed to open: %s\n", strerror(status)); @@ -95,7 +200,6 @@ KeyboardDevice::Open(uint32 flags) fCurrentRepeatDelay = B_INFINITE_TIMEOUT; fCurrentRepeatKey = 0; - return B_OK; } @@ -107,30 +211,15 @@ KeyboardDevice::Control(uint32 op, void *buffer, size_t length) case KB_READ: { bigtime_t enterTime = system_time(); - while (_RingBufferReadable() == 0) { - if (!_IsTransferUnprocessed()) { - status_t result = _ScheduleTransfer(); - if (result != B_OK) - return result; - } - - // NOTE: this thread is now blocking until the semaphore is - // released from the callback function or the repeat timeout - // expires - status_t result = acquire_sem_etc(fTransferNotifySem, 1, - B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, fCurrentRepeatDelay); - if (result == B_OK) { - result = _InterpretBuffer(); - _SetTransferProcessed(); - if (result != B_OK) - return result; - } else if (result != B_TIMED_OUT) + while (RingBufferReadable() == 0) { + status_t result = _ReadReport(fCurrentRepeatDelay); + if (result != B_OK && result != B_TIMED_OUT) return result; - if (!IsOpen()) + if (!Device()->IsOpen()) return B_ERROR; - if (_RingBufferReadable() == 0 && fCurrentRepeatKey != 0 + if (RingBufferReadable() == 0 && fCurrentRepeatKey != 0 && system_time() - enterTime > fCurrentRepeatDelay) { // this case is for handling key repeats, it means no // interrupt transfer has happened or it didn't produce any @@ -146,7 +235,7 @@ KeyboardDevice::Control(uint32 op, void *buffer, size_t length) // process what is in the ring_buffer, it could be written // there because we handled an interrupt transfer or because // we wrote the current repeat key - return _RingBufferRead(buffer, sizeof(raw_key_info)); + return RingBufferRead(buffer, sizeof(raw_key_info)); } case KB_SET_LEDS: @@ -203,50 +292,72 @@ KeyboardDevice::_WriteKey(uint32 key, bool down) info.be_keycode = key; info.is_keydown = down; info.timestamp = system_time(); - - _RingBufferWrite(&info, sizeof(raw_key_info)); + RingBufferWrite(&info, sizeof(raw_key_info)); } status_t KeyboardDevice::_SetLEDs(uint8 *data) { - if (IsRemoved()) + if (fOutputReport == NULL || fOutputReport->Device()->IsRemoved()) return B_ERROR; - uint8 leds = 0; - if (data[0] == 1) - leds |= (1 << 0); - if (data[1] == 1) - leds |= (1 << 1); - if (data[2] == 1) - leds |= (1 << 2); + for (uint32 i = 0; i < MAX_LEDS; i++) { + if (fLEDs[i] == NULL) + continue; - size_t actualLength; - return gUSBModule->send_request(fDevice, - USB_REQTYPE_INTERFACE_OUT | USB_REQTYPE_CLASS, - USB_REQUEST_HID_SET_REPORT, - 0x200 | 0 /* TODO: report id */, fInterfaceIndex, - sizeof(leds), &leds, &actualLength); + fLEDs[i]->SetData(data[i]); + } + + return fOutputReport->SendReport(); } status_t -KeyboardDevice::_InterpretBuffer() +KeyboardDevice::_ReadReport(bigtime_t timeout) { - if (fTransferStatus != B_OK) { - if (IsRemoved()) - return B_ERROR; - - if (fTransferStatus == B_DEV_STALLED - && gUSBModule->clear_feature(fInterruptPipe, - USB_FEATURE_ENDPOINT_HALT) != B_OK) + status_t result = fInputReport->WaitForReport(timeout); + if (result != B_OK) { + if (fInputReport->Device()->IsRemoved()) { + TRACE("device has been removed\n"); return B_ERROR; + } + TRACE_ALWAYS("error waiting for report: %s\n", strerror(result)); + // signal that we simply want to try again return B_OK; } - const static uint32 kModifierTable[] = { + TRACE("got keyboard input report\n"); + + uint8 modifiers = 0; + for (uint32 i = 0; i < fModifierCount; i++) { + HIDReportItem *modifier = fModifiers[i]; + if (modifier == NULL) + break; + + if (modifier->Extract() == B_OK && modifier->Valid()) { + modifiers |= (modifier->Data() & 1) + << (modifier->UsageID() - HID_USAGE_ID_LEFT_CONTROL); + } + } + + for (uint32 i = 0; i < fKeyCount; i++) { + HIDReportItem *key = fKeys[i]; + if (key == NULL) + break; + + if (key->Extract() == B_OK && key->Valid()) { + // note that if there are ever more than 8 bit usage ids + // we need to change all these key arrays to use bugger sizes + fCurrentKeys[i] = key->Data(); + } else + fCurrentKeys[i] = 0; + } + + fInputReport->DoneProcessing(); + + static const uint32 kModifierTable[] = { KEY_ControlL, KEY_ShiftL, KEY_AltL, @@ -257,7 +368,16 @@ KeyboardDevice::_InterpretBuffer() KEY_WinR }; - const static uint32 kKeyTable[] = { + // find modifier changes and push them into the buffer + uint8 modifierChange = fLastModifiers ^ modifiers; + for (uint8 i = 0; modifierChange; i++, modifierChange >>= 1) { + if (modifierChange & 1) + _WriteKey(kModifierTable[i], (modifiers >> i) & 1); + } + + fLastModifiers = modifiers; + + static const uint32 kKeyTable[] = { 0x00, // ERROR 0x00, // ERROR 0x00, // ERROR @@ -400,18 +520,12 @@ KeyboardDevice::_InterpretBuffer() 0x6c, // Muhenkan, key left to spacebar, japanese }; - const static size_t kKeyTableSize + static const size_t kKeyTableSize = sizeof(kKeyTable) / sizeof(kKeyTable[0]); - uint8 modifierChange = fLastTransferBuffer[0] ^ fTransferBuffer[0]; - for (uint8 i = 0; modifierChange; i++, modifierChange >>= 1) { - if (modifierChange & 1) - _WriteKey(kModifierTable[i], (fTransferBuffer[0] >> i) & 1); - } - bool phantomState = true; - for (size_t i = 2; i < fTotalReportSize; i++) { - if (fTransferBuffer[i] != 0x01) { + for (size_t i = 0; i < fKeyCount; i++) { + if (fCurrentKeys[i] != 0x01) { phantomState = false; break; } @@ -428,15 +542,15 @@ KeyboardDevice::_InterpretBuffer() static bool sysReqPressed = false; bool keyDown = false; - uint8 *current = fLastTransferBuffer; - uint8 *compare = fTransferBuffer; + uint8 *current = fLastKeys; + uint8 *compare = fCurrentKeys; for (int32 twice = 0; twice < 2; twice++) { - for (size_t i = 2; i < fTotalReportSize; i++) { + for (size_t i = 0; i < fKeyCount; i++) { if (current[i] == 0x00 || current[i] == 0x01) continue; bool found = false; - for (size_t j = 2; j < fTotalReportSize; j++) { + for (size_t j = 0; j < fKeyCount; j++) { if (compare[j] == current[i]) { found = true; break; @@ -451,17 +565,18 @@ KeyboardDevice::_InterpretBuffer() if (current[i] < kKeyTableSize) key = kKeyTable[current[i]]; - if (key == KEY_Pause && (current[0] & ALT_KEYS) != 0) + if (key == KEY_Pause && (modifiers & ALT_KEYS) != 0) key = KEY_Break; - else if (key == 0xe && (current[0] & ALT_KEYS) != 0) { + else if (key == 0xe && (modifiers & ALT_KEYS) != 0) { key = KEY_SysRq; sysReqPressed = keyDown; } else if (sysReqPressed && keyDown - && current[i] >= 4 && current[i] <= 30 - && (fLastTransferBuffer[0] & ALT_KEYS) != 0) { + && current[i] >= 4 && current[i] <= 29 + && (fLastModifiers & ALT_KEYS) != 0) { // Alt-SysReq+letter was pressed - sDebugKeyboardPipe = fInterruptPipe; - sDebugKeyboardReportSize = fTotalReportSize; + sDebugKeyboardPipe = fInputReport->Device()->InterruptPipe(); + sDebugKeyboardReportSize + = fInputReport->Parser()->MaxReportSize(); char letter = current[i] - 4 + 'a'; @@ -490,11 +605,11 @@ KeyboardDevice::_InterpretBuffer() } } - current = fTransferBuffer; - compare = fLastTransferBuffer; + current = fCurrentKeys; + compare = fLastKeys; keyDown = true; } - memcpy(fLastTransferBuffer, fTransferBuffer, fTotalReportSize); + memcpy(fLastKeys, fCurrentKeys, fKeyCount); return B_OK; } diff --git a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.h b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.h index d4f084863c..51b69d819a 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.h @@ -1,37 +1,52 @@ /* - Driver for USB Human Interface Devices. - Copyright (C) 2008 Michael Lotz + Copyright (C) 2008-2009 Michael Lotz Distributed under the terms of the MIT license. */ -#ifndef _USB_KEYBOARD_DEVICE_H_ -#define _USB_KEYBOARD_DEVICE_H_ +#ifndef USB_KEYBOARD_DEVICE_H +#define USB_KEYBOARD_DEVICE_H -#include "HIDDevice.h" +#include "ProtocolHandler.h" -class KeyboardDevice : public HIDDevice { +#define MAX_MODIFIERS 16 +#define MAX_KEYS 16 +#define MAX_LEDS 3 + +class HIDReportItem; + +class KeyboardDevice : public ProtocolHandler { public: - KeyboardDevice(usb_device device, - usb_pipe interruptPipe, - size_t interfaceIndex, - report_insn *instructions, - size_t instructionCount, - size_t totalReportSize); + KeyboardDevice(HIDReport *inputReport, + HIDReport *outputReport); virtual ~KeyboardDevice(); +static ProtocolHandler * AddHandler(HIDDevice *device); + virtual status_t Open(uint32 flags); virtual status_t Control(uint32 op, void *buffer, size_t length); private: void _WriteKey(uint32 key, bool down); status_t _SetLEDs(uint8 *data); - status_t _InterpretBuffer(); + status_t _ReadReport(bigtime_t timeout); + + HIDReport * fInputReport; + HIDReport * fOutputReport; + + HIDReportItem * fModifiers[MAX_MODIFIERS]; + HIDReportItem * fKeys[MAX_KEYS]; + HIDReportItem * fLEDs[MAX_LEDS]; bigtime_t fRepeatDelay; bigtime_t fRepeatRate; bigtime_t fCurrentRepeatDelay; uint32 fCurrentRepeatKey; - uint8 * fLastTransferBuffer; + uint32 fKeyCount; + uint32 fModifierCount; + + uint8 fLastModifiers; + uint8 * fCurrentKeys; + uint8 * fLastKeys; }; -#endif // _USB_KEYBOARD_DEVICE_H_ +#endif // USB_KEYBOARD_DEVICE_H diff --git a/src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.cpp b/src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.cpp index c038d2e61e..aa01c5f42b 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.cpp @@ -1,13 +1,16 @@ /* Driver for USB Human Interface Devices. - Copyright (C) 2008 Michael Lotz + Copyright (C) 2008-2009 Michael Lotz Distributed under the terms of the MIT license. - - Interpretation code based on the previous usb_hid driver which was written - by Jérôme Duval. */ + #include "Driver.h" #include "MouseDevice.h" + +#include "HIDDevice.h" +#include "HIDReport.h" +#include "HIDReportItem.h" + #include #include @@ -15,18 +18,62 @@ #include "kb_mouse_driver.h" -MouseDevice::MouseDevice(usb_device device, usb_pipe interruptPipe, - size_t interfaceIndex, report_insn *instructions, size_t instructionCount, - size_t totalReportSize) - : HIDDevice(device, interruptPipe, interfaceIndex, instructions, - instructionCount, totalReportSize, 512), - fLastButtons(0), - fClickCount(0), - fLastClickTime(0), - fClickSpeed(250000), - fMaxButtons(16) +MouseDevice::MouseDevice(HIDReport *report, HIDReportItem *xAxis, + HIDReportItem *yAxis) + : + ProtocolHandler(report->Device(), "input/mouse/usb/", 512), + fReport(report), + fXAxis(xAxis), + fYAxis(yAxis), + fWheel(NULL), + fLastButtons(0), + fClickCount(0), + fLastClickTime(0), + fClickSpeed(250000) { - SetBaseName("input/mouse/usb/"); + uint32 buttonCount = 0; + for (uint32 i = 0; i < report->CountItems(); i++) { + HIDReportItem *item = report->ItemAt(i); + if (!item->HasData()) + continue; + + if (item->UsagePage() == HID_USAGE_PAGE_BUTTON + && item->UsageID() - 1 < B_MAX_MOUSE_BUTTONS) + fButtons[buttonCount++] = item; + } + + fButtons[buttonCount] = NULL; + + fWheel = report->FindItem(HID_USAGE_PAGE_GENERIC_DESKTOP, + HID_USAGE_ID_WHEEL); +} + + +ProtocolHandler * +MouseDevice::AddHandler(HIDDevice *device) +{ + HIDParser *parser = device->Parser(); + + // try to find at least an x and y axis + HIDReport *report = NULL; + HIDReportItem *xAxis = NULL; + HIDReportItem *yAxis = NULL; + uint32 reportCount = parser->CountReports(HID_REPORT_TYPE_INPUT); + for (uint32 i = 0; i < reportCount; i++) { + report = parser->ReportAt(HID_REPORT_TYPE_INPUT, i); + xAxis = report->FindItem(HID_USAGE_PAGE_GENERIC_DESKTOP, + HID_USAGE_ID_X); + yAxis = report->FindItem(HID_USAGE_PAGE_GENERIC_DESKTOP, + HID_USAGE_ID_Y); + + if (xAxis != NULL && yAxis != NULL) + break; + } + + if (xAxis == NULL || yAxis == NULL) + return NULL; + + return new(std::nothrow) MouseDevice(report, xAxis, yAxis); } @@ -35,30 +82,16 @@ MouseDevice::Control(uint32 op, void *buffer, size_t length) { switch (op) { case MS_READ: - while (_RingBufferReadable() == 0) { - if (!_IsTransferUnprocessed()) { - status_t result = _ScheduleTransfer(); - if (result != B_OK) - return result; - } - - // NOTE: this thread is now blocking until the semaphore is - // released in the callback function - status_t result = acquire_sem_etc(fTransferNotifySem, 1, - B_CAN_INTERRUPT, B_INFINITE_TIMEOUT); - if (result != B_OK) - return result; - - result = _InterpretBuffer(); - _SetTransferProcessed(); + while (RingBufferReadable() == 0) { + status_t result = _ReadReport(); if (result != B_OK) return result; } - return _RingBufferRead(buffer, sizeof(mouse_movement)); + return RingBufferRead(buffer, sizeof(mouse_movement)); case MS_NUM_EVENTS: - return _RingBufferReadable() / sizeof(mouse_movement); + return RingBufferReadable() / sizeof(mouse_movement); case MS_SET_CLICKSPEED: #ifdef __HAIKU__ @@ -74,55 +107,43 @@ MouseDevice::Control(uint32 op, void *buffer, size_t length) status_t -MouseDevice::_InterpretBuffer() +MouseDevice::_ReadReport() { - if (fTransferStatus != B_OK) { - if (IsRemoved()) - return B_ERROR; - - if (fTransferStatus == B_DEV_STALLED - && gUSBModule->clear_feature(fInterruptPipe, - USB_FEATURE_ENDPOINT_HALT) != B_OK) + status_t result = fReport->WaitForReport(B_INFINITE_TIMEOUT); + if (result != B_OK) { + if (fReport->Device()->IsRemoved()) { + TRACE("device has been removed\n"); return B_ERROR; + } + TRACE_ALWAYS("error waiting for report: %s\n", strerror(result)); + // signal that we simply want to try again return B_OK; } mouse_movement info; memset(&info, 0, sizeof(info)); - for (size_t i = 0; i < fInstructionCount; i++) { - const report_insn *instruction = &fInstructions[i]; - int32 value = (((fTransferBuffer[instruction->byte_idx + 1] << 8) - | fTransferBuffer[instruction->byte_idx]) >> instruction->bit_pos) - & ((1 << instruction->num_bits) - 1); - switch (instruction->usage_page) { - case USAGE_PAGE_BUTTON: - if (instruction->usage_id - 1 < fMaxButtons) - info.buttons |= (value & 1) << (instruction->usage_id - 1); - break; + if (fXAxis->Extract() == B_OK && fXAxis->Valid()) + info.xdelta = fXAxis->Data(); + if (fYAxis->Extract() == B_OK && fYAxis->Valid()) + info.ydelta = -fYAxis->Data(); - case USAGE_PAGE_GENERIC_DESKTOP: - if (instruction->is_phy_signed) - value = sign_extend(value, instruction->num_bits); + if (fWheel != NULL && fWheel->Extract() == B_OK && fWheel->Valid()) + info.wheel_ydelta = -fWheel->Data(); - switch (instruction->usage_id) { - case USAGE_ID_X: - info.xdelta = value; - break; + for (uint32 i = 0; i < B_MAX_MOUSE_BUTTONS; i++) { + HIDReportItem *button = fButtons[i]; + if (button == NULL) + break; - case USAGE_ID_Y: - info.ydelta = -value; - break; - - case USAGE_ID_WHEEL: - info.wheel_ydelta = -value; - break; - } - break; - } + if (button->Extract() == B_OK && button->Valid()) + info.buttons |= (button->Data() & 1) << (button->UsageID() - 1); } + fReport->DoneProcessing(); + TRACE("got mouse report\n"); + bigtime_t timestamp = system_time(); if (info.buttons != 0) { if (fLastButtons == 0) { @@ -138,5 +159,5 @@ MouseDevice::_InterpretBuffer() fLastButtons = info.buttons; info.timestamp = timestamp; - return _RingBufferWrite(&info, sizeof(mouse_movement)); + return RingBufferWrite(&info, sizeof(mouse_movement)); } diff --git a/src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.h b/src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.h index dff6bf0134..740b0458a0 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.h @@ -1,26 +1,34 @@ /* - Driver for USB Human Interface Devices. - Copyright (C) 2008 Michael Lotz + Copyright (C) 2008-2009 Michael Lotz Distributed under the terms of the MIT license. */ -#ifndef _USB_MOUSE_DEVICE_H_ -#define _USB_MOUSE_DEVICE_H_ +#ifndef USB_MOUSE_DEVICE_H +#define USB_MOUSE_DEVICE_H -#include "HIDDevice.h" +#include -class MouseDevice : public HIDDevice { +#include "ProtocolHandler.h" + +class HIDReportItem; + +class MouseDevice : public ProtocolHandler { public: - MouseDevice(usb_device device, - usb_pipe interruptPipe, - size_t interfaceIndex, - report_insn *instructions, - size_t instructionCount, - size_t totalReportSize); + MouseDevice(HIDReport *report, + HIDReportItem *xAxis, HIDReportItem *yAxis); + +static ProtocolHandler * AddHandler(HIDDevice *device); virtual status_t Control(uint32 op, void *buffer, size_t length); private: - status_t _InterpretBuffer(); + status_t _ReadReport(); + + HIDReport * fReport; + + HIDReportItem * fXAxis; + HIDReportItem * fYAxis; + HIDReportItem * fWheel; + HIDReportItem * fButtons[B_MAX_MOUSE_BUTTONS]; uint32 fLastButtons; uint32 fClickCount; @@ -29,4 +37,4 @@ private: uint32 fMaxButtons; }; -#endif // _USB_MOUSE_DEVICE_H_ +#endif // USB_MOUSE_DEVICE_H diff --git a/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.cpp b/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.cpp new file mode 100644 index 0000000000..1080d39be0 --- /dev/null +++ b/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.cpp @@ -0,0 +1,141 @@ +/* + * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. + * Distributed under the terms of the MIT License. + */ + +#include + +#include "Driver.h" +#include "HIDDevice.h" +#include "HIDReport.h" +#include "ProtocolHandler.h" + +// includes for the different protocol handlers +#include "KeyboardDevice.h" +#include "MouseDevice.h" +//#include "GenericDevice.h" + + +ProtocolHandler::ProtocolHandler(HIDDevice *device, const char *basePath, + size_t ringBufferSize) + : fStatus(B_NO_INIT), + fDevice(device), + fBasePath(basePath), + fPublishPath(NULL), + fRingBuffer(NULL) +{ + if (ringBufferSize > 0) { + fRingBuffer = create_ring_buffer(ringBufferSize); + if (fRingBuffer == NULL) { + TRACE_ALWAYS("failed to create requested ring buffer\n"); + fStatus = B_NO_MEMORY; + return; + } + } + + fStatus = B_OK; +} + + +ProtocolHandler::~ProtocolHandler() +{ + if (fRingBuffer) { + delete_ring_buffer(fRingBuffer); + fRingBuffer = NULL; + } + + free(fPublishPath); +} + + +void +ProtocolHandler::SetPublishPath(char *publishPath) +{ + free(fPublishPath); + fPublishPath = publishPath; +} + + +void +ProtocolHandler::AddHandlers(HIDDevice *device, ProtocolHandler ***handlerList, + uint32 *handlerCount) +{ + TRACE("adding protocol handlers\n"); + + uint32 count = 3; + ProtocolHandler *handlers[count]; + handlers[0] = KeyboardDevice::AddHandler(device); + handlers[1] = MouseDevice::AddHandler(device); + handlers[2] = NULL; //GenericDevice::AddHandler(device); + + *handlerCount = 0; + uint32 actualCount = 0; + for (uint32 i = 0; i < count; i++) { + if (handlers[i] != NULL) + actualCount++; + } + + if (actualCount == 0) { + TRACE_ALWAYS("no handlers for hid device\n"); + return; + } + + *handlerList = (ProtocolHandler **)malloc(sizeof(ProtocolHandler *) + * actualCount); + if (*handlerList == NULL) { + TRACE_ALWAYS("out of memory allocating handler list\n"); + return; + } + + for (uint32 i = 0; i < count; i++) { + if (handlers[i] != NULL) + *handlerList[(*handlerCount)++] = handlers[i]; + } + + TRACE("added %ld handlers for hid device\n", *handlerCount); +} + + +status_t +ProtocolHandler::Open(uint32 flags) +{ + return fDevice->Open(this, flags); +} + + +status_t +ProtocolHandler::Close() +{ + return fDevice->Close(this); +} + + +status_t +ProtocolHandler::Control(uint32 op, void *buffer, size_t length) +{ + TRACE_ALWAYS("control on base class\n"); + return B_ERROR; +} + + +int32 +ProtocolHandler::RingBufferReadable() +{ + return ring_buffer_readable(fRingBuffer); +} + + +status_t +ProtocolHandler::RingBufferRead(void *buffer, size_t length) +{ + ring_buffer_user_read(fRingBuffer, (uint8 *)buffer, length); + return B_OK; +} + + +status_t +ProtocolHandler::RingBufferWrite(const void *buffer, size_t length) +{ + ring_buffer_write(fRingBuffer, (const uint8 *)buffer, length); + return B_OK; +} diff --git a/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h b/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h new file mode 100644 index 0000000000..6a20e10f98 --- /dev/null +++ b/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h @@ -0,0 +1,52 @@ +/* + * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. + * Distributed under the terms of the MIT License. + */ +#ifndef PROTOCOL_HANDLER_H +#define PROTOCOL_HANDLER_H + +#include + +class HIDDevice; +class HIDReport; + +class ProtocolHandler { +public: + ProtocolHandler(HIDDevice *device, + const char *basePath, + size_t ringBufferSize); +virtual ~ProtocolHandler(); + + status_t InitCheck() { return fStatus; }; + + HIDDevice * Device() { return fDevice; }; + + const char * BasePath() { return fBasePath; }; + void SetPublishPath(char *publishPath); + const char * PublishPath() { return fPublishPath; }; + +static void AddHandlers(HIDDevice *device, + ProtocolHandler ***handlerList, + uint32 *handlerCount); + +virtual status_t Open(uint32 flags); +virtual status_t Close(); + +virtual status_t Control(uint32 op, void *buffer, size_t length); + + int32 RingBufferReadable(); + status_t RingBufferRead(void *buffer, size_t length); + status_t RingBufferWrite(const void *buffer, + size_t length); + +protected: + status_t fStatus; + +private: + HIDDevice * fDevice; + const char * fBasePath; + char * fPublishPath; + struct ring_buffer * fRingBuffer; +}; + +#endif // PROTOCOL_HANDLER_H diff --git a/src/add-ons/kernel/drivers/input/usb_hid/hidparse.c b/src/add-ons/kernel/drivers/input/usb_hid/hidparse.c deleted file mode 100644 index 663bb28aa6..0000000000 --- a/src/add-ons/kernel/drivers/input/usb_hid/hidparse.c +++ /dev/null @@ -1,352 +0,0 @@ -/*****************************************************************************/ -// HID usb driver -// Written by Jérôme Duval -// -// hidparse.c -// -// Copyright (c) 2004 Haiku Project -// -// Some portions of code are copyrighted by -// USB Joystick driver for BeOS R5 -// Copyright 2000 (C) ITO, Takayuki -// All rights reserved -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. -/*****************************************************************************/ - - -#include -#include -#include -#include "hidparse.h" -#include - -/* - decompose report descriptor into array of uniform structure -*/ - -int -sign_extend(int value, int size) -{ - if (value & (1 << (size - 1))) - return value | (UINT_MAX << size); - - return value; -} - - -int -decompose_report_descriptor(const unsigned char *desc, - size_t desc_len, decomp_item *items, size_t *num_items) -{ - unsigned int desc_idx, item_idx; - static int item_size [4] = { 0, 1, 2, 4 }; - - if (desc == NULL || items == NULL || num_items == NULL || - desc_len <= 0 || *num_items <= 0) - return FAILURE; - - /* process one item per loop */ - for (desc_idx = item_idx = 0; - desc_idx < desc_len && item_idx < *num_items; item_idx++) { - item_prefix pfx; - int size; - unsigned short value16; - unsigned char value8; - - decomp_item *item = &items [item_idx]; - item->offset = desc_idx; - item->prefix = pfx.i = desc [desc_idx++]; - item->type = pfx.b.bType; - - if (pfx.i == LONG_ITEM_PREFIX) { - /* XXX no long item support */ - item->size = desc [desc_idx++]; - item->tag = desc [desc_idx++]; - item->value = item->signed_value = 0; - desc_idx += item->size; - continue; - } - - item->size = size = item_size [pfx.b.bSize]; - item->tag = pfx.b.bTag; - - switch (size) { - case 4: - item->signed_value = - item->value = - ((unsigned long) desc [desc_idx + 3] << 24) | - ((unsigned long) desc [desc_idx + 2] << 16) | - ( desc [desc_idx + 1] << 8) | - desc [desc_idx ]; - break; - case 2: - value16 = (desc [desc_idx + 1] << 8) | desc [desc_idx]; - item->value = value16; - item->signed_value = (signed short) value16; - break; - case 1: - value8 = desc [desc_idx]; - item->value = value8; - item->signed_value = (signed char) value8; - break; - case 0: - item->value = item->signed_value = 0; - break; - } - - desc_idx += size; - } - - *num_items = item_idx; - return SUCCESS; -} - -/* - parse decomposed items and generate "instructions" to interpret a report - - limitations: - only frequently used items are supported - only first collection is used - report ID is abandoned - output/feature reports are not implemented -*/ - -#ifndef min -#define min(a,b) ((a)<(b)?(a):(b)) -#endif - -int -parse_report_descriptor(const decomp_item *items, size_t num_items, - report_insn *insns, size_t *num_insns, - size_t *total_report_size, int *first_report_id) -{ - #define ITEM_STACK_SIZE 32 - - /* global items */ - typedef struct global_items { - unsigned int usage_page; - BOOL is_log_signed, is_phy_signed; - unsigned long log_max, log_min, - phy_max, phy_min; - signed long signed_log_max, signed_log_min, - signed_phy_max, signed_phy_min; - int report_size, report_id; - unsigned int report_count; - } global_items; - - global_items item_state, item_stack [ITEM_STACK_SIZE]; - int item_sp = ITEM_STACK_SIZE; - - /* local items */ - unsigned int usage_id = 0, usage_min = 0, usage_max; - unsigned int insn_idx_bias = 0, i, insn_idx, item_idx; - - int bit_pos = 0, byte_idx = 0, collection = 0; - - if (items == NULL || insns == NULL || num_insns == NULL || - *num_insns <= 0 || num_items <= 0) - return FAILURE; - - memset (&item_state, 0, sizeof (item_state)); - - /* interpret one item per loop */ - for (insn_idx = item_idx = 0; - item_idx < num_items && insn_idx < *num_insns; - item_idx++) - { - const decomp_item *item = &items [item_idx]; - report_insn *insn = &insns [insn_idx]; - int tag = item->tag; - switch (item->type) { - case ITEM_TYPE_MAIN: - switch (tag) { - case ITEM_TAG_INPUT: - for (i = 0; i < item_state.report_count && insn_idx < *num_insns; i++) { - if ((item->value & 3) == 2) { /* data,variable */ - if (insn_idx_bias == 0) { - insn->usage_page = item_state.usage_page; - insn->usage_id = usage_id; - } else - --insn_idx_bias; - - insn->attributes = item->value; - - insn->is_log_signed = item_state.is_log_signed; - if (item_state.is_log_signed) { - insn->signed_log_min = item_state.signed_log_min; - insn->signed_log_max = item_state.signed_log_max; - } else { - insn->log_min = item_state.log_min; - insn->log_max = item_state.log_max; - } - - insn->is_phy_signed = item_state.is_phy_signed; - if (item_state.is_phy_signed) { - insn->signed_phy_min = item_state.signed_phy_min; - insn->signed_phy_max = item_state.signed_phy_max; - } else { - insn->phy_min = item_state.phy_min; - insn->phy_max = item_state.phy_max; - } - - insn->byte_idx = byte_idx; - insn->bit_pos = bit_pos; - insn->num_bits = item_state.report_size; - - insn++; - insn_idx++; - } - else - insn_idx_bias = 0; /* XXX */ - - /* to next bit-field */ - bit_pos += item_state.report_size; - if (bit_pos >= 8) { - byte_idx += bit_pos / 8; - bit_pos = bit_pos % 8; - } - } - break; - - case ITEM_TAG_OUTPUT: - /* XXX similar to input */ - break; - case ITEM_TAG_COLLECTION: - collection++; - insn_idx_bias = 0; - break; - case ITEM_TAG_FEATURE: - /* XXX similar to input */ - break; - case ITEM_TAG_END_COLLECTION: - if (--collection == 0) - /* exit at end of first collection */ - goto end; - break; - default: - break; - } - break; - - case ITEM_TYPE_GLOBAL: - switch (tag) { - case ITEM_TAG_USAGE_PAGE: - item_state.usage_page = item->value; - break; - case ITEM_TAG_LOGICAL_MINIMUM: - item_state.log_min = item->value; - item_state.signed_log_min = item->signed_value; - /* FALLTHROUGH */ - case ITEM_TAG_PHYSICAL_MINIMUM: - item_state.phy_min = item->value; - item_state.signed_phy_min = item->signed_value; - break; - case ITEM_TAG_LOGICAL_MAXIMUM: - item_state.log_max = item->value; - item_state.signed_log_max = item->signed_value; - item_state.is_log_signed = item_state.log_min > item_state.log_max; - /* FALLTHROUGH */ - case ITEM_TAG_PHYSICAL_MAXIMUM: - item_state.phy_max = item->value; - item_state.signed_phy_max = item->signed_value; - item_state.is_phy_signed = item_state.phy_min > item_state.phy_max; - break; - case ITEM_TAG_UNIT_EXPONENT: - break; - case ITEM_TAG_UNIT: - break; - case ITEM_TAG_REPORT_SIZE: - item_state.report_size = item->value; - break; - case ITEM_TAG_REPORT_ID: - /* FIXME */ - if (item_state.report_id == 0) { - item_state.report_id = item->value; - byte_idx++; - } - else - goto end; - break; - case ITEM_TAG_REPORT_COUNT: - item_state.report_count = item->value; - break; - case ITEM_TAG_PUSH: - if (item_sp > 0) - item_stack [--item_sp] = item_state; - break; - case ITEM_TAG_POP: - if (item_sp < ITEM_STACK_SIZE) - item_state = item_stack [item_sp++]; - break; - } - break; - - case ITEM_TYPE_LOCAL: - switch (tag) - { - case ITEM_TAG_USAGE: - /* can be sequentially used */ - /* XXX should be limited to "practical" usages */ - /* XXX should support extended (32-bit) usage */ - if (insn_idx + insn_idx_bias < *num_insns) { - insn [insn_idx_bias].usage_page = item_state.usage_page; - insn [insn_idx_bias].usage_id = usage_id = item->value; - insn_idx_bias++; - } - break; - case ITEM_TAG_USAGE_MINIMUM: - usage_min = item->value; - break; - case ITEM_TAG_USAGE_MAXIMUM: - usage_max = item->value; - insn_idx_bias = min (usage_max - usage_min + 1, - *num_insns - insn_idx); - for (i = 0; i < insn_idx_bias; i++) { - insn [i].usage_page = item_state.usage_page; - insn [i].usage_id = usage_min + i; - } - break; - case ITEM_TAG_DESIGNATOR_INDEX: - break; - case ITEM_TAG_DESIGNATOR_MINIMUM: - break; - case ITEM_TAG_DESIGNATOR_MAXIMUM: - break; - case ITEM_TAG_STRING_INDEX: - break; - case ITEM_TAG_STRING_MINIMUM: - break; - case ITEM_TAG_STRING_MAXIMUM: - break; - case ITEM_TAG_DELIMITER: - break; - } - break; - } - } - -end: - *num_insns = insn_idx; - if (total_report_size != NULL) - *total_report_size = byte_idx; - if (first_report_id != NULL) - *first_report_id = item_state.report_id; - return SUCCESS; -} diff --git a/src/add-ons/kernel/drivers/input/usb_hid/hidparse.h b/src/add-ons/kernel/drivers/input/usb_hid/hidparse.h deleted file mode 100644 index 294277ebf3..0000000000 --- a/src/add-ons/kernel/drivers/input/usb_hid/hidparse.h +++ /dev/null @@ -1,174 +0,0 @@ -/*****************************************************************************/ -// HID usb driver -// Written by Jérôme Duval -// -// hidparse.h -// -// Copyright (c) 2004 Haiku Project -// -// Some portions of code are copyrighted by -// USB Joystick driver for BeOS R5 -// Copyright 2000 (C) ITO, Takayuki -// All rights reserved -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. -/*****************************************************************************/ - - -#include - -#define SUCCESS 0 -#define FAILURE (-1) - -#define BOOL int -#define TRUE 1 -#define FALSE 0 - -/* - Report Descriptor Items - see - 5.3 Generic Item Format - 6.2.2 Report Descriptor - 8. Report Protocol - */ - -enum -{ - ITEM_SIZE_0, - ITEM_SIZE_1, - ITEM_SIZE_2, /* long item */ - ITEM_SIZE_4, -}; - -enum -{ - ITEM_TYPE_MAIN, - ITEM_TYPE_GLOBAL, - ITEM_TYPE_LOCAL, - ITEM_TYPE_RESERVED, /* long item */ -}; - -enum -{ - /* main items */ - ITEM_TAG_INPUT = 8, - ITEM_TAG_OUTPUT, - ITEM_TAG_COLLECTION, - ITEM_TAG_FEATURE, - ITEM_TAG_END_COLLECTION, - - /* global items */ - ITEM_TAG_USAGE_PAGE = 0, - ITEM_TAG_LOGICAL_MINIMUM, - ITEM_TAG_LOGICAL_MAXIMUM, - ITEM_TAG_PHYSICAL_MINIMUM, - ITEM_TAG_PHYSICAL_MAXIMUM, - ITEM_TAG_UNIT_EXPONENT, - ITEM_TAG_UNIT, - ITEM_TAG_REPORT_SIZE, - ITEM_TAG_REPORT_ID, - ITEM_TAG_REPORT_COUNT, - ITEM_TAG_PUSH, - ITEM_TAG_POP, - - /* local items */ - ITEM_TAG_USAGE = 0, - ITEM_TAG_USAGE_MINIMUM, - ITEM_TAG_USAGE_MAXIMUM, - ITEM_TAG_DESIGNATOR_INDEX, - ITEM_TAG_DESIGNATOR_MINIMUM, - ITEM_TAG_DESIGNATOR_MAXIMUM, - /* 6 is missing */ - ITEM_TAG_STRING_INDEX = 7, - ITEM_TAG_STRING_MINIMUM, - ITEM_TAG_STRING_MAXIMUM, - ITEM_TAG_DELIMITER, -}; - -typedef struct -{ - unsigned char bSize:2, bType:2, bTag:4; -} item_prefix_bitfields; - -typedef union -{ - item_prefix_bitfields b; - unsigned char i; -} item_prefix; - -#define LONG_ITEM_PREFIX 0xfe - -/* - parsed item -*/ - -typedef struct -{ - int offset; /* byte offset in report descriptor */ - int prefix, size, type, tag; - unsigned long value; - signed long signed_value; /* sign extended: for logical min/max */ -} decomp_item; - -/* - report "instruction" -*/ - -typedef struct -{ - unsigned int usage_page, usage_id; - int ctrl_type; /* TYPE_*; set by count_controls() */ - int attributes; - - BOOL is_log_signed, is_phy_signed; - unsigned long log_min, log_max; - unsigned long phy_min, phy_max; - signed long signed_log_min, signed_log_max; - signed long signed_phy_min, signed_phy_max; - - /* used to extract bit-field from report */ - /* value = (report [byte_idx] >> bit_pos) & ((1 << num_bits) - 1) */ - /* N.B. you need sign extension if signed */ - int byte_idx, bit_pos, num_bits; - -} report_insn; - -#if defined(__cplusplus) -extern "C" { -#endif - -int sign_extend(int value, int size); - -int decompose_report_descriptor - (const unsigned char *desc, - size_t desc_len, - decomp_item *items, - size_t *num_items); - -int parse_report_descriptor - (const decomp_item *items, - size_t num_items, - report_insn *insns, - size_t *num_insns, - size_t *total_report_size, - int *first_report_id); - -#if defined(__cplusplus) -} -#endif diff --git a/src/add-ons/kernel/drivers/input/usb_hid/kernel_cpp.h b/src/add-ons/kernel/drivers/input/usb_hid/kernel_cpp.h index 7d7b025872..e69de29bb2 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/kernel_cpp.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/kernel_cpp.h @@ -1,45 +0,0 @@ -#ifndef _KERNEL_CPP_H_ -#define _KERNEL_CPP_H_ - -#include - -inline void * -operator new(size_t size) -{ - return malloc(size); -} - - -inline void * -operator new[](size_t size) -{ - return malloc(size); -} - - -inline void -operator delete(void *pointer) -{ - free(pointer); -} - - -inline void -operator delete[](void *pointer) -{ - free(pointer); -} - - -inline void -terminate(void) -{ -} - - -static inline void -__throw() -{ -} - -#endif // _KERNEL_CPP_H_