source: mainline/uspace/drv/bus/usb/xhci/bus.c@ 25251bb

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

xhci: move pointer to hc from device to bus

Also, fixes the bug of hc ptr not set on tier 2+ device.

  • Property mode set to 100644
File size: 10.5 KB
Line 
1/*
2 * Copyright (c) 2017 Ondrej Hlavaty <aearsis@eideo.cz>
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/utils/malloc32.h>
36#include <usb/host/ddf_helpers.h>
37#include <usb/host/endpoint.h>
38#include <usb/host/hcd.h>
39#include <usb/debug.h>
40
41#include <assert.h>
42#include <errno.h>
43#include <str_error.h>
44#include <macros.h>
45#include <stdbool.h>
46
47#include "hc.h"
48#include "bus.h"
49#include "endpoint.h"
50#include "transfers.h"
51
52
53/* FIXME Are these really static? Older HCs fetch it from descriptor. */
54/* FIXME Add USB3 options, if applicable. */
55static const usb_endpoint_desc_t ep0_desc = {
56 .endpoint_no = 0,
57 .direction = USB_DIRECTION_BOTH,
58 .transfer_type = USB_TRANSFER_CONTROL,
59 .max_packet_size = CTRL_PIPE_MIN_PACKET_SIZE,
60 .packets = 1,
61};
62
63static int prepare_endpoint(xhci_endpoint_t *ep, const usb_endpoint_desc_t *desc)
64{
65 /* Extract information from endpoint_desc */
66 ep->base.endpoint = desc->endpoint_no;
67 ep->base.direction = desc->direction;
68 ep->base.transfer_type = desc->transfer_type;
69 ep->base.max_packet_size = desc->max_packet_size;
70 ep->base.packets = desc->packets;
71 ep->max_streams = desc->usb3.max_streams;
72 ep->max_burst = desc->usb3.max_burst;
73 // TODO add this property to usb_endpoint_desc_t and fetch it from ss companion desc
74 ep->mult = 0;
75
76 return xhci_endpoint_alloc_transfer_ds(ep);
77}
78
79static endpoint_t *create_endpoint(bus_t *base);
80
81static int address_device(xhci_hc_t *hc, xhci_device_t *dev)
82{
83 int err;
84
85 /* Enable new slot. */
86 if ((err = hc_enable_slot(hc, &dev->slot_id)) != EOK)
87 return err;
88 usb_log_debug2("Obtained slot ID: %u.\n", dev->slot_id);
89
90 /* Create and configure control endpoint. */
91 endpoint_t *ep0_base = create_endpoint(&hc->bus.base);
92 if (!ep0_base)
93 goto err_slot;
94
95 /* Temporary reference */
96 endpoint_add_ref(ep0_base);
97
98 ep0_base->device = &dev->base;
99 xhci_endpoint_t *ep0 = xhci_endpoint_get(ep0_base);
100
101 if ((err = prepare_endpoint(ep0, &ep0_desc)))
102 goto err_ep;
103
104 /* Address device */
105 if ((err = hc_address_device(hc, dev, ep0)))
106 goto err_prepared_ep;
107
108 /* Register EP0, passing Temporary reference */
109 dev->endpoints[0] = ep0;
110
111 return EOK;
112
113err_prepared_ep:
114 xhci_endpoint_free_transfer_ds(ep0);
115err_ep:
116 endpoint_del_ref(ep0_base);
117err_slot:
118 hc_disable_slot(hc, dev->slot_id);
119 return err;
120}
121
122int xhci_bus_enumerate_device(xhci_bus_t *bus, xhci_hc_t *hc, device_t *dev)
123{
124 int err;
125 xhci_device_t *xhci_dev = xhci_device_get(dev);
126
127 /* Manage TT */
128 if (dev->hub->speed == USB_SPEED_HIGH && usb_speed_is_11(dev->speed)) {
129 /* For LS devices under HS hub */
130 /* TODO: How about SS hubs? */
131 dev->tt.address = dev->hub->address;
132 dev->tt.port = dev->port;
133 }
134 else {
135 /* Inherit hub's TT */
136 dev->tt = dev->hub->tt;
137 }
138
139 /* Calculate route string */
140 xhci_device_t *xhci_hub = xhci_device_get(dev->hub);
141 xhci_dev->tier = xhci_hub->tier + 1;
142 xhci_dev->route_str = xhci_hub->route_str;
143
144 /* Roothub port is not part of the route string */
145 if (xhci_dev->tier >= 2) {
146 const unsigned offset = 4 * (xhci_dev->tier - 2);
147 xhci_dev->route_str |= (dev->port & 0xf) << offset;
148 xhci_dev->rh_port = xhci_hub->rh_port;
149 }
150
151 fibril_mutex_lock(&bus->base.guard);
152 /* Assign an address to the device */
153 if ((err = address_device(hc, xhci_dev))) {
154 usb_log_error("Failed to setup address of the new device: %s", str_error(err));
155 return err;
156 }
157
158 // TODO: Fetch descriptor of EP0 and reconfigure it accordingly
159 assert(xhci_dev->endpoints[0]);
160
161 assert(bus->devices_by_slot[xhci_dev->slot_id] == NULL);
162 bus->devices_by_slot[xhci_dev->slot_id] = xhci_dev;
163 fibril_mutex_unlock(&bus->base.guard);
164
165 /* Read the device descriptor, derive the match ids */
166 if ((err = hcd_ddf_device_explore(hc->hcd, dev))) {
167 usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
168 goto err_address;
169 }
170
171 return EOK;
172
173err_address:
174 bus_release_address(&bus->base, dev->address);
175 return err;
176}
177
178static int unregister_endpoint(bus_t *, endpoint_t *);
179
180int xhci_bus_remove_device(xhci_bus_t *bus, xhci_hc_t *hc, device_t *dev)
181{
182 xhci_device_t *xhci_dev = xhci_device_get(dev);
183
184 /* Unregister remaining endpoints. */
185 for (unsigned i = 0; i < ARRAY_SIZE(xhci_dev->endpoints); ++i) {
186 if (!xhci_dev->endpoints[i])
187 continue;
188
189 const int err = unregister_endpoint(&bus->base, &xhci_dev->endpoints[i]->base);
190 if (err)
191 usb_log_warning("Failed to unregister EP (%u:%u): %s", dev->address, i, str_error(err));
192 }
193
194 // XXX: Ugly here. Move to device_destroy at endpoint.c?
195 free32(xhci_dev->dev_ctx);
196 hc->dcbaa[xhci_dev->slot_id] = 0;
197 return EOK;
198}
199
200/** Ops receive generic bus_t pointer. */
201static inline xhci_bus_t *bus_to_xhci_bus(bus_t *bus_base)
202{
203 assert(bus_base);
204 return (xhci_bus_t *) bus_base;
205}
206
207static int enumerate_device(bus_t *bus_base, hcd_t *hcd, device_t *dev)
208{
209 xhci_hc_t *hc = hcd_get_driver_data(hcd);
210 assert(hc);
211
212 xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
213 assert(bus);
214
215 return xhci_bus_enumerate_device(bus, hc, dev);
216}
217
218static int remove_device(bus_t *bus_base, hcd_t *hcd, device_t *dev)
219{
220 xhci_hc_t *hc = hcd_get_driver_data(hcd);
221 assert(hc);
222
223 xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
224 assert(bus);
225
226 return xhci_bus_remove_device(bus, hc, dev);
227}
228
229static endpoint_t *create_endpoint(bus_t *base)
230{
231 xhci_bus_t *bus = bus_to_xhci_bus(base);
232
233 xhci_endpoint_t *ep = calloc(1, sizeof(xhci_endpoint_t));
234 if (!ep)
235 return NULL;
236
237 if (xhci_endpoint_init(ep, bus)) {
238 free(ep);
239 return NULL;
240 }
241
242 return &ep->base;
243}
244
245static void destroy_endpoint(endpoint_t *ep)
246{
247 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);
248
249 xhci_endpoint_fini(xhci_ep);
250 free(xhci_ep);
251}
252
253static int register_endpoint(bus_t *bus_base, endpoint_t *ep, const usb_endpoint_desc_t *desc)
254{
255 int err;
256 xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
257 assert(bus);
258
259 assert(ep->device);
260
261 xhci_device_t *xhci_dev = xhci_device_get(ep->device);
262 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);
263
264 if ((err = prepare_endpoint(xhci_ep, desc)))
265 return err;
266
267 usb_log_info("Endpoint(%d:%d) registered to XHCI bus.", ep->device->address, ep->endpoint);
268 return xhci_device_add_endpoint(bus->hc, xhci_dev, xhci_ep);
269}
270
271static int unregister_endpoint(bus_t *bus_base, endpoint_t *ep)
272{
273 xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
274 assert(bus);
275
276 usb_log_info("Endpoint(%d:%d) unregistered from XHCI bus.", ep->device->address, ep->endpoint);
277
278 xhci_device_t *xhci_dev = xhci_device_get(ep->device);
279 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);
280 const int res = xhci_device_remove_endpoint(bus->hc, xhci_dev, xhci_ep);
281 if (res != EOK)
282 return res;
283
284 return EOK;
285}
286
287static endpoint_t* find_endpoint(bus_t *bus_base, device_t *dev_base, usb_target_t target, usb_direction_t direction)
288{
289 xhci_device_t *dev = xhci_device_get(dev_base);
290
291 xhci_endpoint_t *ep = xhci_device_get_endpoint(dev, target.endpoint);
292 if (!ep)
293 return NULL;
294
295 return &ep->base;
296}
297
298static int reset_toggle(bus_t *bus_base, usb_target_t target, bool all)
299{
300 // TODO: Implement me!
301 return ENOTSUP;
302}
303
304static size_t count_bw(endpoint_t *ep, size_t size)
305{
306 // TODO: Implement me!
307 return 0;
308}
309
310/* Endpoint ops, optional (have generic fallback) */
311static bool endpoint_get_toggle(endpoint_t *ep)
312{
313 // TODO: Implement me!
314 return ENOTSUP;
315}
316
317static void endpoint_set_toggle(endpoint_t *ep, bool toggle)
318{
319 // TODO: Implement me!
320}
321
322static int request_address(bus_t *bus_base, usb_address_t *addr, bool strict, usb_speed_t speed)
323{
324 assert(addr);
325
326 if (*addr != USB_ADDRESS_DEFAULT)
327 /* xHCI does not allow software to assign addresses. */
328 return ENOTSUP;
329
330 assert(strict);
331
332 xhci_bus_t *xhci_bus = bus_to_xhci_bus(bus_base);
333
334 if (xhci_bus->default_address_speed != USB_SPEED_MAX)
335 /* Already allocated */
336 return ENOENT;
337
338 xhci_bus->default_address_speed = speed;
339 return EOK;
340}
341
342static int release_address(bus_t *bus_base, usb_address_t addr)
343{
344 if (addr != USB_ADDRESS_DEFAULT)
345 return ENOTSUP;
346
347 xhci_bus_t *xhci_bus = bus_to_xhci_bus(bus_base);
348
349 xhci_bus->default_address_speed = USB_SPEED_MAX;
350 return EOK;
351}
352
353static usb_transfer_batch_t *create_batch(bus_t *bus, endpoint_t *ep)
354{
355 xhci_transfer_t *transfer = xhci_transfer_create(ep);
356 return &transfer->batch;
357}
358
359static void destroy_batch(usb_transfer_batch_t *batch)
360{
361 xhci_transfer_destroy(xhci_transfer_from_batch(batch));
362}
363
364static const bus_ops_t xhci_bus_ops = {
365 .enumerate_device = enumerate_device,
366 .remove_device = remove_device,
367
368 .create_endpoint = create_endpoint,
369 .destroy_endpoint = destroy_endpoint,
370
371 .register_endpoint = register_endpoint,
372 .unregister_endpoint = unregister_endpoint,
373 .find_endpoint = find_endpoint,
374
375 .request_address = request_address,
376 .release_address = release_address,
377 .reset_toggle = reset_toggle,
378
379 .count_bw = count_bw,
380
381 .endpoint_get_toggle = endpoint_get_toggle,
382 .endpoint_set_toggle = endpoint_set_toggle,
383
384 .create_batch = create_batch,
385 .destroy_batch = destroy_batch,
386};
387
388int xhci_bus_init(xhci_bus_t *bus, xhci_hc_t *hc)
389{
390 assert(bus);
391
392 bus_init(&bus->base, sizeof(xhci_device_t));
393
394 bus->devices_by_slot = calloc(hc->max_slots, sizeof(xhci_device_t *));
395 if (!bus->devices_by_slot)
396 return ENOMEM;
397
398 bus->hc = hc;
399 bus->base.ops = xhci_bus_ops;
400 bus->default_address_speed = USB_SPEED_MAX;
401 return EOK;
402}
403
404void xhci_bus_fini(xhci_bus_t *bus)
405{
406
407}
408
409/**
410 * @}
411 */
Note: See TracBrowser for help on using the repository browser.