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

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

usbhost endpoint: removed target

The reasons for having usb_target_t inside endpoint have been dismissed. Enpoint is not a target of a transaction, so this was just misleading.

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