Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/usbhub/port.c

    rb7fd2a0 raa148b3  
    4040#include <inttypes.h>
    4141#include <fibril_synch.h>
     42#include <usbhc_iface.h>
    4243
    4344#include <usb/debug.h>
     
    4748#include "status.h"
    4849
    49 /** Information for fibril for device discovery. */
    50 struct add_device_phase1 {
    51         usb_hub_dev_t *hub;
    52         usb_hub_port_t *port;
    53         usb_speed_t speed;
    54 };
    55 
    56 static errno_t usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub);
    57 static void usb_hub_port_reset_completed(usb_hub_port_t *port,
    58     usb_hub_dev_t *hub, usb_port_status_t status);
    59 static errno_t get_port_status(usb_hub_port_t *port, usb_port_status_t *status);
    60 static errno_t add_device_phase1_worker_fibril(void *arg);
    61 static errno_t create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub,
    62     usb_speed_t speed);
    63 
    64 errno_t usb_hub_port_fini(usb_hub_port_t *port, usb_hub_dev_t *hub)
     50#define port_log(lvl, port, fmt, ...) do { usb_log_##lvl("(%p-%u): " fmt, (port->hub), (port->port_number), ##__VA_ARGS__); } while (0)
     51
     52/** Initialize hub port information.
     53 *
     54 * @param port Port to be initialized.
     55 */
     56void usb_hub_port_init(usb_hub_port_t *port, usb_hub_dev_t *hub, unsigned int port_number)
    6557{
    6658        assert(port);
    67         if (port->device_attached)
    68                 return usb_hub_port_device_gone(port, hub);
     59        memset(port, 0, sizeof(*port));
     60        port->hub = hub;
     61        port->port_number = port_number;
     62        usb_port_init(&port->base);
     63}
     64
     65static inline usb_hub_port_t *get_hub_port(usb_port_t *port)
     66{
     67        assert(port);
     68        return (usb_hub_port_t *) port;
     69}
     70
     71/**
     72 * Inform the HC that the device on port is gone.
     73 */
     74static void remove_device(usb_port_t *port_base)
     75{
     76        usb_hub_port_t *port = get_hub_port(port_base);
     77
     78        async_exch_t *exch = usb_device_bus_exchange_begin(port->hub->usb_device);
     79        if (!exch) {
     80                port_log(error, port, "Cannot remove the device, failed creating exchange.");
     81                return;
     82        }
     83       
     84        const errno_t err = usbhc_device_remove(exch, port->port_number);
     85        if (err)
     86                port_log(error, port, "Failed to remove device: %s", str_error(err));
     87
     88        usb_device_bus_exchange_end(exch);
     89}
     90
     91
     92static usb_speed_t get_port_speed(usb_hub_port_t *port, uint32_t status)
     93{
     94        assert(port);
     95        assert(port->hub);
     96
     97        return usb_port_speed(port->hub->speed, status);
     98}
     99
     100/**
     101 * Routine for adding a new device in USB2.
     102 */
     103static errno_t enumerate_device_usb2(usb_hub_port_t *port, async_exch_t *exch)
     104{
     105        errno_t err;
     106
     107        port_log(debug, port, "Requesting default address.");
     108        err = usb_hub_reserve_default_address(port->hub, exch, &port->base);
     109        if (err != EOK) {
     110                port_log(error, port, "Failed to reserve default address: %s", str_error(err));
     111                return err;
     112        }
     113
     114        /* Reservation of default address could have blocked */
     115        if (port->base.state != PORT_CONNECTING)
     116                goto out_address;
     117
     118        port_log(debug, port, "Resetting port.");
     119        if ((err = usb_hub_set_port_feature(port->hub, port->port_number, USB_HUB_FEATURE_PORT_RESET))) {
     120                port_log(warning, port, "Port reset request failed: %s", str_error(err));
     121                goto out_address;
     122        }
     123
     124        if ((err = usb_port_wait_for_enabled(&port->base))) {
     125                port_log(error, port, "Failed to reset port: %s", str_error(err));
     126                goto out_address;
     127        }
     128
     129        port_log(debug, port, "Enumerating device.");
     130        if ((err = usbhc_device_enumerate(exch, port->port_number, port->speed))) {
     131                port_log(error, port, "Failed to enumerate device: %s", str_error(err));
     132                /* Disable the port */
     133                usb_hub_clear_port_feature(port->hub, port->port_number, USB2_HUB_FEATURE_PORT_ENABLE);
     134                goto out_address;
     135        }
     136
     137        port_log(debug, port, "Device enumerated");
     138
     139out_address:
     140        usb_hub_release_default_address(port->hub, exch);
     141        return err;
     142}
     143
     144/**
     145 * Routine for adding a new device in USB 3.
     146 */
     147static errno_t enumerate_device_usb3(usb_hub_port_t *port, async_exch_t *exch)
     148{
     149        errno_t err;
     150
     151        port_log(debug, port, "Issuing a warm reset.");
     152        if ((err = usb_hub_set_port_feature(port->hub, port->port_number, USB3_HUB_FEATURE_BH_PORT_RESET))) {
     153                port_log(warning, port, "Port reset request failed: %s", str_error(err));
     154                return err;
     155        }
     156
     157        if ((err = usb_port_wait_for_enabled(&port->base))) {
     158                port_log(error, port, "Failed to reset port: %s", str_error(err));
     159                return err;
     160        }
     161
     162        port_log(debug, port, "Enumerating device.");
     163        if ((err = usbhc_device_enumerate(exch, port->port_number, port->speed))) {
     164                port_log(error, port, "Failed to enumerate device: %s", str_error(err));
     165                return err;
     166        }
     167
     168        port_log(debug, port, "Device enumerated");
    69169        return EOK;
    70170}
    71171
    72 /**
    73  * Clear feature on hub port.
    74  *
    75  * @param port Port structure.
    76  * @param feature Feature selector.
    77  * @return Operation result
    78  */
    79 errno_t usb_hub_port_clear_feature(
    80     usb_hub_port_t *port, usb_hub_class_feature_t feature)
    81 {
    82         assert(port);
    83         const usb_device_request_setup_packet_t clear_request = {
    84                 .request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE,
    85                 .request = USB_DEVREQ_CLEAR_FEATURE,
    86                 .value = feature,
    87                 .index = port->port_number,
    88                 .length = 0,
    89         };
    90         return usb_pipe_control_write(port->control_pipe, &clear_request,
    91             sizeof(clear_request), NULL, 0);
    92 }
    93 
    94 /**
    95  * Set feature on hub port.
    96  *
    97  * @param port Port structure.
    98  * @param feature Feature selector.
    99  * @return Operation result
    100  */
    101 errno_t usb_hub_port_set_feature(
    102     usb_hub_port_t *port, usb_hub_class_feature_t feature)
    103 {
    104         assert(port);
    105         const usb_device_request_setup_packet_t clear_request = {
    106                 .request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE,
    107                 .request = USB_DEVREQ_SET_FEATURE,
    108                 .index = port->port_number,
    109                 .value = feature,
    110                 .length = 0,
    111         };
    112         return usb_pipe_control_write(port->control_pipe, &clear_request,
    113             sizeof(clear_request), NULL, 0);
    114 }
    115 
    116 /**
    117  * Mark reset process as failed due to external reasons
    118  *
    119  * @param port Port structure
    120  */
    121 void usb_hub_port_reset_fail(usb_hub_port_t *port)
    122 {
    123         assert(port);
    124         fibril_mutex_lock(&port->mutex);
    125         if (port->reset_status == IN_RESET)
    126                 port->reset_status = RESET_FAIL;
    127         fibril_condvar_broadcast(&port->reset_cv);
    128         fibril_mutex_unlock(&port->mutex);
     172static errno_t enumerate_device(usb_port_t *port_base)
     173{
     174        usb_hub_port_t *port = get_hub_port(port_base);
     175
     176        port_log(debug, port, "Setting up new device.");
     177        async_exch_t *exch = usb_device_bus_exchange_begin(port->hub->usb_device);
     178        if (!exch) {
     179                port_log(error, port, "Failed to create exchange.");
     180                return ENOMEM;
     181        }
     182
     183        const errno_t err = port->hub->speed == USB_SPEED_SUPER
     184                ? enumerate_device_usb3(port, exch)
     185                : enumerate_device_usb2(port, exch);
     186
     187        usb_device_bus_exchange_end(exch);
     188        return err;
     189}
     190
     191static void port_changed_connection(usb_hub_port_t *port, usb_port_status_t status)
     192{
     193        const bool connected = !!(status & USB_HUB_PORT_STATUS_CONNECTION);
     194        port_log(debug, port, "Connection change: device %s.", connected ? "attached" : "removed");
     195
     196        if (connected) {
     197                usb_port_connected(&port->base, &enumerate_device);
     198        } else {
     199                usb_port_disabled(&port->base, &remove_device);
     200        }
     201}
     202
     203static void port_changed_enabled(usb_hub_port_t *port, usb_port_status_t status)
     204{
     205        const bool enabled = !!(status & USB_HUB_PORT_STATUS_ENABLE);
     206        if (enabled) {
     207                port_log(warning, port, "Port unexpectedly changed to enabled.");
     208        } else {
     209                usb_port_disabled(&port->base, &remove_device);
     210        }
     211}
     212
     213static void port_changed_overcurrent(usb_hub_port_t *port, usb_port_status_t status)
     214{
     215        const bool overcurrent = !!(status & USB_HUB_PORT_STATUS_OC);
     216
     217        /* According to the USB specs:
     218         * 11.13.5 Over-current Reporting and Recovery
     219         * Hub device is responsible for putting port in power off
     220         * mode. USB system software is responsible for powering port
     221         * back on when the over-current condition is gone */
     222
     223        usb_port_disabled(&port->base, &remove_device);
     224
     225        if (!overcurrent) {
     226                const errno_t err = usb_hub_set_port_feature(port->hub, port->port_number, USB_HUB_FEATURE_PORT_POWER);
     227                if (err)
     228                        port_log(error, port, "Failed to set port power after OC: %s.", str_error(err));
     229        }
     230}
     231
     232static void port_changed_reset(usb_hub_port_t *port, usb_port_status_t status)
     233{
     234        const bool enabled = !!(status & USB_HUB_PORT_STATUS_ENABLE);
     235
     236        if (enabled) {
     237                port->speed = get_port_speed(port, status);
     238                usb_port_enabled(&port->base);
     239        } else
     240                usb_port_disabled(&port->base, &remove_device);
     241}
     242
     243typedef void (*change_handler_t)(usb_hub_port_t *, usb_port_status_t);
     244
     245static void check_port_change(usb_hub_port_t *port, usb_port_status_t *status,
     246    change_handler_t handler, usb_port_status_t mask, usb_hub_class_feature_t feature)
     247{
     248        if ((*status & mask) == 0)
     249                return;
     250
     251        /* Clear the change so it won't come again */
     252        usb_hub_clear_port_feature(port->hub, port->port_number, feature);
     253
     254        if (handler)
     255                handler(port, *status);
     256
     257        /* Mark the change as resolved */
     258        *status &= ~mask;
    129259}
    130260
     
    136266 * @param hub hub representation
    137267 */
    138 void usb_hub_port_process_interrupt(usb_hub_port_t *port, usb_hub_dev_t *hub)
     268void usb_hub_port_process_interrupt(usb_hub_port_t *port)
    139269{
    140270        assert(port);
    141         assert(hub);
    142         usb_log_debug2("(%p-%u): Interrupt.\n", hub, port->port_number);
     271        port_log(debug2, port, "Interrupt.");
    143272
    144273        usb_port_status_t status = 0;
    145         const errno_t opResult = get_port_status(port, &status);
    146         if (opResult != EOK) {
    147                 usb_log_error("(%p-%u): Failed to get port status: %s.\n", hub,
    148                     port->port_number, str_error(opResult));
     274        const errno_t err = usb_hub_get_port_status(port->hub, port->port_number, &status);
     275        if (err != EOK) {
     276                port_log(error, port, "Failed to get port status: %s.", str_error(err));
    149277                return;
    150278        }
    151279
    152         /* Connection change */
    153         if (status & USB_HUB_PORT_C_STATUS_CONNECTION) {
    154                 const bool connected =
    155                     (status & USB_HUB_PORT_STATUS_CONNECTION) != 0;
    156                 usb_log_debug("(%p-%u): Connection change: device %s.\n", hub,
    157                     port->port_number, connected ? "attached" : "removed");
    158 
    159                 /* ACK the change */
    160                 const errno_t opResult = usb_hub_port_clear_feature(port,
    161                     USB_HUB_FEATURE_C_PORT_CONNECTION);
    162                 if (opResult != EOK) {
    163                         usb_log_warning("(%p-%u): Failed to clear "
    164                             "port-change-connection flag: %s.\n", hub,
    165                             port->port_number, str_error(opResult));
    166                 }
    167 
    168                 if (connected) {
    169                         const errno_t opResult = create_add_device_fibril(port, hub,
    170                             usb_port_speed(status));
    171                         if (opResult != EOK) {
    172                                 usb_log_error("(%p-%u): Cannot handle change on"
    173                                    " port: %s.\n", hub, port->port_number,
    174                                    str_error(opResult));
    175                         }
    176                 } else {
    177                         /* Handle the case we were in reset */
    178                         // FIXME: usb_hub_port_reset_fail(port);
    179                         /* If enabled change was reported leave the removal
    180                          * to that handler, it shall ACK the change too. */
    181                         if (!(status & USB_HUB_PORT_C_STATUS_ENABLED)) {
    182                                 usb_hub_port_device_gone(port, hub);
    183                         }
    184                 }
    185         }
    186 
    187         /* Enable change, ports are automatically disabled on errors. */
    188         if (status & USB_HUB_PORT_C_STATUS_ENABLED) {
    189                 // TODO: maybe HS reset failed?
    190                 usb_log_info("(%p-%u): Port disabled because of errors.\n", hub,
    191                    port->port_number);
    192                 usb_hub_port_device_gone(port, hub);
    193                 const errno_t rc = usb_hub_port_clear_feature(port,
    194                         USB_HUB_FEATURE_C_PORT_ENABLE);
    195                 if (rc != EOK) {
    196                         usb_log_error("(%p-%u): Failed to clear port enable "
    197                             "change feature: %s.", hub, port->port_number,
    198                             str_error(rc));
    199                 }
    200 
    201         }
    202 
    203         /* Suspend change */
    204         if (status & USB_HUB_PORT_C_STATUS_SUSPEND) {
    205                 usb_log_error("(%p-%u): Port went to suspend state, this should"
    206                     " NOT happen as we do not support suspend state!", hub,
    207                     port->port_number);
    208                 const errno_t rc = usb_hub_port_clear_feature(port,
    209                         USB_HUB_FEATURE_C_PORT_SUSPEND);
    210                 if (rc != EOK) {
    211                         usb_log_error("(%p-%u): Failed to clear port suspend "
    212                             "change feature: %s.", hub, port->port_number,
    213                             str_error(rc));
    214                 }
    215         }
    216 
    217         /* Over current */
    218         if (status & USB_HUB_PORT_C_STATUS_OC) {
    219                 usb_log_debug("(%p-%u): Port OC reported!.", hub,
    220                     port->port_number);
    221                 /* According to the USB specs:
    222                  * 11.13.5 Over-current Reporting and Recovery
    223                  * Hub device is responsible for putting port in power off
    224                  * mode. USB system software is responsible for powering port
    225                  * back on when the over-current condition is gone */
    226                 const errno_t rc = usb_hub_port_clear_feature(port,
    227                     USB_HUB_FEATURE_C_PORT_OVER_CURRENT);
    228                 if (rc != EOK) {
    229                         usb_log_error("(%p-%u): Failed to clear port OC change "
    230                             "feature: %s.\n", hub, port->port_number,
    231                             str_error(rc));
    232                 }
    233                 if (!(status & ~USB_HUB_PORT_STATUS_OC)) {
    234                         const errno_t rc = usb_hub_port_set_feature(
    235                             port, USB_HUB_FEATURE_PORT_POWER);
    236                         if (rc != EOK) {
    237                                 usb_log_error("(%p-%u): Failed to set port "
    238                                     "power after OC: %s.", hub,
    239                                     port->port_number, str_error(rc));
    240                         }
    241                 }
    242         }
    243 
    244         /* Port reset, set on port reset complete. */
    245         if (status & USB_HUB_PORT_C_STATUS_RESET) {
    246                 usb_hub_port_reset_completed(port, hub, status);
    247         }
    248 
    249         usb_log_debug2("(%p-%u): Port status %#08" PRIx32, hub,
    250             port->port_number, status);
    251 }
    252 
    253 /**
    254  * routine called when a device on port has been removed
    255  *
    256  * If the device on port had default address, it releases default address.
    257  * Otherwise does not do anything, because DDF does not allow to remove device
    258  * from it`s device tree.
    259  * @param port port structure
    260  * @param hub hub representation
    261  */
    262 errno_t usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub)
    263 {
    264         assert(port);
    265         assert(hub);
    266         async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device);
    267         if (!exch)
    268                 return ENOMEM;
    269         const errno_t rc = usb_device_remove(exch, port->port_number);
    270         usb_device_bus_exchange_end(exch);
    271         if (rc == EOK)
    272                 port->device_attached = false;
    273         return rc;
    274 
    275 }
    276 
    277 /**
    278  * Process port reset change
    279  *
    280  * After this change port should be enabled, unless some problem occurred.
    281  * This functions triggers second phase of enabling new device.
    282  * @param port Port structure
    283  * @param status Port status mask
    284  */
    285 void usb_hub_port_reset_completed(usb_hub_port_t *port, usb_hub_dev_t *hub,
    286     usb_port_status_t status)
    287 {
    288         assert(port);
    289         fibril_mutex_lock(&port->mutex);
    290         const bool enabled = (status & USB_HUB_PORT_STATUS_ENABLED) != 0;
    291         /* Finalize device adding. */
    292 
    293         if (enabled) {
    294                 port->reset_status = RESET_OK;
    295                 usb_log_debug("(%p-%u): Port reset complete.\n", hub,
    296                     port->port_number);
     280        check_port_change(port, &status, &port_changed_connection,
     281            USB_HUB_PORT_STATUS_C_CONNECTION, USB_HUB_FEATURE_C_PORT_CONNECTION);
     282
     283        check_port_change(port, &status, &port_changed_overcurrent,
     284            USB_HUB_PORT_STATUS_C_OC, USB_HUB_FEATURE_C_PORT_OVER_CURRENT);
     285
     286        check_port_change(port, &status, &port_changed_reset,
     287            USB_HUB_PORT_STATUS_C_RESET, USB_HUB_FEATURE_C_PORT_RESET);
     288
     289        if (port->hub->speed <= USB_SPEED_HIGH) {
     290                check_port_change(port, &status, &port_changed_enabled,
     291                    USB2_HUB_PORT_STATUS_C_ENABLE, USB2_HUB_FEATURE_C_PORT_ENABLE);
    297292        } else {
    298                 port->reset_status = RESET_FAIL;
    299                 usb_log_warning("(%p-%u): Port reset complete but port not "
    300                     "enabled.", hub, port->port_number);
    301         }
    302         fibril_condvar_broadcast(&port->reset_cv);
    303         fibril_mutex_unlock(&port->mutex);
    304 
    305         /* Clear the port reset change. */
    306         errno_t rc = usb_hub_port_clear_feature(port, USB_HUB_FEATURE_C_PORT_RESET);
    307         if (rc != EOK) {
    308                 usb_log_error("(%p-%u): Failed to clear port reset change: %s.",
    309                     hub, port->port_number, str_error(rc));
    310         }
    311 }
    312 
    313 /** Retrieve port status.
    314  *
    315  * @param[in] port Port structure
    316  * @param[out] status Where to store the port status.
    317  * @return Error code.
    318  */
    319 static errno_t get_port_status(usb_hub_port_t *port, usb_port_status_t *status)
    320 {
    321         assert(port);
    322         /* USB hub specific GET_PORT_STATUS request. See USB Spec 11.16.2.6
    323          * Generic GET_STATUS request cannot be used because of the difference
    324          * in status data size (2B vs. 4B)*/
    325         const usb_device_request_setup_packet_t request = {
    326                 .request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS,
    327                 .request = USB_HUB_REQUEST_GET_STATUS,
    328                 .value = 0,
    329                 .index = uint16_host2usb(port->port_number),
    330                 .length = sizeof(usb_port_status_t),
    331         };
    332         size_t recv_size;
    333         usb_port_status_t status_tmp;
    334 
    335         const errno_t rc = usb_pipe_control_read(port->control_pipe,
    336             &request, sizeof(usb_device_request_setup_packet_t),
    337             &status_tmp, sizeof(status_tmp), &recv_size);
    338         if (rc != EOK) {
    339                 return rc;
    340         }
    341 
    342         if (recv_size != sizeof (status_tmp)) {
    343                 return ELIMIT;
    344         }
    345 
    346         if (status != NULL) {
    347                 *status = status_tmp;
    348         }
    349 
    350         return EOK;
    351 }
    352 
    353 static errno_t port_enable(usb_hub_port_t *port, usb_hub_dev_t *hub, bool enable)
    354 {
    355         if (enable) {
    356                 errno_t rc =
    357                     usb_hub_port_set_feature(port, USB_HUB_FEATURE_PORT_RESET);
    358                 if (rc != EOK) {
    359                         usb_log_error("(%p-%u): Port reset request failed: %s.",
    360                             hub, port->port_number, str_error(rc));
    361                         return rc;
    362                 }
    363                 /* Wait until reset completes. */
    364                 fibril_mutex_lock(&port->mutex);
    365                 port->reset_status = IN_RESET;
    366                 while (port->reset_status == IN_RESET)
    367                         fibril_condvar_wait(&port->reset_cv, &port->mutex);
    368                 rc = port->reset_status == RESET_OK ? EOK : ESTALL;
    369                 fibril_mutex_unlock(&port->mutex);
    370                 return rc;
    371         } else {
    372                 return usb_hub_port_clear_feature(port,
    373                                 USB_HUB_FEATURE_PORT_ENABLE);
    374         }
    375 }
    376 
    377 /** Fibril for adding a new device.
    378  *
    379  * Separate fibril is needed because the port reset completion is announced
    380  * via interrupt pipe and thus we cannot block here.
    381  *
    382  * @param arg Pointer to struct add_device_phase1.
    383  * @return 0 Always.
    384  */
    385 errno_t add_device_phase1_worker_fibril(void *arg)
    386 {
    387         struct add_device_phase1 *params = arg;
    388         assert(params);
    389 
    390         errno_t ret = EOK;
    391         usb_hub_dev_t *hub = params->hub;
    392         usb_hub_port_t *port = params->port;
    393         const usb_speed_t speed = params->speed;
    394         free(arg);
    395 
    396         usb_log_debug("(%p-%u): New device sequence.", hub, port->port_number);
    397 
    398         async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device);
    399         if (!exch) {
    400                 usb_log_error("(%p-%u): Failed to begin bus exchange.", hub,
    401                     port->port_number);
    402                 ret = ENOMEM;
    403                 goto out;
    404         }
    405 
    406         /* Reserve default address */
    407         while ((ret = usb_reserve_default_address(exch, speed)) == ENOENT) {
    408                 async_usleep(1000000);
    409         }
    410         if (ret != EOK) {
    411                 usb_log_error("(%p-%u): Failed to reserve default address: %s",
    412                     hub, port->port_number, str_error(ret));
    413                 goto out;
    414         }
    415 
    416         usb_log_debug("(%p-%u): Got default address reseting port.", hub,
    417             port->port_number);
    418         /* Reset port */
    419         ret = port_enable(port, hub, true);
    420         if (ret != EOK) {
    421                 usb_log_error("(%p-%u): Failed to reset port.", hub,
    422                     port->port_number);
    423                 if (usb_release_default_address(exch) != EOK)
    424                         usb_log_warning("(%p-%u): Failed to release default "
    425                             "address.", hub, port->port_number);
    426                 ret = EIO;
    427                 goto out;
    428         }
    429         usb_log_debug("(%p-%u): Port reset, enumerating device", hub,
    430             port->port_number);
    431 
    432         ret = usb_device_enumerate(exch, port->port_number);
    433         if (ret != EOK) {
    434                 usb_log_error("(%p-%u): Failed to enumerate device: %s", hub,
    435                     port->port_number, str_error(ret));
    436                 const errno_t ret = port_enable(port, hub, false);
    437                 if (ret != EOK) {
    438                         usb_log_warning("(%p-%u)Failed to disable port (%s), "
    439                             "NOT releasing default address.", hub,
    440                             port->port_number, str_error(ret));
    441                 } else {
    442                         const errno_t ret = usb_release_default_address(exch);
    443                         if (ret != EOK)
    444                                 usb_log_warning("(%p-%u): Failed to release "
    445                                     "default address: %s", hub,
    446                                     port->port_number, str_error(ret));
    447                 }
    448         } else {
    449                 usb_log_debug("(%p-%u): Device enumerated", hub,
    450                     port->port_number);
    451                 port->device_attached = true;
    452                 if (usb_release_default_address(exch) != EOK)
    453                         usb_log_warning("(%p-%u): Failed to release default "
    454                             "address", hub, port->port_number);
    455         }
    456 out:
    457         usb_device_bus_exchange_end(exch);
    458 
    459         fibril_mutex_lock(&hub->pending_ops_mutex);
    460         assert(hub->pending_ops_count > 0);
    461         --hub->pending_ops_count;
    462         fibril_condvar_signal(&hub->pending_ops_cv);
    463         fibril_mutex_unlock(&hub->pending_ops_mutex);
    464 
    465         return ret;
    466 }
    467 
    468 /** Start device adding when connection change is detected.
    469  *
    470  * This fires a new fibril to complete the device addition.
    471  *
    472  * @param hub Hub where the change occured.
    473  * @param port Port index (starting at 1).
    474  * @param speed Speed of the device.
    475  * @return Error code.
    476  */
    477 static errno_t create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub,
    478     usb_speed_t speed)
    479 {
    480         assert(hub);
    481         assert(port);
    482         struct add_device_phase1 *data
    483             = malloc(sizeof(struct add_device_phase1));
    484         if (data == NULL) {
    485                 return ENOMEM;
    486         }
    487         data->hub = hub;
    488         data->port = port;
    489         data->speed = speed;
    490 
    491         fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data);
    492         if (fibril == 0) {
    493                 free(data);
    494                 return ENOMEM;
    495         }
    496         fibril_mutex_lock(&hub->pending_ops_mutex);
    497         ++hub->pending_ops_count;
    498         fibril_mutex_unlock(&hub->pending_ops_mutex);
    499         fibril_add_ready(fibril);
    500 
    501         return EOK;
    502 }
     293                check_port_change(port, &status, &port_changed_reset,
     294                    USB3_HUB_PORT_STATUS_C_BH_RESET, USB3_HUB_FEATURE_C_BH_PORT_RESET);
     295
     296                check_port_change(port, &status, NULL,
     297                    USB3_HUB_PORT_STATUS_C_LINK_STATE, USB3_HUB_FEATURE_C_PORT_LINK_STATE);
     298        }
     299
     300        /* Check for changes we ignored */
     301        if (status & 0xffff0000) {
     302                port_log(debug, port, "Port status change igored. Status: %#08" PRIx32, status);
     303        }
     304}
     305
    503306
    504307/**
Note: See TracChangeset for help on using the changeset viewer.