Ignore:
File:
1 edited

Legend:

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

    rc50941f r3e490eb  
    3737#include <errno.h>
    3838#include <str_error.h>
     39#include <inttypes.h>
    3940
    4041#include <usb_iface.h>
     
    5354#include "usb/classes/classes.h"
    5455
    55 static int usb_hub_trigger_connecting_non_removable_devices(
    56                 usb_hub_info_t * hub, usb_hub_descriptor_t * descriptor);
    57 
     56
     57/** Information for fibril for device discovery. */
     58struct add_device_phase1 {
     59        usb_hub_info_t *hub;
     60        size_t port;
     61        usb_speed_t speed;
     62};
     63
     64
     65static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev);
     66
     67static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info);
     68
     69static int usb_hub_set_configuration(usb_hub_info_t * hub_info);
     70
     71static int usb_hub_release_default_address(usb_hub_info_t * hub);
     72
     73//static int usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port,
     74//      usb_speed_t speed);
     75
     76//static void usb_hub_finalize_add_device(usb_hub_info_t * hub,
     77//      uint16_t port, usb_speed_t speed);
     78
     79static void usb_hub_removed_device(
     80        usb_hub_info_t * hub, uint16_t port);
     81
     82static void usb_hub_port_over_current(usb_hub_info_t * hub,
     83        uint16_t port, uint32_t status);
     84
     85static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port,
     86    usb_port_status_t *status);
     87
     88static int enable_port_callback(int port_no, void *arg);
     89
     90static int add_device_phase1_worker_fibril(void *arg);
     91
     92static int add_device_phase1_new_fibril(usb_hub_info_t *hub, size_t port,
     93    usb_speed_t speed);
     94
     95static void usb_hub_process_interrupt(usb_hub_info_t * hub,
     96        uint16_t port);
     97
     98static int usb_process_hub_over_current(usb_hub_info_t * hub_info,
     99        usb_hub_status_t status);
     100
     101static int usb_process_hub_power_change(usb_hub_info_t * hub_info,
     102        usb_hub_status_t status);
     103
     104static void usb_hub_process_global_interrupt(usb_hub_info_t * hub_info);
     105
     106//static int initialize_non_removable(usb_hub_info_t * hub_info,
     107//      unsigned int port);
     108
     109//static int usb_hub_trigger_connecting_non_removable_devices(
     110//      usb_hub_info_t * hub, usb_hub_descriptor_t * descriptor);
     111
     112
     113/**
     114 * control loop running in hub`s fibril
     115 *
     116 * Hub`s fibril periodically asks for changes on hub and if needded calls
     117 * change handling routine.
     118 * @warning currently hub driver asks for changes once a second
     119 * @param hub_info_param hub representation pointer
     120 * @return zero
     121 */
     122/*
     123int usb_hub_control_loop(void * hub_info_param) {
     124        usb_hub_info_t * hub_info = (usb_hub_info_t*) hub_info_param;
     125        int errorCode = EOK;
     126
     127        while (errorCode == EOK) {
     128                async_usleep(1000 * 1000 * 10); /// \TODO proper number once
     129                errorCode = usb_hub_check_hub_changes(hub_info);
     130        }
     131        usb_log_error("something in ctrl loop went wrong, errno %d\n",
     132                errorCode);
     133
     134        return 0;
     135}
     136 */
     137/// \TODO malloc checking
    58138
    59139//*********************************************
     
    63143//*********************************************
    64144
    65 /**
    66  * create usb_hub_info_t structure
    67  *
    68  * Does only basic copying of known information into new structure.
    69  * @param usb_dev usb device structure
    70  * @return basic usb_hub_info_t structure
    71  */
    72 static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev) {
    73         usb_hub_info_t * result = usb_new(usb_hub_info_t);
    74         if(!result) return NULL;
    75         result->usb_device = usb_dev;
    76         result->status_change_pipe = usb_dev->pipes[0].pipe;
    77         result->control_pipe = &usb_dev->ctrl_pipe;
    78         result->is_default_address_used = false;
    79         return result;
    80 }
    81 
    82 /**
    83  * Load hub-specific information into hub_info structure and process if needed
    84  *
    85  * Particularly read port count and initialize structure holding port
    86  * information. If there are non-removable devices, start initializing them.
    87  * This function is hub-specific and should be run only after the hub is
    88  * configured using usb_hub_set_configuration function.
    89  * @param hub_info hub representation
    90  * @return error code
    91  */
    92 static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info){
    93         // get hub descriptor
    94         usb_log_debug("creating serialized descriptor\n");
    95         void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
    96         usb_hub_descriptor_t * descriptor;
    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          */
    107         size_t 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);
    113 
    114         if (opResult != EOK) {
    115                 usb_log_error("failed when receiving hub descriptor, badcode = %d\n",
    116                                 opResult);
    117                 free(serialized_descriptor);
    118                 return opResult;
    119         }
    120         usb_log_debug2("deserializing descriptor\n");
    121         descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
    122         if(descriptor==NULL){
    123                 usb_log_warning("could not deserialize descriptor \n");
    124                 return opResult;
    125         }
    126         usb_log_debug("setting port count to %d\n",descriptor->ports_count);
    127         hub_info->port_count = descriptor->ports_count;
    128         hub_info->ports = malloc(sizeof(usb_hub_port_t) * (hub_info->port_count+1));
    129         size_t port;
    130         for (port = 0; port < hub_info->port_count + 1; port++) {
    131                 usb_hub_port_init(&hub_info->ports[port]);
    132         }
    133         //handle non-removable devices
    134         usb_hub_trigger_connecting_non_removable_devices(hub_info, descriptor);
    135         usb_log_debug2("freeing data\n");
    136         free(serialized_descriptor);
    137         free(descriptor->devices_removable);
    138         free(descriptor);
    139         return EOK;
    140 }
    141 /**
    142  * Set configuration of hub
    143  *
    144  * Check whether there is at least one configuration and sets the first one.
    145  * This function should be run prior to running any hub-specific action.
    146  * @param hub_info hub representation
    147  * @return error code
    148  */
    149 static int usb_hub_set_configuration(usb_hub_info_t * hub_info){
    150         //device descriptor
    151         usb_standard_device_descriptor_t *std_descriptor
    152             = &hub_info->usb_device->descriptors.device;
    153         usb_log_debug("hub has %d configurations\n",
    154             std_descriptor->configuration_count);
    155         if(std_descriptor->configuration_count<1){
    156                 usb_log_error("there are no configurations available\n");
    157                 return EINVAL;
    158         }
    159 
    160         usb_standard_configuration_descriptor_t *config_descriptor
    161             = (usb_standard_configuration_descriptor_t *)
    162             hub_info->usb_device->descriptors.configuration;
    163 
    164         /* Set configuration. */
    165         int opResult = usb_request_set_configuration(
    166             &hub_info->usb_device->ctrl_pipe,
    167             config_descriptor->configuration_number);
    168 
    169         if (opResult != EOK) {
    170                 usb_log_error("Failed to set hub configuration: %s.\n",
    171                     str_error(opResult));
    172                 return opResult;
    173         }
    174         usb_log_debug("\tused configuration %d\n",
    175                         config_descriptor->configuration_number);
    176 
    177         return EOK;
    178 }
     145
    179146
    180147/**
     
    186153 * @return error code
    187154 */
    188 int usb_hub_add_device(usb_device_t * usb_dev){
    189         if(!usb_dev) return EINVAL;
     155int usb_hub_add_device(usb_device_t * usb_dev) {
     156        if (!usb_dev) return EINVAL;
    190157        usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev);
    191158        //create hc connection
    192159        usb_log_debug("Initializing USB wire abstraction.\n");
    193160        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);
     161                &hub_info->connection,
     162                hub_info->usb_device->ddf_dev);
     163        if (opResult != EOK) {
     164                usb_log_error("could not initialize connection to device, "
     165                        "errno %d\n",
     166                        opResult);
    199167                free(hub_info);
    200168                return opResult;
    201169        }
    202        
     170
    203171        usb_pipe_start_session(hub_info->control_pipe);
    204172        //set hub configuration
    205173        opResult = usb_hub_set_configuration(hub_info);
    206         if(opResult!=EOK){
    207                 usb_log_error("could not set hub configuration, errno %d\n",opResult);
     174        if (opResult != EOK) {
     175                usb_log_error("could not set hub configuration, errno %d\n",
     176                        opResult);
    208177                free(hub_info);
    209178                return opResult;
     
    211180        //get port count and create attached_devs
    212181        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);
     182        if (opResult != EOK) {
     183                usb_log_error("could not set hub configuration, errno %d\n",
     184                        opResult);
    215185                free(hub_info);
    216186                return opResult;
     
    222192        usb_log_debug("Creating `hub' function.\n");
    223193        ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
    224                         fun_exposed, "hub");
     194                fun_exposed, "hub");
    225195        assert(hub_fun != NULL);
    226196        hub_fun->ops = NULL;
     
    264234
    265235        usb_log_info("Controlling hub `%s' (%d ports).\n",
    266             hub_info->usb_device->ddf_dev->name, hub_info->port_count);
     236                hub_info->usb_device->ddf_dev->name, hub_info->port_count);
    267237        return EOK;
    268 
    269238leave:
    270239        free(hub_info);
     
    280249//*********************************************
    281250
    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
     251
     252/** Callback for polling hub for port changes.
     253 *
     254 * @param dev Device where the change occured.
     255 * @param change_bitmap Bitmap of changed ports.
     256 * @param change_bitmap_size Size of the bitmap in bytes.
     257 * @param arg Custom argument, points to @c usb_hub_info_t.
     258 * @return Whether to continue polling.
     259 */
     260bool hub_port_changes_callback(usb_device_t *dev,
     261    uint8_t *change_bitmap, size_t change_bitmap_size, void *arg)
     262{
     263        usb_hub_info_t *hub = (usb_hub_info_t *) arg;
     264
     265        /* FIXME: check that we received enough bytes. */
     266        if (change_bitmap_size == 0) {
     267                goto leave;
     268        }
     269
     270        size_t port;
     271        for (port = 1; port < hub->port_count + 1; port++) {
     272                bool change = (change_bitmap[port / 8] >> (port % 8)) % 2;
     273                if (change) {
     274                        usb_hub_process_interrupt(hub, port);
     275                }
     276        }
     277
     278
     279leave:
     280        /* FIXME: proper interval. */
     281        async_usleep(1000 * 1000 * 10 );
     282
     283        return true;
     284}
     285
     286
     287/**
     288 * check changes on hub
     289 *
     290 * Handles changes on each port with a status change.
     291 * @param hub_info hub representation
    289292 * @return error code
    290293 */
    291 static 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;
     294int usb_hub_check_hub_changes(usb_hub_info_t * hub_info) {
    296295        int opResult;
    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                                         );
    312                         if (opResult != EOK) {
    313                                 usb_log_error("could not get port status of port %d errno:%d\n",
    314                                                 port, opResult);
    315                                 return opResult;
     296        opResult = usb_pipe_start_session(
     297                hub_info->status_change_pipe);
     298        //this might not be necessary - if all non-removables are ok, it is
     299        //not needed here
     300        opResult = usb_pipe_start_session(hub_info->control_pipe);
     301        if (opResult != EOK) {
     302                usb_log_error("could not initialize communication for hub; %d\n",
     303                        opResult);
     304                return opResult;
     305        }
     306
     307        size_t port_count = hub_info->port_count;
     308        //first check non-removable devices
     309        /*
     310        {
     311                unsigned int port;
     312                for (port = 0; port < port_count; ++port) {
     313                        bool is_non_removable =
     314                                hub_info->not_initialized_non_removables[port/8]
     315                                & (1 << (port-1 % 8));
     316                        if (is_non_removable) {
     317                                opResult = initialize_non_removable(hub_info,
     318                                        port+1);
    316319                        }
    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");
    345                         }
    346                 }
    347         }
    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         }
     320                }
     321        }
     322        */
     323
     324        /// FIXME: count properly
     325        size_t byte_length = ((port_count + 1) / 8) + 1;
     326        void *change_bitmap = malloc(byte_length);
     327        size_t actual_size;
     328
     329        /*
     330         * Send the request.
     331         */
     332        opResult = usb_pipe_read(
     333                hub_info->status_change_pipe,
     334                change_bitmap, byte_length, &actual_size
     335                );
     336
     337        if (opResult != EOK) {
     338                free(change_bitmap);
     339                usb_log_warning("something went wrong while getting the"
     340                        "status of hub\n");
     341                usb_pipe_end_session(hub_info->status_change_pipe);
     342                return opResult;
     343        }
     344        unsigned int port;
     345
     346        if (opResult != EOK) {
     347                usb_log_error("could not start control pipe session %d\n",
     348                        opResult);
     349                usb_pipe_end_session(hub_info->status_change_pipe);
     350                return opResult;
     351        }
     352        opResult = usb_hc_connection_open(&hub_info->connection);
     353        if (opResult != EOK) {
     354                usb_log_error("could not start host controller session %d\n",
     355                        opResult);
     356                usb_pipe_end_session(hub_info->control_pipe);
     357                usb_pipe_end_session(hub_info->status_change_pipe);
     358                return opResult;
     359        }
     360
     361        ///todo, opresult check, pre obe konekce
     362        bool interrupt;
     363        interrupt = ((uint8_t*)change_bitmap)[0] & 1;
     364        if(interrupt){
     365                usb_hub_process_global_interrupt(hub_info);
     366        }
     367        for (port = 1; port < port_count + 1; ++port) {
     368                interrupt =
     369                        ((uint8_t*) change_bitmap)[port / 8] & (1<<(port % 8));
     370                if (interrupt) {
     371                        usb_hub_process_interrupt(
     372                                hub_info, port);
     373                }
     374        }
     375        /// \todo check hub status
     376        usb_hc_connection_close(&hub_info->connection);
     377        usb_pipe_end_session(hub_info->control_pipe);
     378        usb_pipe_end_session(hub_info->status_change_pipe);
     379        free(change_bitmap);
    379380        return EOK;
    380381}
    381382
     383//*********************************************
     384//
     385//  support functions
     386//
     387//*********************************************
     388
     389/**
     390 * create usb_hub_info_t structure
     391 *
     392 * Does only basic copying of known information into new structure.
     393 * @param usb_dev usb device structure
     394 * @return basic usb_hub_info_t structure
     395 */
     396static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev) {
     397        usb_hub_info_t * result = usb_new(usb_hub_info_t);
     398        if (!result) return NULL;
     399        result->usb_device = usb_dev;
     400        result->status_change_pipe = usb_dev->pipes[0].pipe;
     401        result->control_pipe = &usb_dev->ctrl_pipe;
     402        result->is_default_address_used = false;
     403        return result;
     404}
     405
     406
     407/**
     408 * Load hub-specific information into hub_info structure and process if needed
     409 *
     410 * Particularly read port count and initialize structure holding port
     411 * information. If there are non-removable devices, start initializing them.
     412 * This function is hub-specific and should be run only after the hub is
     413 * configured using usb_hub_set_configuration function.
     414 * @param hub_info hub representation
     415 * @return error code
     416 */
     417static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info) {
     418        // get hub descriptor
     419        usb_log_debug("creating serialized descriptor\n");
     420        void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
     421        usb_hub_descriptor_t * descriptor;
     422        int opResult;
     423
     424        /* this was one fix of some bug, should not be needed anymore
     425         * these lines allow to reset hub once more, it can be used as
     426         * brute-force initialization for non-removable devices
     427         *
     428        opResult = usb_request_set_configuration(hub_info->control_pipe,
     429                1);
     430        if (opResult != EOK) {
     431                usb_log_error("could not set default configuration, errno %d",
     432                        opResult);
     433                return opResult;
     434        }*/
     435
     436
     437        size_t received_size;
     438        opResult = usb_request_get_descriptor(hub_info->control_pipe,
     439                USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
     440                USB_DESCTYPE_HUB,
     441                0, 0, serialized_descriptor,
     442                USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
     443
     444        if (opResult != EOK) {
     445                usb_log_error("failed when receiving hub descriptor, "
     446                        "badcode = %d\n",
     447                        opResult);
     448                free(serialized_descriptor);
     449                return opResult;
     450        }
     451        usb_log_debug2("deserializing descriptor\n");
     452        descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
     453        if (descriptor == NULL) {
     454                usb_log_warning("could not deserialize descriptor \n");
     455                return opResult;
     456        }
     457        usb_log_debug("setting port count to %d\n", descriptor->ports_count);
     458        hub_info->port_count = descriptor->ports_count;
     459        /// \TODO check attached_devices array: this is not semantically correct
     460        //hub_info->attached_devs = (usb_hc_attached_device_t*)
     461//              malloc((hub_info->port_count + 1) *
     462//                      sizeof (usb_hc_attached_device_t)
     463//              );
     464        hub_info->ports = malloc(sizeof(usb_hub_port_t) * (hub_info->port_count+1));
     465        size_t port;
     466        for (port = 0; port < hub_info->port_count + 1; port++) {
     467                usb_hub_port_init(&hub_info->ports[port]);
     468        }
     469        //handle non-removable devices
     470        //usb_hub_trigger_connecting_non_removable_devices(hub_info, descriptor);
     471        usb_log_debug2("freeing data\n");
     472        free(serialized_descriptor);
     473        free(descriptor->devices_removable);
     474        free(descriptor);
     475        return EOK;
     476}
     477
     478/**
     479 * Set configuration of hub
     480 *
     481 * Check whether there is at least one configuration and sets the first one.
     482 * This function should be run prior to running any hub-specific action.
     483 * @param hub_info hub representation
     484 * @return error code
     485 */
     486static int usb_hub_set_configuration(usb_hub_info_t * hub_info) {
     487        //device descriptor
     488        usb_standard_device_descriptor_t *std_descriptor
     489                = &hub_info->usb_device->descriptors.device;
     490        usb_log_debug("hub has %d configurations\n",
     491                std_descriptor->configuration_count);
     492        if (std_descriptor->configuration_count < 1) {
     493                usb_log_error("there are no configurations available\n");
     494                return EINVAL;
     495        }
     496
     497        usb_standard_configuration_descriptor_t *config_descriptor
     498                = (usb_standard_configuration_descriptor_t *)
     499                hub_info->usb_device->descriptors.configuration;
     500
     501        /* Set configuration. */
     502        int opResult = usb_request_set_configuration(
     503                &hub_info->usb_device->ctrl_pipe,
     504                config_descriptor->configuration_number);
     505
     506        if (opResult != EOK) {
     507                usb_log_error("Failed to set hub configuration: %s.\n",
     508                        str_error(opResult));
     509                return opResult;
     510        }
     511        usb_log_debug("\tused configuration %d\n",
     512                config_descriptor->configuration_number);
     513
     514        return EOK;
     515}
    382516
    383517/**
     
    389523 * @return error code
    390524 */
    391 static int usb_hub_release_default_address(usb_hub_info_t * hub){
     525static int usb_hub_release_default_address(usb_hub_info_t * hub) {
    392526        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);
     527        if (opResult != EOK) {
     528                usb_log_error("could not release default address, errno %d\n",
     529                        opResult);
    395530                return opResult;
    396531        }
     
    398533        return EOK;
    399534}
     535
     536#if 0
     537/**
     538 * Reset the port with new device and reserve the default address.
     539 * @param hub hub representation
     540 * @param port port number, starting from 1
     541 * @param speed transfer speed of attached device, one of low, full or high
     542 * @return error code
     543 */
     544static int usb_hub_init_add_device(usb_hub_info_t * hub, uint16_t port,
     545        usb_speed_t speed) {
     546        //if this hub already uses default address, it cannot request it once more
     547        if (hub->is_default_address_used) {
     548                usb_log_info("default address used, another time\n");
     549                return EREFUSED;
     550        }
     551        usb_log_debug("some connection changed\n");
     552        assert(hub->control_pipe->hc_phone);
     553        int opResult = usb_hub_clear_port_feature(hub->control_pipe,
     554                port, USB_HUB_FEATURE_C_PORT_CONNECTION);
     555        if (opResult != EOK) {
     556                usb_log_warning("could not clear port-change-connection flag\n");
     557        }
     558        usb_device_request_setup_packet_t request;
     559
     560        //get default address
     561        opResult = usb_hc_reserve_default_address(&hub->connection, speed);
     562
     563        if (opResult != EOK) {
     564                usb_log_warning("cannot assign default address, it is probably "
     565                        "used %d\n",
     566                        opResult);
     567                return opResult;
     568        }
     569        hub->is_default_address_used = true;
     570        //reset port
     571        usb_hub_set_reset_port_request(&request, port);
     572        opResult = usb_pipe_control_write(
     573                hub->control_pipe,
     574                &request, sizeof (usb_device_request_setup_packet_t),
     575                NULL, 0
     576                );
     577        if (opResult != EOK) {
     578                usb_log_error("something went wrong when reseting a port %d\n",
     579                        opResult);
     580                usb_hub_release_default_address(hub);
     581        }
     582        return opResult;
     583}
     584#endif
     585
     586#if 0
     587/**
     588 * Finalize adding new device after port reset
     589 *
     590 * Set device`s address and start it`s driver.
     591 * @param hub hub representation
     592 * @param port port number, starting from 1
     593 * @param speed transfer speed of attached device, one of low, full or high
     594 */
     595static void usb_hub_finalize_add_device(usb_hub_info_t * hub,
     596        uint16_t port, usb_speed_t speed) {
     597
     598        int opResult;
     599        usb_log_debug("finalizing add device\n");
     600        opResult = usb_hub_clear_port_feature(hub->control_pipe,
     601                port, USB_HUB_FEATURE_C_PORT_RESET);
     602
     603        if (opResult != EOK) {
     604                usb_log_error("failed to clear port reset feature\n");
     605                usb_hub_release_default_address(hub);
     606                return;
     607        }
     608        //create connection to device
     609        usb_pipe_t new_device_pipe;
     610        usb_device_connection_t new_device_connection;
     611        usb_device_connection_initialize_on_default_address(
     612                &new_device_connection,
     613                &hub->connection
     614                );
     615        usb_pipe_initialize_default_control(
     616                &new_device_pipe,
     617                &new_device_connection);
     618        usb_pipe_probe_default_control(&new_device_pipe);
     619
     620        /* Request address from host controller. */
     621        usb_address_t new_device_address = usb_hc_request_address(
     622                &hub->connection,
     623                speed
     624                );
     625        if (new_device_address < 0) {
     626                usb_log_error("failed to get free USB address\n");
     627                opResult = new_device_address;
     628                usb_hub_release_default_address(hub);
     629                return;
     630        }
     631        usb_log_debug("setting new address %d\n", new_device_address);
     632        //opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
     633        //    new_device_address);
     634        usb_pipe_start_session(&new_device_pipe);
     635        opResult = usb_request_set_address(&new_device_pipe,
     636                new_device_address);
     637        usb_pipe_end_session(&new_device_pipe);
     638        if (opResult != EOK) {
     639                usb_log_error("could not set address for new device %d\n",
     640                        opResult);
     641                usb_hub_release_default_address(hub);
     642                return;
     643        }
     644
     645        //opResult = usb_hub_release_default_address(hc);
     646        opResult = usb_hub_release_default_address(hub);
     647        if (opResult != EOK) {
     648                return;
     649        }
     650
     651        devman_handle_t child_handle;
     652        //??
     653        opResult = usb_device_register_child_in_devman(new_device_address,
     654                hub->connection.hc_handle, hub->usb_device->ddf_dev,
     655                &child_handle,
     656                NULL, NULL, NULL);
     657
     658        if (opResult != EOK) {
     659                usb_log_error("could not start driver for new device %d\n",
     660                        opResult);
     661                return;
     662        }
     663        hub->attached_devs[port].handle = child_handle;
     664        hub->attached_devs[port].address = new_device_address;
     665
     666        //opResult = usb_drv_bind_address(hc, new_device_address, child_handle);
     667        opResult = usb_hc_register_device(
     668                &hub->connection,
     669                &hub->attached_devs[port]);
     670        if (opResult != EOK) {
     671                usb_log_error("could not assign address of device in hcd %d\n",
     672                        opResult);
     673                return;
     674        }
     675        usb_log_info("Detected new device on `%s' (port %d), " \
     676            "address %d (handle %llu).\n",
     677                hub->usb_device->ddf_dev->name, (int) port,
     678                new_device_address, child_handle);
     679}
     680#endif
    400681
    401682/**
     
    408689 * @param port port number, starting from 1
    409690 */
    410 void usb_hub_removed_device(
    411     usb_hub_info_t * hub,uint16_t port) {
     691static void usb_hub_removed_device(
     692        usb_hub_info_t * hub, uint16_t port) {
    412693
    413694        int opResult = usb_hub_clear_port_feature(hub->control_pipe,
    414                                 port, USB_HUB_FEATURE_C_PORT_CONNECTION);
    415         if(opResult != EOK){
     695                port, USB_HUB_FEATURE_C_PORT_CONNECTION);
     696        if (opResult != EOK) {
    416697                usb_log_warning("could not clear port-change-connection flag\n");
    417698        }
     
    419700         * devide manager
    420701         */
    421        
     702
    422703        //close address
     704        //if (hub->attached_devs[port].address != 0) {
    423705        if(hub->ports[port].attached_device.address >= 0){
    424706                /*uncomment this code to use it when DDF allows device removal
    425707                opResult = usb_hc_unregister_device(
    426                                 &hub->connection, hub->attached_devs[port].address);
     708                        &hub->connection,
     709                        hub->attached_devs[port].address);
    427710                if(opResult != EOK) {
    428                         dprintf(USB_LOG_LEVEL_WARNING, "could not release address of " \
     711                        dprintf(USB_LOG_LEVEL_WARNING, "could not release "
     712                                "address of "
    429713                            "removed device: %d", opResult);
    430714                }
     
    432716                hub->attached_devs[port].handle = 0;
    433717                 */
    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
     718        } else {
     719                usb_log_warning("this is strange, disconnected device had "
     720                        "no address\n");
     721                //device was disconnected before it`s port was reset -
     722                //return default address
    437723                usb_hub_release_default_address(hub);
    438724        }
    439725}
    440726
    441 
    442727/**
    443728 * Process over current condition on port.
    444  * 
     729 *
    445730 * Turn off the power on the port.
    446731 *
     
    448733 * @param port port number, starting from 1
    449734 */
    450 void usb_hub_over_current( usb_hub_info_t * hub,
    451                 uint16_t port){
     735static void usb_hub_port_over_current(usb_hub_info_t * hub,
     736        uint16_t port, uint32_t status) {
    452737        int opResult;
    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",
     738        if(usb_port_over_current(&status)){
     739                opResult = usb_hub_clear_port_feature(hub->control_pipe,
     740                        port, USB_HUB_FEATURE_PORT_POWER);
     741                if (opResult != EOK) {
     742                        usb_log_error("cannot power off port %d;  %d\n",
    457743                                port, opResult);
    458         }
    459 }
     744                }
     745        }else{
     746                opResult = usb_hub_set_port_feature(hub->control_pipe,
     747                        port, USB_HUB_FEATURE_PORT_POWER);
     748                if (opResult != EOK) {
     749                        usb_log_error("cannot power on port %d;  %d\n",
     750                                port, opResult);
     751                }
     752        }
     753}
     754
     755/** Retrieve port status.
     756 *
     757 * @param[in] ctrl_pipe Control pipe to use.
     758 * @param[in] port Port number (starting at 1).
     759 * @param[out] status Where to store the port status.
     760 * @return Error code.
     761 */
     762static int get_port_status(usb_pipe_t *ctrl_pipe, size_t port,
     763    usb_port_status_t *status)
     764{
     765        size_t recv_size;
     766        usb_device_request_setup_packet_t request;
     767        usb_port_status_t status_tmp;
     768
     769        usb_hub_set_port_status_request(&request, port);
     770        int rc = usb_pipe_control_read(ctrl_pipe,
     771            &request, sizeof(usb_device_request_setup_packet_t),
     772            &status_tmp, sizeof(status_tmp), &recv_size);
     773        if (rc != EOK) {
     774                return rc;
     775        }
     776
     777        if (recv_size != sizeof (status_tmp)) {
     778                return ELIMIT;
     779        }
     780
     781        if (status != NULL) {
     782                *status = status_tmp;
     783        }
     784
     785        return EOK;
     786}
     787
     788/** Callback for enabling a specific port.
     789 *
     790 * We wait on a CV until port is reseted.
     791 * That is announced via change on interrupt pipe.
     792 *
     793 * @param port_no Port number (starting at 1).
     794 * @param arg Custom argument, points to @c usb_hub_info_t.
     795 * @return Error code.
     796 */
     797static int enable_port_callback(int port_no, void *arg)
     798{
     799        usb_hub_info_t *hub = (usb_hub_info_t *) arg;
     800        int rc;
     801        usb_device_request_setup_packet_t request;
     802        usb_hub_port_t *my_port = hub->ports + port_no;
     803
     804        usb_hub_set_reset_port_request(&request, port_no);
     805        rc = usb_pipe_control_write(hub->control_pipe,
     806            &request, sizeof(request), NULL, 0);
     807        if (rc != EOK) {
     808                usb_log_warning("Port reset failed: %s.\n", str_error(rc));
     809                return rc;
     810        }
     811
     812        /*
     813         * Wait until reset completes.
     814         */
     815        fibril_mutex_lock(&my_port->reset_mutex);
     816        while (!my_port->reset_completed) {
     817                fibril_condvar_wait(&my_port->reset_cv, &my_port->reset_mutex);
     818        }
     819        fibril_mutex_unlock(&my_port->reset_mutex);
     820
     821        /* Clear the port reset change. */
     822        rc = usb_hub_clear_port_feature(hub->control_pipe,
     823            port_no, USB_HUB_FEATURE_C_PORT_RESET);
     824        if (rc != EOK) {
     825                usb_log_error("Failed to clear port %d reset feature: %s.\n",
     826                    port_no, str_error(rc));
     827                return rc;
     828        }
     829
     830        return EOK;
     831}
     832
     833/** Fibril for adding a new device.
     834 *
     835 * Separate fibril is needed because the port reset completion is announced
     836 * via interrupt pipe and thus we cannot block here.
     837 *
     838 * @param arg Pointer to struct add_device_phase1.
     839 * @return 0 Always.
     840 */
     841static int add_device_phase1_worker_fibril(void *arg)
     842{
     843        struct add_device_phase1 *data
     844            = (struct add_device_phase1 *) arg;
     845
     846        usb_address_t new_address;
     847        devman_handle_t child_handle;
     848
     849        int rc = usb_hc_new_device_wrapper(data->hub->usb_device->ddf_dev,
     850            &data->hub->connection, data->speed,
     851            enable_port_callback, (int) data->port, data->hub,
     852            &new_address, &child_handle,
     853            NULL, NULL, NULL);
     854
     855        if (rc != EOK) {
     856                usb_log_error("Failed registering device on port %zu: %s.\n",
     857                    data->port, str_error(rc));
     858                goto leave;
     859        }
     860
     861        data->hub->ports[data->port].attached_device.handle = child_handle;
     862        data->hub->ports[data->port].attached_device.address = new_address;
     863
     864        usb_log_info("Detected new device on `%s' (port %zu), "
     865            "address %d (handle %" PRIun ").\n",
     866            data->hub->usb_device->ddf_dev->name, data->port,
     867            new_address, child_handle);
     868
     869leave:
     870        free(arg);
     871
     872        return EOK;
     873}
     874
     875
     876/** Start device adding when connection change is detected.
     877 *
     878 * This fires a new fibril to complete the device addition.
     879 *
     880 * @param hub Hub where the change occured.
     881 * @param port Port index (starting at 1).
     882 * @param speed Speed of the device.
     883 * @return Error code.
     884 */
     885static int add_device_phase1_new_fibril(usb_hub_info_t *hub, size_t port,
     886    usb_speed_t speed)
     887{
     888        struct add_device_phase1 *data
     889            = malloc(sizeof(struct add_device_phase1));
     890        if (data == NULL) {
     891                return ENOMEM;
     892        }
     893        data->hub = hub;
     894        data->port = port;
     895        data->speed = speed;
     896
     897        usb_hub_port_t *the_port = hub->ports + port;
     898
     899        fibril_mutex_lock(&the_port->reset_mutex);
     900        the_port->reset_completed = false;
     901        fibril_mutex_unlock(&the_port->reset_mutex);
     902
     903        int rc = usb_hub_clear_port_feature(hub->control_pipe, port,
     904            USB_HUB_FEATURE_C_PORT_CONNECTION);
     905        if (rc != EOK) {
     906                free(data);
     907                usb_log_warning("Failed to clear port change flag: %s.\n",
     908                    str_error(rc));
     909                return rc;
     910        }
     911
     912        fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data);
     913        if (fibril == 0) {
     914                free(data);
     915                return ENOMEM;
     916        }
     917        fibril_add_ready(fibril);
     918
     919        return EOK;
     920}
     921
     922
     923/**
     924 * Process interrupts on given hub port
     925 *
     926 * Accepts connection, over current and port reset change.
     927 * @param hub hub representation
     928 * @param port port number, starting from 1
     929 */
     930static void usb_hub_process_interrupt(usb_hub_info_t * hub,
     931        uint16_t port) {
     932        usb_log_debug("interrupt at port %d\n", port);
     933        //determine type of change
     934        //usb_pipe_t *pipe = hub->control_pipe;
     935
     936        int opResult;
     937
     938        usb_port_status_t status;
     939        opResult = get_port_status(&hub->usb_device->ctrl_pipe, port, &status);
     940        if (opResult != EOK) {
     941                usb_log_error("Failed to get port %zu status: %s.\n",
     942                    port, str_error(opResult));
     943                return;
     944        }
     945
     946        //something connected/disconnected
     947        /*
     948        if (usb_port_connect_change(&status)) {
     949                usb_log_debug("connection change on port\n");
     950                if (usb_port_dev_connected(&status)) {
     951                        usb_hub_init_add_device(hub, port,
     952                                usb_port_speed(&status));
     953                } else {
     954                        usb_hub_removed_device(hub, port);
     955                }
     956        }*/
     957        if (usb_port_connect_change(&status)) {
     958                bool device_connected = usb_port_dev_connected(&status);
     959                usb_log_debug("Connection change on port %zu: %s.\n", port,
     960                    device_connected ? "device attached" : "device removed");
     961
     962                if (device_connected) {
     963                        opResult = add_device_phase1_new_fibril(hub, port,
     964                            usb_port_speed(&status));
     965                        if (opResult != EOK) {
     966                                usb_log_error(
     967                                    "Cannot handle change on port %zu: %s.\n",
     968                                    str_error(opResult));
     969                        }
     970                } else {
     971                        usb_hub_removed_device(hub, port);
     972                }
     973        }
     974        //over current
     975        if (usb_port_overcurrent_change(&status)) {
     976                //check if it was not auto-resolved
     977                usb_log_debug("overcurrent change on port\n");
     978                usb_hub_port_over_current(hub, port, status);
     979        }
     980        //port reset
     981        if (usb_port_reset_completed(&status)) {
     982                /*
     983                usb_log_debug("port reset complete\n");
     984                if (usb_port_enabled(&status)) {
     985                        usb_hub_finalize_add_device(hub, port,
     986                                usb_port_speed(&status));
     987                } else {
     988                        usb_log_warning("port reset, but port still not "
     989                                "enabled\n");
     990                }
     991                 * */
     992                usb_log_debug("Port %zu reset complete.\n", port);
     993                if (usb_port_enabled(&status)) {
     994                        /* Finalize device adding. */
     995                        usb_hub_port_t *the_port = hub->ports + port;
     996                        fibril_mutex_lock(&the_port->reset_mutex);
     997                        the_port->reset_completed = true;
     998                        fibril_condvar_broadcast(&the_port->reset_cv);
     999                        fibril_mutex_unlock(&the_port->reset_mutex);
     1000                } else {
     1001                        usb_log_warning(
     1002                            "Port %zu reset complete but port not enabled.\n",
     1003                            port);
     1004                }
     1005        }
     1006        usb_log_debug("status x%x : %d\n ", status, status);
     1007
     1008        usb_port_set_connect_change(&status, false);
     1009        usb_port_set_reset(&status, false);
     1010        usb_port_set_reset_completed(&status, false);
     1011        usb_port_set_dev_connected(&status, false);
     1012        usb_port_set_overcurrent_change(&status,false);
     1013        /// \TODO what about port power change?
     1014        if (status >> 16) {
     1015                usb_log_info("there was unsupported change on port %d: %X\n",
     1016                        port, status);
     1017
     1018        }
     1019}
     1020
     1021/**
     1022 * process hub over current change
     1023 *
     1024 * This means either to power off the hub or power it on.
     1025 * @param hub_info hub instance
     1026 * @param status hub status bitmask
     1027 * @return error code
     1028 */
     1029static int usb_process_hub_over_current(usb_hub_info_t * hub_info,
     1030        usb_hub_status_t status)
     1031{
     1032        int opResult;
     1033        if(usb_hub_over_current(&status)){
     1034                opResult = usb_hub_clear_feature(hub_info->control_pipe,
     1035                        USB_HUB_FEATURE_PORT_POWER);
     1036                if (opResult != EOK) {
     1037                        usb_log_error("cannot power off hub: %d\n",
     1038                                opResult);
     1039                }
     1040        }else{
     1041                opResult = usb_hub_set_feature(hub_info->control_pipe,
     1042                        USB_HUB_FEATURE_PORT_POWER);
     1043                if (opResult != EOK) {
     1044                        usb_log_error("cannot power on hub: %d\n",
     1045                                opResult);
     1046                }
     1047        }
     1048        return opResult;
     1049}
     1050
     1051/**
     1052 * process hub power change
     1053 *
     1054 * If the power has been lost, reestablish it.
     1055 * If it was reestablished, re-power all ports.
     1056 * @param hub_info hub instance
     1057 * @param status hub status bitmask
     1058 * @return error code
     1059 */
     1060static int usb_process_hub_power_change(usb_hub_info_t * hub_info,
     1061        usb_hub_status_t status)
     1062{
     1063        int opResult;
     1064        if(usb_hub_local_power_lost(&status)){
     1065                //restart power on hub
     1066                opResult = usb_hub_set_feature(hub_info->control_pipe,
     1067                        USB_HUB_FEATURE_PORT_POWER);
     1068                if (opResult != EOK) {
     1069                        usb_log_error("cannot power on hub: %d\n",
     1070                                opResult);
     1071                }
     1072        }else{//power reestablished on hub- restart ports
     1073                size_t port;
     1074                for(port=0;port<hub_info->port_count;++port){
     1075                        opResult = usb_hub_set_port_feature(
     1076                                hub_info->control_pipe,
     1077                                port, USB_HUB_FEATURE_PORT_POWER);
     1078                        if (opResult != EOK) {
     1079                                usb_log_error("cannot power on port %d;  %d\n",
     1080                                        port, opResult);
     1081                        }
     1082                }
     1083        }
     1084        return opResult;
     1085}
     1086
     1087/**
     1088 * process hub interrupts
     1089 *
     1090 * The change can be either in the over-current condition or
     1091 * local-power lost condition.
     1092 * @param hub_info hub instance
     1093 */
     1094static void usb_hub_process_global_interrupt(usb_hub_info_t * hub_info){
     1095        usb_log_debug("global interrupt on a hub\n");
     1096        usb_pipe_t *pipe = hub_info->control_pipe;
     1097        int opResult;
     1098
     1099        usb_port_status_t status;
     1100        size_t rcvd_size;
     1101        usb_device_request_setup_packet_t request;
     1102        //int opResult;
     1103        usb_hub_set_hub_status_request(&request);
     1104        //endpoint 0
     1105
     1106        opResult = usb_pipe_control_read(
     1107                pipe,
     1108                &request, sizeof (usb_device_request_setup_packet_t),
     1109                &status, 4, &rcvd_size
     1110                );
     1111        if (opResult != EOK) {
     1112                usb_log_error("could not get hub status\n");
     1113                return;
     1114        }
     1115        if (rcvd_size != sizeof (usb_port_status_t)) {
     1116                usb_log_error("received status has incorrect size\n");
     1117                return;
     1118        }
     1119        //port reset
     1120        if (usb_hub_over_current_change(&status)) {
     1121                usb_process_hub_over_current(hub_info,status);
     1122        }
     1123        if (usb_hub_local_power_change(&status)) {
     1124                usb_process_hub_power_change(hub_info,status);
     1125        }
     1126}
     1127
    4601128
    4611129
Note: See TracChangeset for help on using the changeset viewer.