source: mainline/uspace/lib/usbhost/src/utility.c@ df6ded8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since df6ded8 was e0a5d4c, checked in by Ondřej Hlavatý <aearsis@…>, 8 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.1 KB
Line 
1/*
2 * Copyright (c) 2013 Jan Vesely
3 * Copyright (c) 2018 Ondrej Hlavaty, Jan Hrach
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/** @addtogroup libusbhost
30 * @{
31 */
32/** @file
33 */
34
35#include <macros.h>
36#include <str_error.h>
37#include <usb/debug.h>
38#include <usb/descriptor.h>
39#include <usb/request.h>
40
41#include "ddf_helpers.h"
42#include "utility.h"
43
44/**
45 * Get initial max packet size for the control endpoint 0.
46 *
47 * For LS, HS, and SS devices this value is final and fixed.
48 * For FS devices, the default value of 8 is returned. The caller needs
49 * to fetch the first 8B of the device descriptor later in the initialization
50 * process and determine whether it should be increased.
51 *
52 * @return Max packet size for EP 0 (in bytes)
53 */
54uint16_t hc_get_ep0_initial_mps(usb_speed_t speed)
55{
56 static const uint16_t mps_fixed [] = {
57 [USB_SPEED_LOW] = 8,
58 [USB_SPEED_HIGH] = 64,
59 [USB_SPEED_SUPER] = 512,
60 };
61
62 if (speed < ARRAY_SIZE(mps_fixed) && mps_fixed[speed] != 0) {
63 return mps_fixed[speed];
64 }
65 return 8; // USB_SPEED_FULL default
66}
67
68/**
69 * Get max packet size for the control endpoint 0.
70 *
71 * For LS, HS, and SS devices the corresponding fixed value is obtained.
72 * For FS devices the first 8B of the device descriptor are fetched to
73 * determine it.
74 *
75 * @return Max packet size for EP 0 (in bytes)
76 */
77int hc_get_ep0_max_packet_size(uint16_t *mps, device_t *dev)
78{
79 assert(mps);
80
81 *mps = hc_get_ep0_initial_mps(dev->speed);
82 if (dev->speed != USB_SPEED_FULL) {
83 return EOK;
84 }
85
86 const usb_target_t control_ep = {{
87 .address = dev->address,
88 .endpoint = 0,
89 }};
90
91 usb_standard_device_descriptor_t desc = { 0 };
92 const usb_device_request_setup_packet_t get_device_desc_8 =
93 GET_DEVICE_DESC(CTRL_PIPE_MIN_PACKET_SIZE);
94
95 usb_log_debug("Requesting first 8B of device descriptor to determine MPS.");
96 size_t got;
97 const errno_t err = bus_device_send_batch_sync(dev, control_ep,
98 USB_DIRECTION_IN, (char *) &desc, CTRL_PIPE_MIN_PACKET_SIZE,
99 *(uint64_t *)&get_device_desc_8,
100 "read first 8 bytes of dev descriptor", &got);
101
102 if (got != CTRL_PIPE_MIN_PACKET_SIZE) {
103 usb_log_error("Failed to get 8B of dev descr: %s.", str_error(err));
104 return err;
105 }
106
107 if (desc.descriptor_type != USB_DESCTYPE_DEVICE) {
108 usb_log_error("The device responded with wrong device descriptor.");
109 return EIO;
110 }
111
112 uint16_t version = uint16_usb2host(desc.usb_spec_version);
113 if (version < 0x0300) {
114 /* USB 2 and below have MPS raw in the field */
115 *mps = desc.max_packet_size;
116 } else {
117 /* USB 3 have MPS as an 2-based exponent */
118 *mps = (1 << desc.max_packet_size);
119 }
120 return EOK;
121}
122
123int hc_get_device_desc(device_t *device, usb_standard_device_descriptor_t *desc)
124{
125 const usb_target_t control_ep = {{
126 .address = device->address,
127 .endpoint = 0,
128 }};
129
130 /* Get std device descriptor */
131 const usb_device_request_setup_packet_t get_device_desc =
132 GET_DEVICE_DESC(sizeof(*desc));
133
134 usb_log_debug("Device(%d): Requesting full device descriptor.",
135 device->address);
136 size_t got;
137 errno_t err = bus_device_send_batch_sync(device, control_ep,
138 USB_DIRECTION_IN, (char *) desc, sizeof(*desc),
139 *(uint64_t *)&get_device_desc, "read device descriptor", &got);
140
141 if (!err && got != sizeof(*desc))
142 err = EOVERFLOW;
143
144 return err;
145}
146
147int hc_get_hub_desc(device_t *device, usb_hub_descriptor_header_t *desc)
148{
149 const usb_target_t control_ep = {{
150 .address = device->address,
151 .endpoint = 0,
152 }};
153
154 const usb_descriptor_type_t type = device->speed >= USB_SPEED_SUPER
155 ? USB_DESCTYPE_SSPEED_HUB : USB_DESCTYPE_HUB;
156
157 const usb_device_request_setup_packet_t get_hub_desc = {
158 .request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST
159 | (USB_REQUEST_TYPE_CLASS << 5)
160 | USB_REQUEST_RECIPIENT_DEVICE,
161 .request = USB_DEVREQ_GET_DESCRIPTOR, \
162 .value = uint16_host2usb(type << 8), \
163 .length = sizeof(*desc),
164 };
165
166 usb_log_debug("Device(%d): Requesting hub descriptor.",
167 device->address);
168
169 size_t got;
170 errno_t err = bus_device_send_batch_sync(device, control_ep,
171 USB_DIRECTION_IN, (char *) desc, sizeof(*desc),
172 *(uint64_t *)&get_hub_desc, "get hub descriptor", &got);
173
174 if (!err && got != sizeof(*desc))
175 err = EOVERFLOW;
176
177 return err;
178}
179
180int hc_device_explore(device_t *device)
181{
182 int err;
183 usb_standard_device_descriptor_t desc = { 0 };
184
185 if ((err = hc_get_device_desc(device, &desc))) {
186 usb_log_error("Device(%d): Failed to get dev descriptor: %s",
187 device->address, str_error(err));
188 return err;
189 }
190
191 if ((err = hcd_ddf_setup_match_ids(device, &desc))) {
192 usb_log_error("Device(%d): Failed to setup match ids: %s", device->address, str_error(err));
193 return err;
194 }
195
196 return EOK;
197}
198
199/** Announce root hub to the DDF
200 *
201 * @param[in] device Host controller ddf device
202 * @return Error code
203 */
204int hc_setup_virtual_root_hub(hc_device_t *hcd, usb_speed_t rh_speed)
205{
206 int err;
207
208 assert(hcd);
209
210 device_t *dev = hcd_ddf_fun_create(hcd, rh_speed);
211 if (!dev) {
212 usb_log_error("Failed to create function for the root hub.");
213 return ENOMEM;
214 }
215
216 ddf_fun_set_name(dev->fun, "roothub");
217
218 /* Assign an address to the device */
219 if ((err = bus_device_enumerate(dev))) {
220 usb_log_error("Failed to enumerate roothub device: %s", str_error(err));
221 goto err_usb_dev;
222 }
223
224 if ((err = ddf_fun_bind(dev->fun))) {
225 usb_log_error("Failed to register roothub: %s.", str_error(err));
226 goto err_enumerated;
227 }
228
229 return EOK;
230
231err_enumerated:
232 bus_device_gone(dev);
233err_usb_dev:
234 hcd_ddf_fun_destroy(dev);
235 return err;
236}
237
238/**
239 * Check setup packet data for signs of toggle reset.
240 *
241 * @param[in] batch USB batch
242 * @param[in] reset_cb Callback to reset an endpoint
243 */
244void hc_reset_toggles(const usb_transfer_batch_t *batch, endpoint_reset_toggle_t reset_cb)
245{
246 if (batch->ep->transfer_type != USB_TRANSFER_CONTROL
247 || batch->dir != USB_DIRECTION_OUT)
248 return;
249
250 const usb_device_request_setup_packet_t *request = &batch->setup.packet;
251 device_t * const dev = batch->ep->device;
252
253 switch (request->request)
254 {
255 /* Clear Feature ENPOINT_STALL */
256 case USB_DEVREQ_CLEAR_FEATURE: /*resets only cleared ep */
257 /* 0x2 ( HOST to device | STANDART | TO ENPOINT) */
258 if ((request->request_type == 0x2) &&
259 (request->value == USB_FEATURE_ENDPOINT_HALT)) {
260 const uint16_t index = uint16_usb2host(request->index);
261 const usb_endpoint_t ep_num = index & 0xf;
262 const usb_direction_t dir = (index >> 7) ? USB_DIRECTION_IN : USB_DIRECTION_OUT;
263
264 endpoint_t *ep = bus_find_endpoint(dev, ep_num, dir);
265 if (ep) {
266 reset_cb(ep);
267 endpoint_del_ref(ep);
268 } else {
269 usb_log_warning("Device(%u): Resetting unregistered endpoint %u %s.", dev->address, ep_num, usb_str_direction(dir));
270 }
271 }
272 break;
273 case USB_DEVREQ_SET_CONFIGURATION:
274 case USB_DEVREQ_SET_INTERFACE:
275 /* Recipient must be device, this resets all endpoints,
276 * In fact there should be no endpoints but EP 0 registered
277 * as different interfaces use different endpoints,
278 * unless you're changing configuration or alternative
279 * interface of an already setup device. */
280 if (!(request->request_type & SETUP_REQUEST_TYPE_DEVICE_TO_HOST))
281 for (usb_endpoint_t i = 0; i < 2 * USB_ENDPOINT_MAX; ++i)
282 if (dev->endpoints[i])
283 reset_cb(dev->endpoints[i]);
284 break;
285 default:
286 break;
287 }
288}
289
290typedef struct joinable_fibril {
291 fid_t fid;
292 void *arg;
293 fibril_worker_t worker;
294
295 bool running;
296 fibril_mutex_t guard;
297 fibril_condvar_t dead_cv;
298} joinable_fibril_t;
299
300static int joinable_fibril_worker(void *arg)
301{
302 joinable_fibril_t *jf = arg;
303
304 jf->worker(jf->arg);
305
306 fibril_mutex_lock(&jf->guard);
307 jf->running = false;
308 fibril_mutex_unlock(&jf->guard);
309 fibril_condvar_broadcast(&jf->dead_cv);
310 return 0;
311}
312
313/**
314 * Create a fibril that is joinable. Similar to fibril_create.
315 */
316joinable_fibril_t *joinable_fibril_create(fibril_worker_t worker, void *arg)
317{
318 joinable_fibril_t *jf = calloc(1, sizeof(joinable_fibril_t));
319 if (!jf)
320 return NULL;
321
322 jf->worker = worker;
323 jf->arg = arg;
324 fibril_mutex_initialize(&jf->guard);
325 fibril_condvar_initialize(&jf->dead_cv);
326
327 if (joinable_fibril_recreate(jf)) {
328 free(jf);
329 return NULL;
330 }
331
332 return jf;
333}
334
335/**
336 * Start a joinable fibril. Similar to fibril_add_ready.
337 */
338void joinable_fibril_start(joinable_fibril_t *jf)
339{
340 assert(jf);
341 assert(!jf->running);
342
343 jf->running = true;
344 fibril_add_ready(jf->fid);
345}
346
347/**
348 * Join a joinable fibril. Not similar to anything, obviously.
349 */
350void joinable_fibril_join(joinable_fibril_t *jf)
351{
352 assert(jf);
353
354 fibril_mutex_lock(&jf->guard);
355 while (jf->running)
356 fibril_condvar_wait(&jf->dead_cv, &jf->guard);
357 fibril_mutex_unlock(&jf->guard);
358
359 jf->fid = 0;
360}
361
362/**
363 * Reinitialize a joinable fibril.
364 */
365errno_t joinable_fibril_recreate(joinable_fibril_t *jf)
366{
367 assert(!jf->fid);
368
369 jf->fid = fibril_create(joinable_fibril_worker, jf);
370 return jf->fid ? EOK : ENOMEM;
371}
372
373/**
374 * Regular fibrils clean after themselves, joinable fibrils cannot.
375 */
376void joinable_fibril_destroy(joinable_fibril_t *jf)
377{
378 if (jf) {
379 joinable_fibril_join(jf);
380 free(jf);
381 }
382}
383
384/**
385 * @}
386 */
Note: See TracBrowser for help on using the repository browser.