source: mainline/uspace/lib/usbdev/src/dp.c@ 10cb47e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 10cb47e was c01987c, checked in by Jan Vesely <jano.vesely@…>, 12 years ago

libusbdev: Sanitize headers.

Include what you use.
https://code.google.com/p/include-what-you-use/

  • Property mode set to 100644
File size: 9.5 KB
RevLine 
[5ccb15c]1/*
2 * Copyright (c) 2011 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[160b75e]29/** @addtogroup libusbdev
[5ccb15c]30 * @{
31 */
32/**
33 * @file
[a6add7a]34 * USB descriptor parser (implementation).
35 *
36 * The descriptor parser is a generic parser for structure, where individual
37 * items are stored in single buffer and each item begins with length followed
38 * by type. These types are organized into tree hierarchy.
39 *
40 * The parser is able of only two actions: find first child and find next
41 * sibling.
[5ccb15c]42 */
[7d521e24]43#include <usb/dev/dp.h>
[745d2ad]44#include <usb/descriptor.h>
45
[c01987c]46#include <assert.h>
47#include <errno.h>
48#include <stdlib.h>
49#include <stdbool.h>
50#include <sys/types.h>
51
[745d2ad]52#define NESTING(parentname, childname) \
53 { \
54 .child = USB_DESCTYPE_##childname, \
55 .parent = USB_DESCTYPE_##parentname, \
56 }
57#define LAST_NESTING { -1, -1 }
58
59/** Nesting of standard USB descriptors. */
[207acc4e]60const usb_dp_descriptor_nesting_t usb_dp_standard_descriptor_nesting[] = {
[745d2ad]61 NESTING(CONFIGURATION, INTERFACE),
62 NESTING(INTERFACE, ENDPOINT),
63 NESTING(INTERFACE, HUB),
64 NESTING(INTERFACE, HID),
65 NESTING(HID, HID_REPORT),
66 LAST_NESTING
67};
68
69#undef NESTING
70#undef LAST_NESTING
[5ccb15c]71
72/** Tells whether pointer points inside descriptor data.
73 *
74 * @param data Parser data.
75 * @param ptr Pointer to be verified.
[3b77628]76 * @return Whether @p ptr points inside <code>data->data</code> field.
[5ccb15c]77 */
[8a121b1]78static bool is_valid_descriptor_pointer(const usb_dp_parser_data_t *data,
79 const uint8_t *ptr)
[5ccb15c]80{
81 if (ptr == NULL) {
82 return false;
83 }
84
85 if (ptr < data->data) {
86 return false;
87 }
88
89 if ((size_t)(ptr - data->data) >= data->size) {
90 return false;
91 }
92
93 return true;
94}
95
96/** Get next descriptor regardless of the nesting.
97 *
98 * @param data Parser data.
99 * @param current Pointer to current descriptor.
100 * @return Pointer to start of next descriptor.
101 * @retval NULL Invalid input or no next descriptor.
102 */
[8a121b1]103static const uint8_t *get_next_descriptor(const usb_dp_parser_data_t *data,
104 const uint8_t *current)
[5ccb15c]105{
106 assert(is_valid_descriptor_pointer(data, current));
107
[8a121b1]108 const uint8_t current_length = *current;
109 const uint8_t *next = current + current_length;
[5ccb15c]110
111 if (!is_valid_descriptor_pointer(data, next)) {
112 return NULL;
113 }
114
115 return next;
116}
117
118/** Get descriptor type.
119 *
120 * @see usb_descriptor_type_t
121 *
122 * @param data Parser data.
123 * @param start Pointer to start of the descriptor.
124 * @return Descriptor type.
125 * @retval -1 Invalid input.
126 */
[8a121b1]127static int get_descriptor_type(const usb_dp_parser_data_t *data, const uint8_t *start)
[5ccb15c]128{
129 if (start == NULL) {
130 return -1;
131 }
132
133 start++;
134 if (!is_valid_descriptor_pointer(data, start)) {
135 return -1;
136 } else {
137 return (int) (*start);
138 }
139}
140
141/** Tells whether descriptors could be nested.
142 *
143 * @param parser Parser.
144 * @param child Child descriptor type.
145 * @param parent Parent descriptor type.
146 * @return Whether @p child could be child of @p parent.
147 */
[8a121b1]148static bool is_nested_descriptor_type(const usb_dp_parser_t *parser,
[5ccb15c]149 int child, int parent)
150{
[8a121b1]151 const usb_dp_descriptor_nesting_t *nesting = parser->nesting;
[5ccb15c]152 while ((nesting->child > 0) && (nesting->parent > 0)) {
153 if ((nesting->child == child) && (nesting->parent == parent)) {
154 return true;
155 }
156 nesting++;
157 }
158 return false;
159}
160
161/** Tells whether descriptors could be nested.
162 *
163 * @param parser Parser.
164 * @param data Parser data.
165 * @param child Pointer to child descriptor.
166 * @param parent Pointer to parent descriptor.
167 * @return Whether @p child could be child of @p parent.
168 */
[8a121b1]169static bool is_nested_descriptor(const usb_dp_parser_t *parser,
170 const usb_dp_parser_data_t *data, const uint8_t *child, const uint8_t *parent)
[5ccb15c]171{
172 return is_nested_descriptor_type(parser,
173 get_descriptor_type(data, child),
174 get_descriptor_type(data, parent));
175}
176
177/** Find first nested descriptor of given parent.
178 *
179 * @param parser Parser.
180 * @param data Parser data.
181 * @param parent Pointer to the beginning of parent descriptor.
182 * @return Pointer to the beginning of the first nested (child) descriptor.
183 * @retval NULL No child descriptor found.
184 * @retval NULL Invalid input.
185 */
[8a121b1]186const uint8_t *usb_dp_get_nested_descriptor(const usb_dp_parser_t *parser,
187 const usb_dp_parser_data_t *data, const uint8_t *parent)
[5ccb15c]188{
189 if (!is_valid_descriptor_pointer(data, parent)) {
190 return NULL;
191 }
192
[8a121b1]193 const uint8_t *next = get_next_descriptor(data, parent);
[5ccb15c]194 if (next == NULL) {
195 return NULL;
196 }
197
198 if (is_nested_descriptor(parser, data, next, parent)) {
199 return next;
200 } else {
201 return NULL;
202 }
203}
204
205/** Skip all nested descriptors.
206 *
207 * @param parser Parser.
208 * @param data Parser data.
209 * @param parent Pointer to the beginning of parent descriptor.
210 * @return Pointer to first non-child descriptor.
211 * @retval NULL No next descriptor.
212 * @retval NULL Invalid input.
213 */
[8a121b1]214static const uint8_t *skip_nested_descriptors(const usb_dp_parser_t *parser,
215 const usb_dp_parser_data_t *data, const uint8_t *parent)
[5ccb15c]216{
[8a121b1]217 const uint8_t *child =
218 usb_dp_get_nested_descriptor(parser, data, parent);
[5ccb15c]219 if (child == NULL) {
220 return get_next_descriptor(data, parent);
221 }
[8a121b1]222 const uint8_t *next_child =
223 skip_nested_descriptors(parser, data, child);
[5ccb15c]224 while (is_nested_descriptor(parser, data, next_child, parent)) {
225 next_child = skip_nested_descriptors(parser, data, next_child);
226 }
227
228 return next_child;
229}
230
231/** Get sibling descriptor.
232 *
233 * @param parser Parser.
234 * @param data Parser data.
235 * @param parent Pointer to common parent descriptor.
236 * @param sibling Left sibling.
237 * @return Pointer to first right sibling of @p sibling.
238 * @retval NULL No sibling exist.
239 * @retval NULL Invalid input.
240 */
[8a121b1]241const uint8_t *usb_dp_get_sibling_descriptor(
242 const usb_dp_parser_t *parser, const usb_dp_parser_data_t *data,
243 const uint8_t *parent, const uint8_t *sibling)
[5ccb15c]244{
245 if (!is_valid_descriptor_pointer(data, parent)
246 || !is_valid_descriptor_pointer(data, sibling)) {
247 return NULL;
248 }
249
[8a121b1]250 const uint8_t *possible_sibling =
251 skip_nested_descriptors(parser, data, sibling);
[5ccb15c]252 if (possible_sibling == NULL) {
253 return NULL;
254 }
255
256 int parent_type = get_descriptor_type(data, parent);
257 int possible_sibling_type = get_descriptor_type(data, possible_sibling);
258 if (is_nested_descriptor_type(parser, possible_sibling_type, parent_type)) {
259 return possible_sibling;
260 } else {
261 return NULL;
262 }
263}
264
[da77278]265/** Browser of the descriptor tree.
266 *
267 * @see usb_dp_walk_simple
268 *
269 * @param parser Descriptor parser.
270 * @param data Data for descriptor parser.
271 * @param root Pointer to current root of the tree.
272 * @param depth Current nesting depth.
273 * @param callback Callback for each found descriptor.
274 * @param arg Custom (user) argument.
275 */
[8a121b1]276static void usb_dp_browse_simple_internal(const usb_dp_parser_t *parser,
277 const usb_dp_parser_data_t *data, const uint8_t *root, size_t depth,
278 void (*callback)(const uint8_t *, size_t, void *), void *arg)
[da77278]279{
280 if (root == NULL) {
281 return;
282 }
283 callback(root, depth, arg);
[8a121b1]284 const uint8_t *child = usb_dp_get_nested_descriptor(parser, data, root);
[da77278]285 do {
286 usb_dp_browse_simple_internal(parser, data, child, depth + 1,
287 callback, arg);
288 child = usb_dp_get_sibling_descriptor(parser, data,
289 root, child);
290 } while (child != NULL);
291}
292
293/** Browse flatten descriptor tree.
294 *
295 * The callback is called with following arguments: pointer to the start
296 * of the descriptor (somewhere inside @p descriptors), depth of the nesting
297 * (starting from 0 for the first descriptor) and the custom argument.
298 * Note that the size of the descriptor is not passed because it can
299 * be read from the first byte of the descriptor.
300 *
301 * @param descriptors Descriptor data.
302 * @param descriptors_size Size of descriptor data (in bytes).
303 * @param descriptor_nesting Possible descriptor nesting.
304 * @param callback Callback for each found descriptor.
305 * @param arg Custom (user) argument.
306 */
[25effe2]307void usb_dp_walk_simple(const uint8_t *descriptors, size_t descriptors_size,
[8a121b1]308 const usb_dp_descriptor_nesting_t *descriptor_nesting,
309 walk_callback_t callback, void *arg)
[da77278]310{
311 if ((descriptors == NULL) || (descriptors_size == 0)
312 || (descriptor_nesting == NULL) || (callback == NULL)) {
313 return;
314 }
315
[8a121b1]316 const usb_dp_parser_data_t data = {
[da77278]317 .data = descriptors,
318 .size = descriptors_size,
319 .arg = NULL
320 };
321
[8a121b1]322 const usb_dp_parser_t parser = {
[da77278]323 .nesting = descriptor_nesting
324 };
325
326 usb_dp_browse_simple_internal(&parser, &data, descriptors,
327 0, callback, arg);
328}
[5ccb15c]329
330/** @}
331 */
Note: See TracBrowser for help on using the repository browser.