Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/usbhub/usbhub.c

    rf35b294 rc50941f  
    3737#include <errno.h>
    3838#include <str_error.h>
    39 #include <inttypes.h>
    4039
    4140#include <usb_iface.h>
     
    5453#include "usb/classes/classes.h"
    5554
    56 
    57 static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev);
    58 
    59 static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info);
    60 
    61 static int usb_hub_set_configuration(usb_hub_info_t * hub_info);
    62 
    63 static int usb_hub_start_hub_fibril(usb_hub_info_t * hub_info);
    64 
    65 static int usb_process_hub_over_current(usb_hub_info_t * hub_info,
    66     usb_hub_status_t status);
    67 
    68 static int usb_process_hub_power_change(usb_hub_info_t * hub_info,
    69     usb_hub_status_t status);
    70 
    71 static void usb_hub_process_global_interrupt(usb_hub_info_t * hub_info);
    72 
    73 
    74 /// \TODO malloc checking
     55static int usb_hub_trigger_connecting_non_removable_devices(
     56                usb_hub_info_t * hub, usb_hub_descriptor_t * descriptor);
     57
    7558
    7659//*********************************************
     
    8164
    8265/**
    83  * Initialize hub device driver fibril
    84  *
    85  * Creates hub representation and fibril that periodically checks hub`s status.
    86  * Hub representation is passed to the fibril.
    87  * @param usb_dev generic usb device information
    88  * @return error code
    89  */
    90 int usb_hub_add_device(usb_device_t * usb_dev) {
    91         if (!usb_dev) return EINVAL;
    92         usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev);
    93         //create hc connection
    94         usb_log_debug("Initializing USB wire abstraction.\n");
    95         int opResult = usb_hc_connection_initialize_from_device(
    96             &hub_info->connection,
    97             hub_info->usb_device->ddf_dev);
    98         if (opResult != EOK) {
    99                 usb_log_error("could not initialize connection to device, "
    100                     "errno %d\n",
    101                     opResult);
    102                 free(hub_info);
    103                 return opResult;
    104         }
    105 
    106         usb_pipe_start_session(hub_info->control_pipe);
    107         //set hub configuration
    108         opResult = usb_hub_set_configuration(hub_info);
    109         if (opResult != EOK) {
    110                 usb_log_error("could not set hub configuration, errno %d\n",
    111                     opResult);
    112                 free(hub_info);
    113                 return opResult;
    114         }
    115         //get port count and create attached_devs
    116         opResult = usb_hub_process_hub_specific_info(hub_info);
    117         if (opResult != EOK) {
    118                 usb_log_error("could process hub specific info, errno %d\n",
    119                     opResult);
    120                 free(hub_info);
    121                 return opResult;
    122         }
    123         usb_pipe_end_session(hub_info->control_pipe);
    124 
    125         /// \TODO what is this?
    126         usb_log_debug("Creating `hub' function.\n");
    127         ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
    128             fun_exposed, "hub");
    129         assert(hub_fun != NULL);
    130         hub_fun->ops = NULL;
    131 
    132         opResult = ddf_fun_bind(hub_fun);
    133         assert(opResult == EOK);
    134         opResult = ddf_fun_add_to_class(hub_fun, "hub");
    135         assert(opResult == EOK);
    136 
    137         opResult = usb_hub_start_hub_fibril(hub_info);
    138         if(opResult!=EOK)
    139                 free(hub_info);
    140         return opResult;
    141 }
    142 
    143 
    144 /** Callback for polling hub for changes.
    145  *
    146  * @param dev Device where the change occured.
    147  * @param change_bitmap Bitmap of changed ports.
    148  * @param change_bitmap_size Size of the bitmap in bytes.
    149  * @param arg Custom argument, points to @c usb_hub_info_t.
    150  * @return Whether to continue polling.
    151  */
    152 bool hub_port_changes_callback(usb_device_t *dev,
    153     uint8_t *change_bitmap, size_t change_bitmap_size, void *arg) {
    154         usb_hub_info_t *hub = (usb_hub_info_t *) arg;
    155 
    156         /* FIXME: check that we received enough bytes. */
    157         if (change_bitmap_size == 0) {
    158                 goto leave;
    159         }
    160 
    161         bool change;
    162         change = ((uint8_t*) change_bitmap)[0] & 1;
    163         if (change) {
    164                 usb_hub_process_global_interrupt(hub);
    165         }
    166 
    167         size_t port;
    168         for (port = 1; port < hub->port_count + 1; port++) {
    169                 bool change = (change_bitmap[port / 8] >> (port % 8)) % 2;
    170                 if (change) {
    171                         usb_hub_process_interrupt(hub, port);
    172                 }
    173         }
    174 leave:
    175         /* FIXME: proper interval. */
    176         async_usleep(1000 * 1000 * 10);
    177 
    178         return true;
    179 }
    180 
    181 /**
    182  * release default address used by given hub
    183  *
    184  * Also unsets hub->is_default_address_used. Convenience wrapper function.
    185  * @note hub->connection MUST be open for communication
    186  * @param hub hub representation
    187  * @return error code
    188  */
    189 int usb_hub_release_default_address(usb_hub_info_t * hub) {
    190         int opResult = usb_hc_release_default_address(&hub->connection);
    191         if (opResult != EOK) {
    192                 usb_log_error("could not release default address, errno %d\n",
    193                     opResult);
    194                 return opResult;
    195         }
    196         hub->is_default_address_used = false;
    197         return EOK;
    198 }
    199 
    200 
    201 //*********************************************
    202 //
    203 //  support functions
    204 //
    205 //*********************************************
    206 
    207 /**
    20866 * create usb_hub_info_t structure
    20967 *
     
    21371 */
    21472static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev) {
    215         usb_hub_info_t * result = malloc(sizeof(usb_hub_info_t));
    216         if (!result) return NULL;
     73        usb_hub_info_t * result = usb_new(usb_hub_info_t);
     74        if(!result) return NULL;
    21775        result->usb_device = usb_dev;
    21876        result->status_change_pipe = usb_dev->pipes[0].pipe;
     
    23290 * @return error code
    23391 */
    234 static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info) {
     92static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info){
    23593        // get hub descriptor
    23694        usb_log_debug("creating serialized descriptor\n");
    23795        void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
    23896        usb_hub_descriptor_t * descriptor;
    239         int opResult;
    240 
     97
     98        /* this was one fix of some bug, should not be needed anymore
     99         * these lines allow to reset hub once more, it can be used as
     100         * brute-force initialization for non-removable devices
     101        int opResult = usb_request_set_configuration(&result->endpoints.control, 1);
     102        if(opResult!=EOK){
     103                usb_log_error("could not set default configuration, errno %d",opResult);
     104                return opResult;
     105        }
     106         */
    241107        size_t received_size;
    242         opResult = usb_request_get_descriptor(hub_info->control_pipe,
    243             USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
    244             USB_DESCTYPE_HUB, 0, 0, serialized_descriptor,
    245             USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
     108        int opResult = usb_request_get_descriptor(&hub_info->usb_device->ctrl_pipe,
     109                        USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
     110                        USB_DESCTYPE_HUB,
     111                        0, 0, serialized_descriptor,
     112                        USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
    246113
    247114        if (opResult != EOK) {
    248                 usb_log_error("failed when receiving hub descriptor, "
    249                     "badcode = %d\n",
    250                     opResult);
     115                usb_log_error("failed when receiving hub descriptor, badcode = %d\n",
     116                                opResult);
    251117                free(serialized_descriptor);
    252118                return opResult;
     
    254120        usb_log_debug2("deserializing descriptor\n");
    255121        descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
    256         if (descriptor == NULL) {
     122        if(descriptor==NULL){
    257123                usb_log_warning("could not deserialize descriptor \n");
    258124                return opResult;
    259125        }
    260         usb_log_debug("setting port count to %d\n", descriptor->ports_count);
     126        usb_log_debug("setting port count to %d\n",descriptor->ports_count);
    261127        hub_info->port_count = descriptor->ports_count;
    262         /// \TODO this is not semantically correct
    263         hub_info->ports = malloc(
    264             sizeof (usb_hub_port_t) * (hub_info->port_count + 1));
     128        hub_info->ports = malloc(sizeof(usb_hub_port_t) * (hub_info->port_count+1));
    265129        size_t port;
    266130        for (port = 0; port < hub_info->port_count + 1; port++) {
    267131                usb_hub_port_init(&hub_info->ports[port]);
    268132        }
     133        //handle non-removable devices
     134        usb_hub_trigger_connecting_non_removable_devices(hub_info, descriptor);
    269135        usb_log_debug2("freeing data\n");
    270136        free(serialized_descriptor);
     
    273139        return EOK;
    274140}
    275 
    276141/**
    277142 * Set configuration of hub
     
    282147 * @return error code
    283148 */
    284 static int usb_hub_set_configuration(usb_hub_info_t * hub_info) {
     149static int usb_hub_set_configuration(usb_hub_info_t * hub_info){
    285150        //device descriptor
    286151        usb_standard_device_descriptor_t *std_descriptor
     
    288153        usb_log_debug("hub has %d configurations\n",
    289154            std_descriptor->configuration_count);
    290         if (std_descriptor->configuration_count < 1) {
     155        if(std_descriptor->configuration_count<1){
    291156                usb_log_error("there are no configurations available\n");
    292157                return EINVAL;
     
    308173        }
    309174        usb_log_debug("\tused configuration %d\n",
    310             config_descriptor->configuration_number);
     175                        config_descriptor->configuration_number);
    311176
    312177        return EOK;
     
    314179
    315180/**
    316  * create and start fibril with hub control loop
    317  *
    318  * Before the fibril is started, the control pipe and host controller
    319  * connection of the hub is open.
    320  *
    321  * @param hub_info hub representing structure
     181 * Initialize hub device driver fibril
     182 *
     183 * Creates hub representation and fibril that periodically checks hub`s status.
     184 * Hub representation is passed to the fibril.
     185 * @param usb_dev generic usb device information
    322186 * @return error code
    323187 */
    324 static int usb_hub_start_hub_fibril(usb_hub_info_t * hub_info){
     188int usb_hub_add_device(usb_device_t * usb_dev){
     189        if(!usb_dev) return EINVAL;
     190        usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev);
     191        //create hc connection
     192        usb_log_debug("Initializing USB wire abstraction.\n");
     193        int opResult = usb_hc_connection_initialize_from_device(
     194                        &hub_info->connection,
     195                        hub_info->usb_device->ddf_dev);
     196        if(opResult != EOK){
     197                usb_log_error("could not initialize connection to device, errno %d\n",
     198                                opResult);
     199                free(hub_info);
     200                return opResult;
     201        }
     202       
     203        usb_pipe_start_session(hub_info->control_pipe);
     204        //set hub configuration
     205        opResult = usb_hub_set_configuration(hub_info);
     206        if(opResult!=EOK){
     207                usb_log_error("could not set hub configuration, errno %d\n",opResult);
     208                free(hub_info);
     209                return opResult;
     210        }
     211        //get port count and create attached_devs
     212        opResult = usb_hub_process_hub_specific_info(hub_info);
     213        if(opResult!=EOK){
     214                usb_log_error("could not set hub configuration, errno %d\n",opResult);
     215                free(hub_info);
     216                return opResult;
     217        }
     218        usb_pipe_end_session(hub_info->control_pipe);
     219
     220
     221        /// \TODO what is this?
     222        usb_log_debug("Creating `hub' function.\n");
     223        ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
     224                        fun_exposed, "hub");
     225        assert(hub_fun != NULL);
     226        hub_fun->ops = NULL;
     227
     228        int rc = ddf_fun_bind(hub_fun);
     229        assert(rc == EOK);
     230        rc = ddf_fun_add_to_class(hub_fun, "hub");
     231        assert(rc == EOK);
     232
    325233        /*
    326234         * The processing will require opened control pipe and connection
     
    331239         * auto destruction, this could work better.
    332240         */
    333         int rc = usb_pipe_start_session(hub_info->control_pipe);
     241        rc = usb_pipe_start_session(&usb_dev->ctrl_pipe);
    334242        if (rc != EOK) {
    335243                usb_log_error("Failed to start session on control pipe: %s.\n",
    336244                    str_error(rc));
    337                 return rc;
     245                goto leave;
    338246        }
    339247        rc = usb_hc_connection_open(&hub_info->connection);
    340248        if (rc != EOK) {
    341                 usb_pipe_end_session(hub_info->control_pipe);
     249                usb_pipe_end_session(&usb_dev->ctrl_pipe);
    342250                usb_log_error("Failed to open connection to HC: %s.\n",
    343251                    str_error(rc));
    344                 return rc;
     252                goto leave;
    345253        }
    346254
    347255        rc = usb_device_auto_poll(hub_info->usb_device, 0,
    348             hub_port_changes_callback, ((hub_info->port_count + 1) / 8) + 1,
     256            hub_port_changes_callback, ((hub_info->port_count+1) / 8) + 1,
    349257            NULL, hub_info);
    350258        if (rc != EOK) {
     
    358266            hub_info->usb_device->ddf_dev->name, hub_info->port_count);
    359267        return EOK;
    360 }
     268
     269leave:
     270        free(hub_info);
     271
     272        return rc;
     273}
     274
    361275
    362276//*********************************************
    363277//
    364 //  change handling functions
     278//  hub driver code, main loop and port handling
    365279//
    366280//*********************************************
    367281
    368 
    369 /**
    370  * process hub over current change
    371  *
    372  * This means either to power off the hub or power it on.
    373  * @param hub_info hub instance
    374  * @param status hub status bitmask
     282/**
     283 * triggers actions to connect non0removable devices
     284 *
     285 * This will trigger operations leading to activated non-removable device.
     286 * Control pipe of the hub must be open fo communication.
     287 * @param hub hub representation
     288 * @param descriptor usb hub descriptor
    375289 * @return error code
    376290 */
    377 static int usb_process_hub_over_current(usb_hub_info_t * hub_info,
    378     usb_hub_status_t status) {
     291static int usb_hub_trigger_connecting_non_removable_devices(usb_hub_info_t * hub,
     292                usb_hub_descriptor_t * descriptor)
     293{
     294        usb_log_info("attaching non-removable devices(if any)\n");
     295        usb_device_request_setup_packet_t request;
    379296        int opResult;
    380         if (usb_hub_is_status(status,USB_HUB_FEATURE_HUB_OVER_CURRENT)){
    381                 opResult = usb_hub_clear_feature(hub_info->control_pipe,
    382                     USB_HUB_FEATURE_HUB_LOCAL_POWER);
    383                 if (opResult != EOK) {
    384                         usb_log_error("cannot power off hub: %d\n",
    385                             opResult);
    386                 }
    387         } else {
    388                 opResult = usb_hub_set_feature(hub_info->control_pipe,
    389                     USB_HUB_FEATURE_HUB_LOCAL_POWER);
    390                 if (opResult != EOK) {
    391                         usb_log_error("cannot power on hub: %d\n",
    392                             opResult);
    393                 }
    394         }
    395         return opResult;
    396 }
    397 
    398 /**
    399  * process hub power change
    400  *
    401  * If the power has been lost, reestablish it.
    402  * If it was reestablished, re-power all ports.
    403  * @param hub_info hub instance
    404  * @param status hub status bitmask
    405  * @return error code
    406  */
    407 static int usb_process_hub_power_change(usb_hub_info_t * hub_info,
    408     usb_hub_status_t status) {
    409         int opResult;
    410         if (usb_hub_is_status(status,USB_HUB_FEATURE_HUB_LOCAL_POWER)) {
    411                 //restart power on hub
    412                 opResult = usb_hub_set_feature(hub_info->control_pipe,
    413                     USB_HUB_FEATURE_HUB_LOCAL_POWER);
    414                 if (opResult != EOK) {
    415                         usb_log_error("cannot power on hub: %d\n",
    416                             opResult);
    417                 }
    418         } else {//power reestablished on hub- restart ports
    419                 size_t port;
    420                 for (port = 0; port < hub_info->port_count; ++port) {
    421                         opResult = usb_hub_set_port_feature(
    422                             hub_info->control_pipe,
    423                             port, USB_HUB_FEATURE_PORT_POWER);
     297        size_t rcvd_size;
     298        usb_port_status_t status;
     299        uint8_t * non_removable_dev_bitmap = descriptor->devices_removable;
     300        int port;
     301        for(port=1;port<=descriptor->ports_count;++port){
     302                bool is_non_removable =
     303                                ((non_removable_dev_bitmap[port/8]) >> (port%8)) %2;
     304                if(is_non_removable){
     305                        usb_log_debug("non-removable device on port %d\n",port);
     306                        usb_hub_set_port_status_request(&request, port);
     307                        opResult = usb_pipe_control_read(
     308                                        hub->control_pipe,
     309                                        &request, sizeof(usb_device_request_setup_packet_t),
     310                                        &status, 4, &rcvd_size
     311                                        );
    424312                        if (opResult != EOK) {
    425                                 usb_log_error("cannot power on port %d;  %d\n",
    426                                     port, opResult);
     313                                usb_log_error("could not get port status of port %d errno:%d\n",
     314                                                port, opResult);
     315                                return opResult;
     316                        }
     317                        //set the status change bit, so it will be noticed in driver loop
     318                        if(usb_port_dev_connected(&status)){
     319                                usb_hub_set_disable_port_feature_request(&request, port,
     320                                                USB_HUB_FEATURE_PORT_CONNECTION);
     321                                opResult = usb_pipe_control_read(
     322                                                hub->control_pipe,
     323                                                &request, sizeof(usb_device_request_setup_packet_t),
     324                                                &status, 4, &rcvd_size
     325                                                );
     326                                if (opResult != EOK) {
     327                                        usb_log_warning(
     328                                                        "could not clear port connection on port %d errno:%d\n",
     329                                                        port, opResult);
     330                                }
     331                                usb_log_debug("cleared port connection\n");
     332                                usb_hub_set_enable_port_feature_request(&request, port,
     333                                                USB_HUB_FEATURE_PORT_ENABLE);
     334                                opResult = usb_pipe_control_read(
     335                                                hub->control_pipe,
     336                                                &request, sizeof(usb_device_request_setup_packet_t),
     337                                                &status, 4, &rcvd_size
     338                                                );
     339                                if (opResult != EOK) {
     340                                        usb_log_warning(
     341                                                        "could not set port enabled on port %d errno:%d\n",
     342                                                        port, opResult);
     343                                }
     344                                usb_log_debug("port set to enabled - should lead to connection change\n");
    427345                        }
    428346                }
    429347        }
    430         return opResult;
    431 }
    432 
    433 /**
    434  * process hub interrupts
    435  *
    436  * The change can be either in the over-current condition or
    437  * local-power lost condition.
    438  * @param hub_info hub instance
    439  */
    440 static void usb_hub_process_global_interrupt(usb_hub_info_t * hub_info) {
    441         usb_log_debug("global interrupt on a hub\n");
    442         usb_pipe_t *pipe = hub_info->control_pipe;
     348        /// \TODO this is just a debug code
     349        for(port=1;port<=descriptor->ports_count;++port){
     350                bool is_non_removable =
     351                                ((non_removable_dev_bitmap[port/8]) >> (port%8)) %2;
     352                if(is_non_removable){
     353                        usb_log_debug("port %d is non-removable\n",port);
     354                        usb_port_status_t status;
     355                        size_t rcvd_size;
     356                        usb_device_request_setup_packet_t request;
     357                        //int opResult;
     358                        usb_hub_set_port_status_request(&request, port);
     359                        //endpoint 0
     360                        opResult = usb_pipe_control_read(
     361                                        hub->control_pipe,
     362                                        &request, sizeof(usb_device_request_setup_packet_t),
     363                                        &status, 4, &rcvd_size
     364                                        );
     365                        if (opResult != EOK) {
     366                                usb_log_error("could not get port status %d\n",opResult);
     367                        }
     368                        if (rcvd_size != sizeof (usb_port_status_t)) {
     369                                usb_log_error("received status has incorrect size\n");
     370                        }
     371                        //something connected/disconnected
     372                        if (usb_port_connect_change(&status)) {
     373                                usb_log_debug("some connection changed\n");
     374                        }
     375                        usb_log_debug("status: %s\n",usb_debug_str_buffer(
     376                                        (uint8_t *)&status,4,4));
     377                }
     378        }
     379        return EOK;
     380}
     381
     382
     383/**
     384 * release default address used by given hub
     385 *
     386 * Also unsets hub->is_default_address_used. Convenience wrapper function.
     387 * @note hub->connection MUST be open for communication
     388 * @param hub hub representation
     389 * @return error code
     390 */
     391static int usb_hub_release_default_address(usb_hub_info_t * hub){
     392        int opResult = usb_hc_release_default_address(&hub->connection);
     393        if(opResult!=EOK){
     394                usb_log_error("could not release default address, errno %d\n",opResult);
     395                return opResult;
     396        }
     397        hub->is_default_address_used = false;
     398        return EOK;
     399}
     400
     401/**
     402 * routine called when a device on port has been removed
     403 *
     404 * If the device on port had default address, it releases default address.
     405 * Otherwise does not do anything, because DDF does not allow to remove device
     406 * from it`s device tree.
     407 * @param hub hub representation
     408 * @param port port number, starting from 1
     409 */
     410void usb_hub_removed_device(
     411    usb_hub_info_t * hub,uint16_t port) {
     412
     413        int opResult = usb_hub_clear_port_feature(hub->control_pipe,
     414                                port, USB_HUB_FEATURE_C_PORT_CONNECTION);
     415        if(opResult != EOK){
     416                usb_log_warning("could not clear port-change-connection flag\n");
     417        }
     418        /** \TODO remove device from device manager - not yet implemented in
     419         * devide manager
     420         */
     421       
     422        //close address
     423        if(hub->ports[port].attached_device.address >= 0){
     424                /*uncomment this code to use it when DDF allows device removal
     425                opResult = usb_hc_unregister_device(
     426                                &hub->connection, hub->attached_devs[port].address);
     427                if(opResult != EOK) {
     428                        dprintf(USB_LOG_LEVEL_WARNING, "could not release address of " \
     429                            "removed device: %d", opResult);
     430                }
     431                hub->attached_devs[port].address = 0;
     432                hub->attached_devs[port].handle = 0;
     433                 */
     434        }else{
     435                usb_log_warning("this is strange, disconnected device had no address\n");
     436                //device was disconnected before it`s port was reset - return default address
     437                usb_hub_release_default_address(hub);
     438        }
     439}
     440
     441
     442/**
     443 * Process over current condition on port.
     444 *
     445 * Turn off the power on the port.
     446 *
     447 * @param hub hub representation
     448 * @param port port number, starting from 1
     449 */
     450void usb_hub_over_current( usb_hub_info_t * hub,
     451                uint16_t port){
    443452        int opResult;
    444 
    445         usb_port_status_t status;
    446         size_t rcvd_size;
    447         usb_device_request_setup_packet_t request;
    448         //int opResult;
    449         usb_hub_set_hub_status_request(&request);
    450         //endpoint 0
    451 
    452         opResult = usb_pipe_control_read(
    453             pipe,
    454             &request, sizeof (usb_device_request_setup_packet_t),
    455             &status, 4, &rcvd_size
    456             );
    457         if (opResult != EOK) {
    458                 usb_log_error("could not get hub status\n");
    459                 return;
    460         }
    461         if (rcvd_size != sizeof (usb_port_status_t)) {
    462                 usb_log_error("received status has incorrect size\n");
    463                 return;
    464         }
    465         //port reset
    466         if (
    467             usb_hub_is_status(status,16+USB_HUB_FEATURE_C_HUB_OVER_CURRENT)) {
    468                 usb_process_hub_over_current(hub_info, status);
    469         }
    470         if (
    471             usb_hub_is_status(status,16+USB_HUB_FEATURE_C_HUB_LOCAL_POWER)) {
    472                 usb_process_hub_power_change(hub_info, status);
    473         }
    474 }
     453        opResult = usb_hub_clear_port_feature(hub->control_pipe,
     454            port, USB_HUB_FEATURE_PORT_POWER);
     455        if(opResult!=EOK){
     456                usb_log_error("cannot power off port %d;  %d\n",
     457                                port, opResult);
     458        }
     459}
     460
    475461
    476462/**
Note: See TracChangeset for help on using the changeset viewer.