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
HIDWriter(size_t blockSize)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
~HIDWriter()30 HIDWriter::~HIDWriter()
31 {
32 free(fBuffer);
33 }
34
35
36 // #pragma mark - High Level
37
38
39 status_t
DefineInputPadding(uint8 count,uint8 bitLength)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
DefineInputData(uint8 count,uint8 bitLength,main_item_data data,uint32 logicalMinimum,uint32 logicalMaximum,uint16 usagePage,uint16 usageMinimum,uint16 usageMaximum)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
BeginCollection(uint8 collectionType,uint16 usagePage,uint16 usageID)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
EndCollection()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
SetUsagePage(uint16 usagePage)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
SetLogicalMinimum(uint32 logicalMinimum)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
SetLogicalMaximum(uint32 logicalMaximum)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
SetReportSize(uint8 reportSize)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
SetReportID(uint8 reportID)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
SetReportCount(uint8 reportCount)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
LocalSetUsageID(uint16 usageID)139 HIDWriter::LocalSetUsageID(uint16 usageID)
140 {
141 return WriteShortItem(ITEM_TYPE_LOCAL, ITEM_TAG_LOCAL_USAGE, usageID);
142 }
143
144
145 status_t
LocalSetUsageMinimum(uint16 usageMinimum)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
LocalSetUsageMaximum(uint16 usageMaximum)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
BeginCollection(uint8 collectionType)162 HIDWriter::BeginCollection(uint8 collectionType)
163 {
164 return WriteShortItem(ITEM_TYPE_MAIN, ITEM_TAG_MAIN_COLLECTION,
165 collectionType);
166 }
167
168
169 status_t
Input(main_item_data data)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
Output(main_item_data data)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
Feature(main_item_data data)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
WriteShortItem(uint8 type,uint8 tag,uint32 value)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
Write(const void * data,size_t length)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
Reset()264 HIDWriter::Reset()
265 {
266 free(fBuffer);
267 fBuffer = NULL;
268 fBufferUsed = 0;
269 fBufferAllocated = 0;
270 fStatus = B_OK;
271 }
272