Author: mmlr Date: 2011-06-05 02:10:07 +0200 (Sun, 05 Jun 2011) New Revision: 41921 Changeset: https://dev.haiku-os.org/changeset/41921 Added: haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.cpp haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.h Modified: haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/Jamfile Log: Implement a HIDWriter that provides a high and lower level interface for writing report descriptors. These descriptors aren't optimized for efficiency (the writer doesn't attempt to avoid writing unneeded global items for example) but they will only serve as input for the HIDParser that parses them correctly regardless. Modified: haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h 2011-06-05 00:02:28 UTC (rev 41920) +++ haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/HIDDataTypes.h 2011-06-05 00:10:07 UTC (rev 41921) @@ -115,6 +115,12 @@ } _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 { Added: haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.cpp (rev 0) +++ haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.cpp 2011-06-05 00:10:07 UTC (rev 41921) @@ -0,0 +1,273 @@ +/* + * Copyright 2011, Michael Lotz, mmlr@xxxxxxxxx + * 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 <stdlib.h> +#include <string.h> + + +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; +} Added: haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.h =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.h (rev 0) +++ haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/HIDWriter.h 2011-06-05 00:10:07 UTC (rev 41921) @@ -0,0 +1,69 @@ +/* + * Copyright 2011, Michael Lotz, mmlr@xxxxxxxxx + * 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 Modified: haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/Jamfile =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/Jamfile 2011-06-05 00:02:28 UTC (rev 41920) +++ haiku/trunk/src/add-ons/kernel/drivers/input/usb_hid/Jamfile 2011-06-05 00:10:07 UTC (rev 41921) @@ -15,6 +15,7 @@ HIDParser.cpp HIDReport.cpp HIDReportItem.cpp + HIDWriter.cpp QuirkyDevices.cpp