source: mainline/uspace/lib/usb/src/pipesinit.c@ 47c573a

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

File reorganization

Functions for USB pipes distributed into more files.

No change in functionality

  • Property mode set to 100644
File size: 11.1 KB
RevLine 
[93ef8f6]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/** @file
33 * Initialization of endpoint pipes.
34 *
35 */
36#include <usb/usb.h>
37#include <usb/pipes.h>
38#include <usb/dp.h>
39#include <errno.h>
40#include <assert.h>
41
42
43#define NESTING(parentname, childname) \
44 { \
45 .child = USB_DESCTYPE_##childname, \
46 .parent = USB_DESCTYPE_##parentname, \
47 }
48#define LAST_NESTING { -1, -1 }
49
50/** Nesting pairs of standard descriptors. */
51static usb_dp_descriptor_nesting_t descriptor_nesting[] = {
52 NESTING(CONFIGURATION, INTERFACE),
53 NESTING(INTERFACE, ENDPOINT),
54 NESTING(INTERFACE, HUB),
55 NESTING(INTERFACE, HID),
56 NESTING(HID, HID_REPORT),
57 LAST_NESTING
58};
59
60/** Tells whether given descriptor is of endpoint type.
61 *
62 * @param descriptor Descriptor in question.
63 * @return Whether the given descriptor is endpoint descriptor.
64 */
65static inline bool is_endpoint_descriptor(uint8_t *descriptor)
66{
67 return descriptor[1] == USB_DESCTYPE_ENDPOINT;
68}
69
70/** Tells whether found endpoint corresponds to endpoint described by user.
71 *
72 * @param wanted Endpoint description as entered by driver author.
73 * @param found Endpoint description obtained from endpoint descriptor.
74 * @return Whether the @p found descriptor fits the @p wanted descriptor.
75 */
76static bool endpoint_fits_description(const usb_endpoint_description_t *wanted,
77 usb_endpoint_description_t *found)
78{
79#define _SAME(fieldname) ((wanted->fieldname) == (found->fieldname))
80
81 if (!_SAME(direction)) {
82 return false;
83 }
84
85 if (!_SAME(transfer_type)) {
86 return false;
87 }
88
89 if ((wanted->interface_class >= 0) && !_SAME(interface_class)) {
90 return false;
91 }
92
93 if ((wanted->interface_subclass >= 0) && !_SAME(interface_subclass)) {
94 return false;
95 }
96
97 if ((wanted->interface_protocol >= 0) && !_SAME(interface_protocol)) {
98 return false;
99 }
100
101#undef _SAME
102
103 return true;
104}
105
106/** Find endpoint mapping for a found endpoint.
107 *
108 * @param mapping Endpoint mapping list.
109 * @param mapping_count Number of endpoint mappings in @p mapping.
110 * @param found_endpoint Description of found endpoint.
111 * @return Endpoint mapping corresponding to @p found_endpoint.
112 * @retval NULL No corresponding endpoint found.
113 */
114static usb_endpoint_mapping_t *find_endpoint_mapping(
115 usb_endpoint_mapping_t *mapping, size_t mapping_count,
116 usb_endpoint_description_t *found_endpoint)
117{
118 while (mapping_count > 0) {
119 if (endpoint_fits_description(mapping->description,
120 found_endpoint)) {
121 return mapping;
122 }
123
124 mapping++;
125 mapping_count--;
126 }
127 return NULL;
128}
129
130/** Process endpoint descriptor.
131 *
132 * @param mapping Endpoint mapping list.
133 * @param mapping_count Number of endpoint mappings in @p mapping.
134 * @param interface Interface descriptor under which belongs the @p endpoint.
135 * @param endpoint Endpoint descriptor.
136 * @param wire Connection backing the endpoint pipes.
137 * @return Error code.
138 */
139static int process_endpoint(
140 usb_endpoint_mapping_t *mapping, size_t mapping_count,
141 usb_standard_interface_descriptor_t *interface,
142 usb_standard_endpoint_descriptor_t *endpoint,
143 usb_device_connection_t *wire)
144{
145 usb_endpoint_description_t description;
146
147 /*
148 * Get endpoint characteristics.
149 */
150
151 /* Actual endpoint number is in bits 0..3 */
152 usb_endpoint_t ep_no = endpoint->endpoint_address & 0x0F;
153
154 /* Endpoint direction is set by bit 7 */
155 description.direction = (endpoint->endpoint_address & 128)
156 ? USB_DIRECTION_IN : USB_DIRECTION_OUT;
157 /* Transfer type is in bits 0..2 and the enum values corresponds 1:1 */
158 description.transfer_type = endpoint->attributes & 3;
159
160 /*
161 * Get interface characteristics.
162 */
163 description.interface_class = interface->interface_class;
164 description.interface_subclass = interface->interface_subclass;
165 description.interface_protocol = interface->interface_protocol;
166
167 /*
168 * Find the most fitting mapping and initialize the pipe.
169 */
170 usb_endpoint_mapping_t *ep_mapping = find_endpoint_mapping(mapping,
171 mapping_count, &description);
172 if (ep_mapping == NULL) {
173 return ENOENT;
174 }
175
176 if (ep_mapping->pipe == NULL) {
177 return EBADMEM;
178 }
179 if (ep_mapping->present) {
180 return EEXISTS;
181 }
182
183 int rc = usb_endpoint_pipe_initialize(ep_mapping->pipe, wire,
[25971d2]184 ep_no, description.transfer_type, endpoint->max_packet_size,
185 description.direction);
[93ef8f6]186 if (rc != EOK) {
187 return rc;
188 }
189
190 ep_mapping->present = true;
191 ep_mapping->descriptor = endpoint;
[9d4579e]192 ep_mapping->interface = interface;
[93ef8f6]193
194 return EOK;
195}
196
197/** Process whole USB interface.
198 *
199 * @param mapping Endpoint mapping list.
200 * @param mapping_count Number of endpoint mappings in @p mapping.
201 * @param parser Descriptor parser.
202 * @param parser_data Descriptor parser data.
203 * @param interface_descriptor Interface descriptor.
204 * @return Error code.
205 */
206static int process_interface(
207 usb_endpoint_mapping_t *mapping, size_t mapping_count,
208 usb_dp_parser_t *parser, usb_dp_parser_data_t *parser_data,
209 uint8_t *interface_descriptor)
210{
211 uint8_t *descriptor = usb_dp_get_nested_descriptor(parser,
212 parser_data, interface_descriptor);
213
214 if (descriptor == NULL) {
215 return ENOENT;
216 }
217
218 do {
219 if (is_endpoint_descriptor(descriptor)) {
220 (void) process_endpoint(mapping, mapping_count,
221 (usb_standard_interface_descriptor_t *)
222 interface_descriptor,
223 (usb_standard_endpoint_descriptor_t *)
224 descriptor,
225 (usb_device_connection_t *) parser_data->arg);
226 }
227
228 descriptor = usb_dp_get_sibling_descriptor(parser, parser_data,
229 interface_descriptor, descriptor);
230 } while (descriptor != NULL);
231
232 return EOK;
233}
234
235/** Initialize endpoint pipes from configuration descriptor.
236 *
237 * The mapping array is expected to conform to following rules:
238 * - @c pipe must point to already allocated structure with uninitialized pipe
239 * - @c description must point to prepared endpoint description
240 * - @c descriptor does not need to be initialized (will be overwritten)
[9d4579e]241 * - @c interface does not need to be initialized (will be overwritten)
[93ef8f6]242 * - @c present does not need to be initialized (will be overwritten)
243 *
244 * After processing the configuration descriptor, the mapping is updated
245 * in the following fashion:
246 * - @c present will be set to @c true when the endpoint was found in the
247 * configuration
248 * - @c descriptor will point inside the configuration descriptor to endpoint
[1110ebd]249 * corresponding to given description (or NULL for not found descriptor)
[9d4579e]250 * - @c interface will point inside the configuration descriptor to interface
251 * descriptor the endpoint @c descriptor belongs to (or NULL for not found
252 * descriptor)
[93ef8f6]253 * - @c pipe will be initialized when found, otherwise left untouched
254 * - @c description will be untouched under all circumstances
255 *
256 * @param mapping Endpoint mapping list.
257 * @param mapping_count Number of endpoint mappings in @p mapping.
258 * @param configuration_descriptor Full configuration descriptor (is expected
259 * to be in USB endianness: i.e. as-is after being retrieved from
260 * the device).
261 * @param configuration_descriptor_size Size of @p configuration_descriptor
262 * in bytes.
263 * @param connection Connection backing the endpoint pipes.
264 * @return Error code.
265 */
266int usb_endpoint_pipe_initialize_from_configuration(
267 usb_endpoint_mapping_t *mapping, size_t mapping_count,
268 uint8_t *configuration_descriptor, size_t configuration_descriptor_size,
269 usb_device_connection_t *connection)
270{
271 assert(connection);
272
273 if (configuration_descriptor == NULL) {
274 return EBADMEM;
275 }
276 if (configuration_descriptor_size
277 < sizeof(usb_standard_configuration_descriptor_t)) {
278 return ERANGE;
279 }
280
281 /*
282 * Go through the mapping and set all endpoints to not present.
283 */
284 size_t i;
285 for (i = 0; i < mapping_count; i++) {
286 mapping[i].present = false;
287 mapping[i].descriptor = NULL;
[9d4579e]288 mapping[i].interface = NULL;
[93ef8f6]289 }
290
291 /*
292 * Prepare the descriptor parser.
293 */
294 usb_dp_parser_t dp_parser = {
295 .nesting = descriptor_nesting
296 };
297 usb_dp_parser_data_t dp_data = {
298 .data = configuration_descriptor,
299 .size = configuration_descriptor_size,
300 .arg = connection
301 };
302
303 /*
304 * Iterate through all interfaces.
305 */
306 uint8_t *interface = usb_dp_get_nested_descriptor(&dp_parser,
307 &dp_data, configuration_descriptor);
308 if (interface == NULL) {
309 return ENOENT;
310 }
311 do {
312 (void) process_interface(mapping, mapping_count,
313 &dp_parser, &dp_data,
314 interface);
315 interface = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
316 configuration_descriptor, interface);
317 } while (interface != NULL);
318
319 return EOK;
320}
321
[dc04868]322/** Initialize USB endpoint pipe.
323 *
324 * @param pipe Endpoint pipe to be initialized.
325 * @param connection Connection to the USB device backing this pipe (the wire).
326 * @param endpoint_no Endpoint number (in USB 1.1 in range 0 to 15).
327 * @param transfer_type Transfer type (e.g. interrupt or bulk).
328 * @param max_packet_size Maximum packet size in bytes.
329 * @param direction Endpoint direction (in/out).
330 * @return Error code.
331 */
332int usb_endpoint_pipe_initialize(usb_endpoint_pipe_t *pipe,
333 usb_device_connection_t *connection, usb_endpoint_t endpoint_no,
334 usb_transfer_type_t transfer_type, size_t max_packet_size,
335 usb_direction_t direction)
336{
337 assert(pipe);
338 assert(connection);
339
340 pipe->wire = connection;
341 pipe->hc_phone = -1;
342 pipe->endpoint_no = endpoint_no;
343 pipe->transfer_type = transfer_type;
344 pipe->max_packet_size = max_packet_size;
345 pipe->direction = direction;
346
347 return EOK;
348}
349
350
351/** Initialize USB endpoint pipe as the default zero control pipe.
352 *
353 * @param pipe Endpoint pipe to be initialized.
354 * @param connection Connection to the USB device backing this pipe (the wire).
355 * @return Error code.
356 */
357int usb_endpoint_pipe_initialize_default_control(usb_endpoint_pipe_t *pipe,
358 usb_device_connection_t *connection)
359{
360 assert(pipe);
361 assert(connection);
362
363 int rc = usb_endpoint_pipe_initialize(pipe, connection,
364 0, USB_TRANSFER_CONTROL, 8, USB_DIRECTION_BOTH);
365
366 return rc;
367}
368
[93ef8f6]369/**
370 * @}
371 */
Note: See TracBrowser for help on using the repository browser.