Ignore:
File:
1 edited

Legend:

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

    rc39e9fb 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->attached_handle != USB_DEVICE_HANDLE_INVALID)
     68        if (port->attached_device.fun)
    6769                return usb_hub_port_device_gone(port, hub);
    6870        return EOK;
     
    141143        usb_log_debug("Interrupt at port %zu\n", port->port_number);
    142144
    143         usb_port_status_t status;
     145        usb_port_status_t status = 0;
    144146        const int opResult = get_port_status(port, &status);
    145147        if (opResult != EOK) {
     
    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->attached_handle);
    263         usb_device_bus_exchange_end(exch);
    264         if (rc == EOK)
    265                 port->attached_handle = -1;
    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
     
    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 %zu\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->attached_handle);
    417         if (ret != EOK) {
    418                 usb_log_error("Failed to reset port %zu\n", port->port_number);
    419                 if (port_enable(port, false) != EOK) {
    420                         usb_log_warning("Failed to disable port %zu, NOT "
    421                             "releasing default address.\n", port->port_number);
    422                 } else {
    423                         if (usb_release_default_address(exch) != EOK)
    424                                 usb_log_warning(
    425                                     "Failed to release default address\n");
    426                 }
    427         } else {
    428                 if (usb_release_default_address(exch) != EOK)
    429                         usb_log_warning("Failed to release default address\n");
    430         }
    431 out:
    432         usb_device_bus_exchange_end(exch);
    433 
    434         fibril_mutex_lock(&hub->pending_ops_mutex);
    435         assert(hub->pending_ops_count > 0);
    436         --hub->pending_ops_count;
    437         fibril_condvar_signal(&hub->pending_ops_cv);
    438         fibril_mutex_unlock(&hub->pending_ops_mutex);
    439 
    440         return ret;
     455        return rc;
    441456}
    442457
Note: See TracChangeset for help on using the changeset viewer.