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 4baeca2cf4..a1fc8d1504 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h @@ -115,6 +115,12 @@ typedef struct main_item_data { } _PACKED main_item_data; +typedef union main_item_data_converter { + main_item_data main_data; + uint16 flat_data; +} main_item_data_converter; + + typedef struct usage_value { union { struct { diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.cpp b/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.cpp new file mode 100644 index 0000000000..270b3a9a19 --- /dev/null +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.cpp @@ -0,0 +1,273 @@ +/* + * Copyright 2011, Michael Lotz, mmlr@mlotz.ch. + * Distributed under the terms of the MIT License. + */ + +#ifndef USERLAND_HID +#include "Driver.h" +#else +#include "UserlandHID.h" +#endif + +#include "HIDWriter.h" + +#include "HIDDataTypes.h" + +#include +#include + + +HIDWriter::HIDWriter(size_t blockSize) + : fBlockSize(blockSize), + fBufferAllocated(0), + fBufferUsed(0), + fBuffer(NULL), + fStatus(B_OK) +{ +} + + +HIDWriter::~HIDWriter() +{ + free(fBuffer); +} + + +// #pragma mark - High Level + + +status_t +HIDWriter::DefineInputPadding(uint8 reportID, uint8 count, uint8 bitLength) +{ + SetReportID(reportID); + SetReportSize(bitLength); + SetReportCount(count); + + main_item_data data; + data.data_constant = 1; + return Input(data); +} + + +status_t +HIDWriter::DefineInputData(uint8 reportID, uint8 count, uint8 bitLength, + main_item_data data, uint32 logicalMinimum, uint32 logicalMaximum, + uint16 usagePage, uint16 usageMinimum, uint16 usageMaximum) +{ + SetReportID(reportID); + SetReportSize(bitLength); + SetReportCount(count); + + SetLogicalMinimum(logicalMinimum); + SetLogicalMaximum(logicalMaximum); + + SetUsagePage(usagePage); + LocalSetUsageMinimum(usageMinimum); + LocalSetUsageMaximum( + usageMaximum == 0xffff ? usageMinimum + count - 1 : usageMaximum); + return Input(data); +} + + +status_t +HIDWriter::BeginCollection(uint8 collectionType, uint16 usagePage, + uint16 usageID) +{ + SetUsagePage(usagePage); + LocalSetUsageID(usageID); + return BeginCollection(collectionType); +} + + +status_t +HIDWriter::EndCollection() +{ + return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_END_COLLECTION, 0); +} + + +// #pragma mark - Low Level + + +status_t +HIDWriter::SetUsagePage(uint16 usagePage) +{ + return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_USAGE_PAGE, + usagePage); +} + + +status_t +HIDWriter::SetLogicalMinimum(uint32 logicalMinimum) +{ + return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_LOGICAL_MINIMUM, + logicalMinimum); +} + + +status_t +HIDWriter::SetLogicalMaximum(uint32 logicalMaximum) +{ + return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM, + logicalMaximum); +} + + +status_t +HIDWriter::SetReportSize(uint8 reportSize) +{ + return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_REPORT_SIZE, + reportSize); +} + + +status_t +HIDWriter::SetReportID(uint8 reportID) +{ + return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_REPORT_ID, + reportID); +} + + +status_t +HIDWriter::SetReportCount(uint8 reportCount) +{ + return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_REPORT_COUNT, + reportCount); +} + + +status_t +HIDWriter::LocalSetUsageID(uint16 usageID) +{ + return WriteShortItem(ITEM_TYPE_LOCAL, ITEM_TAG_LOCAL_USAGE, usageID); +} + + +status_t +HIDWriter::LocalSetUsageMinimum(uint16 usageMinimum) +{ + return WriteShortItem(ITEM_TYPE_LOCAL, ITEM_TAG_LOCAL_USAGE_MINIMUM, + usageMinimum); +} + + +status_t +HIDWriter::LocalSetUsageMaximum(uint16 usageMaximum) +{ + return WriteShortItem(ITEM_TYPE_LOCAL, ITEM_TAG_LOCAL_USAGE_MAXIMUM, + usageMaximum); +} + + +status_t +HIDWriter::BeginCollection(uint8 collectionType) +{ + return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_COLLECTION, + collectionType); +} + + +status_t +HIDWriter::Input(main_item_data data) +{ + main_item_data_converter converter; + converter.main_data = data; + return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_INPUT, + converter.flat_data); +} + + +status_t +HIDWriter::Output(main_item_data data) +{ + main_item_data_converter converter; + converter.main_data = data; + return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_OUTPUT, + converter.flat_data); +} + + +status_t +HIDWriter::Feature(main_item_data data) +{ + main_item_data_converter converter; + converter.main_data = data; + return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_FEATURE, + converter.flat_data); +} + + +// #pragma mark - Generic + + +status_t +HIDWriter::WriteShortItem(uint8 type, uint8 tag, uint32 value) +{ + short_item item; + item.prefix.size = 0; + + if (value > 0) { + if (value <= 0xff) + item.prefix.size = 1; + else if (value <= 0xffff) + item.prefix.size = 2; + else + item.prefix.size = 3; // actually means 4 + } + + item.prefix.type = type; + item.prefix.tag = tag; + + switch (item.prefix.size) { + case 0: + return Write(&item, sizeof(item_prefix)); + case 1: + item.data.as_uint8[0] = value; + return Write(&item, sizeof(item_prefix) + sizeof(uint8)); + case 2: + item.data.as_uint16[0] = value; + return Write(&item, sizeof(item_prefix) + sizeof(uint16)); + case 3: + item.data.as_uint32 = value; + return Write(&item, sizeof(item_prefix) + sizeof(uint32)); + } + + return B_OK; +} + + +status_t +HIDWriter::Write(const void *data, size_t length) +{ + if (fStatus != B_OK) + return fStatus; + + size_t available = fBufferAllocated - fBufferUsed; + if (length > available) { + fBufferAllocated += length > fBlockSize ? length : fBlockSize; + uint8 *newBuffer = (uint8 *)realloc(fBuffer, fBufferAllocated); + if (newBuffer == NULL) { + fBufferAllocated -= fBlockSize; + fStatus = B_NO_MEMORY; + return fStatus; + } + + fBuffer = newBuffer; + } + + memcpy(fBuffer + fBufferUsed, data, length); + fBufferUsed += length; + return B_OK; +} + + +void +HIDWriter::Reset() +{ + free(fBuffer); + fBuffer = NULL; + fBufferUsed = 0; + fBufferAllocated = 0; + fStatus = B_OK; +} diff --git a/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.h b/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.h new file mode 100644 index 0000000000..4a1ea69c0f --- /dev/null +++ b/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.h @@ -0,0 +1,69 @@ +/* + * Copyright 2011, Michael Lotz, mmlr@mlotz.ch. + * Distributed under the terms of the MIT License. + */ +#ifndef HID_WRITER_H +#define HID_WRITER_H + +#include "HIDDataTypes.h" + + +class HIDWriter { +public: + HIDWriter(size_t blockSize = 20); + ~HIDWriter(); + + // High Level + + status_t DefineInputPadding(uint8 reportID, uint8 count, + uint8 bitLength); + status_t DefineInputData(uint8 reportID, uint8 count, + uint8 bitLength, main_item_data data, + uint32 logicalMinimum, + uint32 logicalMaximum, uint16 usagePage, + uint16 usageMinimum, + uint16 usageMaximum = 0xffff); + + status_t BeginCollection(uint8 collectionType, + uint16 usagePage, uint16 usageID); + status_t EndCollection(); + + // Low Level + + status_t SetUsagePage(uint16 usagePage); + status_t SetLogicalMinimum(uint32 logicalMinimum); + status_t SetLogicalMaximum(uint32 logicalMaximum); + status_t SetReportSize(uint8 reportSize); + status_t SetReportID(uint8 reportID); + status_t SetReportCount(uint8 reportCount); + + status_t LocalSetUsageID(uint16 usageID); + status_t LocalSetUsageMinimum(uint16 usageMinimum); + status_t LocalSetUsageMaximum(uint16 usageMaximum); + + status_t BeginCollection(uint8 collectionType); + + status_t Input(main_item_data data); + status_t Output(main_item_data data); + status_t Feature(main_item_data data); + + // Generic + + status_t WriteShortItem(uint8 type, uint8 tag, + uint32 value); + status_t Write(const void *data, size_t length); + + size_t BufferLength() { return fBufferUsed; }; + const uint8 * Buffer() { return fBuffer; }; + + void Reset(); + +private: + size_t fBlockSize; + size_t fBufferAllocated; + size_t fBufferUsed; + uint8 * fBuffer; + status_t fStatus; +}; + +#endif // HID_WRITER_H diff --git a/src/add-ons/kernel/drivers/input/usb_hid/Jamfile b/src/add-ons/kernel/drivers/input/usb_hid/Jamfile index 913ccd2ea1..a521899043 100644 --- a/src/add-ons/kernel/drivers/input/usb_hid/Jamfile +++ b/src/add-ons/kernel/drivers/input/usb_hid/Jamfile @@ -15,6 +15,7 @@ KernelAddon usb_hid : HIDParser.cpp HIDReport.cpp HIDReportItem.cpp + HIDWriter.cpp QuirkyDevices.cpp