xref: /haiku/src/add-ons/kernel/drivers/input/hid_shared/HIDWriter.cpp (revision 2b4bf3eef6a26d0221f803c296baae95a2ef2426)
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