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

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

Extend pipe initialization with interface number

  • Property mode set to 100644
File size: 11.4 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.
[18cb870]111 * @param interface_number Number of currently processed interface.
[93ef8f6]112 * @return Endpoint mapping corresponding to @p found_endpoint.
113 * @retval NULL No corresponding endpoint found.
114 */
115static usb_endpoint_mapping_t *find_endpoint_mapping(
116 usb_endpoint_mapping_t *mapping, size_t mapping_count,
[18cb870]117 usb_endpoint_description_t *found_endpoint,
118 int interface_number)
[93ef8f6]119{
120 while (mapping_count > 0) {
[18cb870]121 bool interface_number_fits = (mapping->interface_no < 0)
122 || (mapping->interface_no == interface_number);
123
124 bool endpoint_descriptions_fits = endpoint_fits_description(
125 mapping->description, found_endpoint);
126
127 if (interface_number_fits && endpoint_descriptions_fits) {
[93ef8f6]128 return mapping;
129 }
130
131 mapping++;
132 mapping_count--;
133 }
134 return NULL;
135}
136
137/** Process endpoint descriptor.
138 *
139 * @param mapping Endpoint mapping list.
140 * @param mapping_count Number of endpoint mappings in @p mapping.
141 * @param interface Interface descriptor under which belongs the @p endpoint.
142 * @param endpoint Endpoint descriptor.
143 * @param wire Connection backing the endpoint pipes.
144 * @return Error code.
145 */
146static int process_endpoint(
147 usb_endpoint_mapping_t *mapping, size_t mapping_count,
148 usb_standard_interface_descriptor_t *interface,
149 usb_standard_endpoint_descriptor_t *endpoint,
150 usb_device_connection_t *wire)
151{
152 usb_endpoint_description_t description;
153
154 /*
155 * Get endpoint characteristics.
156 */
157
158 /* Actual endpoint number is in bits 0..3 */
159 usb_endpoint_t ep_no = endpoint->endpoint_address & 0x0F;
160
161 /* Endpoint direction is set by bit 7 */
162 description.direction = (endpoint->endpoint_address & 128)
163 ? USB_DIRECTION_IN : USB_DIRECTION_OUT;
164 /* Transfer type is in bits 0..2 and the enum values corresponds 1:1 */
165 description.transfer_type = endpoint->attributes & 3;
166
167 /*
168 * Get interface characteristics.
169 */
170 description.interface_class = interface->interface_class;
171 description.interface_subclass = interface->interface_subclass;
172 description.interface_protocol = interface->interface_protocol;
173
174 /*
175 * Find the most fitting mapping and initialize the pipe.
176 */
177 usb_endpoint_mapping_t *ep_mapping = find_endpoint_mapping(mapping,
[18cb870]178 mapping_count, &description, interface->interface_number);
[93ef8f6]179 if (ep_mapping == NULL) {
180 return ENOENT;
181 }
182
183 if (ep_mapping->pipe == NULL) {
184 return EBADMEM;
185 }
186 if (ep_mapping->present) {
187 return EEXISTS;
188 }
189
190 int rc = usb_endpoint_pipe_initialize(ep_mapping->pipe, wire,
[25971d2]191 ep_no, description.transfer_type, endpoint->max_packet_size,
192 description.direction);
[93ef8f6]193 if (rc != EOK) {
194 return rc;
195 }
196
197 ep_mapping->present = true;
198 ep_mapping->descriptor = endpoint;
[9d4579e]199 ep_mapping->interface = interface;
[93ef8f6]200
201 return EOK;
202}
203
204/** Process whole USB interface.
205 *
206 * @param mapping Endpoint mapping list.
207 * @param mapping_count Number of endpoint mappings in @p mapping.
208 * @param parser Descriptor parser.
209 * @param parser_data Descriptor parser data.
210 * @param interface_descriptor Interface descriptor.
211 * @return Error code.
212 */
213static int process_interface(
214 usb_endpoint_mapping_t *mapping, size_t mapping_count,
215 usb_dp_parser_t *parser, usb_dp_parser_data_t *parser_data,
216 uint8_t *interface_descriptor)
217{
218 uint8_t *descriptor = usb_dp_get_nested_descriptor(parser,
219 parser_data, interface_descriptor);
220
221 if (descriptor == NULL) {
222 return ENOENT;
223 }
224
225 do {
226 if (is_endpoint_descriptor(descriptor)) {
227 (void) process_endpoint(mapping, mapping_count,
228 (usb_standard_interface_descriptor_t *)
229 interface_descriptor,
230 (usb_standard_endpoint_descriptor_t *)
231 descriptor,
232 (usb_device_connection_t *) parser_data->arg);
233 }
234
235 descriptor = usb_dp_get_sibling_descriptor(parser, parser_data,
236 interface_descriptor, descriptor);
237 } while (descriptor != NULL);
238
239 return EOK;
240}
241
242/** Initialize endpoint pipes from configuration descriptor.
243 *
244 * The mapping array is expected to conform to following rules:
245 * - @c pipe must point to already allocated structure with uninitialized pipe
246 * - @c description must point to prepared endpoint description
247 * - @c descriptor does not need to be initialized (will be overwritten)
[9d4579e]248 * - @c interface does not need to be initialized (will be overwritten)
[93ef8f6]249 * - @c present does not need to be initialized (will be overwritten)
250 *
251 * After processing the configuration descriptor, the mapping is updated
252 * in the following fashion:
253 * - @c present will be set to @c true when the endpoint was found in the
254 * configuration
255 * - @c descriptor will point inside the configuration descriptor to endpoint
[1110ebd]256 * corresponding to given description (or NULL for not found descriptor)
[9d4579e]257 * - @c interface will point inside the configuration descriptor to interface
258 * descriptor the endpoint @c descriptor belongs to (or NULL for not found
259 * descriptor)
[93ef8f6]260 * - @c pipe will be initialized when found, otherwise left untouched
261 * - @c description will be untouched under all circumstances
262 *
263 * @param mapping Endpoint mapping list.
264 * @param mapping_count Number of endpoint mappings in @p mapping.
265 * @param configuration_descriptor Full configuration descriptor (is expected
266 * to be in USB endianness: i.e. as-is after being retrieved from
267 * the device).
268 * @param configuration_descriptor_size Size of @p configuration_descriptor
269 * in bytes.
270 * @param connection Connection backing the endpoint pipes.
271 * @return Error code.
272 */
273int usb_endpoint_pipe_initialize_from_configuration(
274 usb_endpoint_mapping_t *mapping, size_t mapping_count,
275 uint8_t *configuration_descriptor, size_t configuration_descriptor_size,
276 usb_device_connection_t *connection)
277{
278 assert(connection);
279
280 if (configuration_descriptor == NULL) {
281 return EBADMEM;
282 }
283 if (configuration_descriptor_size
284 < sizeof(usb_standard_configuration_descriptor_t)) {
285 return ERANGE;
286 }
287
288 /*
289 * Go through the mapping and set all endpoints to not present.
290 */
291 size_t i;
292 for (i = 0; i < mapping_count; i++) {
293 mapping[i].present = false;
294 mapping[i].descriptor = NULL;
[9d4579e]295 mapping[i].interface = NULL;
[93ef8f6]296 }
297
298 /*
299 * Prepare the descriptor parser.
300 */
301 usb_dp_parser_t dp_parser = {
302 .nesting = descriptor_nesting
303 };
304 usb_dp_parser_data_t dp_data = {
305 .data = configuration_descriptor,
306 .size = configuration_descriptor_size,
307 .arg = connection
308 };
309
310 /*
311 * Iterate through all interfaces.
312 */
313 uint8_t *interface = usb_dp_get_nested_descriptor(&dp_parser,
314 &dp_data, configuration_descriptor);
315 if (interface == NULL) {
316 return ENOENT;
317 }
318 do {
319 (void) process_interface(mapping, mapping_count,
320 &dp_parser, &dp_data,
321 interface);
322 interface = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
323 configuration_descriptor, interface);
324 } while (interface != NULL);
325
326 return EOK;
327}
328
[dc04868]329/** Initialize USB endpoint pipe.
330 *
331 * @param pipe Endpoint pipe to be initialized.
332 * @param connection Connection to the USB device backing this pipe (the wire).
333 * @param endpoint_no Endpoint number (in USB 1.1 in range 0 to 15).
334 * @param transfer_type Transfer type (e.g. interrupt or bulk).
335 * @param max_packet_size Maximum packet size in bytes.
336 * @param direction Endpoint direction (in/out).
337 * @return Error code.
338 */
339int usb_endpoint_pipe_initialize(usb_endpoint_pipe_t *pipe,
340 usb_device_connection_t *connection, usb_endpoint_t endpoint_no,
341 usb_transfer_type_t transfer_type, size_t max_packet_size,
342 usb_direction_t direction)
343{
344 assert(pipe);
345 assert(connection);
346
347 pipe->wire = connection;
348 pipe->hc_phone = -1;
349 pipe->endpoint_no = endpoint_no;
350 pipe->transfer_type = transfer_type;
351 pipe->max_packet_size = max_packet_size;
352 pipe->direction = direction;
353
354 return EOK;
355}
356
357
358/** Initialize USB endpoint pipe as the default zero control pipe.
359 *
360 * @param pipe Endpoint pipe to be initialized.
361 * @param connection Connection to the USB device backing this pipe (the wire).
362 * @return Error code.
363 */
364int usb_endpoint_pipe_initialize_default_control(usb_endpoint_pipe_t *pipe,
365 usb_device_connection_t *connection)
366{
367 assert(pipe);
368 assert(connection);
369
370 int rc = usb_endpoint_pipe_initialize(pipe, connection,
371 0, USB_TRANSFER_CONTROL, 8, USB_DIRECTION_BOTH);
372
373 return rc;
374}
375
[93ef8f6]376/**
377 * @}
378 */
Note: See TracBrowser for help on using the repository browser.