xref: /haiku/src/add-ons/kernel/drivers/input/hid_shared/HIDCollection.cpp (revision 3d4afef9cba2f328e238089d4609d00d4b1524f3)
1 /*
2  * Copyright 2009-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 "HIDCollection.h"
13 #include "HIDReport.h"
14 #include "HIDReportItem.h"
15 
16 #include <new>
17 #include <stdlib.h>
18 #include <string.h>
19 
20 
21 HIDCollection::HIDCollection(HIDCollection *parent, uint8 type,
22 	local_item_state &localState)
23 	:	fParent(parent),
24 		fType(type),
25 		fStringID(localState.string_index),
26 		fPhysicalID(localState.designator_index)
27 {
28 	usage_value usageValue;
29 	if (localState.usage_stack != NULL && localState.usage_stack_used > 0)
30 		usageValue.u.extended = localState.usage_stack[0].u.extended;
31 	else if (localState.usage_minimum_set)
32 		usageValue.u.extended = localState.usage_minimum.u.extended;
33 	else if (localState.usage_maximum_set)
34 		usageValue.u.extended = localState.usage_maximum.u.extended;
35 	else if (type == COLLECTION_LOGICAL) {
36 		// this is just a logical grouping collection
37 		usageValue.u.extended = 0;
38 	} else {
39 		TRACE_ALWAYS("none of the possible usages for the collection are "
40 			"set\n");
41 	}
42 
43 	fUsage = usageValue.u.extended;
44 }
45 
46 
47 HIDCollection::~HIDCollection()
48 {
49 	for (int32 i = 0; i < fChildren.Count(); i++)
50 		delete fChildren[i];
51 }
52 
53 
54 uint16
55 HIDCollection::UsagePage()
56 {
57 	usage_value value;
58 	value.u.extended = fUsage;
59 	return value.u.s.usage_page;
60 }
61 
62 
63 uint16
64 HIDCollection::UsageID()
65 {
66 	usage_value value;
67 	value.u.extended = fUsage;
68 	return value.u.s.usage_id;
69 }
70 
71 
72 status_t
73 HIDCollection::AddChild(HIDCollection *child)
74 {
75 	if (fChildren.PushBack(child) == B_NO_MEMORY) {
76 		TRACE_ALWAYS("no memory when trying to resize collection child list\n");
77 	}
78 
79 	return B_OK;
80 }
81 
82 
83 HIDCollection *
84 HIDCollection::ChildAt(uint32 index)
85 {
86 	if (index >= fChildren.Count())
87 		return NULL;
88 
89 	return fChildren[index];
90 }
91 
92 
93 uint32
94 HIDCollection::CountChildrenFlat(uint8 type)
95 {
96 	uint32 count = 0;
97 	if (type == COLLECTION_ALL || fType == type)
98 		count++;
99 
100 	for (int32 i = 0; i < fChildren.Count(); i++) {
101 		HIDCollection *child = fChildren[i];
102 		if (child == NULL)
103 			continue;
104 
105 		count += child->CountChildrenFlat(type);
106 	}
107 
108 	return count;
109 }
110 
111 
112 HIDCollection *
113 HIDCollection::ChildAtFlat(uint8 type, uint32 index)
114 {
115 	return _ChildAtFlat(type, index);
116 }
117 
118 
119 void
120 HIDCollection::AddItem(HIDReportItem *item)
121 {
122 	if (fItems.PushBack(item) == B_NO_MEMORY) {
123 		TRACE_ALWAYS("no memory when trying to resize collection items\n");
124 	}
125 
126 }
127 
128 
129 HIDReportItem *
130 HIDCollection::ItemAt(uint32 index)
131 {
132 	if (index >= fItems.Count())
133 		return NULL;
134 
135 	return fItems[index];
136 }
137 
138 
139 uint32
140 HIDCollection::CountItemsFlat()
141 {
142 	uint32 count = fItems.Count();
143 
144 	for (int32 i = 0; i < fChildren.Count(); i++) {
145 		HIDCollection *child = fChildren[i];
146 		if (child != NULL)
147 			count += child->CountItemsFlat();
148 	}
149 
150 	return count;
151 }
152 
153 
154 HIDReportItem *
155 HIDCollection::ItemAtFlat(uint32 index)
156 {
157 	return _ItemAtFlat(index);
158 }
159 
160 
161 void
162 HIDCollection::PrintToStream(uint32 indentLevel)
163 {
164 	char indent[indentLevel + 1];
165 	memset(indent, '\t', indentLevel);
166 	indent[indentLevel] = 0;
167 
168 	const char *typeName = "unknown";
169 	switch (fType) {
170 		case COLLECTION_PHYSICAL:
171 			typeName = "physical";
172 			break;
173 		case COLLECTION_APPLICATION:
174 			typeName = "application";
175 			break;
176 		case COLLECTION_LOGICAL:
177 			typeName = "logical";
178 			break;
179 		case COLLECTION_REPORT:
180 			typeName = "report";
181 			break;
182 		case COLLECTION_NAMED_ARRAY:
183 			typeName = "named array";
184 			break;
185 		case COLLECTION_USAGE_SWITCH:
186 			typeName = "usage switch";
187 			break;
188 		case COLLECTION_USAGE_MODIFIER:
189 			typeName = "usage modifier";
190 			break;
191 	}
192 
193 	TRACE_ALWAYS("%sHIDCollection %p\n", indent, this);
194 	TRACE_ALWAYS("%s\ttype: %u %s\n", indent, fType, typeName);
195 	TRACE_ALWAYS("%s\tusage: 0x%08" B_PRIx32 "\n", indent, fUsage);
196 	TRACE_ALWAYS("%s\tstring id: %u\n", indent, fStringID);
197 	TRACE_ALWAYS("%s\tphysical id: %u\n", indent, fPhysicalID);
198 
199 	TRACE_ALWAYS("%s\titem count: %" B_PRIu32 "\n", indent, fItems.Count());
200 	for (int32 i = 0; i < fItems.Count(); i++) {
201 		HIDReportItem *item = fItems[i];
202 		if (item != NULL)
203 			item->PrintToStream(indentLevel + 1);
204 	}
205 
206 	TRACE_ALWAYS("%s\tchild count: %" B_PRIu32 "\n", indent, fChildren.Count());
207 	for (int32 i = 0; i < fChildren.Count(); i++) {
208 		HIDCollection *child = fChildren[i];
209 		if (child != NULL)
210 			child->PrintToStream(indentLevel + 1);
211 	}
212 }
213 
214 
215 HIDCollection *
216 HIDCollection::_ChildAtFlat(uint8 type, uint32 &index)
217 {
218 	if (type == COLLECTION_ALL || fType == type) {
219 		if (index == 0)
220 			return this;
221 
222 		index--;
223 	}
224 
225 	for (int32 i = 0; i < fChildren.Count(); i++) {
226 		HIDCollection *child = fChildren[i];
227 		if (child == NULL)
228 			continue;
229 
230 		HIDCollection *result = child->_ChildAtFlat(type, index);
231 		if (result != NULL)
232 			return result;
233 	}
234 
235 	return NULL;
236 }
237 
238 
239 HIDReportItem *
240 HIDCollection::_ItemAtFlat(uint32 &index)
241 {
242 	if (index < fItems.Count())
243 		return fItems[index];
244 
245 	index -= fItems.Count();
246 
247 	for (int32 i = 0; i < fChildren.Count(); i++) {
248 		HIDCollection *child = fChildren[i];
249 		if (child == NULL)
250 			continue;
251 
252 		HIDReportItem *result = child->_ItemAtFlat(index);
253 		if (result != NULL)
254 			return result;
255 	}
256 
257 	return NULL;
258 }
259 
260 
261 void
262 HIDCollection::BuildReportList(uint8 reportType,
263 	HIDReport **reportList, uint32 &reportCount)
264 {
265 
266 	for (int32 i = 0; i < fItems.Count(); i++) {
267 		HIDReportItem *item = fItems[i];
268 		if (item == NULL)
269 			continue;
270 
271 		HIDReport *report = item->Report();
272 		if (reportType != HID_REPORT_TYPE_ANY && report->Type() != reportType)
273 			continue;
274 
275 		bool found = false;
276 		for (uint32 j = 0; j < reportCount; j++) {
277 			if (reportList[j] == report) {
278 				found = true;
279 				break;
280 			}
281 		}
282 
283 		if (found)
284 			continue;
285 
286 		reportList[reportCount++] = report;
287 	}
288 
289 	for (int32 i = 0; i < fChildren.Count(); i++) {
290 		HIDCollection *child = fChildren[i];
291 		if (child == NULL)
292 			continue;
293 
294 		child->BuildReportList(reportType, reportList, reportCount);
295 	}
296 }
297