source: mainline/uspace/drv/usbhub/usbhub.c@ 3036735

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3036735 was a7528a16, checked in by Matus Dekanek <smekideki@…>, 15 years ago

speed on port is low/full/high

  • Property mode set to 100644
File size: 20.5 KB
Line 
1/*
2 * Copyright (c) 2010 Matus Dekanek
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 drvusbhub
29 * @{
30 */
31/** @file
32 * @brief usb hub main functionality
33 */
34
35#include <ddf/driver.h>
36#include <bool.h>
37#include <errno.h>
38#include <str_error.h>
39
40#include <usb_iface.h>
41#include <usb/ddfiface.h>
42#include <usb/descriptor.h>
43#include <usb/recognise.h>
44#include <usb/request.h>
45#include <usb/classes/hub.h>
46#include <stdio.h>
47
48#include "usbhub.h"
49#include "usbhub_private.h"
50#include "port_status.h"
51#include "usb/usb.h"
52#include "usb/pipes.h"
53#include "usb/classes/classes.h"
54
55static ddf_dev_ops_t hub_device_ops = {
56 .interfaces[USB_DEV_IFACE] = &usb_iface_hub_impl
57};
58
59/** Hub status-change endpoint description
60 *
61 * For more see usb hub specification in 11.15.1 of
62 */
63static usb_endpoint_description_t status_change_endpoint_description = {
64 .transfer_type = USB_TRANSFER_INTERRUPT,
65 .direction = USB_DIRECTION_IN,
66 .interface_class = USB_CLASS_HUB,
67 .interface_subclass = 0,
68 .interface_protocol = 0,
69 .flags = 0
70};
71
72int usb_hub_control_loop(void * hub_info_param){
73 usb_hub_info_t * hub_info = (usb_hub_info_t*)hub_info_param;
74 int errorCode = EOK;
75
76 while(errorCode == EOK){
77 errorCode = usb_hub_check_hub_changes(hub_info);
78 async_usleep(1000 * 1000 );/// \TODO proper number once
79 }
80 usb_log_error("something in ctrl loop went wrong, errno %d",errorCode);
81
82 return 0;
83}
84
85
86//*********************************************
87//
88// hub driver code, initialization
89//
90//*********************************************
91
92/**
93 * Initialize connnections to host controller, device, and device
94 * control endpoint
95 * @param hub
96 * @param device
97 * @return
98 */
99static int usb_hub_init_communication(usb_hub_info_t * hub){
100 usb_log_debug("Initializing hub USB communication (hub->device->handle=%zu).\n", hub->device->handle);
101 int opResult;
102 opResult = usb_device_connection_initialize_from_device(
103 &hub->device_connection,
104 hub->device);
105 if(opResult != EOK){
106 usb_log_error("could not initialize connection to hc, errno %d",opResult);
107 return opResult;
108 }
109 usb_log_debug("Initializing USB wire abstraction.\n");
110 opResult = usb_hc_connection_initialize_from_device(&hub->connection,
111 hub->device);
112 if(opResult != EOK){
113 usb_log_error("could not initialize connection to device, errno %d",
114 opResult);
115 return opResult;
116 }
117 usb_log_debug("Initializing default control pipe.\n");
118 opResult = usb_endpoint_pipe_initialize_default_control(&hub->endpoints.control,
119 &hub->device_connection);
120 if(opResult != EOK){
121 usb_log_error("could not initialize connection to device endpoint, errno %d",
122 opResult);
123 return opResult;
124 }
125
126 opResult = usb_endpoint_pipe_probe_default_control(&hub->endpoints.control);
127 if (opResult != EOK) {
128 usb_log_error("failed probing endpoint 0, %d", opResult);
129 return opResult;
130 }
131
132 return EOK;
133}
134
135/**
136 * When entering this function, hub->endpoints.control should be active.
137 * @param hub
138 * @return
139 */
140static int usb_hub_process_configuration_descriptors(
141 usb_hub_info_t * hub){
142 if(hub==NULL) {
143 return EINVAL;
144 }
145 int opResult;
146
147 //device descriptor
148 usb_standard_device_descriptor_t std_descriptor;
149 opResult = usb_request_get_device_descriptor(&hub->endpoints.control,
150 &std_descriptor);
151 if(opResult!=EOK){
152 usb_log_error("could not get device descriptor, %d",opResult);
153 return opResult;
154 }
155 usb_log_info("hub has %d configurations",
156 std_descriptor.configuration_count);
157 if(std_descriptor.configuration_count<1){
158 usb_log_error("THERE ARE NO CONFIGURATIONS AVAILABLE");
159 //shouldn`t I return?
160 }
161
162 /* Retrieve full configuration descriptor. */
163 uint8_t *descriptors = NULL;
164 size_t descriptors_size = 0;
165 opResult = usb_request_get_full_configuration_descriptor_alloc(
166 &hub->endpoints.control, 0,
167 (void **) &descriptors, &descriptors_size);
168 if (opResult != EOK) {
169 usb_log_error("Could not get configuration descriptor: %s.\n",
170 str_error(opResult));
171 return opResult;
172 }
173 usb_standard_configuration_descriptor_t *config_descriptor
174 = (usb_standard_configuration_descriptor_t *) descriptors;
175
176 /* Set configuration. */
177 opResult = usb_request_set_configuration(&hub->endpoints.control,
178 config_descriptor->configuration_number);
179
180 if (opResult != EOK) {
181 usb_log_error("Failed to set hub configuration: %s.\n",
182 str_error(opResult));
183 return opResult;
184 }
185 usb_log_debug("\tused configuration %d",
186 config_descriptor->configuration_number);
187
188 usb_endpoint_mapping_t endpoint_mapping[1] = {
189 {
190 .pipe = &hub->endpoints.status_change,
191 .description = &status_change_endpoint_description,
192 .interface_no =
193 usb_device_get_assigned_interface(hub->device)
194 }
195 };
196 opResult = usb_endpoint_pipe_initialize_from_configuration(
197 endpoint_mapping, 1,
198 descriptors, descriptors_size,
199 &hub->device_connection);
200 if (opResult != EOK) {
201 usb_log_error("Failed to initialize status change pipe: %s",
202 str_error(opResult));
203 return opResult;
204 }
205 if (!endpoint_mapping[0].present) {
206 usb_log_error("Not accepting device, " \
207 "cannot understand what is happenning");
208 return EREFUSED;
209 }
210
211 free(descriptors);
212 return EOK;
213
214}
215
216
217/**
218 * Create hub representation from device information.
219 * @param device
220 * @return pointer to created structure or NULL in case of error
221 */
222usb_hub_info_t * usb_create_hub_info(ddf_dev_t * device) {
223 usb_hub_info_t* result = usb_new(usb_hub_info_t);
224 result->device = device;
225 int opResult;
226 opResult = usb_hub_init_communication(result);
227 if(opResult != EOK){
228 free(result);
229 return NULL;
230 }
231
232 //result->device = device;
233 result->port_count = -1;
234 result->device = device;
235 result->is_default_address_used = false;
236
237 //result->usb_device = usb_new(usb_hcd_attached_device_info_t);
238 size_t received_size;
239
240 // get hub descriptor
241 usb_log_debug("creating serialized descripton");
242 void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
243 usb_hub_descriptor_t * descriptor;
244 usb_log_debug("starting control transaction");
245 usb_endpoint_pipe_start_session(&result->endpoints.control);
246 opResult = usb_request_set_configuration(&result->endpoints.control, 1);
247 assert(opResult == EOK);
248
249 opResult = usb_request_get_descriptor(&result->endpoints.control,
250 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
251 USB_DESCTYPE_HUB,
252 0, 0, serialized_descriptor,
253 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
254 usb_endpoint_pipe_end_session(&result->endpoints.control);
255
256 if (opResult != EOK) {
257 usb_log_error("failed when receiving hub descriptor, badcode = %d",
258 opResult);
259 free(serialized_descriptor);
260 free(result);
261 return NULL;
262 }
263 usb_log_debug2("deserializing descriptor");
264 descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
265 if(descriptor==NULL){
266 usb_log_warning("could not deserialize descriptor ");
267 free(result);
268 return NULL;
269 }
270
271 usb_log_info("setting port count to %d",descriptor->ports_count);
272 result->port_count = descriptor->ports_count;
273 result->attached_devs = (usb_hc_attached_device_t*)
274 malloc((result->port_count+1) * sizeof(usb_hc_attached_device_t));
275 int i;
276 for(i=0;i<result->port_count+1;++i){
277 result->attached_devs[i].handle=0;
278 result->attached_devs[i].address=0;
279 }
280 usb_log_debug2("freeing data");
281 free(serialized_descriptor);
282 free(descriptor->devices_removable);
283 free(descriptor);
284
285 //finish
286
287 usb_log_info("hub info created");
288
289 return result;
290}
291
292/**
293 * Create hub representation and add it into hub list
294 * @param dev
295 * @return
296 */
297int usb_add_hub_device(ddf_dev_t *dev) {
298 usb_log_info("add_hub_device(handle=%d)", (int) dev->handle);
299
300 //dev->ops = &hub_device_ops;
301 (void) hub_device_ops;
302
303 usb_hub_info_t * hub_info = usb_create_hub_info(dev);
304 if(!hub_info){
305 return EINTR;
306 }
307
308 int opResult;
309
310 //perform final configurations
311 usb_endpoint_pipe_start_session(&hub_info->endpoints.control);
312 // process descriptors
313 opResult = usb_hub_process_configuration_descriptors(hub_info);
314 if(opResult != EOK){
315 usb_log_error("could not get configuration descriptors, %d",
316 opResult);
317 return opResult;
318 }
319 //power ports
320 usb_device_request_setup_packet_t request;
321 int port;
322 for (port = 1; port < hub_info->port_count+1; ++port) {
323 usb_hub_set_power_port_request(&request, port);
324 opResult = usb_endpoint_pipe_control_write(&hub_info->endpoints.control,
325 &request,sizeof(usb_device_request_setup_packet_t), NULL, 0);
326 usb_log_info("powering port %d",port);
327 if (opResult != EOK) {
328 usb_log_warning("something went wrong when setting hub`s %dth port", port);
329 }
330 }
331 //ports powered, hub seems to be enabled
332 usb_endpoint_pipe_end_session(&hub_info->endpoints.control);
333
334 //add the hub to list
335 //is this needed now?
336 fibril_mutex_lock(&usb_hub_list_lock);
337 usb_lst_append(&usb_hub_list, hub_info);
338 fibril_mutex_unlock(&usb_hub_list_lock);
339 usb_log_debug("hub info added to list");
340
341 usb_log_debug("adding to ddf");
342 ddf_fun_t *hub_fun = ddf_fun_create(dev, fun_exposed, "hub");
343 assert(hub_fun != NULL);
344 hub_fun->ops = NULL;
345
346 int rc = ddf_fun_bind(hub_fun);
347 assert(rc == EOK);
348 rc = ddf_fun_add_to_class(hub_fun, "hub");
349 assert(rc == EOK);
350
351 fid_t fid = fibril_create(usb_hub_control_loop, hub_info);
352 if (fid == 0) {
353 usb_log_error("failed to start monitoring fibril for new hub");
354 return ENOMEM;
355 }
356 fibril_add_ready(fid);
357
358 usb_log_debug("hub fibril created");
359 //(void)hub_info;
360 //usb_hub_check_hub_changes();
361
362 usb_log_info("hub dev added");
363 //address is lost...
364 usb_log_debug("\taddress %d, has %d ports ",
365 //hub_info->endpoints.control.,
366 hub_info->port_count);
367
368 return EOK;
369 //return ENOTSUP;
370}
371
372
373//*********************************************
374//
375// hub driver code, main loop
376//
377//*********************************************
378
379/**
380 * release default address used by given hub
381 *
382 * Also unsets hub->is_default_address_used. Convenience wrapper function.
383 * @note hub->connection MUST be open for communication
384 * @param hub hub representation
385 * @return error code
386 */
387static int usb_hub_release_default_address(usb_hub_info_t * hub){
388 int opResult = usb_hc_release_default_address(&hub->connection);
389 if(opResult!=EOK){
390 usb_log_error("could not release default address, errno %d",opResult);
391 return opResult;
392 }
393 hub->is_default_address_used = false;
394 return EOK;
395}
396
397/**
398 * Reset the port with new device and reserve the default address.
399 * @param hc
400 * @param port
401 * @param target
402 */
403static void usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port,
404 usb_speed_t speed) {
405 //if this hub already uses default address, it cannot request it once more
406 if(hub->is_default_address_used) return;
407
408 usb_device_request_setup_packet_t request;
409 int opResult;
410 usb_log_info("some connection changed");
411 assert(hub->endpoints.control.hc_phone);
412 //get default address
413 opResult = usb_hc_reserve_default_address(&hub->connection, speed);
414
415 if (opResult != EOK) {
416 usb_log_warning("cannot assign default address, it is probably used %d",
417 opResult);
418 return;
419 }
420 hub->is_default_address_used = true;
421 //reset port
422 usb_hub_set_reset_port_request(&request, port);
423 opResult = usb_endpoint_pipe_control_write(
424 &hub->endpoints.control,
425 &request,sizeof(usb_device_request_setup_packet_t),
426 NULL, 0
427 );
428 if (opResult != EOK) {
429 usb_log_error("something went wrong when reseting a port %d",opResult);
430 //usb_hub_release_default_address(hc);
431 usb_hub_release_default_address(hub);
432 }
433}
434
435/**
436 * Finalize adding new device after port reset
437 * @param hc
438 * @param port
439 * @param target
440 */
441static void usb_hub_finalize_add_device( usb_hub_info_t * hub,
442 uint16_t port, bool isLowSpeed) {
443
444 int opResult;
445 usb_log_info("finalizing add device");
446 opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
447 port, USB_HUB_FEATURE_C_PORT_RESET);
448
449 if (opResult != EOK) {
450 usb_log_error("failed to clear port reset feature");
451 usb_hub_release_default_address(hub);
452 return;
453 }
454 //create connection to device
455 usb_endpoint_pipe_t new_device_pipe;
456 usb_device_connection_t new_device_connection;
457 usb_device_connection_initialize_on_default_address(
458 &new_device_connection,
459 &hub->connection
460 );
461 usb_endpoint_pipe_initialize_default_control(
462 &new_device_pipe,
463 &new_device_connection);
464 usb_endpoint_pipe_probe_default_control(&new_device_pipe);
465 /// \TODO get highspeed info
466 usb_speed_t speed = isLowSpeed?USB_SPEED_LOW:USB_SPEED_FULL;
467
468
469 /* Request address from host controller. */
470 usb_address_t new_device_address = usb_hc_request_address(
471 &hub->connection,
472 speed
473 );
474 if (new_device_address < 0) {
475 usb_log_error("failed to get free USB address");
476 opResult = new_device_address;
477 usb_hub_release_default_address(hub);
478 return;
479 }
480 usb_log_info("setting new address %d",new_device_address);
481 //opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
482 // new_device_address);
483 usb_endpoint_pipe_start_session(&new_device_pipe);
484 opResult = usb_request_set_address(&new_device_pipe,new_device_address);
485 usb_endpoint_pipe_end_session(&new_device_pipe);
486 if (opResult != EOK) {
487 usb_log_error("could not set address for new device %d",opResult);
488 usb_hub_release_default_address(hub);
489 return;
490 }
491
492
493 //opResult = usb_hub_release_default_address(hc);
494 opResult = usb_hub_release_default_address(hub);
495 if(opResult!=EOK){
496 return;
497 }
498
499 devman_handle_t child_handle;
500 //??
501 opResult = usb_device_register_child_in_devman(new_device_address,
502 hub->connection.hc_handle, hub->device, &child_handle,
503 NULL, NULL, NULL);
504
505 if (opResult != EOK) {
506 usb_log_error("could not start driver for new device %d",opResult);
507 return;
508 }
509 hub->attached_devs[port].handle = child_handle;
510 hub->attached_devs[port].address = new_device_address;
511
512 //opResult = usb_drv_bind_address(hc, new_device_address, child_handle);
513 opResult = usb_hc_register_device(
514 &hub->connection,
515 &hub->attached_devs[port]);
516 if (opResult != EOK) {
517 usb_log_error("could not assign address of device in hcd %d",opResult);
518 return;
519 }
520 usb_log_info("new device address %d, handle %zu",
521 new_device_address, child_handle);
522
523}
524
525/**
526 * Unregister device address in hc
527 * @param hc
528 * @param port
529 * @param target
530 */
531static void usb_hub_removed_device(
532 usb_hub_info_t * hub,uint16_t port) {
533
534 /** \TODO remove device from device manager - not yet implemented in
535 * devide manager
536 */
537
538 //close address
539 if(hub->attached_devs[port].address!=0){
540 /*uncomment this code to use it when DDF allows device removal
541 opResult = usb_hc_unregister_device(
542 &hub->connection, hub->attached_devs[port].address);
543 if(opResult != EOK) {
544 dprintf(USB_LOG_LEVEL_WARNING, "could not release address of " \
545 "removed device: %d", opResult);
546 }
547 hub->attached_devs[port].address = 0;
548 hub->attached_devs[port].handle = 0;
549 */
550 }else{
551 usb_log_warning("this is strange, disconnected device had no address");
552 //device was disconnected before it`s port was reset - return default address
553 usb_hub_release_default_address(hub);
554 }
555}
556
557
558/**
559 * Process over current condition on port.
560 *
561 * Turn off the power on the port.
562 *
563 * @param hub
564 * @param port
565 */
566static void usb_hub_over_current( usb_hub_info_t * hub,
567 uint16_t port){
568 int opResult;
569 opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
570 port, USB_HUB_FEATURE_PORT_POWER);
571 if(opResult!=EOK){
572 usb_log_error("cannot power off port %d; %d",
573 port, opResult);
574 }
575}
576
577/**
578 * Process interrupts on given hub port
579 * @param hc
580 * @param port
581 * @param target
582 */
583static void usb_hub_process_interrupt(usb_hub_info_t * hub,
584 uint16_t port) {
585 usb_log_debug("interrupt at port %d", port);
586 //determine type of change
587 usb_endpoint_pipe_t *pipe = &hub->endpoints.control;
588
589 int opResult;
590
591 usb_port_status_t status;
592 size_t rcvd_size;
593 usb_device_request_setup_packet_t request;
594 //int opResult;
595 usb_hub_set_port_status_request(&request, port);
596 //endpoint 0
597
598 opResult = usb_endpoint_pipe_control_read(
599 pipe,
600 &request, sizeof(usb_device_request_setup_packet_t),
601 &status, 4, &rcvd_size
602 );
603 if (opResult != EOK) {
604 usb_log_error("could not get port status");
605 return;
606 }
607 if (rcvd_size != sizeof (usb_port_status_t)) {
608 usb_log_error("received status has incorrect size");
609 return;
610 }
611 //something connected/disconnected
612 if (usb_port_connect_change(&status)) {
613 opResult = usb_hub_clear_port_feature(pipe,
614 port, USB_HUB_FEATURE_C_PORT_CONNECTION);
615 // TODO: check opResult
616 if (usb_port_dev_connected(&status)) {
617 usb_log_info("some connection changed");
618 usb_hub_init_add_device(hub, port, usb_port_speed(&status));
619 } else {
620 usb_hub_removed_device(hub, port);
621 }
622 }
623 //over current
624 if (usb_port_overcurrent_change(&status)) {
625 //check if it was not auto-resolved
626 if(usb_port_over_current(&status)){
627 usb_hub_over_current(hub,port);
628 }else{
629 usb_log_info("over current condition was auto-resolved on port %d",
630 port);
631 }
632 }
633 //port reset
634 if (usb_port_reset_completed(&status)) {
635 usb_log_info("port reset complete");
636 if (usb_port_enabled(&status)) {
637 usb_hub_finalize_add_device(hub, port, usb_port_low_speed(&status));
638 } else {
639 usb_log_warning("port reset, but port still not enabled");
640 }
641 }
642
643 usb_port_set_connect_change(&status, false);
644 usb_port_set_reset(&status, false);
645 usb_port_set_reset_completed(&status, false);
646 usb_port_set_dev_connected(&status, false);
647 if (status>>16) {
648 usb_log_info("there was some unsupported change on port %d: %X",
649 port,status);
650
651 }
652 /// \TODO handle other changes - is there any?
653}
654
655/**
656 * Check changes on particular hub
657 * @param hub_info_param pointer to usb_hub_info_t structure
658 * @return error code if there is problem when initializing communication with
659 * hub, EOK otherwise
660 */
661int usb_hub_check_hub_changes(usb_hub_info_t * hub_info){
662 int opResult;
663 opResult = usb_endpoint_pipe_start_session(&hub_info->endpoints.status_change);
664 if(opResult != EOK){
665 usb_log_error("could not initialize communication for hub; %d",
666 opResult);
667 return opResult;
668 }
669
670 size_t port_count = hub_info->port_count;
671
672 /// FIXME: count properly
673 size_t byte_length = ((port_count+1) / 8) + 1;
674 void *change_bitmap = malloc(byte_length);
675 size_t actual_size;
676
677 /*
678 * Send the request.
679 */
680 opResult = usb_endpoint_pipe_read(
681 &hub_info->endpoints.status_change,
682 change_bitmap, byte_length, &actual_size
683 );
684
685 if (opResult != EOK) {
686 free(change_bitmap);
687 usb_log_warning("something went wrong while getting status of hub");
688 usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
689 return opResult;
690 }
691 unsigned int port;
692 opResult = usb_endpoint_pipe_start_session(&hub_info->endpoints.control);
693 if(opResult!=EOK){
694 usb_log_error("could not start control pipe session %d", opResult);
695 usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
696 return opResult;
697 }
698 opResult = usb_hc_connection_open(&hub_info->connection);
699 if(opResult!=EOK){
700 usb_log_error("could not start host controller session %d",
701 opResult);
702 usb_endpoint_pipe_end_session(&hub_info->endpoints.control);
703 usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
704 return opResult;
705 }
706
707 ///todo, opresult check, pre obe konekce
708 for (port = 1; port < port_count+1; ++port) {
709 bool interrupt =
710 (((uint8_t*) change_bitmap)[port / 8] >> (port % 8)) % 2;
711 if (interrupt) {
712 usb_hub_process_interrupt(
713 hub_info, port);
714 }
715 }
716 usb_hc_connection_close(&hub_info->connection);
717 usb_endpoint_pipe_end_session(&hub_info->endpoints.control);
718 usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
719 free(change_bitmap);
720 return EOK;
721}
722
723
724
725/**
726 * @}
727 */
Note: See TracBrowser for help on using the repository browser.