/* * 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 count, uint8 bitLength) { SetReportSize(bitLength); SetReportCount(count); main_item_data data = { 0 }; data.data_constant = 1; return Input(data); } status_t HIDWriter::DefineInputData(uint8 count, uint8 bitLength, main_item_data data, uint32 logicalMinimum, uint32 logicalMaximum, uint16 usagePage, uint16 usageMinimum, uint16 usageMaximum) { 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; }