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 20 HIDWriter::HIDWriter(size_t blockSize) 21 : fBlockSize(blockSize), 22 fBufferAllocated(0), 23 fBufferUsed(0), 24 fBuffer(NULL), 25 fStatus(B_OK) 26 { 27 } 28 29 30 HIDWriter::~HIDWriter() 31 { 32 free(fBuffer); 33 } 34 35 36 // #pragma mark - High Level 37 38 39 status_t 40 HIDWriter::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 51 status_t 52 HIDWriter::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 70 status_t 71 HIDWriter::BeginCollection(uint8 collectionType, uint16 usagePage, 72 uint16 usageID) 73 { 74 SetUsagePage(usagePage); 75 LocalSetUsageID(usageID); 76 return BeginCollection(collectionType); 77 } 78 79 80 status_t 81 HIDWriter::EndCollection() 82 { 83 return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_END_COLLECTION, 0); 84 } 85 86 87 // #pragma mark - Low Level 88 89 90 status_t 91 HIDWriter::SetUsagePage(uint16 usagePage) 92 { 93 return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_USAGE_PAGE, 94 usagePage); 95 } 96 97 98 status_t 99 HIDWriter::SetLogicalMinimum(uint32 logicalMinimum) 100 { 101 return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_LOGICAL_MINIMUM, 102 logicalMinimum); 103 } 104 105 106 status_t 107 HIDWriter::SetLogicalMaximum(uint32 logicalMaximum) 108 { 109 return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM, 110 logicalMaximum); 111 } 112 113 114 status_t 115 HIDWriter::SetReportSize(uint8 reportSize) 116 { 117 return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_REPORT_SIZE, 118 reportSize); 119 } 120 121 122 status_t 123 HIDWriter::SetReportID(uint8 reportID) 124 { 125 return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_REPORT_ID, 126 reportID); 127 } 128 129 130 status_t 131 HIDWriter::SetReportCount(uint8 reportCount) 132 { 133 return WriteShortItem(ITEM_TYPE_GLOBAL, ITEM_TAG_GLOBAL_REPORT_COUNT, 134 reportCount); 135 } 136 137 138 status_t 139 HIDWriter::LocalSetUsageID(uint16 usageID) 140 { 141 return WriteShortItem(ITEM_TYPE_LOCAL, ITEM_TAG_LOCAL_USAGE, usageID); 142 } 143 144 145 status_t 146 HIDWriter::LocalSetUsageMinimum(uint16 usageMinimum) 147 { 148 return WriteShortItem(ITEM_TYPE_LOCAL, ITEM_TAG_LOCAL_USAGE_MINIMUM, 149 usageMinimum); 150 } 151 152 153 status_t 154 HIDWriter::LocalSetUsageMaximum(uint16 usageMaximum) 155 { 156 return WriteShortItem(ITEM_TYPE_LOCAL, ITEM_TAG_LOCAL_USAGE_MAXIMUM, 157 usageMaximum); 158 } 159 160 161 status_t 162 HIDWriter::BeginCollection(uint8 collectionType) 163 { 164 return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_COLLECTION, 165 collectionType); 166 } 167 168 169 status_t 170 HIDWriter::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 179 status_t 180 HIDWriter::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 189 status_t 190 HIDWriter::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 202 status_t 203 HIDWriter::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 238 status_t 239 HIDWriter::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 263 void 264 HIDWriter::Reset() 265 { 266 free(fBuffer); 267 fBuffer = NULL; 268 fBufferUsed = 0; 269 fBufferAllocated = 0; 270 fStatus = B_OK; 271 } 272