From 305aff3f787ca5d2e0e5ef44fe3487ca3fb7adae Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sat, 28 May 2011 19:59:02 +0000 Subject: [PATCH] * Changed the way how devices are enumerated and protocol handlers are added to handle the different device classes. Handlers are now added based on the application collections that the HID descriptor describes instead of by enumerating the different report items inside the reports. This means that a device is now logically treated as a mouse when it comes with an application collection that designates it as a mouse, instead of when there is a report that contains an X and a Y axis. This resolves the conflicts that gamepads and joysticks were added as mice due to them containing such elements. This therefore fixes #4499 and opens up the way to properly handle other device types like joysticks (#7429), gamepads, tablets (#7354, #5989 and #7481) and so on. I'll work on gamepads/joysticks next and see where we stand for tablets later. * Added a few enumeration functions to HIDCollection to support the above. * Fix the root collection handling. A device doesn't describe a single root collection and then adds everything as a child. Instead it just has multiple collections on level 0. We account for that now by always creating an empty logical collection as the root collection where all the collections of the descriptor get added. * Rename the {Mouse|Keyboard}Device.{cpp|h} to {Mouse|Keyboard}ProtocolHandler.{cpp|h} as that more clearly describes their purpose. These classes are protocol handlers, i.e. they handle the ioctl based mouse and keyboard protocol between the driver and the input_server add-ons. * Change a lot of stuff to use references instead of pointers where it makes sense (not necessarily complete yet). I've tested this successfully on a keyboard with extended keys, a combo device with a keyboard with extended keys and a mouse, a mouse and a gamepad (that now doesn't do anything anymore) and found no regressions. However, since there are a lot of very varied ways how to describe such functions with HID, it's not too unlikely that some more curiously described devices will now stop working. These have to be handled case by case and their usages have to be added to the added to the appropriate handlers (or new handlers have to be written). Please test and create bug reports (preferrably including the report descriptor that is written out to /tmp). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41794 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../drivers/input/usb_hid/HIDCollection.cpp | 158 ++++++++++++++- .../drivers/input/usb_hid/HIDCollection.h | 21 +- .../drivers/input/usb_hid/HIDDataTypes.h | 3 +- .../drivers/input/usb_hid/HIDDevice.cpp | 30 ++- .../kernel/drivers/input/usb_hid/HIDDevice.h | 6 +- .../drivers/input/usb_hid/HIDParser.cpp | 19 +- .../drivers/input/usb_hid/HIDReportItem.h | 2 + .../kernel/drivers/input/usb_hid/Jamfile | 7 +- ...Device.cpp => KeyboardProtocolHandler.cpp} | 184 ++++++++++++------ ...oardDevice.h => KeyboardProtocolHandler.h} | 22 ++- ...useDevice.cpp => MouseProtocolHandler.cpp} | 95 ++++++--- .../{MouseDevice.h => MouseProtocolHandler.h} | 26 +-- .../drivers/input/usb_hid/ProtocolHandler.cpp | 78 ++++---- .../drivers/input/usb_hid/ProtocolHandler.h | 13 +- 14 files changed, 485 insertions(+), 179 deletions(-) rename src/add-ons/kernel/drivers/input/usb_hid/{KeyboardDevice.cpp => KeyboardProtocolHandler.cpp} (77%) rename src/add-ons/kernel/drivers/input/usb_hid/{KeyboardDevice.h => KeyboardProtocolHandler.h} (68%) rename src/add-ons/kernel/drivers/input/usb_hid/{MouseDevice.cpp => MouseProtocolHandler.cpp} (52%) rename src/add-ons/kernel/drivers/input/usb_hid/{MouseDevice.h => MouseProtocolHandler.h} (50%) diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.cpp b/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.cpp index f0a24c473e..650d4947d9 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. + * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch. * Distributed under the terms of the MIT License. */ @@ -10,6 +10,7 @@ #endif #include "HIDCollection.h" +#include "HIDReport.h" #include "HIDReportItem.h" #include @@ -36,7 +37,10 @@ HIDCollection::HIDCollection(HIDCollection *parent, uint8 type, usageValue.u.extended = localState.usage_minimum.u.extended; else if (localState.usage_maximum_set) usageValue.u.extended = localState.usage_maximum.u.extended; - else { + else if (type == COLLECTION_LOGICAL) { + // this is just a logical grouping collection + usageValue.u.extended = 0; + } else { TRACE_ALWAYS("non of the possible usages for the collection are set\n"); } @@ -53,6 +57,24 @@ HIDCollection::~HIDCollection() } +uint16 +HIDCollection::UsagePage() +{ + usage_value value; + value.u.extended = fUsage; + return value.u.s.usage_page; +} + + +uint16 +HIDCollection::UsageID() +{ + usage_value value; + value.u.extended = fUsage; + return value.u.s.usage_id; +} + + status_t HIDCollection::AddChild(HIDCollection *child) { @@ -79,6 +101,32 @@ HIDCollection::ChildAt(uint32 index) } +uint32 +HIDCollection::CountChildrenFlat(uint8 type) +{ + uint32 count = 0; + if (type == COLLECTION_ALL || fType == type) + count++; + + for (uint32 i = 0; i < fChildCount; i++) { + HIDCollection *child = fChildren[i]; + if (child == NULL) + continue; + + count += child->CountChildrenFlat(type); + } + + return count; +} + + +HIDCollection * +HIDCollection::ChildAtFlat(uint8 type, uint32 index) +{ + return _ChildAtFlat(type, index); +} + + void HIDCollection::AddItem(HIDReportItem *item) { @@ -109,6 +157,28 @@ HIDCollection::ItemAt(uint32 index) } +uint32 +HIDCollection::CountItemsFlat() +{ + uint32 count = fItemCount; + + for (uint32 i = 0; i < fChildCount; i++) { + HIDCollection *child = fChildren[i]; + if (child != NULL) + count += child->CountItemsFlat(); + } + + return count; +} + + +HIDReportItem * +HIDCollection::ItemAtFlat(uint32 index) +{ + return _ItemAtFlat(index); +} + + void HIDCollection::PrintToStream(uint32 indentLevel) { @@ -161,3 +231,87 @@ HIDCollection::PrintToStream(uint32 indentLevel) child->PrintToStream(indentLevel + 1); } } + + +HIDCollection * +HIDCollection::_ChildAtFlat(uint8 type, uint32 &index) +{ + if (type == COLLECTION_ALL || fType == type) { + if (index == 0) + return this; + + index--; + } + + for (uint32 i = 0; i < fChildCount; i++) { + HIDCollection *child = fChildren[i]; + if (child == NULL) + continue; + + HIDCollection *result = child->_ChildAtFlat(type, index); + if (result != NULL) + return result; + } + + return NULL; +} + + +HIDReportItem * +HIDCollection::_ItemAtFlat(uint32 &index) +{ + if (index < fItemCount) + return fItems[index]; + + index -= fItemCount; + + for (uint32 i = 0; i < fChildCount; i++) { + HIDCollection *child = fChildren[i]; + if (child == NULL) + continue; + + HIDReportItem *result = child->_ItemAtFlat(index); + if (result != NULL) + return result; + } + + return NULL; +} + + +void +HIDCollection::BuildReportList(uint8 reportType, + HIDReport **reportList, uint32 &reportCount) +{ + + for (uint32 i = 0; i < fItemCount; i++) { + HIDReportItem *item = fItems[i]; + if (item == NULL) + continue; + + HIDReport *report = item->Report(); + if (reportType != HID_REPORT_TYPE_ANY && report->Type() != reportType) + continue; + + bool found = false; + for (uint32 j = 0; j < reportCount; j++) { + if (reportList[j] == report) { + found = true; + break; + } + } + + if (found) + continue; + + reportList[reportCount++] = report; + } + + for (uint32 i = 0; i < fChildCount; i++) { + HIDCollection *child = fChildren[i]; + if (child == NULL) + continue; + + child->BuildReportList(reportType, reportList, reportCount); + } +} diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.h b/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.h index 917ebc3503..49f2d56f5d 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDCollection.h @@ -1,5 +1,5 @@ /* - * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. + * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch. * Distributed under the terms of the MIT License. */ #ifndef HID_COLLECTION_H @@ -7,6 +7,7 @@ #include "HIDParser.h" +class HIDReport; class HIDReportItem; class HIDCollection { @@ -15,19 +16,37 @@ public: uint8 type, local_item_state &localState); ~HIDCollection(); + uint8 Type() { return fType; }; + + uint16 UsagePage(); + uint16 UsageID(); + HIDCollection * Parent() { return fParent; }; status_t AddChild(HIDCollection *child); uint32 CountChildren() { return fChildCount; }; HIDCollection * ChildAt(uint32 index); + uint32 CountChildrenFlat(uint8 type); + HIDCollection * ChildAtFlat(uint8 type, uint32 index); + void AddItem(HIDReportItem *item); uint32 CountItems() { return fItemCount; }; HIDReportItem * ItemAt(uint32 index); + uint32 CountItemsFlat(); + HIDReportItem * ItemAtFlat(uint32 index); + + void BuildReportList(uint8 reportType, + HIDReport **reportList, + uint32 &reportCount); + void PrintToStream(uint32 indentLevel = 0); private: + HIDCollection * _ChildAtFlat(uint8 type, uint32 &index); + HIDReportItem * _ItemAtFlat(uint32 &index); + HIDCollection * fParent; uint8 fType; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h b/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h index f847ebb0c2..4baeca2cf4 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h @@ -1,5 +1,5 @@ /* - * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. + * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch. * Distributed under the terms of the MIT License. */ #ifndef HID_DATA_TYPES_H @@ -51,6 +51,7 @@ #define COLLECTION_NAMED_ARRAY 0x04 #define COLLECTION_USAGE_SWITCH 0x05 #define COLLECTION_USAGE_MODIFIER 0x06 +#define COLLECTION_ALL 0xff #define UNIT_SYSTEM 0x0 #define UNIT_LENGTH 0x1 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 d4cf3e426a..9db4753d23 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Michael Lotz + * Copyright 2008-2011, Michael Lotz * Distributed under the terms of the MIT license. */ @@ -35,7 +35,7 @@ HIDDevice::HIDDevice(usb_device device, const usb_configuration_info *config, fRemoved(false), fParser(this), fProtocolHandlerCount(0), - fProtocolHandlers(NULL) + fProtocolHandlerList(NULL) { uint8 *reportDescriptor = NULL; size_t descriptorLength = 0; @@ -166,18 +166,21 @@ HIDDevice::HIDDevice(usb_device device, const usb_configuration_info *config, return; } - ProtocolHandler::AddHandlers(this, &fProtocolHandlers, - &fProtocolHandlerCount); + ProtocolHandler::AddHandlers(*this, fProtocolHandlerList, + fProtocolHandlerCount); fStatus = B_OK; } HIDDevice::~HIDDevice() { - for (uint32 i = 0; i < fProtocolHandlerCount; i++) - delete fProtocolHandlers[i]; + ProtocolHandler *handler = fProtocolHandlerList; + while (handler != NULL) { + ProtocolHandler *next = handler->NextHandler(); + delete handler; + handler = next; + } - free(fProtocolHandlers); free(fTransferBuffer); } @@ -250,9 +253,16 @@ HIDDevice::SendReport(HIDReport *report) ProtocolHandler * HIDDevice::ProtocolHandlerAt(uint32 index) const { - if (index >= fProtocolHandlerCount) - return NULL; - return fProtocolHandlers[index]; + ProtocolHandler *handler = fProtocolHandlerList; + while (handler != NULL) { + if (index == 0) + return handler; + + handler = handler->NextHandler(); + index--; + } + + return NULL; } 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 80484d4769..677fab9d8b 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDDevice.h @@ -1,5 +1,5 @@ /* - * Copyright 2008 Michael Lotz + * Copyright 2008-2011, Michael Lotz * Distributed under the terms of the MIT license. */ #ifndef USB_HID_DEVICE_H @@ -38,7 +38,7 @@ public: status_t SendReport(HIDReport *report); - HIDParser * Parser() { return &fParser; } + HIDParser & Parser() { return fParser; } ProtocolHandler * ProtocolHandlerAt(uint32 index) const; // only to be used for the kernel debugger information @@ -66,7 +66,7 @@ private: HIDParser fParser; uint32 fProtocolHandlerCount; - ProtocolHandler ** fProtocolHandlers; + ProtocolHandler * fProtocolHandlerList; }; 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 5461b9b7bf..9a29032a00 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. + * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch. * Distributed under the terms of the MIT License. */ @@ -62,7 +62,14 @@ HIDParser::ParseReportDescriptor(const uint8 *reportDescriptor, return B_NO_MEMORY; } - HIDCollection *collection = NULL; + fRootCollection = new(std::nothrow) HIDCollection(NULL, COLLECTION_LOGICAL, + localState); + if (fRootCollection == NULL) { + TRACE_ALWAYS("no memory to allocate root collection\n"); + return B_NO_MEMORY; + } + + HIDCollection *collection = fRootCollection; const uint8 *pointer = reportDescriptor; const uint8 *end = pointer + descriptorLength; @@ -138,14 +145,10 @@ HIDParser::ParseReportDescriptor(const uint8 *reportDescriptor, break; } - if (collection == NULL) - fRootCollection = newCollection; - else - collection->AddChild(newCollection); - + collection->AddChild(newCollection); collection = newCollection; } else if (item->tag == ITEM_TAG_MAIN_END_COLLECTION) { - if (collection == NULL) { + if (collection == fRootCollection) { TRACE_ALWAYS("end collection with no open one\n"); break; } 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 ca9f489d9b..f1f8f60795 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDReportItem.h @@ -17,6 +17,8 @@ public: uint32 minimum, uint32 maximum, uint32 usageMinimum, uint32 usageMaximum); + HIDReport * Report() { return fReport; }; + bool HasData() { return fHasData; }; bool Relative() { return fRelative; }; bool Array() { return fArray; }; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/Jamfile b/src/add-ons/kernel/drivers/input/usb_hid/Jamfile index e877d9fb7a..9a42a821c5 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/Jamfile +++ b/src/add-ons/kernel/drivers/input/usb_hid/Jamfile @@ -10,12 +10,13 @@ KernelAddon usb_hid : DeviceList.cpp Driver.cpp HIDDevice.cpp - KeyboardDevice.cpp - MouseDevice.cpp - ProtocolHandler.cpp HIDCollection.cpp HIDParser.cpp HIDReport.cpp HIDReportItem.cpp + + ProtocolHandler.cpp + KeyboardProtocolHandler.cpp + MouseProtocolHandler.cpp ; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.cpp similarity index 77% rename from src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp rename to src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.cpp index 66d562628e..e1f90f988e 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Michael Lotz + * Copyright 2008-2011 Michael Lotz * Distributed under the terms of the MIT license. */ @@ -14,8 +14,9 @@ #include #include "Driver.h" -#include "KeyboardDevice.h" +#include "KeyboardProtocolHandler.h" +#include "HIDCollection.h" #include "HIDDevice.h" #include "HIDReport.h" #include "HIDReportItem.h" @@ -48,9 +49,10 @@ debug_get_keyboard_config(int argc, char **argv) // #pragma mark - -KeyboardDevice::KeyboardDevice(HIDReport *inputReport, HIDReport *outputReport) +KeyboardProtocolHandler::KeyboardProtocolHandler(HIDReport &inputReport, + HIDReport *outputReport) : - ProtocolHandler(inputReport->Device(), "input/keyboard/usb/", 512), + ProtocolHandler(inputReport.Device(), "input/keyboard/usb/", 512), fInputReport(inputReport), fOutputReport(outputReport), fRepeatDelay(300000), @@ -68,8 +70,8 @@ KeyboardDevice::KeyboardDevice(HIDReport *inputReport, HIDReport *outputReport) mutex_init(&fLock, "usb keyboard"); // find modifiers and keys - for (uint32 i = 0; i < inputReport->CountItems(); i++) { - HIDReportItem *item = inputReport->ItemAt(i); + for (uint32 i = 0; i < inputReport.CountItems(); i++) { + HIDReportItem *item = inputReport.ItemAt(i); if (!item->HasData()) continue; @@ -96,7 +98,7 @@ KeyboardDevice::KeyboardDevice(HIDReport *inputReport, HIDReport *outputReport) TRACE("keyboard device with %lu keys and %lu modifiers\n", fKeyCount, fModifierCount); - TRACE("input report: %u; output report: %u\n", inputReport->ID(), + TRACE("input report: %u; output report: %u\n", inputReport.ID(), outputReport != NULL ? outputReport->ID() : 255); fLastKeys = (uint16 *)malloc(fKeyCount * 2 * sizeof(uint16)); @@ -142,7 +144,7 @@ KeyboardDevice::KeyboardDevice(HIDReport *inputReport, HIDReport *outputReport) } -KeyboardDevice::~KeyboardDevice() +KeyboardProtocolHandler::~KeyboardProtocolHandler() { free(fLastKeys); @@ -155,59 +157,122 @@ KeyboardDevice::~KeyboardDevice() } -ProtocolHandler * -KeyboardDevice::AddHandler(HIDDevice *device, HIDReport *input) +void +KeyboardProtocolHandler::AddHandlers(HIDDevice &device, + HIDCollection &collection, ProtocolHandler *&handlerList) { - bool mayHaveOutput = false; - bool foundKeyboardUsage = false; - for (uint32 i = 0; i < input->CountItems(); i++) { - HIDReportItem *item = input->ItemAt(i); - if (!item->HasData()) - continue; + bool handled = false; + switch (collection.UsagePage()) { + case B_HID_USAGE_PAGE_GENERIC_DESKTOP: + { + switch (collection.UsageID()) { + case B_HID_UID_GD_KEYBOARD: + case B_HID_UID_GD_KEYPAD: + case B_HID_UID_GD_SYSTEM_CONTROL: + handled = true; + } + + break; + } + + case B_HID_USAGE_PAGE_CONSUMER: + { + switch (collection.UsageID()) { + case B_HID_UID_CON_CONSUMER_CONTROL: + handled = true; + } - if (item->UsagePage() == B_HID_USAGE_PAGE_KEYBOARD - || (item->UsagePage() == B_HID_USAGE_PAGE_CONSUMER && item->Array()) - || (item->UsagePage() == B_HID_USAGE_PAGE_BUTTON && item->Array())) { - // found at least one item with a keyboard usage or with - // a consumer/button usage that is handled like a key - mayHaveOutput = item->UsagePage() == B_HID_USAGE_PAGE_KEYBOARD; - foundKeyboardUsage = true; break; } } - if (!foundKeyboardUsage) - return NULL; - - HIDReport *output = NULL; - bool foundOutputReport = false; - if (mayHaveOutput) { - // try to find the led output report - HIDParser *parser = device->Parser(); - uint32 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() == B_HID_USAGE_PAGE_LED) { - foundOutputReport = true; - break; - } - } - - if (foundOutputReport) - break; - } + if (!handled) { + TRACE("collection not a supported keyboard subset\n"); + return; } - return new(std::nothrow) KeyboardDevice(input, - foundOutputReport ? output : NULL); + HIDParser &parser = device.Parser(); + uint32 maxReportCount = parser.CountReports(HID_REPORT_TYPE_INPUT); + if (maxReportCount == 0) + return; + + uint32 inputReportCount = 0; + HIDReport *inputReports[maxReportCount]; + collection.BuildReportList(HID_REPORT_TYPE_INPUT, inputReports, + inputReportCount); + + TRACE("input report count: %lu\n", inputReportCount); + + for (uint32 i = 0; i < inputReportCount; i++) { + HIDReport *inputReport = inputReports[i]; + + bool mayHaveOutput = false; + bool foundKeyboardUsage = false; + for (uint32 j = 0; j < inputReport->CountItems(); j++) { + HIDReportItem *item = inputReport->ItemAt(j); + if (!item->HasData()) + continue; + + if (item->UsagePage() == B_HID_USAGE_PAGE_KEYBOARD + || (item->UsagePage() == B_HID_USAGE_PAGE_CONSUMER + && item->Array()) + || (item->UsagePage() == B_HID_USAGE_PAGE_BUTTON + && item->Array())) { + // found at least one item with a keyboard usage or with + // a consumer/button usage that is handled like a key + mayHaveOutput = item->UsagePage() == B_HID_USAGE_PAGE_KEYBOARD; + foundKeyboardUsage = true; + break; + } + } + + if (!foundKeyboardUsage) + continue; + + bool foundOutputReport = false; + HIDReport *outputReport = NULL; + do { + // try to find the led output report + maxReportCount = parser.CountReports(HID_REPORT_TYPE_OUTPUT); + if (maxReportCount == 0) + break; + + uint32 outputReportCount = 0; + HIDReport *outputReports[maxReportCount]; + collection.BuildReportList(HID_REPORT_TYPE_OUTPUT, + outputReports, outputReportCount); + + for (uint32 j = 0; j < outputReportCount; j++) { + outputReport = outputReports[j]; + + for (uint32 k = 0; k < outputReport->CountItems(); k++) { + HIDReportItem *item = outputReport->ItemAt(k); + if (item->UsagePage() == B_HID_USAGE_PAGE_LED) { + foundOutputReport = true; + break; + } + } + + if (foundOutputReport) + break; + } + } while (false); + + ProtocolHandler *newHandler = new(std::nothrow) KeyboardProtocolHandler( + *inputReport, foundOutputReport ? outputReport : NULL); + if (newHandler == NULL) { + TRACE("failed to allocated keyboard protocol handler\n"); + continue; + } + + newHandler->SetNextHandler(handlerList); + handlerList = newHandler; + } } status_t -KeyboardDevice::Open(uint32 flags, uint32 *cookie) +KeyboardProtocolHandler::Open(uint32 flags, uint32 *cookie) { status_t status = ProtocolHandler::Open(flags, cookie); if (status != B_OK) { @@ -226,7 +291,7 @@ KeyboardDevice::Open(uint32 flags, uint32 *cookie) status_t -KeyboardDevice::Close(uint32 *cookie) +KeyboardProtocolHandler::Close(uint32 *cookie) { if ((*cookie & KEYBOARD_FLAG_DEBUGGER) != 0) fHasDebugReader = false; @@ -238,7 +303,8 @@ KeyboardDevice::Close(uint32 *cookie) status_t -KeyboardDevice::Control(uint32 *cookie, uint32 op, void *buffer, size_t length) +KeyboardProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer, + size_t length) { switch (op) { case KB_READ: @@ -347,7 +413,7 @@ KeyboardDevice::Control(uint32 *cookie, uint32 op, void *buffer, size_t length) void -KeyboardDevice::_WriteKey(uint32 key, bool down) +KeyboardProtocolHandler::_WriteKey(uint32 key, bool down) { raw_key_info info; info.keycode = key; @@ -358,7 +424,7 @@ KeyboardDevice::_WriteKey(uint32 key, bool down) status_t -KeyboardDevice::_SetLEDs(uint8 *data) +KeyboardProtocolHandler::_SetLEDs(uint8 *data) { if (fOutputReport == NULL || fOutputReport->Device()->IsRemoved()) return B_ERROR; @@ -375,11 +441,11 @@ KeyboardDevice::_SetLEDs(uint8 *data) status_t -KeyboardDevice::_ReadReport(bigtime_t timeout) +KeyboardProtocolHandler::_ReadReport(bigtime_t timeout) { - status_t result = fInputReport->WaitForReport(timeout); + status_t result = fInputReport.WaitForReport(timeout); if (result != B_OK) { - if (fInputReport->Device()->IsRemoved()) { + if (fInputReport.Device()->IsRemoved()) { TRACE("device has been removed\n"); return B_ERROR; } @@ -420,7 +486,7 @@ KeyboardDevice::_ReadReport(bigtime_t timeout) fCurrentKeys[i] = 0; } - fInputReport->DoneProcessing(); + fInputReport.DoneProcessing(); static const uint32 kModifierTable[] = { KEY_ControlL, @@ -643,9 +709,9 @@ KeyboardDevice::_ReadReport(bigtime_t timeout) && (fLastModifiers & ALT_KEYS) != 0) { // Alt-SysReq+letter was pressed sDebugKeyboardPipe - = fInputReport->Device()->InterruptPipe(); + = fInputReport.Device()->InterruptPipe(); sDebugKeyboardReportSize - = fInputReport->Parser()->MaxReportSize(); + = fInputReport.Parser()->MaxReportSize(); char letter = current[i] - 4 + 'a'; diff --git a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.h b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.h similarity index 68% rename from src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.h rename to src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.h index 3c9cfb950f..16a290c7ad 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/KeyboardDevice.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/KeyboardProtocolHandler.h @@ -1,9 +1,9 @@ /* - * Copyright 2008-2009 Michael Lotz + * Copyright 2008-2011 Michael Lotz * Distributed under the terms of the MIT license. */ -#ifndef USB_KEYBOARD_DEVICE_H -#define USB_KEYBOARD_DEVICE_H +#ifndef USB_KEYBOARD_PROTOCOL_HANDLER_H +#define USB_KEYBOARD_PROTOCOL_HANDLER_H #include "ProtocolHandler.h" @@ -12,6 +12,7 @@ class HIDReportItem; +class HIDCollection; #define MAX_MODIFIERS 16 @@ -19,14 +20,15 @@ class HIDReportItem; #define MAX_LEDS 3 -class KeyboardDevice : public ProtocolHandler { +class KeyboardProtocolHandler : public ProtocolHandler { public: - KeyboardDevice(HIDReport *inputReport, + KeyboardProtocolHandler(HIDReport &inputReport, HIDReport *outputReport); - virtual ~KeyboardDevice(); + virtual ~KeyboardProtocolHandler(); - static ProtocolHandler * AddHandler(HIDDevice *device, - HIDReport *input); + static void AddHandlers(HIDDevice &device, + HIDCollection &collection, + ProtocolHandler *&handlerList); virtual status_t Open(uint32 flags, uint32 *cookie); virtual status_t Close(uint32 *cookie); @@ -42,7 +44,7 @@ private: private: mutex fLock; - HIDReport * fInputReport; + HIDReport & fInputReport; HIDReport * fOutputReport; HIDReportItem * fModifiers[MAX_MODIFIERS]; @@ -66,4 +68,4 @@ private: }; -#endif // USB_KEYBOARD_DEVICE_H +#endif // USB_KEYBOARD_PROTOCOL_HANDLER_H diff --git a/src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.cpp b/src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.cpp similarity index 52% rename from src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.cpp rename to src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.cpp index 3e8cac1821..4f80bf723f 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008-2009 Michael Lotz + * Copyright 2008-2011 Michael Lotz * Distributed under the terms of the MIT license. */ @@ -8,8 +8,9 @@ #include "Driver.h" -#include "MouseDevice.h" +#include "MouseProtocolHandler.h" +#include "HIDCollection.h" #include "HIDDevice.h" #include "HIDReport.h" #include "HIDReportItem.h" @@ -21,10 +22,10 @@ #include -MouseDevice::MouseDevice(HIDReport *report, HIDReportItem *xAxis, - HIDReportItem *yAxis) +MouseProtocolHandler::MouseProtocolHandler(HIDReport &report, + HIDReportItem &xAxis, HIDReportItem &yAxis) : - ProtocolHandler(report->Device(), "input/mouse/usb/", 512), + ProtocolHandler(report.Device(), "input/mouse/usb/", 512), fReport(report), fXAxis(xAxis), fYAxis(yAxis), @@ -35,47 +36,77 @@ MouseDevice::MouseDevice(HIDReport *report, HIDReportItem *xAxis, fClickSpeed(250000) { uint32 buttonCount = 0; - for (uint32 i = 0; i < report->CountItems(); i++) { - HIDReportItem *item = report->ItemAt(i); + for (uint32 i = 0; i < report.CountItems(); i++) { + HIDReportItem *item = report.ItemAt(i); if (!item->HasData()) continue; if (item->UsagePage() == B_HID_USAGE_PAGE_BUTTON - && item->UsageID() - 1 < B_MAX_MOUSE_BUTTONS) + && item->UsageID() - 1 < B_MAX_MOUSE_BUTTONS) { fButtons[buttonCount++] = item; + } } fButtons[buttonCount] = NULL; - fWheel = report->FindItem(B_HID_USAGE_PAGE_GENERIC_DESKTOP, + fWheel = report.FindItem(B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_WHEEL); TRACE("mouse device with %lu buttons and %swheel\n", buttonCount, fWheel == NULL ? "no " : ""); - TRACE("report id: %u\n", report->ID()); + TRACE("report id: %u\n", report.ID()); } -ProtocolHandler * -MouseDevice::AddHandler(HIDDevice *device, HIDReport *report) +void +MouseProtocolHandler::AddHandlers(HIDDevice &device, HIDCollection &collection, + ProtocolHandler *&handlerList) { - // try to find at least an x and y axis - HIDReportItem *xAxis = report->FindItem(B_HID_USAGE_PAGE_GENERIC_DESKTOP, - B_HID_UID_GD_X); - if (xAxis == NULL) - return NULL; + if (collection.UsagePage() != B_HID_USAGE_PAGE_GENERIC_DESKTOP + || collection.UsageID() != B_HID_UID_GD_MOUSE) { + TRACE("collection not a mouse\n"); + return; + } - HIDReportItem *yAxis = report->FindItem(B_HID_USAGE_PAGE_GENERIC_DESKTOP, - B_HID_UID_GD_Y); - if (yAxis == NULL) - return NULL; + HIDParser &parser = device.Parser(); + uint32 maxReportCount = parser.CountReports(HID_REPORT_TYPE_INPUT); + if (maxReportCount == 0) + return; - return new(std::nothrow) MouseDevice(report, xAxis, yAxis); + uint32 inputReportCount = 0; + HIDReport *inputReports[maxReportCount]; + collection.BuildReportList(HID_REPORT_TYPE_INPUT, inputReports, + inputReportCount); + + for (uint32 i = 0; i < inputReportCount; i++) { + HIDReport *inputReport = inputReports[i]; + + // try to find at least an x and y axis + HIDReportItem *xAxis = inputReport->FindItem( + B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X); + if (xAxis == NULL) + continue; + + HIDReportItem *yAxis = inputReport->FindItem( + B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Y); + if (yAxis == NULL) + continue; + + ProtocolHandler *newHandler = new(std::nothrow) MouseProtocolHandler( + *inputReport, *xAxis, *yAxis); + if (newHandler == NULL) { + TRACE("failed to allocated mouse protocol handler\n"); + continue; + } + + newHandler->SetNextHandler(handlerList); + handlerList = newHandler; + } } status_t -MouseDevice::Control(uint32 *cookie, uint32 op, void *buffer, size_t length) +MouseProtocolHandler::Control(uint32 *cookie, uint32 op, void *buffer, size_t length) { switch (op) { case MS_READ: @@ -90,7 +121,7 @@ MouseDevice::Control(uint32 *cookie, uint32 op, void *buffer, size_t length) case MS_NUM_EVENTS: { int32 count = RingBufferReadable() / sizeof(mouse_movement); - if (count == 0 && fReport->Device()->IsRemoved()) + if (count == 0 && fReport.Device()->IsRemoved()) return B_DEV_NOT_READY; return count; } @@ -109,11 +140,11 @@ MouseDevice::Control(uint32 *cookie, uint32 op, void *buffer, size_t length) status_t -MouseDevice::_ReadReport() +MouseProtocolHandler::_ReadReport() { - status_t result = fReport->WaitForReport(B_INFINITE_TIMEOUT); + status_t result = fReport.WaitForReport(B_INFINITE_TIMEOUT); if (result != B_OK) { - if (fReport->Device()->IsRemoved()) { + if (fReport.Device()->IsRemoved()) { TRACE("device has been removed\n"); return B_DEV_NOT_READY; } @@ -131,10 +162,10 @@ MouseDevice::_ReadReport() mouse_movement info; memset(&info, 0, sizeof(info)); - if (fXAxis->Extract() == B_OK && fXAxis->Valid()) - info.xdelta = fXAxis->Data(); - if (fYAxis->Extract() == B_OK && fYAxis->Valid()) - info.ydelta = -fYAxis->Data(); + if (fXAxis.Extract() == B_OK && fXAxis.Valid()) + info.xdelta = fXAxis.Data(); + if (fYAxis.Extract() == B_OK && fYAxis.Valid()) + info.ydelta = -fYAxis.Data(); if (fWheel != NULL && fWheel->Extract() == B_OK && fWheel->Valid()) info.wheel_ydelta = -fWheel->Data(); @@ -148,7 +179,7 @@ MouseDevice::_ReadReport() info.buttons |= (button->Data() & 1) << (button->UsageID() - 1); } - fReport->DoneProcessing(); + fReport.DoneProcessing(); TRACE("got mouse report\n"); bigtime_t timestamp = system_time(); diff --git a/src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.h b/src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.h similarity index 50% rename from src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.h rename to src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.h index 4d30753e05..ac598b9a6c 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/MouseDevice.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/MouseProtocolHandler.h @@ -1,9 +1,9 @@ /* - * Copyright 2008-2009 Michael Lotz + * Copyright 2008-2011 Michael Lotz * Distributed under the terms of the MIT license. */ -#ifndef USB_MOUSE_DEVICE_H -#define USB_MOUSE_DEVICE_H +#ifndef USB_MOUSE_PROTOCOL_HANDLER_H +#define USB_MOUSE_PROTOCOL_HANDLER_H #include @@ -11,6 +11,7 @@ #include "ProtocolHandler.h" +class HIDCollection; class HIDReportItem; @@ -19,13 +20,14 @@ class HIDReportItem; #endif -class MouseDevice : public ProtocolHandler { +class MouseProtocolHandler : public ProtocolHandler { public: - MouseDevice(HIDReport *report, - HIDReportItem *xAxis, HIDReportItem *yAxis); + MouseProtocolHandler(HIDReport &report, + HIDReportItem &xAxis, HIDReportItem &yAxis); - static ProtocolHandler * AddHandler(HIDDevice *device, - HIDReport *report); + static void AddHandlers(HIDDevice &device, + HIDCollection &collection, + ProtocolHandler *&handlerList); virtual status_t Control(uint32 *cookie, uint32 op, void *buffer, size_t length); @@ -34,10 +36,10 @@ private: status_t _ReadReport(); private: - HIDReport * fReport; + HIDReport & fReport; - HIDReportItem * fXAxis; - HIDReportItem * fYAxis; + HIDReportItem & fXAxis; + HIDReportItem & fYAxis; HIDReportItem * fWheel; HIDReportItem * fButtons[B_MAX_MOUSE_BUTTONS]; @@ -47,4 +49,4 @@ private: bigtime_t fClickSpeed; }; -#endif // USB_MOUSE_DEVICE_H +#endif // USB_MOUSE_PROTOCOL_HANDLER_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 index bcb8a27b41..cb04b5973a 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.cpp +++ b/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. + * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch. * Distributed under the terms of the MIT License. */ @@ -8,14 +8,15 @@ #include #include "Driver.h" +#include "HIDCollection.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" +#include "KeyboardProtocolHandler.h" +#include "MouseProtocolHandler.h" +//#include "JoystickProtocolHandler.h" ProtocolHandler::ProtocolHandler(HIDDevice *device, const char *basePath, @@ -24,7 +25,8 @@ ProtocolHandler::ProtocolHandler(HIDDevice *device, const char *basePath, fDevice(device), fBasePath(basePath), fPublishPath(NULL), - fRingBuffer(NULL) + fRingBuffer(NULL), + fNextHandler(NULL) { if (ringBufferSize > 0) { fRingBuffer = create_ring_buffer(ringBufferSize); @@ -59,47 +61,48 @@ ProtocolHandler::SetPublishPath(char *publishPath) void -ProtocolHandler::AddHandlers(HIDDevice *device, ProtocolHandler ***handlerList, - uint32 *handlerCount) +ProtocolHandler::AddHandlers(HIDDevice &device, ProtocolHandler *&handlerList, + uint32 &handlerCount) { TRACE("adding protocol handlers\n"); - HIDParser *parser = device->Parser(); - uint32 reportCount = parser->CountReports(HID_REPORT_TYPE_INPUT); - - *handlerCount = 0; - *handlerList = (ProtocolHandler **)malloc(sizeof(ProtocolHandler *) - * reportCount * 2 /* handler type count */); - if (*handlerList == NULL) { - TRACE_ALWAYS("out of memory allocating handler list\n"); + HIDParser &parser = device.Parser(); + HIDCollection *rootCollection = parser.RootCollection(); + if (rootCollection == NULL) return; + + uint32 appCollectionCount = rootCollection->CountChildrenFlat( + COLLECTION_APPLICATION); + TRACE("root collection holds %lu application collection%s\n", + appCollectionCount, appCollectionCount != 1 ? "s" : ""); + + handlerCount = 0; + for (uint32 i = 0; i < appCollectionCount; i++) { + HIDCollection *collection = rootCollection->ChildAtFlat( + COLLECTION_APPLICATION, i); + if (collection == NULL) + continue; + + TRACE("collection usage page %u usage id %u\n", + collection->UsagePage(), collection->UsageID()); + + KeyboardProtocolHandler::AddHandlers(device, *collection, handlerList); + MouseProtocolHandler::AddHandlers(device, *collection, handlerList); + //JoystickProtocolHandler::AddHandlers(device, *collection, handlerList); } - uint32 usedCount = 0; - ProtocolHandler *handler = NULL; - for (uint32 i = 0; i < reportCount; i++) { - HIDReport *report = parser->ReportAt(HID_REPORT_TYPE_INPUT, i); - - handler = KeyboardDevice::AddHandler(device, report); - if (handler != NULL) - (*handlerList)[usedCount++] = handler; - handler = MouseDevice::AddHandler(device, report); - if (handler != NULL) - (*handlerList)[usedCount++] = handler; + ProtocolHandler *handler = handlerList; + while (handler != NULL) { + handler = handler->NextHandler(); + handlerCount++; } - if (usedCount == 0) { + if (handlerCount == 0) { TRACE_ALWAYS("no handlers for hid device\n"); return; } - *handlerCount = usedCount; - ProtocolHandler **shrunkList = (ProtocolHandler **)realloc( - *handlerList, sizeof(ProtocolHandler *) * usedCount); - if (shrunkList != NULL) - *handlerList = shrunkList; - - TRACE("added %ld handlers for hid device\n", *handlerCount); + TRACE("added %ld handlers for hid device\n", handlerCount); } @@ -146,3 +149,10 @@ ProtocolHandler::RingBufferWrite(const void *buffer, size_t length) ring_buffer_write(fRingBuffer, (const uint8 *)buffer, length); return B_OK; } + + +void +ProtocolHandler::SetNextHandler(ProtocolHandler *nextHandler) +{ + fNextHandler = nextHandler; +} diff --git a/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h b/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h index 2d5724f0e1..21be52c27e 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/ProtocolHandler.h @@ -1,5 +1,5 @@ /* - * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. + * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch. * Distributed under the terms of the MIT License. */ #ifndef PROTOCOL_HANDLER_H @@ -28,9 +28,9 @@ public: void SetPublishPath(char *publishPath); const char * PublishPath() { return fPublishPath; } - static void AddHandlers(HIDDevice *device, - ProtocolHandler ***handlerList, - uint32 *handlerCount); + static void AddHandlers(HIDDevice &device, + ProtocolHandler *&handlerList, + uint32 &handlerCount); virtual status_t Open(uint32 flags, uint32 *cookie); virtual status_t Close(uint32 *cookie); @@ -43,6 +43,9 @@ public: status_t RingBufferWrite(const void *buffer, size_t length); + void SetNextHandler(ProtocolHandler *next); + ProtocolHandler * NextHandler() { return fNextHandler; }; + protected: status_t fStatus; @@ -51,6 +54,8 @@ private: const char * fBasePath; char * fPublishPath; struct ring_buffer *fRingBuffer; + + ProtocolHandler * fNextHandler; };