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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2770b66 was 2770b66, checked in by Petr Manek <petr.manek@…>, 8 years ago

Fixed few bugs related to control transfers and some deadlocks. Registering control endpoint with HelenOS. Can read out device descriptors through MID and initialize mouse driver!

  • Property mode set to 100644
File size: 8.9 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 <adt/hash_table.h>
36#include <adt/hash.h>
37#include <usb/host/ddf_helpers.h>
38#include <usb/host/endpoint.h>
39#include <usb/host/hcd.h>
40#include <usb/debug.h>
41
42#include <assert.h>
43#include <errno.h>
44#include <str_error.h>
45#include <macros.h>
46#include <stdbool.h>
47
48#include "bus.h"
49#include "endpoint.h"
50
51/** Element of the hash table. */
52typedef struct {
53 ht_link_t link;
54
55 /** Device */
56 xhci_device_t *device;
57} hashed_device_t;
58
59/** TODO: Still some copy-pasta left...
60 */
61int xhci_bus_enumerate_device(xhci_bus_t *bus, xhci_hc_t *hc, device_t *dev)
62{
63 int err;
64
65 /* TODO: get speed from the default address reservation */
66 dev->speed = USB_SPEED_FULL;
67
68 /* Manage TT */
69 if (dev->hub->speed == USB_SPEED_HIGH && usb_speed_is_11(dev->speed)) {
70 /* For LS devices under HS hub */
71 /* TODO: How about SS hubs? */
72 dev->tt.address = dev->hub->address;
73 dev->tt.port = dev->port;
74 }
75 else {
76 /* Inherit hub's TT */
77 dev->tt = dev->hub->tt;
78 }
79
80 /* Assign an address to the device */
81 if ((err = xhci_rh_address_device(&hc->rh, dev, bus))) {
82 usb_log_error("Failed to setup address of the new device: %s", str_error(err));
83 return err;
84 }
85
86 /* Read the device descriptor, derive the match ids */
87 if ((err = hcd_ddf_device_explore(hc->hcd, dev))) {
88 usb_log_error("Device(%d): Failed to explore device: %s", dev->address, str_error(err));
89 bus_release_address(&bus->base, dev->address);
90 return err;
91 }
92
93 return EOK;
94}
95
96static int enumerate_device(bus_t *bus, hcd_t *hcd, device_t *dev)
97{
98 xhci_hc_t *hc = hcd_get_driver_data(hcd);
99 assert(hc);
100
101 return xhci_bus_enumerate_device((xhci_bus_t *) bus, hc, dev);
102}
103
104static int remove_device(bus_t *bus, hcd_t *hcd, device_t *dev)
105{
106 // TODO: Implement me!
107
108 return ENOTSUP;
109}
110
111/** Ops receive generic bus_t pointer. */
112static inline xhci_bus_t *bus_to_xhci_bus(bus_t *bus_base)
113{
114 assert(bus_base);
115 return (xhci_bus_t *) bus_base;
116}
117
118static endpoint_t *create_endpoint(bus_t *base)
119{
120 xhci_bus_t *bus = bus_to_xhci_bus(base);
121
122 xhci_endpoint_t *ep = malloc(sizeof(xhci_endpoint_t));
123 if (!ep)
124 return NULL;
125
126 if (xhci_endpoint_init(ep, bus)) {
127 free(ep);
128 return NULL;
129 }
130
131 return &ep->base;
132}
133
134static void destroy_endpoint(endpoint_t *ep)
135{
136 xhci_endpoint_t *xhci_ep = xhci_endpoint_get(ep);
137
138 xhci_endpoint_fini(xhci_ep);
139 free(xhci_ep);
140}
141
142static int hashed_device_find_by_address(xhci_bus_t *bus, usb_address_t address, hashed_device_t **dev)
143{
144 ht_link_t *link = hash_table_find(&bus->devices, &address);
145 if (link == NULL)
146 return ENOENT;
147
148 *dev = hash_table_get_inst(link, hashed_device_t, link);
149 return EOK;
150}
151
152static int xhci_endpoint_find_by_target(xhci_bus_t *bus, usb_target_t target, xhci_endpoint_t **ep)
153{
154 hashed_device_t *dev;
155 int res = hashed_device_find_by_address(bus, target.address, &dev);
156 if (res != EOK)
157 return res;
158
159 xhci_endpoint_t *ret_ep = xhci_device_get_endpoint(dev->device, target.endpoint);
160 if (!ret_ep)
161 return ENOENT;
162
163 *ep = ret_ep;
164 return EOK;
165}
166
167static int hashed_device_create(xhci_bus_t *bus, hashed_device_t **hashed_dev, usb_address_t address)
168{
169 int res;
170 xhci_device_t *dev = (xhci_device_t *) malloc(sizeof(xhci_device_t));
171 if (!dev) {
172 res = ENOMEM;
173 goto err_xhci_dev_alloc;
174 }
175
176 res = xhci_device_init(dev, bus, address);
177 if (res != EOK) {
178 goto err_xhci_dev_init;
179 }
180
181 hashed_device_t *ret_dev = (hashed_device_t *) malloc(sizeof(hashed_device_t));
182 if (!ret_dev) {
183 res = ENOMEM;
184 goto err_hashed_dev_alloc;
185 }
186
187 ret_dev->device = dev;
188
189 hash_table_insert(&bus->devices, &ret_dev->link);
190 *hashed_dev = ret_dev;
191 return EOK;
192
193err_hashed_dev_alloc:
194err_xhci_dev_init:
195 free(dev);
196err_xhci_dev_alloc:
197 return res;
198}
199
200static int hashed_device_remove(xhci_bus_t *bus, hashed_device_t *hashed_dev)
201{
202 hash_table_remove(&bus->devices, &hashed_dev->device->address);
203 xhci_device_fini(hashed_dev->device);
204 free(hashed_dev->device);
205 free(hashed_dev);
206
207 return EOK;
208}
209
210static int register_endpoint(bus_t *bus_base, endpoint_t *ep)
211{
212 xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
213 assert(bus);
214
215 hashed_device_t *hashed_dev;
216 int res = hashed_device_find_by_address(bus, ep->target.address, &hashed_dev);
217 if (res != EOK && res != ENOENT)
218 return res;
219
220 if (res == ENOENT) {
221 res = hashed_device_create(bus, &hashed_dev, ep->target.address);
222
223 if (res != EOK)
224 return res;
225 }
226
227 return xhci_device_add_endpoint(hashed_dev->device, xhci_endpoint_get(ep));
228}
229
230static int release_endpoint(bus_t *bus_base, endpoint_t *ep)
231{
232 xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
233 assert(bus);
234
235 hashed_device_t *hashed_dev;
236 int res = hashed_device_find_by_address(bus, ep->target.address, &hashed_dev);
237 if (res != EOK)
238 return res;
239
240 xhci_device_remove_endpoint(hashed_dev->device, xhci_endpoint_get(ep));
241
242 if (hashed_dev->device->active_endpoint_count == 0) {
243 res = hashed_device_remove(bus, hashed_dev);
244
245 if (res != EOK)
246 return res;
247 }
248
249 return EOK;
250}
251
252static endpoint_t* find_endpoint(bus_t *bus_base, usb_target_t target, usb_direction_t direction)
253{
254 xhci_bus_t *bus = bus_to_xhci_bus(bus_base);
255 assert(bus);
256
257 xhci_endpoint_t *ep;
258 int res = xhci_endpoint_find_by_target(bus, target, &ep);
259 if (res != EOK)
260 return NULL;
261
262 return &ep->base;
263}
264
265static int request_address(bus_t *bus_base, usb_address_t *addr, bool strict, usb_speed_t speed)
266{
267 // TODO: Implement me!
268 return ENOTSUP;
269}
270
271static int release_address(bus_t *bus_base, usb_address_t address)
272{
273 // TODO: Implement me!
274 return ENOTSUP;
275}
276
277static int reset_toggle(bus_t *bus_base, usb_target_t target, bool all)
278{
279 // TODO: Implement me!
280 return ENOTSUP;
281}
282
283static size_t count_bw(endpoint_t *ep, size_t size)
284{
285 // TODO: Implement me!
286 return 0;
287}
288
289/* Endpoint ops, optional (have generic fallback) */
290static bool endpoint_get_toggle(endpoint_t *ep)
291{
292 // TODO: Implement me!
293 return ENOTSUP;
294}
295
296static void endpoint_set_toggle(endpoint_t *ep, bool toggle)
297{
298 // TODO: Implement me!
299}
300
301static const bus_ops_t xhci_bus_ops = {
302 .enumerate_device = enumerate_device,
303 .remove_device = remove_device,
304
305 .create_endpoint = create_endpoint,
306 .destroy_endpoint = destroy_endpoint,
307
308 .register_endpoint = register_endpoint,
309 .release_endpoint = release_endpoint,
310 .find_endpoint = find_endpoint,
311
312 .request_address = request_address,
313 .release_address = release_address,
314 .reset_toggle = reset_toggle,
315
316 .count_bw = count_bw,
317
318 .endpoint_get_toggle = endpoint_get_toggle,
319 .endpoint_set_toggle = endpoint_set_toggle,
320};
321
322static size_t device_ht_hash(const ht_link_t *item)
323{
324 hashed_device_t *dev = hash_table_get_inst(item, hashed_device_t, link);
325 return (size_t) hash_mix(dev->device->address);
326}
327
328static size_t device_ht_key_hash(void *key)
329{
330 return (size_t) hash_mix(*(usb_address_t *)key);
331}
332
333static bool device_ht_key_equal(void *key, const ht_link_t *item)
334{
335 hashed_device_t *dev = hash_table_get_inst(item, hashed_device_t, link);
336 return dev->device->address == *(usb_address_t *) key;
337}
338
339/** Operations for the device hash table. */
340static hash_table_ops_t device_ht_ops = {
341 .hash = device_ht_hash,
342 .key_hash = device_ht_key_hash,
343 .key_equal = device_ht_key_equal,
344 .equal = NULL,
345 .remove_callback = NULL
346};
347
348int xhci_bus_init(xhci_bus_t *bus)
349{
350 assert(bus);
351
352 bus_init(&bus->base, sizeof(device_t));
353
354 if (!hash_table_create(&bus->devices, 0, 0, &device_ht_ops)) {
355 // FIXME: Dealloc base!
356 return ENOMEM;
357 }
358
359 bus->base.ops = xhci_bus_ops;
360 return EOK;
361}
362
363void xhci_bus_fini(xhci_bus_t *bus)
364{
365 // FIXME: Make sure no devices are in the hash table.
366
367 hash_table_destroy(&bus->devices);
368}
369
370/**
371 * @}
372 */
Note: See TracBrowser for help on using the repository browser.