Ignore:
File:
1 edited

Legend:

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

    rc4f7bf6 r58563585  
    2727 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2828 */
     29
    2930/** @addtogroup drvusbhub
    3031 * @{
     
    4142
    4243#include <usb/debug.h>
    43 #include <usb/dev/hub.h>
    4444
    4545#include "port.h"
     
    5656static int usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub);
    5757static void usb_hub_port_reset_completed(usb_hub_port_t *port,
    58     usb_port_status_t status);
     58    usb_hub_dev_t *hub, usb_port_status_t status);
    5959static int get_port_status(usb_hub_port_t *port, usb_port_status_t *status);
    60 static int enable_port_callback(void *arg);
    6160static int add_device_phase1_worker_fibril(void *arg);
    6261static int create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub,
     
    6665{
    6766        assert(port);
    68         if (port->attached_device.fun)
     67        if (port->device_attached)
    6968                return usb_hub_port_device_gone(port, hub);
    7069        return EOK;
     
    124123        assert(port);
    125124        fibril_mutex_lock(&port->mutex);
    126         port->reset_completed = true;
    127         port->reset_okay = false;
     125        if (port->reset_status == IN_RESET)
     126                port->reset_status = RESET_FAIL;
    128127        fibril_condvar_broadcast(&port->reset_cv);
    129128        fibril_mutex_unlock(&port->mutex);
     
    141140        assert(port);
    142141        assert(hub);
    143         usb_log_debug("Interrupt at port %zu\n", port->port_number);
     142        usb_log_debug2("(%p-%u): Interrupt.\n", hub, port->port_number);
    144143
    145144        usb_port_status_t status = 0;
    146145        const int opResult = get_port_status(port, &status);
    147146        if (opResult != EOK) {
    148                 usb_log_error("Failed to get port %zu status: %s.\n",
     147                usb_log_error("(%p-%u): Failed to get port status: %s.\n", hub,
    149148                    port->port_number, str_error(opResult));
    150149                return;
     
    155154                const bool connected =
    156155                    (status & USB_HUB_PORT_STATUS_CONNECTION) != 0;
    157                 usb_log_debug("Connection change on port %zu: device %s.\n",
     156                usb_log_debug("(%p-%u): Connection change: device %s.\n", hub,
    158157                    port->port_number, connected ? "attached" : "removed");
    159158
     
    162161                    USB_HUB_FEATURE_C_PORT_CONNECTION);
    163162                if (opResult != EOK) {
    164                         usb_log_warning("Failed to clear port-change-connection"
    165                             " flag: %s.\n", str_error(opResult));
     163                        usb_log_warning("(%p-%u): Failed to clear "
     164                            "port-change-connection flag: %s.\n", hub,
     165                            port->port_number, str_error(opResult));
    166166                }
    167167
     
    170170                            usb_port_speed(status));
    171171                        if (opResult != EOK) {
    172                                 usb_log_error(
    173                                     "Cannot handle change on port %zu: %s.\n",
    174                                     port->port_number, str_error(opResult));
     172                                usb_log_error("(%p-%u): Cannot handle change on"
     173                                   " port: %s.\n", hub, port->port_number,
     174                                   str_error(opResult));
    175175                        }
    176176                } else {
     177                        /* Handle the case we were in reset */
     178                        // FIXME: usb_hub_port_reset_fail(port);
    177179                        /* If enabled change was reported leave the removal
    178180                         * to that handler, it shall ACK the change too. */
     
    185187        /* Enable change, ports are automatically disabled on errors. */
    186188        if (status & USB_HUB_PORT_C_STATUS_ENABLED) {
    187                 usb_log_info("Port %zu, disabled because of errors.\n",
     189                // TODO: maybe HS reset failed?
     190                usb_log_info("(%p-%u): Port disabled because of errors.\n", hub,
    188191                   port->port_number);
    189192                usb_hub_port_device_gone(port, hub);
     
    191194                        USB_HUB_FEATURE_C_PORT_ENABLE);
    192195                if (rc != EOK) {
    193                         usb_log_error(
    194                             "Failed to clear port %zu enable change feature: "
    195                             "%s.\n", port->port_number, str_error(rc));
     196                        usb_log_error("(%p-%u): Failed to clear port enable "
     197                            "change feature: %s.", hub, port->port_number,
     198                            str_error(rc));
    196199                }
    197200
     
    200203        /* Suspend change */
    201204        if (status & USB_HUB_PORT_C_STATUS_SUSPEND) {
    202                 usb_log_error("Port %zu went to suspend state, this should"
    203                     "NOT happen as we do not support suspend state!",
     205                usb_log_error("(%p-%u): Port went to suspend state, this should"
     206                    " NOT happen as we do not support suspend state!", hub,
    204207                    port->port_number);
    205208                const int rc = usb_hub_port_clear_feature(port,
    206209                        USB_HUB_FEATURE_C_PORT_SUSPEND);
    207210                if (rc != EOK) {
    208                         usb_log_error(
    209                             "Failed to clear port %zu suspend change feature: "
    210                             "%s.\n", port->port_number, str_error(rc));
     211                        usb_log_error("(%p-%u): Failed to clear port suspend "
     212                            "change feature: %s.", hub, port->port_number,
     213                            str_error(rc));
    211214                }
    212215        }
     
    214217        /* Over current */
    215218        if (status & USB_HUB_PORT_C_STATUS_OC) {
     219                usb_log_debug("(%p-%u): Port OC reported!.", hub,
     220                    port->port_number);
    216221                /* According to the USB specs:
    217222                 * 11.13.5 Over-current Reporting and Recovery
     
    222227                    USB_HUB_FEATURE_C_PORT_OVER_CURRENT);
    223228                if (rc != EOK) {
    224                         usb_log_error(
    225                             "Failed to clear port %zu OC change feature: %s.\n",
    226                             port->port_number, str_error(rc));
     229                        usb_log_error("(%p-%u): Failed to clear port OC change "
     230                            "feature: %s.\n", hub, port->port_number,
     231                            str_error(rc));
    227232                }
    228233                if (!(status & ~USB_HUB_PORT_STATUS_OC)) {
     
    230235                            port, USB_HUB_FEATURE_PORT_POWER);
    231236                        if (rc != EOK) {
    232                                 usb_log_error(
    233                                     "Failed to set port %zu power after OC:"
    234                                     " %s.\n", port->port_number, str_error(rc));
     237                                usb_log_error("(%p-%u): Failed to set port "
     238                                    "power after OC: %s.", hub,
     239                                    port->port_number, str_error(rc));
    235240                        }
    236241                }
     
    239244        /* Port reset, set on port reset complete. */
    240245        if (status & USB_HUB_PORT_C_STATUS_RESET) {
    241                 usb_hub_port_reset_completed(port, status);
    242         }
    243 
    244         usb_log_debug("Port %zu status 0x%08" PRIx32 "\n",
     246                usb_hub_port_reset_completed(port, hub, status);
     247        }
     248
     249        usb_log_debug2("(%p-%u): Port status %#08" PRIx32, hub,
    245250            port->port_number, status);
    246251}
     
    259264        assert(port);
    260265        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;
     266        async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device);
     267        if (!exch)
     268                return ENOMEM;
     269        const int 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
    300275}
    301276
     
    308283 * @param status Port status mask
    309284 */
    310 void usb_hub_port_reset_completed(usb_hub_port_t *port,
     285void usb_hub_port_reset_completed(usb_hub_port_t *port, usb_hub_dev_t *hub,
    311286    usb_port_status_t status)
    312287{
    313288        assert(port);
    314289        fibril_mutex_lock(&port->mutex);
     290        const bool enabled = (status & USB_HUB_PORT_STATUS_ENABLED) != 0;
    315291        /* Finalize device adding. */
    316         port->reset_completed = true;
    317         port->reset_okay = (status & USB_HUB_PORT_STATUS_ENABLED) != 0;
    318 
    319         if (port->reset_okay) {
    320                 usb_log_debug("Port %zu reset complete.\n", port->port_number);
     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);
    321297        } else {
    322                 usb_log_warning(
    323                     "Port %zu reset complete but port not enabled.\n",
    324                     port->port_number);
     298                port->reset_status = RESET_FAIL;
     299                usb_log_warning("(%p-%u): Port reset complete but port not "
     300                    "enabled.", hub, port->port_number);
    325301        }
    326302        fibril_condvar_broadcast(&port->reset_cv);
     
    330306        int rc = usb_hub_port_clear_feature(port, USB_HUB_FEATURE_C_PORT_RESET);
    331307        if (rc != EOK) {
    332                 usb_log_error(
    333                     "Failed to clear port %zu reset change feature: %s.\n",
    334                     port->port_number, str_error(rc));
     308                usb_log_error("(%p-%u): Failed to clear port reset change: %s.",
     309                    hub, port->port_number, str_error(rc));
    335310        }
    336311}
     
    376351}
    377352
    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));
     353static int port_enable(usb_hub_port_t *port, usb_hub_dev_t *hub, bool enable)
     354{
     355        if (enable) {
     356                int 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);
    395370                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;
     371        } else {
     372                return usb_hub_port_clear_feature(port,
     373                                USB_HUB_FEATURE_PORT_ENABLE);
     374        }
    408375}
    409376
     
    418385int add_device_phase1_worker_fibril(void *arg)
    419386{
    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));
     387        struct add_device_phase1 *params = arg;
     388        assert(params);
     389
     390        int 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 int 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 int 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                }
    441448        } 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;
     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        }
     456out:
     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;
    456466}
    457467
     
    479489        data->speed = speed;
    480490
    481         fibril_mutex_lock(&port->mutex);
    482         port->reset_completed = false;
    483         fibril_mutex_unlock(&port->mutex);
    484 
    485491        fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data);
    486492        if (fibril == 0) {
Note: See TracChangeset for help on using the changeset viewer.