source: mainline/uspace/lib/usbhost/src/ddf_helpers.c@ 14dd4c9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 14dd4c9 was 14dd4c9, checked in by Jan Vesely <jano.vesely@…>, 12 years ago

libusbhost: consolidate device lists and locking.

Root hub is added only once, there's no need for lock or list. Make the list
guard per device. Protect list append as well as removal.

  • Property mode set to 100644
File size: 17.2 KB
RevLine 
[53332b5b]1/*
[d2cfe72]2 * Copyright (c) 2013 Jan Vesely
[53332b5b]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
29/** @addtogroup libusbhost
30 * @{
31 */
32/** @file
33 *
34 */
35
36#include <usb_iface.h>
[237df2f]37#include <usb/classes/classes.h>
[53332b5b]38#include <usb/debug.h>
[237df2f]39#include <usb/descriptor.h>
40#include <usb/request.h>
[53332b5b]41#include <errno.h>
42#include <str_error.h>
43
44#include "ddf_helpers.h"
45
[237df2f]46#define CTRL_PIPE_MIN_PACKET_SIZE 8
47
[14dd4c9]48typedef struct usb_dev {
49 link_t link;
[daf59d1]50 list_t devices;
[b995183]51 fibril_mutex_t guard;
[14dd4c9]52 ddf_fun_t *fun;
53 usb_address_t address;
54 usb_speed_t speed;
55 unsigned port;
56} usb_dev_t;
57
58typedef struct hc_dev {
59 ddf_fun_t *ctl_fun;
[e991937]60 hcd_t hcd;
[14dd4c9]61 usb_dev_t *root_hub;
[53332b5b]62} hc_dev_t;
63
64static hc_dev_t *dev_to_hc_dev(ddf_dev_t *dev)
65{
66 return ddf_dev_data_get(dev);
67}
68
69hcd_t *dev_to_hcd(ddf_dev_t *dev)
70{
71 hc_dev_t *hc_dev = dev_to_hc_dev(dev);
[e991937]72 if (!hc_dev) {
[2b0929e]73 usb_log_error("Invalid HCD device.\n");
[53332b5b]74 return NULL;
75 }
[e991937]76 return &hc_dev->hcd;
[53332b5b]77}
78
79
[0918382f]80static int hcd_ddf_new_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port);
81static int hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port);
[2757247]82
83
84/* DDF INTERFACE */
85
[d2cfe72]86/** Register endpoint interface function.
87 * @param fun DDF function.
88 * @param address USB address of the device.
89 * @param endpoint USB endpoint number to be registered.
90 * @param transfer_type Endpoint's transfer type.
91 * @param direction USB communication direction the endpoint is capable of.
92 * @param max_packet_size Maximu size of packets the endpoint accepts.
93 * @param interval Preferred timeout between communication.
94 * @return Error code.
95 */
96static int register_endpoint(
97 ddf_fun_t *fun, usb_endpoint_t endpoint,
98 usb_transfer_type_t transfer_type, usb_direction_t direction,
99 size_t max_packet_size, unsigned interval)
100{
101 assert(fun);
102 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
103 usb_dev_t *dev = ddf_fun_data_get(fun);
104 assert(hcd);
105 assert(dev);
106 const size_t size = max_packet_size;
107 const usb_target_t target =
108 {{.address = dev->address, .endpoint = endpoint}};
109
110 usb_log_debug("Register endpoint %d:%d %s-%s %zuB %ums.\n",
111 dev->address, endpoint, usb_str_transfer_type(transfer_type),
112 usb_str_direction(direction), max_packet_size, interval);
113
114 return hcd_add_ep(hcd, target, direction, transfer_type,
115 max_packet_size, size);
116}
117
118/** Unregister endpoint interface function.
119 * @param fun DDF function.
120 * @param address USB address of the endpoint.
121 * @param endpoint USB endpoint number.
122 * @param direction Communication direction of the enpdoint to unregister.
123 * @return Error code.
124 */
125static int unregister_endpoint(
126 ddf_fun_t *fun, usb_endpoint_t endpoint, usb_direction_t direction)
127{
128 assert(fun);
129 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
130 usb_dev_t *dev = ddf_fun_data_get(fun);
131 assert(hcd);
132 assert(dev);
133 const usb_target_t target =
134 {{.address = dev->address, .endpoint = endpoint}};
135 usb_log_debug("Unregister endpoint %d:%d %s.\n",
136 dev->address, endpoint, usb_str_direction(direction));
137 return hcd_remove_ep(hcd, target, direction);
138}
139
[56bd6f11]140static int reserve_default_address(ddf_fun_t *fun, usb_speed_t speed)
141{
142 assert(fun);
143 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
144 usb_dev_t *dev = ddf_fun_data_get(fun);
145 assert(hcd);
146 assert(dev);
147
148 usb_log_debug("Device %d requested default address at %s speed\n",
149 dev->address, usb_str_speed(speed));
150 return hcd_reserve_default_address(hcd, speed);
151}
152
153static int release_default_address(ddf_fun_t *fun)
154{
155 assert(fun);
156 hcd_t *hcd = dev_to_hcd(ddf_fun_get_dev(fun));
157 usb_dev_t *dev = ddf_fun_data_get(fun);
158 assert(hcd);
159 assert(dev);
160
161 usb_log_debug("Device %d released default address\n", dev->address);
162 return hcd_release_default_address(hcd);
163}
164
[0918382f]165static int device_enumerate(ddf_fun_t *fun, unsigned port)
[56bd6f11]166{
167 assert(fun);
168 ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun);
169 usb_dev_t *dev = ddf_fun_data_get(fun);
170 assert(ddf_dev);
171 assert(dev);
[0918382f]172 usb_log_debug("Hub %d reported a new USB device on port: %u\n",
173 dev->address, port);
174 return hcd_ddf_new_device(ddf_dev, dev, port);
[56bd6f11]175}
176
[0918382f]177static int device_remove(ddf_fun_t *fun, unsigned port)
[56bd6f11]178{
179 assert(fun);
180 ddf_dev_t *ddf_dev = ddf_fun_get_dev(fun);
181 usb_dev_t *dev = ddf_fun_data_get(fun);
182 assert(ddf_dev);
183 assert(dev);
[0918382f]184 usb_log_debug("Hub `%s' reported removal of device on port %u\n",
185 ddf_fun_get_name(fun), port);
186 return hcd_ddf_remove_device(ddf_dev, dev, port);
[56bd6f11]187}
188
[3121b5f]189/** Gets handle of the respective device.
[8e4219ab]190 *
[3121b5f]191 * @param[in] fun Device function.
[8e4219ab]192 * @param[out] handle Place to write the handle.
193 * @return Error code.
194 */
[3121b5f]195static int get_my_device_handle(ddf_fun_t *fun, devman_handle_t *handle)
[8e4219ab]196{
197 assert(fun);
198 if (handle)
199 *handle = ddf_fun_get_handle(fun);
200 return EOK;
201}
202
[1845003]203/** Inbound communication interface function.
204 * @param fun DDF function.
205 * @param target Communication target.
206 * @param setup_data Data to use in setup stage (control transfers).
207 * @param data Pointer to data buffer.
208 * @param size Size of the data buffer.
209 * @param callback Function to call on communication end.
210 * @param arg Argument passed to the callback function.
211 * @return Error code.
212 */
213static int dev_read(ddf_fun_t *fun, usb_endpoint_t endpoint,
214 uint64_t setup_data, uint8_t *data, size_t size,
215 usbhc_iface_transfer_in_callback_t callback, void *arg)
216{
217 assert(fun);
218 usb_dev_t *usb_dev = ddf_fun_data_get(fun);
219 assert(usb_dev);
220 const usb_target_t target = {{
221 .address = usb_dev->address,
222 .endpoint = endpoint,
223 }};
224 return hcd_send_batch(dev_to_hcd(ddf_fun_get_dev(fun)), target,
225 USB_DIRECTION_IN, data, size, setup_data, callback, NULL, arg,
226 "READ");
227}
228
229/** Outbound communication interface function.
230 * @param fun DDF function.
231 * @param target Communication target.
232 * @param setup_data Data to use in setup stage (control transfers).
233 * @param data Pointer to data buffer.
234 * @param size Size of the data buffer.
235 * @param callback Function to call on communication end.
236 * @param arg Argument passed to the callback function.
237 * @return Error code.
238 */
239static int dev_write(ddf_fun_t *fun, usb_endpoint_t endpoint,
240 uint64_t setup_data, const uint8_t *data, size_t size,
241 usbhc_iface_transfer_out_callback_t callback, void *arg)
242{
243 assert(fun);
244 usb_dev_t *usb_dev = ddf_fun_data_get(fun);
245 assert(usb_dev);
246 const usb_target_t target = {{
247 .address = usb_dev->address,
248 .endpoint = endpoint,
249 }};
250 return hcd_send_batch(dev_to_hcd(ddf_fun_get_dev(fun)),
251 target, USB_DIRECTION_OUT, (uint8_t*)data, size, setup_data, NULL,
252 callback, arg, "WRITE");
253}
254
[2757247]255/** USB device interface */
[53332b5b]256static usb_iface_t usb_iface = {
[3121b5f]257 .get_my_device_handle = get_my_device_handle,
[8e4219ab]258
[56bd6f11]259 .reserve_default_address = reserve_default_address,
260 .release_default_address = release_default_address,
[4b8ecff]261
[56bd6f11]262 .device_enumerate = device_enumerate,
263 .device_remove = device_remove,
[4b8ecff]264
[d2cfe72]265 .register_endpoint = register_endpoint,
266 .unregister_endpoint = unregister_endpoint,
[4b8ecff]267
[1845003]268 .read = dev_read,
269 .write = dev_write,
[53332b5b]270};
[8e4219ab]271
[2757247]272/** Standard USB device interface) */
[53332b5b]273static ddf_dev_ops_t usb_ops = {
274 .interfaces[USB_DEV_IFACE] = &usb_iface,
275};
276
[2757247]277
278/* DDF HELPERS */
279
[237df2f]280#define GET_DEVICE_DESC(size) \
281{ \
282 .request_type = SETUP_REQUEST_TYPE_DEVICE_TO_HOST \
283 | (USB_REQUEST_TYPE_STANDARD << 5) \
284 | USB_REQUEST_RECIPIENT_DEVICE, \
285 .request = USB_DEVREQ_GET_DESCRIPTOR, \
286 .value = uint16_host2usb(USB_DESCTYPE_DEVICE << 8), \
287 .index = uint16_host2usb(0), \
288 .length = uint16_host2usb(size), \
289};
290
291#define SET_ADDRESS(address) \
292{ \
293 .request_type = SETUP_REQUEST_TYPE_HOST_TO_DEVICE \
294 | (USB_REQUEST_TYPE_STANDARD << 5) \
295 | USB_REQUEST_RECIPIENT_DEVICE, \
296 .request = USB_DEVREQ_SET_ADDRESS, \
297 .value = uint16_host2usb(address), \
298 .index = uint16_host2usb(0), \
299 .length = uint16_host2usb(0), \
300};
301
[2757247]302static int hcd_ddf_add_device(ddf_dev_t *parent, usb_dev_t *hub_dev,
303 unsigned port, usb_address_t address, usb_speed_t speed, const char *name,
[53332b5b]304 const match_id_list_t *mids)
305{
306 assert(parent);
307
[237df2f]308 char default_name[10] = { 0 }; /* usbxyz-ss */
[0a12879]309 if (!name) {
310 snprintf(default_name, sizeof(default_name) - 1,
[237df2f]311 "usb%u-%cs", address, usb_str_speed(speed)[0]);
[0a12879]312 name = default_name;
313 }
314
[53332b5b]315 ddf_fun_t *fun = ddf_fun_create(parent, fun_inner, name);
316 if (!fun)
317 return ENOMEM;
318 usb_dev_t *info = ddf_fun_data_alloc(fun, sizeof(usb_dev_t));
319 if (!info) {
320 ddf_fun_destroy(fun);
321 return ENOMEM;
322 }
323 info->address = address;
324 info->speed = speed;
325 info->fun = fun;
[2757247]326 info->port = port;
[53332b5b]327 link_initialize(&info->link);
[2757247]328 list_initialize(&info->devices);
[14dd4c9]329 fibril_mutex_initialize(&info->guard);
[53332b5b]330
331 ddf_fun_set_ops(fun, &usb_ops);
332 list_foreach(mids->ids, iter) {
333 match_id_t *mid = list_get_instance(iter, match_id_t, link);
334 ddf_fun_add_match_id(fun, mid->id, mid->score);
335 }
336
337 int ret = ddf_fun_bind(fun);
338 if (ret != EOK) {
339 ddf_fun_destroy(fun);
340 return ret;
341 }
342
[2757247]343 if (hub_dev) {
[14dd4c9]344 fibril_mutex_lock(&hub_dev->guard);
[2757247]345 list_append(&info->link, &hub_dev->devices);
[14dd4c9]346 fibril_mutex_unlock(&hub_dev->guard);
[2757247]347 } else {
348 hc_dev_t *hc_dev = dev_to_hc_dev(parent);
[14dd4c9]349 assert(hc_dev->root_hub == NULL);
350 hc_dev->root_hub = info;
[2757247]351 }
[53332b5b]352 return EOK;
353}
354
[237df2f]355#define ADD_MATCHID_OR_RETURN(list, sc, str, ...) \
356do { \
357 match_id_t *mid = malloc(sizeof(match_id_t)); \
358 if (!mid) { \
359 clean_match_ids(list); \
360 return ENOMEM; \
361 } \
362 char *id = NULL; \
363 int ret = asprintf(&id, str, ##__VA_ARGS__); \
364 if (ret < 0) { \
365 clean_match_ids(list); \
366 free(mid); \
367 return ENOMEM; \
368 } \
369 mid->score = sc; \
370 mid->id = id; \
371 add_match_id(list, mid); \
372} while (0)
[b995183]373
[237df2f]374/* This is a copy of lib/usbdev/src/recognise.c */
375static int create_match_ids(match_id_list_t *l,
376 usb_standard_device_descriptor_t *d)
377{
378 assert(l);
379 assert(d);
380
381 if (d->vendor_id != 0) {
382 /* First, with release number. */
383 ADD_MATCHID_OR_RETURN(l, 100,
384 "usb&vendor=%#04x&product=%#04x&release=%x.%x",
385 d->vendor_id, d->product_id, (d->device_version >> 8),
386 (d->device_version & 0xff));
387
388 /* Next, without release number. */
389 ADD_MATCHID_OR_RETURN(l, 90, "usb&vendor=%#04x&product=%#04x",
390 d->vendor_id, d->product_id);
391 }
392
393 /* Class match id */
394 ADD_MATCHID_OR_RETURN(l, 50, "usb&class=%s",
395 usb_str_class(d->device_class));
396
397 /* As a last resort, try fallback driver. */
398 ADD_MATCHID_OR_RETURN(l, 10, "usb&fallback");
399
400 return EOK;
401
402}
403
[2757247]404static int hcd_ddf_remove_device(ddf_dev_t *device, usb_dev_t *hub,
[0918382f]405 unsigned port)
[237df2f]406{
407 assert(device);
408
409 hcd_t *hcd = dev_to_hcd(device);
410 assert(hcd);
[b995183]411
412 hc_dev_t *hc_dev = dev_to_hc_dev(device);
413 assert(hc_dev);
414
[14dd4c9]415 fibril_mutex_lock(&hub->guard);
[b995183]416
417 usb_dev_t *victim = NULL;
418
[2757247]419 list_foreach(hub->devices, it) {
[b995183]420 victim = list_get_instance(it, usb_dev_t, link);
[0918382f]421 if (victim->port == port)
[b995183]422 break;
423 }
[0918382f]424 if (victim && victim->port == port) {
[b995183]425 list_remove(&victim->link);
[14dd4c9]426 fibril_mutex_unlock(&hub->guard);
[e6becb9]427 const int ret = ddf_fun_unbind(victim->fun);
428 if (ret == EOK) {
429 ddf_fun_destroy(victim->fun);
[2757247]430 hcd_release_address(hcd, victim->address);
[e6becb9]431 } else {
[0918382f]432 usb_log_warning("Failed to unbind device `%s': %s\n",
433 ddf_fun_get_name(victim->fun), str_error(ret));
[e6becb9]434 }
[b995183]435 return EOK;
436 }
437 return ENOENT;
438}
439
[0918382f]440static int hcd_ddf_new_device(ddf_dev_t *device, usb_dev_t *hub, unsigned port)
[b995183]441{
442 assert(device);
443
444 hcd_t *hcd = dev_to_hcd(device);
445 assert(hcd);
446
[237df2f]447 usb_speed_t speed = USB_SPEED_MAX;
448
449 /* This checks whether the default address is reserved and gets speed */
[423c749]450 int ret = usb_endpoint_manager_get_info_by_address(&hcd->ep_manager,
[059d507]451 USB_ADDRESS_DEFAULT, &speed);
[237df2f]452 if (ret != EOK) {
453 return ret;
454 }
455
456 static const usb_target_t default_target = {{
457 .address = USB_ADDRESS_DEFAULT,
458 .endpoint = 0,
459 }};
460
461 const usb_address_t address = hcd_request_address(hcd, speed);
462 if (address < 0)
463 return address;
464
465 const usb_target_t target = {{
466 .address = address,
467 .endpoint = 0,
468 }};
469
470 /* Add default pipe on default address */
[ec6766a]471 ret = hcd_add_ep(hcd,
[237df2f]472 default_target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,
473 CTRL_PIPE_MIN_PACKET_SIZE, CTRL_PIPE_MIN_PACKET_SIZE);
474
475 if (ret != EOK) {
476 hcd_release_address(hcd, address);
477 return ret;
478 }
479
480 /* Get max packet size for default pipe */
481 usb_standard_device_descriptor_t desc = { 0 };
482 static const usb_device_request_setup_packet_t get_device_desc_8 =
483 GET_DEVICE_DESC(CTRL_PIPE_MIN_PACKET_SIZE);
484
485 // TODO CALLBACKS
486 ssize_t got = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_IN,
487 &desc, CTRL_PIPE_MIN_PACKET_SIZE, *(uint64_t *)&get_device_desc_8,
488 "read first 8 bytes of dev descriptor");
489
490 if (got != CTRL_PIPE_MIN_PACKET_SIZE) {
491 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);
492 hcd_release_address(hcd, address);
493 return got < 0 ? got : EOVERFLOW;
494 }
495
496 /* Register EP on the new address */
497 ret = hcd_add_ep(hcd, target, USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL,
498 desc.max_packet_size, desc.max_packet_size);
499 if (ret != EOK) {
500 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);
501 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
502 hcd_release_address(hcd, address);
503 return ret;
504 }
505
506 /* Set new address */
507 const usb_device_request_setup_packet_t set_address =
508 SET_ADDRESS(target.address);
509
510 got = hcd_send_batch_sync(hcd, default_target, USB_DIRECTION_OUT,
511 NULL, 0, *(uint64_t *)&set_address, "set address");
512
513 hcd_remove_ep(hcd, default_target, USB_DIRECTION_BOTH);
514
515 if (got != 0) {
516 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
517 hcd_release_address(hcd, address);
518 return got;
519 }
520
521 /* Get std device descriptor */
522 static const usb_device_request_setup_packet_t get_device_desc =
523 GET_DEVICE_DESC(sizeof(desc));
524
525 got = hcd_send_batch_sync(hcd, target, USB_DIRECTION_IN,
526 &desc, sizeof(desc), *(uint64_t *)&get_device_desc,
527 "read device descriptor");
528 if (ret != EOK) {
529 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
530 hcd_release_address(hcd, target.address);
531 return got < 0 ? got : EOVERFLOW;
532 }
[b995183]533
[237df2f]534 /* Create match ids from the device descriptor */
535 match_id_list_t mids;
536 init_match_ids(&mids);
537
538 ret = create_match_ids(&mids, &desc);
539 if (ret != EOK) {
540 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
541 hcd_release_address(hcd, target.address);
542 return ret;
543 }
544
[b995183]545 /* Register device */
[2757247]546 ret = hcd_ddf_add_device(device, hub, port, address, speed, NULL, &mids);
[237df2f]547 clean_match_ids(&mids);
548 if (ret != EOK) {
549 hcd_remove_ep(hcd, target, USB_DIRECTION_BOTH);
550 hcd_release_address(hcd, target.address);
551 }
552
553 return ret;
554}
555
556/** Announce root hub to the DDF
557 *
558 * @param[in] device Host controller ddf device
559 * @return Error code
560 */
[cb8ede1]561int hcd_ddf_setup_root_hub(ddf_dev_t *device)
[237df2f]562{
563 assert(device);
564 hcd_t *hcd = dev_to_hcd(device);
565 assert(hcd);
566
[cb8ede1]567 const usb_speed_t speed = hcd->ep_manager.max_speed;
568
[237df2f]569 hcd_reserve_default_address(hcd, speed);
[0918382f]570 const int ret = hcd_ddf_new_device(device, NULL, 0);
[237df2f]571 hcd_release_default_address(hcd);
572 return ret;
573}
574
[53332b5b]575/** Initialize hc structures.
576 *
577 * @param[in] device DDF instance of the device to use.
578 *
[2b0929e]579 * This function does all the ddf work for hc driver.
[53332b5b]580 */
[e991937]581int hcd_ddf_setup_hc(ddf_dev_t *device, usb_speed_t max_speed,
582 size_t bw, bw_count_func_t bw_count)
[53332b5b]583{
[e991937]584 assert(device);
[53332b5b]585
586 hc_dev_t *instance = ddf_dev_data_alloc(device, sizeof(hc_dev_t));
587 if (instance == NULL) {
[2b0929e]588 usb_log_error("Failed to allocate HCD ddf structure.\n");
[53332b5b]589 return ENOMEM;
590 }
[14dd4c9]591 instance->root_hub = NULL;
[e991937]592 hcd_init(&instance->hcd, max_speed, bw, bw_count);
[53332b5b]593
[e991937]594 int ret = ENOMEM;
595 instance->ctl_fun = ddf_fun_create(device, fun_exposed, "ctl");
596 if (!instance->ctl_fun) {
[cce3228]597 usb_log_error("Failed to create HCD ddf fun.\n");
598 goto err_destroy_fun;
599 }
600
[e991937]601 ret = ddf_fun_bind(instance->ctl_fun);
[cce3228]602 if (ret != EOK) {
[e991937]603 usb_log_error("Failed to bind ctl_fun: %s.\n", str_error(ret));
[cce3228]604 goto err_destroy_fun;
605 }
606
[e991937]607 ret = ddf_fun_add_to_category(instance->ctl_fun, USB_HC_CATEGORY);
[cce3228]608 if (ret != EOK) {
609 usb_log_error("Failed to add fun to category: %s.\n",
610 str_error(ret));
[e991937]611 ddf_fun_unbind(instance->ctl_fun);
[cce3228]612 goto err_destroy_fun;
613 }
[53332b5b]614
615 /* HC should be ok at this point (except it can't do anything) */
616 return EOK;
[cce3228]617
618err_destroy_fun:
[e991937]619 ddf_fun_destroy(instance->ctl_fun);
620 instance->ctl_fun = NULL;
[cce3228]621 return ret;
[53332b5b]622}
623
[e991937]624void hcd_ddf_clean_hc(ddf_dev_t *device)
625{
626 assert(device);
627 hc_dev_t *hc = dev_to_hc_dev(device);
628 assert(hc);
629 const int ret = ddf_fun_unbind(hc->ctl_fun);
630 if (ret == EOK)
631 ddf_fun_destroy(hc->ctl_fun);
632}
[53332b5b]633/**
634 * @}
635 */
Note: See TracBrowser for help on using the repository browser.