source: mainline/uspace/lib/usbdev/src/pipesinit.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was e0a5d4c, checked in by Ondřej Hlavatý <aearsis@…>, 7 years ago

usb: update copyrights

The data was generated by a script, guided manually. If you feel your
name is missing somewhere, please add it!

The semi-automated process was roughly:

1) Changes per file and author (limited to our team) were counted
2) Trivial numbers were thrown away
3) Authors were sorted by lines added to file
4) All previous copyrights were replaced by the newly generated one
5) Hunks changing only year were discarded

It seems that a lot of my copyrights were added. It is due to me being
both sticking my nose everywhere and lazy to update the copyright right
away :)

  • Property mode set to 100644
File size: 10.9 KB
Line 
1/*
2 * Copyright (c) 2011 Vojtech Horky
3 * Copyright (c) 2018 Ondrej Hlavaty, Michal Staruch
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libusbdev
31 * @{
32 */
33/** @file
34 * Non trivial initialization of endpoint pipes.
35 *
36 */
37#include <usb/dev/pipes.h>
38#include <usb/dev/dp.h>
39#include <usb/dev/request.h>
40#include <usb/usb.h>
41#include <usb/debug.h>
42#include <usb/descriptor.h>
43
44#include <assert.h>
45#include <errno.h>
46
47#define DEV_DESCR_MAX_PACKET_SIZE_OFFSET 7
48
49#define NESTING(parentname, childname) \
50 { \
51 .child = USB_DESCTYPE_##childname, \
52 .parent = USB_DESCTYPE_##parentname, \
53 }
54#define LAST_NESTING { -1, -1 }
55
56/** Nesting pairs of standard descriptors. */
57static const usb_dp_descriptor_nesting_t descriptor_nesting[] = {
58 NESTING(CONFIGURATION, INTERFACE),
59 NESTING(INTERFACE, ENDPOINT),
60 NESTING(INTERFACE, HUB),
61 NESTING(INTERFACE, HID),
62 NESTING(HID, HID_REPORT),
63 NESTING(ENDPOINT, SSPEED_EP_COMPANION),
64 LAST_NESTING
65};
66
67/** Tells whether given descriptor is of endpoint type.
68 *
69 * @param descriptor Descriptor in question.
70 * @return Whether the given descriptor is endpoint descriptor.
71 */
72static inline bool is_endpoint_descriptor(const uint8_t *descriptor)
73{
74 return descriptor[1] == USB_DESCTYPE_ENDPOINT;
75}
76
77/** Tells whether given descriptor is of superspeed companion type.
78 *
79 * @param descriptor Descriptor in question.
80 * @return Whether the given descriptor is superspeed companion descriptor.
81 */
82static inline bool is_superspeed_companion_descriptor(const uint8_t *descriptor)
83{
84 return descriptor[1] == USB_DESCTYPE_SSPEED_EP_COMPANION;
85}
86
87/** Tells whether found endpoint corresponds to endpoint described by user.
88 *
89 * @param wanted Endpoint description as entered by driver author.
90 * @param found Endpoint description obtained from endpoint descriptor.
91 * @return Whether the @p found descriptor fits the @p wanted descriptor.
92 */
93static bool endpoint_fits_description(const usb_endpoint_description_t *wanted,
94 const usb_endpoint_description_t *found)
95{
96#define _SAME(fieldname) ((wanted->fieldname) == (found->fieldname))
97
98 if (!_SAME(direction)) {
99 return false;
100 }
101
102 if (!_SAME(transfer_type)) {
103 return false;
104 }
105
106 if ((wanted->interface_class >= 0) && !_SAME(interface_class)) {
107 return false;
108 }
109
110 if ((wanted->interface_subclass >= 0) && !_SAME(interface_subclass)) {
111 return false;
112 }
113
114 if ((wanted->interface_protocol >= 0) && !_SAME(interface_protocol)) {
115 return false;
116 }
117
118#undef _SAME
119
120 return true;
121}
122
123/** Find endpoint mapping for a found endpoint.
124 *
125 * @param mapping Endpoint mapping list.
126 * @param mapping_count Number of endpoint mappings in @p mapping.
127 * @param found_endpoint Description of found endpoint.
128 * @param interface_number Number of currently processed interface.
129 * @return Endpoint mapping corresponding to @p found_endpoint.
130 * @retval NULL No corresponding endpoint found.
131 */
132static usb_endpoint_mapping_t *find_endpoint_mapping(
133 usb_endpoint_mapping_t *mapping, size_t mapping_count,
134 const usb_endpoint_description_t *found_endpoint,
135 int interface_number, int interface_setting)
136{
137 while (mapping_count > 0) {
138 bool interface_number_fits = (mapping->interface_no < 0)
139 || (mapping->interface_no == interface_number);
140
141 bool interface_setting_fits = (mapping->interface_setting < 0)
142 || (mapping->interface_setting == interface_setting);
143
144 bool endpoint_descriptions_fits = endpoint_fits_description(
145 mapping->description, found_endpoint);
146
147 if (interface_number_fits
148 && interface_setting_fits
149 && endpoint_descriptions_fits
150 && !mapping->present) {
151 return mapping;
152 }
153
154 mapping++;
155 mapping_count--;
156 }
157
158 return NULL;
159}
160
161/** Process endpoint descriptor.
162 *
163 * @param mapping Endpoint mapping list.
164 * @param mapping_count Number of endpoint mappings in @p mapping.
165 * @param interface Interface descriptor under which belongs the @p endpoint.
166 * @param endpoint Endpoint descriptor.
167 * @param companion Superspeed companion descriptor.
168 * @return Error code.
169 */
170static errno_t process_endpoint(
171 usb_endpoint_mapping_t *mapping, size_t mapping_count,
172 usb_standard_interface_descriptor_t *interface,
173 usb_standard_endpoint_descriptor_t *endpoint_desc,
174 usb_superspeed_endpoint_companion_descriptor_t *companion_desc,
175 usb_dev_session_t *bus_session)
176{
177
178 /*
179 * Get endpoint characteristics.
180 */
181 const usb_endpoint_description_t description = {
182 .transfer_type = USB_ED_GET_TRANSFER_TYPE(*endpoint_desc),
183 .direction = USB_ED_GET_DIR(*endpoint_desc),
184
185 /* Get interface characteristics. */
186 .interface_class = interface->interface_class,
187 .interface_subclass = interface->interface_subclass,
188 .interface_protocol = interface->interface_protocol,
189 };
190
191 /*
192 * Find the most fitting mapping and initialize the pipe.
193 */
194 usb_endpoint_mapping_t *ep_mapping = find_endpoint_mapping(mapping,
195 mapping_count, &description,
196 interface->interface_number, interface->alternate_setting);
197 if (ep_mapping == NULL) {
198 return ENOENT;
199 }
200
201 if (ep_mapping->present) {
202 return EEXIST;
203 }
204
205 errno_t err = usb_pipe_initialize(&ep_mapping->pipe, bus_session);
206 if (err)
207 return err;
208
209 ep_mapping->present = true;
210 ep_mapping->descriptor = endpoint_desc;
211 ep_mapping->companion_descriptor = companion_desc;
212 ep_mapping->interface = interface;
213
214 return EOK;
215}
216
217/** Process whole USB interface.
218 *
219 * @param mapping Endpoint mapping list.
220 * @param mapping_count Number of endpoint mappings in @p mapping.
221 * @param parser Descriptor parser.
222 * @param parser_data Descriptor parser data.
223 * @param interface_descriptor Interface descriptor.
224 * @return Error code.
225 */
226static errno_t process_interface(
227 usb_endpoint_mapping_t *mapping, size_t mapping_count,
228 const usb_dp_parser_t *parser, const usb_dp_parser_data_t *parser_data,
229 const uint8_t *interface_descriptor, usb_dev_session_t *bus_session)
230{
231 const uint8_t *descriptor = usb_dp_get_nested_descriptor(parser,
232 parser_data, interface_descriptor);
233
234 if (descriptor == NULL) {
235 return ENOENT;
236 }
237
238 do {
239 if (is_endpoint_descriptor(descriptor)) {
240 /* Check if companion descriptor is present too, it should immediatelly follow. */
241 const uint8_t *companion_desc = usb_dp_get_nested_descriptor(parser,
242 parser_data, descriptor);
243 if (companion_desc && !is_superspeed_companion_descriptor(companion_desc)) {
244 /* Not what we wanted, don't pass it further. */
245 companion_desc = NULL;
246 }
247
248 (void) process_endpoint(mapping, mapping_count,
249 (usb_standard_interface_descriptor_t *)
250 interface_descriptor,
251 (usb_standard_endpoint_descriptor_t *)
252 descriptor,
253 (usb_superspeed_endpoint_companion_descriptor_t *)
254 companion_desc,
255 bus_session);
256 }
257
258 descriptor = usb_dp_get_sibling_descriptor(parser, parser_data,
259 interface_descriptor, descriptor);
260 } while (descriptor != NULL);
261
262 return EOK;
263}
264
265/** Initialize endpoint pipes from configuration descriptor.
266 *
267 * The mapping array is expected to conform to following rules:
268 * - @c pipe must be uninitialized pipe
269 * - @c description must point to prepared endpoint description
270 * - @c descriptor does not need to be initialized (will be overwritten)
271 * - @c interface does not need to be initialized (will be overwritten)
272 * - @c present does not need to be initialized (will be overwritten)
273 *
274 * After processing the configuration descriptor, the mapping is updated
275 * in the following fashion:
276 * - @c present will be set to @c true when the endpoint was found in the
277 * configuration
278 * - @c descriptor will point inside the configuration descriptor to endpoint
279 * corresponding to given description (or NULL for not found descriptor)
280 * - @c interface will point inside the configuration descriptor to interface
281 * descriptor the endpoint @c descriptor belongs to (or NULL for not found
282 * descriptor)
283 * - @c pipe will be initialized when found, otherwise left untouched
284 * - @c description will be untouched under all circumstances
285 *
286 * @param mapping Endpoint mapping list.
287 * @param mapping_count Number of endpoint mappings in @p mapping.
288 * @param configuration_descriptor Full configuration descriptor (is expected
289 * to be in USB endianness: i.e. as-is after being retrieved from
290 * the device).
291 * @param configuration_descriptor_size Size of @p configuration_descriptor
292 * in bytes.
293 * @param connection Connection backing the endpoint pipes.
294 * @return Error code.
295 */
296errno_t usb_pipe_initialize_from_configuration(
297 usb_endpoint_mapping_t *mapping, size_t mapping_count,
298 const uint8_t *config_descriptor, size_t config_descriptor_size,
299 usb_dev_session_t *bus_session)
300{
301 if (config_descriptor == NULL)
302 return EBADMEM;
303
304 if (config_descriptor_size <
305 sizeof(usb_standard_configuration_descriptor_t)) {
306 return ERANGE;
307 }
308
309 /* Go through the mapping and set all endpoints to not present. */
310 for (size_t i = 0; i < mapping_count; i++) {
311 mapping[i].present = false;
312 mapping[i].descriptor = NULL;
313 mapping[i].interface = NULL;
314 }
315
316 /* Prepare the descriptor parser. */
317 const usb_dp_parser_t dp_parser = {
318 .nesting = descriptor_nesting
319 };
320 const usb_dp_parser_data_t dp_data = {
321 .data = config_descriptor,
322 .size = config_descriptor_size,
323 };
324
325 /*
326 * Iterate through all interfaces.
327 */
328 const uint8_t *interface = usb_dp_get_nested_descriptor(&dp_parser,
329 &dp_data, config_descriptor);
330 if (interface == NULL) {
331 return ENOENT;
332 }
333 do {
334 (void) process_interface(mapping, mapping_count,
335 &dp_parser, &dp_data, interface, bus_session);
336 interface = usb_dp_get_sibling_descriptor(&dp_parser, &dp_data,
337 config_descriptor, interface);
338 } while (interface != NULL);
339
340 return EOK;
341}
342
343/**
344 * @}
345 */
Note: See TracBrowser for help on using the repository browser.