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