1/* 2 * Copyright 2011, Michael Lotz, mmlr@mlotz.ch. 3 * Distributed under the terms of the MIT License. 4 */ 5 6#ifndef USERLAND_HID 7#include "Driver.h" 8#else 9#include "UserlandHID.h" 10#endif 11 12#include "HIDWriter.h" 13 14#include "HIDDataTypes.h" 15 16#include <stdlib.h> 17#include <string.h> 18 19 20HIDWriter::HIDWriter(size_t blockSize) 21 : fBlockSize(blockSize), 22 fBufferAllocated(0), 23 fBufferUsed(0), 24 fBuffer(NULL), 25 fStatus(B_OK) 26{ 27} 28 29 30HIDWriter::~HIDWriter() 31{ 32 free(fBuffer); 33} 34 35 36// #pragma mark - High Level 37 38 39status_t 40HIDWriter::DefineInputPadding(uint8 count, uint8 bitLength) 41{ 42 SetReportSize(bitLength); 43 SetReportCount(count); 44 45 main_item_data data = { 0 }; 46 data.data_constant = 1; 47 return Input(data); 48} 49 50 51status_t 52HIDWriter::DefineInputData(uint8 count, uint8 bitLength, main_item_data data, 53 uint32 logicalMinimum, uint32 logicalMaximum, uint16 usagePage, 54 uint16 usageMinimum, uint16 usageMaximum) 55{ 56 SetReportSize(bitLength); 57 SetReportCount(count); 58 59 SetLogicalMinimum(logicalMinimum); 60 SetLogicalMaximum(logicalMaximum); 61 62 SetUsagePage(usagePage); 63 LocalSetUsageMinimum(usageMinimum); 64 LocalSetUsageMaximum( 65 usageMaximum == 0xffff ? usageMinimum + count - 1 : usageMaximum); 66 return Input(data); 67} 68 69 70status_t 71HIDWriter::BeginCollection(uint8 collectionType, uint16 usagePage, 72 uint16 usageID) 73{ 74 SetUsagePage(usagePage); 75 LocalSetUsageID(usageID); 76 return BeginCollection(collectionType); 77} 78 79 80status_t 81HIDWriter::EndCollection() 82{ 83 return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_END_COLLECTION, 0); 84} 85 86 87// #pragma mark - Low Level 88 89 90status_t 91HIDWriter::SetUsagePage(uint16 usagePage) 92{ 93 return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_USAGE_PAGE, 94 usagePage); 95} 96 97 98status_t 99HIDWriter::SetLogicalMinimum(uint32 logicalMinimum) 100{ 101 return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_LOGICAL_MINIMUM, 102 logicalMinimum); 103} 104 105 106status_t 107HIDWriter::SetLogicalMaximum(uint32 logicalMaximum) 108{ 109 return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM, 110 logicalMaximum); 111} 112 113 114status_t 115HIDWriter::SetReportSize(uint8 reportSize) 116{ 117 return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_REPORT_SIZE, 118 reportSize); 119} 120 121 122status_t 123HIDWriter::SetReportID(uint8 reportID) 124{ 125 return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_REPORT_ID, 126 reportID); 127} 128 129 130status_t 131HIDWriter::SetReportCount(uint8 reportCount) 132{ 133 return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_REPORT_COUNT, 134 reportCount); 135} 136 137 138status_t 139HIDWriter::LocalSetUsageID(uint16 usageID) 140{ 141 return WriteShortItem(ITEM_TYPE_LOCAL, ITEM_TAG_LOCAL_USAGE, usageID); 142} 143 144 145status_t 146HIDWriter::LocalSetUsageMinimum(uint16 usageMinimum) 147{ 148 return WriteShortItem(ITEM_TYPE_LOCAL, ITEM_TAG_LOCAL_USAGE_MINIMUM, 149 usageMinimum); 150} 151 152 153status_t 154HIDWriter::LocalSetUsageMaximum(uint16 usageMaximum) 155{ 156 return WriteShortItem(ITEM_TYPE_LOCAL, ITEM_TAG_LOCAL_USAGE_MAXIMUM, 157 usageMaximum); 158} 159 160 161status_t 162HIDWriter::BeginCollection(uint8 collectionType) 163{ 164 return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_COLLECTION, 165 collectionType); 166} 167 168 169status_t 170HIDWriter::Input(main_item_data data) 171{ 172 main_item_data_converter converter; 173 converter.main_data = data; 174 return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_INPUT, 175 converter.flat_data); 176} 177 178 179status_t 180HIDWriter::Output(main_item_data data) 181{ 182 main_item_data_converter converter; 183 converter.main_data = data; 184 return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_OUTPUT, 185 converter.flat_data); 186} 187 188 189status_t 190HIDWriter::Feature(main_item_data data) 191{ 192 main_item_data_converter converter; 193 converter.main_data = data; 194 return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_FEATURE, 195 converter.flat_data); 196} 197 198 199// #pragma mark - Generic 200 201 202status_t 203HIDWriter::WriteShortItem(uint8 type, uint8 tag, uint32 value) 204{ 205 short_item item; 206 item.prefix.size = 0; 207 208 if (value > 0) { 209 if (value <= 0xff) 210 item.prefix.size = 1; 211 else if (value <= 0xffff) 212 item.prefix.size = 2; 213 else 214 item.prefix.size = 3; // actually means 4 215 } 216 217 item.prefix.type = type; 218 item.prefix.tag = tag; 219 220 switch (item.prefix.size) { 221 case 0: 222 return Write(&item, sizeof(item_prefix)); 223 case 1: 224 item.data.as_uint8[0] = value; 225 return Write(&item, sizeof(item_prefix) + sizeof(uint8)); 226 case 2: 227 item.data.as_uint16[0] = value; 228 return Write(&item, sizeof(item_prefix) + sizeof(uint16)); 229 case 3: 230 item.data.as_uint32 = value; 231 return Write(&item, sizeof(item_prefix) + sizeof(uint32)); 232 } 233 234 return B_OK; 235} 236 237 238status_t 239HIDWriter::Write(const void *data, size_t length) 240{ 241 if (fStatus != B_OK) 242 return fStatus; 243 244 size_t available = fBufferAllocated - fBufferUsed; 245 if (length > available) { 246 fBufferAllocated += length > fBlockSize ? length : fBlockSize; 247 uint8 *newBuffer = (uint8 *)realloc(fBuffer, fBufferAllocated); 248 if (newBuffer == NULL) { 249 fBufferAllocated -= fBlockSize; 250 fStatus = B_NO_MEMORY; 251 return fStatus; 252 } 253 254 fBuffer = newBuffer; 255 } 256 257 memcpy(fBuffer + fBufferUsed, data, length); 258 fBufferUsed += length; 259 return B_OK; 260} 261 262 263void 264HIDWriter::Reset() 265{ 266 free(fBuffer); 267 fBuffer = NULL; 268 fBufferUsed = 0; 269 fBufferAllocated = 0; 270 fStatus = B_OK; 271} 272