source: mainline/uspace/drv/bus/usb/xhci/device.c@ 47b2d7e3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 47b2d7e3 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.2 KB
Line 
1/*
2 * Copyright (c) 2018 Ondrej Hlavaty, Jan Hrach
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/** @addtogroup libusbhost
29 * @{
30 */
31/** @file
32 * HC Endpoint management.
33 */
34
35#include <usb/host/utility.h>
36#include <usb/host/ddf_helpers.h>
37#include <usb/host/endpoint.h>
38#include <usb/host/hcd.h>
39#include <usb/host/utility.h>
40#include <usb/classes/classes.h>
41#include <usb/classes/hub.h>
42#include <usb/descriptor.h>
43#include <usb/debug.h>
44
45#include <assert.h>
46#include <errno.h>
47#include <str_error.h>
48#include <macros.h>
49#include <stdbool.h>
50
51#include "hc.h"
52#include "bus.h"
53#include "endpoint.h"
54#include "hw_struct/context.h"
55
56#include "device.h"
57
58/**
59 * Initial descriptor used for control endpoint 0,
60 * before more configuration is retrieved.
61 */
62static const usb_endpoint_descriptors_t ep0_initial_desc = {
63 .endpoint.max_packet_size = CTRL_PIPE_MIN_PACKET_SIZE,
64};
65
66/**
67 * Assign address and control endpoint to a new XHCI device. Once this function
68 * successfully returns, the device is online.
69 *
70 * @param[in] bus XHCI bus, in which the address is assigned.
71 * @param[in] dev New device to address and configure./e
72 * @return Error code.
73 */
74static errno_t address_device(xhci_device_t *dev)
75{
76 errno_t err;
77
78 /* Enable new slot. */
79 if ((err = hc_enable_slot(dev)) != EOK)
80 return err;
81 usb_log_debug("Obtained slot ID: %u.", dev->slot_id);
82
83 /* Temporary reference */
84 endpoint_t *ep0_base;
85 if ((err = bus_endpoint_add(&dev->base, &ep0_initial_desc, &ep0_base)))
86 goto err_slot;
87
88 usb_log_debug("Looking up new device initial MPS: %s",
89 usb_str_speed(dev->base.speed));
90 ep0_base->max_packet_size = hc_get_ep0_initial_mps(dev->base.speed);
91
92 /* Address device */
93 if ((err = hc_address_device(dev)))
94 goto err_added;
95
96 /* Temporary reference */
97 endpoint_del_ref(ep0_base);
98
99 return EOK;
100
101err_added:
102 bus_endpoint_remove(ep0_base);
103 /* Temporary reference */
104 endpoint_del_ref(ep0_base);
105err_slot:
106 hc_disable_slot(dev);
107 return err;
108}
109
110/**
111 * Retrieve and set maximum packet size for endpoint zero of a XHCI device.
112 *
113 * @param[in] hc Host controller, which manages the device.
114 * @param[in] dev Device with operational endpoint zero.
115 * @return Error code.
116 */
117static errno_t setup_ep0_packet_size(xhci_hc_t *hc, xhci_device_t *dev)
118{
119 errno_t err;
120
121 uint16_t max_packet_size;
122 if ((err = hc_get_ep0_max_packet_size(&max_packet_size, &dev->base)))
123 return err;
124
125 xhci_endpoint_t *ep0 = xhci_endpoint_get(dev->base.endpoints[0]);
126 assert(ep0);
127
128 if (ep0->base.max_packet_size == max_packet_size)
129 return EOK;
130
131 ep0->base.max_packet_size = max_packet_size;
132 ep0->base.max_transfer_size = max_packet_size * ep0->base.packets_per_uframe;
133
134 if ((err = hc_update_endpoint(ep0)))
135 return err;
136
137 return EOK;
138}
139
140/**
141 * Check whether the device is a hub and if so, fill its characterstics.
142 *
143 * If this fails, it does not necessarily mean the device is unusable.
144 * Just the TT will not work correctly.
145 */
146static errno_t setup_hub(xhci_device_t *dev, usb_standard_device_descriptor_t *desc)
147{
148 if (desc->device_class != USB_CLASS_HUB)
149 return EOK;
150
151 usb_hub_descriptor_header_t hub_desc = { 0 };
152 const errno_t err = hc_get_hub_desc(&dev->base, &hub_desc);
153 if (err)
154 return err;
155
156 dev->is_hub = 1;
157 dev->num_ports = hub_desc.port_count;
158
159 if (dev->base.speed == USB_SPEED_HIGH) {
160 dev->tt_think_time = 8 +
161 8 * !!(hub_desc.characteristics & HUB_CHAR_TT_THINK_8) +
162 16 * !!(hub_desc.characteristics & HUB_CHAR_TT_THINK_16);
163 }
164
165 usb_log_debug("Device(%u): recognised USB hub with %u ports",
166 dev->base.address, dev->num_ports);
167 return EOK;
168}
169
170/**
171 * Respond to a new device on the XHCI bus. Address it, negotiate packet size
172 * and retrieve USB descriptors.
173 *
174 * @param[in] bus XHCI bus, where the new device emerged.
175 * @param[in] dev XHCI device, which has appeared on the bus.
176 *
177 * @return Error code.
178 */
179errno_t xhci_device_enumerate(device_t *dev)
180{
181 errno_t err;
182 xhci_bus_t *bus = bus_to_xhci_bus(dev->bus);
183 xhci_device_t *xhci_dev = xhci_device_get(dev);
184
185 /* Calculate route string */
186 xhci_device_t *xhci_hub = xhci_device_get(dev->hub);
187 xhci_dev->route_str = xhci_hub->route_str;
188
189 /* Roothub port is not part of the route string */
190 if (dev->tier >= 2) {
191 const unsigned offset = 4 * (dev->tier - 2);
192 xhci_dev->route_str |= (dev->port & 0xf) << offset;
193 xhci_dev->rh_port = xhci_hub->rh_port;
194 }
195
196 int retries = 3;
197 do {
198 /* Assign an address to the device */
199 err = address_device(xhci_dev);
200 } while (err == ESTALL && --retries > 0);
201
202 if (err) {
203 usb_log_error("Failed to setup address of the new device: %s",
204 str_error(err));
205 return err;
206 }
207
208 /* Setup EP0 might already need to issue a transfer. */
209 fibril_mutex_lock(&bus->base.guard);
210 assert(bus->devices_by_slot[xhci_dev->slot_id] == NULL);
211 bus->devices_by_slot[xhci_dev->slot_id] = xhci_dev;
212 fibril_mutex_unlock(&bus->base.guard);
213
214 if ((err = setup_ep0_packet_size(bus->hc, xhci_dev))) {
215 usb_log_error("Failed to setup control endpoint "
216 "of the new device: %s", str_error(err));
217 goto err_address;
218 }
219
220 usb_standard_device_descriptor_t desc = { 0 };
221
222 if ((err = hc_get_device_desc(dev, &desc))) {
223 usb_log_error("Device(%d): failed to get device "
224 "descriptor: %s", dev->address, str_error(err));
225 goto err_address;
226 }
227
228 if ((err = setup_hub(xhci_dev, &desc)))
229 usb_log_warning("Device(%d): failed to setup hub "
230 "characteristics: %s. Continuing anyway.",
231 dev->address, str_error(err));
232
233 if ((err = hcd_ddf_setup_match_ids(dev, &desc))) {
234 usb_log_error("Device(%d): failed to setup match IDs: %s",
235 dev->address, str_error(err));
236 goto err_address;
237 }
238
239 return EOK;
240
241err_address:
242 bus_endpoint_remove(xhci_dev->base.endpoints[0]);
243 bus->devices_by_slot[xhci_dev->slot_id] = NULL;
244 hc_disable_slot(xhci_dev);
245 return err;
246}
247
248/**
249 * Remove device from XHCI bus. Transition it to the offline state, abort all
250 * ongoing transfers and unregister all of its endpoints.
251 *
252 * Bus callback.
253 *
254 * @param[in] bus XHCI bus, from which the device is removed.
255 * @param[in] dev XHCI device, which is removed from the bus.
256 * @return Error code.
257 */
258void xhci_device_gone(device_t *dev)
259{
260 errno_t err;
261 xhci_bus_t *bus = bus_to_xhci_bus(dev->bus);
262 xhci_device_t *xhci_dev = xhci_device_get(dev);
263
264 /* Disable the slot, dropping all endpoints. */
265 const uint32_t slot_id = xhci_dev->slot_id;
266 if ((err = hc_disable_slot(xhci_dev))) {
267 usb_log_warning("Failed to disable slot of device " XHCI_DEV_FMT
268 ": %s", XHCI_DEV_ARGS(*xhci_dev), str_error(err));
269 }
270
271 bus->devices_by_slot[slot_id] = NULL;
272}
273
274/**
275 * Reverts things device_offline did, getting the device back up.
276 *
277 * Bus callback.
278 */
279errno_t xhci_device_online(device_t *dev_base)
280{
281 errno_t err;
282
283 xhci_bus_t *bus = bus_to_xhci_bus(dev_base->bus);
284 assert(bus);
285
286 xhci_device_t *dev = xhci_device_get(dev_base);
287 assert(dev);
288
289 /* Transition the device from the Addressed to the Configured state. */
290 if ((err = hc_configure_device(dev))) {
291 usb_log_warning("Failed to configure device " XHCI_DEV_FMT ".",
292 XHCI_DEV_ARGS(*dev));
293 return err;
294 }
295
296 return EOK;
297}
298
299/**
300 * Make given device offline. Offline the DDF function, tear down all
301 * endpoints, issue Deconfigure Device command to xHC.
302 *
303 * Bus callback.
304 */
305void xhci_device_offline(device_t *dev_base)
306{
307 errno_t err;
308
309 xhci_bus_t *bus = bus_to_xhci_bus(dev_base->bus);
310 assert(bus);
311
312 xhci_device_t *dev = xhci_device_get(dev_base);
313 assert(dev);
314
315 /* Issue one HC command to simultaneously drop all endpoints except zero. */
316 if ((err = hc_deconfigure_device(dev))) {
317 usb_log_warning("Failed to deconfigure device "
318 XHCI_DEV_FMT ".", XHCI_DEV_ARGS(*dev));
319 }
320}
321
322/**
323 * Fill a slot context that is part of an Input Context with appropriate
324 * values.
325 *
326 * @param ctx Slot context, zeroed out.
327 */
328void xhci_setup_slot_context(xhci_device_t *dev, xhci_slot_ctx_t *ctx)
329{
330 /* Initialize slot_ctx according to section 4.3.3 point 3. */
331 XHCI_SLOT_ROOT_HUB_PORT_SET(*ctx, dev->rh_port);
332 XHCI_SLOT_ROUTE_STRING_SET(*ctx, dev->route_str);
333 XHCI_SLOT_SPEED_SET(*ctx, hc_speed_to_psiv(dev->base.speed));
334
335 /*
336 * Note: This function is used even before this flag can be set, to
337 * issue the address device command. It is OK, because these
338 * flags are not required to be valid for that command.
339 */
340 if (dev->is_hub) {
341 XHCI_SLOT_HUB_SET(*ctx, 1);
342 XHCI_SLOT_NUM_PORTS_SET(*ctx, dev->num_ports);
343 XHCI_SLOT_TT_THINK_TIME_SET(*ctx, dev->tt_think_time);
344 XHCI_SLOT_MTT_SET(*ctx, 0); // MTT not supported yet
345 }
346
347 /* Setup Transaction Translation. TODO: Test this with HS hub. */
348 if (dev->base.tt.dev != NULL) {
349 xhci_device_t *hub = xhci_device_get(dev->base.tt.dev);
350 XHCI_SLOT_TT_HUB_SLOT_ID_SET(*ctx, hub->slot_id);
351 XHCI_SLOT_TT_HUB_PORT_SET(*ctx, dev->base.tt.port);
352 }
353
354 /*
355 * As we always allocate space for whole input context, we can set this
356 * to maximum. The only exception being Address Device command, which
357 * explicitly requires this to be se to 1.
358 */
359 XHCI_SLOT_CTX_ENTRIES_SET(*ctx, 31);
360}
361
362
363/**
364 * @}
365 */
Note: See TracBrowser for help on using the repository browser.