Ignore:
File:
1 edited

Legend:

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

    rb300d2b rc4f7bf6  
    4141
    4242#include <usb/debug.h>
     43#include <usb/dev/hub.h>
    4344
    4445#include "port.h"
     
    5758    usb_port_status_t status);
    5859static int get_port_status(usb_hub_port_t *port, usb_port_status_t *status);
     60static int enable_port_callback(void *arg);
    5961static int add_device_phase1_worker_fibril(void *arg);
    6062static int create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub,
     
    6466{
    6567        assert(port);
    66         if (port->device_attached)
     68        if (port->attached_device.fun)
    6769                return usb_hub_port_device_gone(port, hub);
    6870        return EOK;
     
    139141        assert(port);
    140142        assert(hub);
    141         usb_log_debug("Interrupt at port %u\n", port->port_number);
     143        usb_log_debug("Interrupt at port %zu\n", port->port_number);
    142144
    143145        usb_port_status_t status = 0;
    144146        const int opResult = get_port_status(port, &status);
    145147        if (opResult != EOK) {
    146                 usb_log_error("Failed to get port %u status: %s.\n",
     148                usb_log_error("Failed to get port %zu status: %s.\n",
    147149                    port->port_number, str_error(opResult));
    148150                return;
     
    153155                const bool connected =
    154156                    (status & USB_HUB_PORT_STATUS_CONNECTION) != 0;
    155                 usb_log_debug("Connection change on port %u: device %s.\n",
     157                usb_log_debug("Connection change on port %zu: device %s.\n",
    156158                    port->port_number, connected ? "attached" : "removed");
    157159
     
    169171                        if (opResult != EOK) {
    170172                                usb_log_error(
    171                                     "Cannot handle change on port %u: %s.\n",
     173                                    "Cannot handle change on port %zu: %s.\n",
    172174                                    port->port_number, str_error(opResult));
    173175                        }
     
    183185        /* Enable change, ports are automatically disabled on errors. */
    184186        if (status & USB_HUB_PORT_C_STATUS_ENABLED) {
    185                 usb_log_info("Port %u, disabled because of errors.\n",
     187                usb_log_info("Port %zu, disabled because of errors.\n",
    186188                   port->port_number);
    187189                usb_hub_port_device_gone(port, hub);
     
    190192                if (rc != EOK) {
    191193                        usb_log_error(
    192                             "Failed to clear port %u enable change feature: "
     194                            "Failed to clear port %zu enable change feature: "
    193195                            "%s.\n", port->port_number, str_error(rc));
    194196                }
     
    198200        /* Suspend change */
    199201        if (status & USB_HUB_PORT_C_STATUS_SUSPEND) {
    200                 usb_log_error("Port %u went to suspend state, this should"
     202                usb_log_error("Port %zu went to suspend state, this should"
    201203                    "NOT happen as we do not support suspend state!",
    202204                    port->port_number);
     
    205207                if (rc != EOK) {
    206208                        usb_log_error(
    207                             "Failed to clear port %u suspend change feature: "
     209                            "Failed to clear port %zu suspend change feature: "
    208210                            "%s.\n", port->port_number, str_error(rc));
    209211                }
     
    221223                if (rc != EOK) {
    222224                        usb_log_error(
    223                             "Failed to clear port %u OC change feature: %s.\n",
     225                            "Failed to clear port %zu OC change feature: %s.\n",
    224226                            port->port_number, str_error(rc));
    225227                }
     
    229231                        if (rc != EOK) {
    230232                                usb_log_error(
    231                                     "Failed to set port %u power after OC:"
     233                                    "Failed to set port %zu power after OC:"
    232234                                    " %s.\n", port->port_number, str_error(rc));
    233235                        }
     
    240242        }
    241243
    242         usb_log_debug("Port %u status %#08" PRIx32 "\n",
     244        usb_log_debug("Port %zu status 0x%08" PRIx32 "\n",
    243245            port->port_number, status);
    244246}
     
    257259        assert(port);
    258260        assert(hub);
    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 
     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;
    268300}
    269301
     
    286318
    287319        if (port->reset_okay) {
    288                 usb_log_debug("Port %u reset complete.\n", port->port_number);
     320                usb_log_debug("Port %zu reset complete.\n", port->port_number);
    289321        } else {
    290322                usb_log_warning(
    291                     "Port %u reset complete but port not enabled.\n",
     323                    "Port %zu reset complete but port not enabled.\n",
    292324                    port->port_number);
    293325        }
     
    299331        if (rc != EOK) {
    300332                usb_log_error(
    301                     "Failed to clear port %u reset change feature: %s.\n",
     333                    "Failed to clear port %zu reset change feature: %s.\n",
    302334                    port->port_number, str_error(rc));
    303335        }
     
    344376}
    345377
    346 static 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         }
     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 */
     387static 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;
    368408}
    369409
     
    378418int add_device_phase1_worker_fibril(void *arg)
    379419{
    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;
     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));
     441        } 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
    387453        free(arg);
    388454
    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: %s",
    419                     port->port_number, str_error(ret));
    420                 const int ret = port_enable(port, false);
    421                 if (ret != EOK) {
    422                         usb_log_warning("Failed to disable port %u (%s), NOT "
    423                             "releasing default address.", port->port_number,
    424                             str_error(ret));
    425                 } else {
    426                         const int ret = usb_release_default_address(exch);
    427                         if (ret != EOK)
    428                                 usb_log_warning("Failed to release default "
    429                                     "address: %s", str_error(ret));
    430                 }
    431         } else {
    432                 port->device_attached = true;
    433                 if (usb_release_default_address(exch) != EOK)
    434                         usb_log_warning("Failed to release default address\n");
    435         }
    436 out:
    437         usb_device_bus_exchange_end(exch);
    438 
    439         fibril_mutex_lock(&hub->pending_ops_mutex);
    440         assert(hub->pending_ops_count > 0);
    441         --hub->pending_ops_count;
    442         fibril_condvar_signal(&hub->pending_ops_cv);
    443         fibril_mutex_unlock(&hub->pending_ops_mutex);
    444 
    445         return ret;
     455        return rc;
    446456}
    447457
Note: See TracChangeset for help on using the changeset viewer.