* 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
This commit is contained in:
Michael Lotz 2011-05-28 19:59:02 +00:00
parent 3035edeb39
commit 305aff3f78
14 changed files with 485 additions and 179 deletions

View File

@ -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 <new>
@ -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);
}
}

View File

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

View File

@ -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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2008-2009 Michael Lotz <mmlr@mlotz.ch>
* Copyright 2008-2011, Michael Lotz <mmlr@mlotz.ch>
* 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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2008 Michael Lotz <mmlr@mlotz.ch>
* Copyright 2008-2011, Michael Lotz <mmlr@mlotz.ch>
* 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;
};

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2008-2009 Michael Lotz <mmlr@mlotz.ch>
* Copyright 2008-2011 Michael Lotz <mmlr@mlotz.ch>
* Distributed under the terms of the MIT license.
*/
@ -14,8 +14,9 @@
#include <debug.h>
#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';

View File

@ -1,9 +1,9 @@
/*
* Copyright 2008-2009 Michael Lotz <mmlr@mlotz.ch>
* Copyright 2008-2011 Michael Lotz <mmlr@mlotz.ch>
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2008-2009 Michael Lotz <mmlr@mlotz.ch>
* Copyright 2008-2011 Michael Lotz <mmlr@mlotz.ch>
* 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 <keyboard_mouse_driver.h>
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();

View File

@ -1,9 +1,9 @@
/*
* Copyright 2008-2009 Michael Lotz <mmlr@mlotz.ch>
* Copyright 2008-2011 Michael Lotz <mmlr@mlotz.ch>
* 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 <InterfaceDefs.h>
@ -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

View File

@ -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 <ring_buffer.h>
#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;
}

View File

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