Ignore:
File:
1 edited

Legend:

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

    rc4f7bf6 r0918382f  
    4141
    4242#include <usb/debug.h>
    43 #include <usb/dev/hub.h>
    4443
    4544#include "port.h"
     
    5857    usb_port_status_t status);
    5958static int get_port_status(usb_hub_port_t *port, usb_port_status_t *status);
    60 static int enable_port_callback(void *arg);
    6159static int add_device_phase1_worker_fibril(void *arg);
    6260static int create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub,
     
    6664{
    6765        assert(port);
    68         if (port->attached_device.fun)
     66        if (port->device_attached)
    6967                return usb_hub_port_device_gone(port, hub);
    7068        return EOK;
     
    141139        assert(port);
    142140        assert(hub);
    143         usb_log_debug("Interrupt at port %zu\n", port->port_number);
     141        usb_log_debug("Interrupt at port %u\n", port->port_number);
    144142
    145143        usb_port_status_t status = 0;
    146144        const int opResult = get_port_status(port, &status);
    147145        if (opResult != EOK) {
    148                 usb_log_error("Failed to get port %zu status: %s.\n",
     146                usb_log_error("Failed to get port %u status: %s.\n",
    149147                    port->port_number, str_error(opResult));
    150148                return;
     
    155153                const bool connected =
    156154                    (status & USB_HUB_PORT_STATUS_CONNECTION) != 0;
    157                 usb_log_debug("Connection change on port %zu: device %s.\n",
     155                usb_log_debug("Connection change on port %u: device %s.\n",
    158156                    port->port_number, connected ? "attached" : "removed");
    159157
     
    171169                        if (opResult != EOK) {
    172170                                usb_log_error(
    173                                     "Cannot handle change on port %zu: %s.\n",
     171                                    "Cannot handle change on port %u: %s.\n",
    174172                                    port->port_number, str_error(opResult));
    175173                        }
     
    185183        /* Enable change, ports are automatically disabled on errors. */
    186184        if (status & USB_HUB_PORT_C_STATUS_ENABLED) {
    187                 usb_log_info("Port %zu, disabled because of errors.\n",
     185                usb_log_info("Port %u, disabled because of errors.\n",
    188186                   port->port_number);
    189187                usb_hub_port_device_gone(port, hub);
     
    192190                if (rc != EOK) {
    193191                        usb_log_error(
    194                             "Failed to clear port %zu enable change feature: "
     192                            "Failed to clear port %u enable change feature: "
    195193                            "%s.\n", port->port_number, str_error(rc));
    196194                }
     
    200198        /* Suspend change */
    201199        if (status & USB_HUB_PORT_C_STATUS_SUSPEND) {
    202                 usb_log_error("Port %zu went to suspend state, this should"
     200                usb_log_error("Port %u went to suspend state, this should"
    203201                    "NOT happen as we do not support suspend state!",
    204202                    port->port_number);
     
    207205                if (rc != EOK) {
    208206                        usb_log_error(
    209                             "Failed to clear port %zu suspend change feature: "
     207                            "Failed to clear port %u suspend change feature: "
    210208                            "%s.\n", port->port_number, str_error(rc));
    211209                }
     
    223221                if (rc != EOK) {
    224222                        usb_log_error(
    225                             "Failed to clear port %zu OC change feature: %s.\n",
     223                            "Failed to clear port %u OC change feature: %s.\n",
    226224                            port->port_number, str_error(rc));
    227225                }
     
    231229                        if (rc != EOK) {
    232230                                usb_log_error(
    233                                     "Failed to set port %zu power after OC:"
     231                                    "Failed to set port %u power after OC:"
    234232                                    " %s.\n", port->port_number, str_error(rc));
    235233                        }
     
    242240        }
    243241
    244         usb_log_debug("Port %zu status 0x%08" PRIx32 "\n",
     242        usb_log_debug("Port %u status %#08" PRIx32 "\n",
    245243            port->port_number, status);
    246244}
     
    259257        assert(port);
    260258        assert(hub);
    261         if (port->attached_device.address < 0) {
    262                 usb_log_warning(
    263                     "Device on port %zu removed before being registered.\n",
    264                     port->port_number);
    265 
    266                 /*
    267                  * Device was removed before port reset completed.
    268                  * We will announce a failed port reset to unblock the
    269                  * port reset callback from new device wrapper.
    270                  */
    271                 usb_hub_port_reset_fail(port);
    272                 return EOK;
    273         }
    274 
    275         fibril_mutex_lock(&port->mutex);
    276         assert(port->attached_device.fun);
    277         usb_log_debug("Removing device on port %zu.\n", port->port_number);
    278         int ret = ddf_fun_unbind(port->attached_device.fun);
    279         if (ret != EOK) {
    280                 usb_log_error("Failed to unbind child function on port"
    281                     " %zu: %s.\n", port->port_number, str_error(ret));
    282                 fibril_mutex_unlock(&port->mutex);
    283                 return ret;
    284         }
    285 
    286         ddf_fun_destroy(port->attached_device.fun);
    287         port->attached_device.fun = NULL;
    288 
    289         ret = usb_hub_unregister_device(&hub->usb_device->hc_conn,
    290             &port->attached_device);
    291         if (ret != EOK) {
    292                 usb_log_warning("Failed to unregister address of the "
    293                     "removed device: %s.\n", str_error(ret));
    294         }
    295 
    296         port->attached_device.address = -1;
    297         fibril_mutex_unlock(&port->mutex);
    298         usb_log_info("Removed device on port %zu.\n", port->port_number);
    299         return EOK;
     259        async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device);
     260        if (!exch)
     261                return ENOMEM;
     262        const int rc = usb_device_remove(exch, port->port_number);
     263        usb_device_bus_exchange_end(exch);
     264        if (rc == EOK)
     265                port->device_attached = false;
     266        return rc;
     267
    300268}
    301269
     
    318286
    319287        if (port->reset_okay) {
    320                 usb_log_debug("Port %zu reset complete.\n", port->port_number);
     288                usb_log_debug("Port %u reset complete.\n", port->port_number);
    321289        } else {
    322290                usb_log_warning(
    323                     "Port %zu reset complete but port not enabled.\n",
     291                    "Port %u reset complete but port not enabled.\n",
    324292                    port->port_number);
    325293        }
     
    331299        if (rc != EOK) {
    332300                usb_log_error(
    333                     "Failed to clear port %zu reset change feature: %s.\n",
     301                    "Failed to clear port %u reset change feature: %s.\n",
    334302                    port->port_number, str_error(rc));
    335303        }
     
    376344}
    377345
    378 /** Callback for enabling a specific port.
    379  *
    380  * We wait on a CV until port is reseted.
    381  * That is announced via change on interrupt pipe.
    382  *
    383  * @param port_no Port number (starting at 1).
    384  * @param arg Custom argument, points to @c usb_hub_dev_t.
    385  * @return Error code.
    386  */
    387 static int enable_port_callback(void *arg)
    388 {
    389         usb_hub_port_t *port = arg;
    390         assert(port);
    391         const int rc =
    392             usb_hub_port_set_feature(port, USB_HUB_FEATURE_PORT_RESET);
    393         if (rc != EOK) {
    394                 usb_log_warning("Port reset failed: %s.\n", str_error(rc));
    395                 return rc;
    396         }
    397 
    398         /*
    399          * Wait until reset completes.
    400          */
    401         fibril_mutex_lock(&port->mutex);
    402         while (!port->reset_completed) {
    403                 fibril_condvar_wait(&port->reset_cv, &port->mutex);
    404         }
    405         fibril_mutex_unlock(&port->mutex);
    406 
    407         return port->reset_okay ? EOK : ESTALL;
     346static int port_enable(usb_hub_port_t *port, bool enable)
     347{
     348        if (enable) {
     349                const int rc =
     350                    usb_hub_port_set_feature(port, USB_HUB_FEATURE_PORT_RESET);
     351                if (rc != EOK) {
     352                        usb_log_error("Port reset failed: %s.\n",
     353                            str_error(rc));
     354                } else {
     355                        /* Wait until reset completes. */
     356                        fibril_mutex_lock(&port->mutex);
     357                        while (!port->reset_completed) {
     358                                fibril_condvar_wait(&port->reset_cv,
     359                                    &port->mutex);
     360                        }
     361                        fibril_mutex_unlock(&port->mutex);
     362                }
     363                return port->reset_okay ? EOK : ESTALL;
     364        } else {
     365                return usb_hub_port_clear_feature(port,
     366                                USB_HUB_FEATURE_PORT_ENABLE);
     367        }
    408368}
    409369
     
    418378int add_device_phase1_worker_fibril(void *arg)
    419379{
    420         struct add_device_phase1 *data = arg;
    421         assert(data);
    422 
    423         usb_address_t new_address;
    424         ddf_fun_t *child_fun;
    425 
    426         const int rc = usb_hc_new_device_wrapper(data->hub->usb_device->ddf_dev,
    427             &data->hub->usb_device->hc_conn, data->speed, enable_port_callback,
    428             data->port, &new_address, NULL, NULL, &child_fun);
    429 
    430         if (rc == EOK) {
    431                 fibril_mutex_lock(&data->port->mutex);
    432                 data->port->attached_device.fun = child_fun;
    433                 data->port->attached_device.address = new_address;
    434                 fibril_mutex_unlock(&data->port->mutex);
    435 
    436                 usb_log_info("Detected new device on `%s' (port %zu), "
    437                     "address %d (handle %" PRIun ").\n",
    438                     ddf_dev_get_name(data->hub->usb_device->ddf_dev),
    439                     data->port->port_number, new_address,
    440                     ddf_fun_get_handle(child_fun));
     380        struct add_device_phase1 *params = arg;
     381        assert(params);
     382
     383        int ret = EOK;
     384        usb_hub_dev_t *hub = params->hub;
     385        usb_hub_port_t *port = params->port;
     386        const usb_speed_t speed = params->speed;
     387        free(arg);
     388
     389        async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device);
     390        if (!exch) {
     391                usb_log_error("Failed to begin bus exchange\n");
     392                ret = ENOMEM;
     393                goto out;
     394        }
     395
     396        /* Reserve default address */
     397        while ((ret = usb_reserve_default_address(exch, speed)) == ENOENT) {
     398                async_usleep(1000000);
     399        }
     400        if (ret != EOK) {
     401                usb_log_error("Failed to reserve default address: %s\n",
     402                    str_error(ret));
     403                goto out;
     404        }
     405
     406        /* Reset port */
     407        port_enable(port, true);
     408        if (!port->reset_completed || !port->reset_okay) {
     409                usb_log_error("Failed to reset port %u\n", port->port_number);
     410                if (usb_release_default_address(exch) != EOK)
     411                        usb_log_warning("Failed to release default address\n");
     412                ret = EIO;
     413                goto out;
     414        }
     415
     416        ret = usb_device_enumerate(exch, port->port_number);
     417        if (ret != EOK) {
     418                usb_log_error("Failed to enumerate device on port %u\n",
     419                    port->port_number);
     420                if (port_enable(port, false) != EOK) {
     421                        usb_log_warning("Failed to disable port %u, NOT "
     422                            "releasing default address.\n", port->port_number);
     423                } else {
     424                        if (usb_release_default_address(exch) != EOK)
     425                                usb_log_warning(
     426                                    "Failed to release default address\n");
     427                }
    441428        } else {
    442                 usb_log_error("Failed registering device on port %zu: %s.\n",
    443                     data->port->port_number, str_error(rc));
    444         }
    445 
    446 
    447         fibril_mutex_lock(&data->hub->pending_ops_mutex);
    448         assert(data->hub->pending_ops_count > 0);
    449         --data->hub->pending_ops_count;
    450         fibril_condvar_signal(&data->hub->pending_ops_cv);
    451         fibril_mutex_unlock(&data->hub->pending_ops_mutex);
    452 
    453         free(arg);
    454 
    455         return rc;
     429                port->device_attached = true;
     430                if (usb_release_default_address(exch) != EOK)
     431                        usb_log_warning("Failed to release default address\n");
     432        }
     433out:
     434        usb_device_bus_exchange_end(exch);
     435
     436        fibril_mutex_lock(&hub->pending_ops_mutex);
     437        assert(hub->pending_ops_count > 0);
     438        --hub->pending_ops_count;
     439        fibril_condvar_signal(&hub->pending_ops_cv);
     440        fibril_mutex_unlock(&hub->pending_ops_mutex);
     441
     442        return ret;
    456443}
    457444
Note: See TracChangeset for help on using the changeset viewer.