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; };