source: mainline/uspace/lib/usb/src/dp.c@ 41b70d30

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 41b70d30 was 0f21c0c, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

Removal of API that use phones directly

  • Property mode set to 100644
File size: 6.9 KB
Line 
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
29/** @addtogroup libusb
30 * @{
31 */
32/**
33 * @file
34 * @brief USB descriptor parser (implementation).
35 */
36#include <stdio.h>
37#include <str_error.h>
38#include <errno.h>
39#include <assert.h>
40#include <bool.h>
41#include <usb/dp.h>
42#include <usb/descriptor.h>
43
44#define NESTING(parentname, childname) \
45 { \
46 .child = USB_DESCTYPE_##childname, \
47 .parent = USB_DESCTYPE_##parentname, \
48 }
49#define LAST_NESTING { -1, -1 }
50
51/** Nesting of standard USB descriptors. */
52usb_dp_descriptor_nesting_t usb_dp_standard_descriptor_nesting[] = {
53 NESTING(CONFIGURATION, INTERFACE),
54 NESTING(INTERFACE, ENDPOINT),
55 NESTING(INTERFACE, HUB),
56 NESTING(INTERFACE, HID),
57 NESTING(HID, HID_REPORT),
58 LAST_NESTING
59};
60
61#undef NESTING
62#undef LAST_NESTING
63
64/** Tells whether pointer points inside descriptor data.
65 *
66 * @param data Parser data.
67 * @param ptr Pointer to be verified.
68 * @return Whether @p ptr points inside <code>data->data</code> field.
69 */
70static bool is_valid_descriptor_pointer(usb_dp_parser_data_t *data,
71 uint8_t *ptr)
72{
73 if (ptr == NULL) {
74 return false;
75 }
76
77 if (ptr < data->data) {
78 return false;
79 }
80
81 if ((size_t)(ptr - data->data) >= data->size) {
82 return false;
83 }
84
85 return true;
86}
87
88/** Get next descriptor regardless of the nesting.
89 *
90 * @param data Parser data.
91 * @param current Pointer to current descriptor.
92 * @return Pointer to start of next descriptor.
93 * @retval NULL Invalid input or no next descriptor.
94 */
95static uint8_t *get_next_descriptor(usb_dp_parser_data_t *data,
96 uint8_t *current)
97{
98 assert(is_valid_descriptor_pointer(data, current));
99
100 uint8_t current_length = *current;
101 uint8_t *next = current + current_length;
102
103 if (!is_valid_descriptor_pointer(data, next)) {
104 return NULL;
105 }
106
107 return next;
108}
109
110/** Get descriptor type.
111 *
112 * @see usb_descriptor_type_t
113 *
114 * @param data Parser data.
115 * @param start Pointer to start of the descriptor.
116 * @return Descriptor type.
117 * @retval -1 Invalid input.
118 */
119static int get_descriptor_type(usb_dp_parser_data_t *data, uint8_t *start)
120{
121 if (start == NULL) {
122 return -1;
123 }
124
125 start++;
126 if (!is_valid_descriptor_pointer(data, start)) {
127 return -1;
128 } else {
129 return (int) (*start);
130 }
131}
132
133/** Tells whether descriptors could be nested.
134 *
135 * @param parser Parser.
136 * @param child Child descriptor type.
137 * @param parent Parent descriptor type.
138 * @return Whether @p child could be child of @p parent.
139 */
140static bool is_nested_descriptor_type(usb_dp_parser_t *parser,
141 int child, int parent)
142{
143 usb_dp_descriptor_nesting_t *nesting = parser->nesting;
144 while ((nesting->child > 0) && (nesting->parent > 0)) {
145 if ((nesting->child == child) && (nesting->parent == parent)) {
146 return true;
147 }
148 nesting++;
149 }
150 return false;
151}
152
153/** Tells whether descriptors could be nested.
154 *
155 * @param parser Parser.
156 * @param data Parser data.
157 * @param child Pointer to child descriptor.
158 * @param parent Pointer to parent descriptor.
159 * @return Whether @p child could be child of @p parent.
160 */
161static bool is_nested_descriptor(usb_dp_parser_t *parser,
162 usb_dp_parser_data_t *data, uint8_t *child, uint8_t *parent)
163{
164 return is_nested_descriptor_type(parser,
165 get_descriptor_type(data, child),
166 get_descriptor_type(data, parent));
167}
168
169/** Find first nested descriptor of given parent.
170 *
171 * @param parser Parser.
172 * @param data Parser data.
173 * @param parent Pointer to the beginning of parent descriptor.
174 * @return Pointer to the beginning of the first nested (child) descriptor.
175 * @retval NULL No child descriptor found.
176 * @retval NULL Invalid input.
177 */
178uint8_t *usb_dp_get_nested_descriptor(usb_dp_parser_t *parser,
179 usb_dp_parser_data_t *data, uint8_t *parent)
180{
181 if (!is_valid_descriptor_pointer(data, parent)) {
182 return NULL;
183 }
184
185 uint8_t *next = get_next_descriptor(data, parent);
186 if (next == NULL) {
187 return NULL;
188 }
189
190 if (is_nested_descriptor(parser, data, next, parent)) {
191 return next;
192 } else {
193 return NULL;
194 }
195}
196
197/** Skip all nested descriptors.
198 *
199 * @param parser Parser.
200 * @param data Parser data.
201 * @param parent Pointer to the beginning of parent descriptor.
202 * @return Pointer to first non-child descriptor.
203 * @retval NULL No next descriptor.
204 * @retval NULL Invalid input.
205 */
206static uint8_t *skip_nested_descriptors(usb_dp_parser_t *parser,
207 usb_dp_parser_data_t *data, uint8_t *parent)
208{
209 uint8_t *child = usb_dp_get_nested_descriptor(parser, data, parent);
210 if (child == NULL) {
211 return get_next_descriptor(data, parent);
212 }
213 uint8_t *next_child = skip_nested_descriptors(parser, data, child);
214 while (is_nested_descriptor(parser, data, next_child, parent)) {
215 next_child = skip_nested_descriptors(parser, data, next_child);
216 }
217
218 return next_child;
219}
220
221/** Get sibling descriptor.
222 *
223 * @param parser Parser.
224 * @param data Parser data.
225 * @param parent Pointer to common parent descriptor.
226 * @param sibling Left sibling.
227 * @return Pointer to first right sibling of @p sibling.
228 * @retval NULL No sibling exist.
229 * @retval NULL Invalid input.
230 */
231uint8_t *usb_dp_get_sibling_descriptor(usb_dp_parser_t *parser,
232 usb_dp_parser_data_t *data, uint8_t *parent, uint8_t *sibling)
233{
234 if (!is_valid_descriptor_pointer(data, parent)
235 || !is_valid_descriptor_pointer(data, sibling)) {
236 return NULL;
237 }
238
239 uint8_t *possible_sibling = skip_nested_descriptors(parser, data, sibling);
240 if (possible_sibling == NULL) {
241 return NULL;
242 }
243
244 int parent_type = get_descriptor_type(data, parent);
245 int possible_sibling_type = get_descriptor_type(data, possible_sibling);
246 if (is_nested_descriptor_type(parser, possible_sibling_type, parent_type)) {
247 return possible_sibling;
248 } else {
249 return NULL;
250 }
251}
252
253
254/** @}
255 */
Note: See TracBrowser for help on using the repository browser.