Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usb/src/hub.c

    r1c258d1 r9f9b31ad  
    4040#include <errno.h>
    4141#include <assert.h>
    42 #include <usb/debug.h>
    43 
    44 /** How much time to wait between attempts to register endpoint 0:0.
    45  * The value is based on typical value for port reset + some overhead.
    46  */
    47 #define ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC (1000 * (10 + 2))
    4842
    4943/** Check that HC connection is alright.
     
    5953        } while (false)
    6054
     55
     56/** Tell host controller to reserve default address.
     57 *
     58 * @param connection Opened connection to host controller.
     59 * @param speed Speed of the device that will respond on the default address.
     60 * @return Error code.
     61 */
     62int usb_hc_reserve_default_address(usb_hc_connection_t *connection,
     63    usb_speed_t speed)
     64{
     65        CHECK_CONNECTION(connection);
     66
     67        return async_req_2_0(connection->hc_phone,
     68            DEV_IFACE_ID(USBHC_DEV_IFACE),
     69            IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS, speed);
     70}
     71
     72/** Tell host controller to release default address.
     73 *
     74 * @param connection Opened connection to host controller.
     75 * @return Error code.
     76 */
     77int usb_hc_release_default_address(usb_hc_connection_t *connection)
     78{
     79        CHECK_CONNECTION(connection);
     80
     81        return async_req_1_0(connection->hc_phone,
     82            DEV_IFACE_ID(USBHC_DEV_IFACE),
     83            IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS);
     84}
     85
    6186/** Ask host controller for free address assignment.
    6287 *
     
    153178 * error codes than those listed as return codes by this function itself).
    154179 *
    155  * The @p connection representing connection with host controller does not
    156  * need to be started.
    157  * This function duplicates the connection to allow simultaneous calls of
    158  * this function (i.e. from different fibrils).
    159  *
    160180 * @param[in] parent Parent device (i.e. the hub device).
    161  * @param[in] connection Connection to host controller.
     181 * @param[in] connection Opened connection to host controller.
    162182 * @param[in] dev_speed New device speed.
    163183 * @param[in] enable_port Function for enabling signaling through the port the
     
    186206    ddf_dev_ops_t *dev_ops, void *new_dev_data, ddf_fun_t **new_fun)
    187207{
    188         assert(connection != NULL);
    189         // FIXME: this is awful, we are accessing directly the structure.
    190         usb_hc_connection_t hc_conn = {
    191                 .hc_handle = connection->hc_handle,
    192                 .hc_phone = -1
    193         };
     208        CHECK_CONNECTION(connection);
     209
     210        /*
     211         * Request new address.
     212         */
     213        usb_address_t dev_addr = usb_hc_request_address(connection, dev_speed);
     214        if (dev_addr < 0) {
     215                return EADDRNOTAVAIL;
     216        }
    194217
    195218        int rc;
    196219
    197         rc = usb_hc_connection_open(&hc_conn);
    198         if (rc != EOK) {
    199                 return rc;
    200         }
    201 
    202 
    203         /*
    204          * Request new address.
    205          */
    206         usb_address_t dev_addr = usb_hc_request_address(&hc_conn, dev_speed);
    207         if (dev_addr < 0) {
    208                 usb_hc_connection_close(&hc_conn);
    209                 return EADDRNOTAVAIL;
    210         }
    211 
    212         /*
    213          * We will not register control pipe on default address.
    214          * The registration might fail. That means that someone else already
    215          * registered that endpoint. We will simply wait and try again.
    216          * (Someone else already wants to add a new device.)
     220        /*
     221         * Reserve the default address.
     222         */
     223        rc = usb_hc_reserve_default_address(connection, dev_speed);
     224        if (rc != EOK) {
     225                rc = EBUSY;
     226                goto leave_release_free_address;
     227        }
     228
     229        /*
     230         * Enable the port (i.e. allow signaling through this port).
     231         */
     232        rc = enable_port(port_no, arg);
     233        if (rc != EOK) {
     234                goto leave_release_default_address;
     235        }
     236
     237        /*
     238         * Change the address from default to the free one.
     239         * We need to create a new control pipe for that.
    217240         */
    218241        usb_device_connection_t dev_conn;
    219242        rc = usb_device_connection_initialize_on_default_address(&dev_conn,
    220             &hc_conn);
     243            connection);
    221244        if (rc != EOK) {
    222245                rc = ENOTCONN;
    223                 goto leave_release_free_address;
     246                goto leave_release_default_address;
    224247        }
    225248
     
    229252        if (rc != EOK) {
    230253                rc = ENOTCONN;
    231                 goto leave_release_free_address;
    232         }
    233 
    234         do {
    235                 rc = usb_pipe_register_with_speed(&ctrl_pipe, dev_speed, 0,
    236                     &hc_conn);
    237                 if (rc != EOK) {
    238                         /* Do not overheat the CPU ;-). */
    239                         async_usleep(ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC);
    240                 }
    241         } while (rc != EOK);
    242 
    243         /*
    244          * Endpoint is registered. We can enable the port and change
    245          * device address.
    246          */
    247         rc = enable_port(port_no, arg);
    248         if (rc != EOK) {
    249                 goto leave_release_default_address;
    250         }
    251 
     254                goto leave_release_default_address;
     255        }
     256
     257        /* Before sending any traffic, we need to register this
     258         * endpoint.
     259         */
     260        rc = usb_pipe_register(&ctrl_pipe, 0, connection);
     261        if (rc != EOK) {
     262                rc = EREFUSED;
     263                goto leave_release_default_address;
     264        }
    252265        rc = usb_pipe_probe_default_control(&ctrl_pipe);
    253266        if (rc != EOK) {
     267                rc = ENOTCONN;
     268                goto leave_release_default_address;
     269        }
     270
     271        rc = usb_pipe_start_session(&ctrl_pipe);
     272        if (rc != EOK) {
     273                rc = ENOTCONN;
     274                goto leave_unregister_endpoint;
     275        }
     276
     277        rc = usb_request_set_address(&ctrl_pipe, dev_addr);
     278        if (rc != EOK) {
    254279                rc = ESTALL;
    255                 goto leave_release_default_address;
    256         }
    257 
    258         rc = usb_request_set_address(&ctrl_pipe, dev_addr);
    259         if (rc != EOK) {
    260                 rc = ESTALL;
    261                 goto leave_release_default_address;
    262         }
    263 
    264         /*
    265          * Address changed. We can release the original endpoint, thus
    266          * allowing other to access the default address.
    267          */
    268         unregister_control_endpoint_on_default_address(&hc_conn);
    269 
    270         /*
    271          * Time to register the new endpoint.
    272          */
    273         rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
    274         if (rc != EOK) {
    275                 goto leave_release_free_address;
    276         }
     280                goto leave_stop_session;
     281        }
     282
     283        usb_pipe_end_session(&ctrl_pipe);
     284
     285        /*
     286         * Register the control endpoint for the new device.
     287         */
     288        rc = usb_pipe_register(&ctrl_pipe, 0, connection);
     289        if (rc != EOK) {
     290                rc = EREFUSED;
     291                goto leave_unregister_endpoint;
     292        }
     293
     294        /*
     295         * Release the original endpoint.
     296         */
     297        unregister_control_endpoint_on_default_address(connection);
     298
     299        /*
     300         * Once the address is changed, we can return the default address.
     301         */
     302        usb_hc_release_default_address(connection);
     303
    277304
    278305        /*
     
    289316        }
    290317
     318
     319
    291320        /*
    292321         * And now inform the host controller about the handle.
     
    296325                .handle = child_handle
    297326        };
    298         rc = usb_hc_register_device(&hc_conn, &new_device);
     327        rc = usb_hc_register_device(connection, &new_device);
    299328        if (rc != EOK) {
    300329                rc = EDESTADDRREQ;
     
    320349         * Completely ignoring errors here.
    321350         */
     351
     352leave_stop_session:
     353        usb_pipe_end_session(&ctrl_pipe);
     354
     355leave_unregister_endpoint:
     356        usb_pipe_unregister(&ctrl_pipe, connection);
     357
    322358leave_release_default_address:
    323         usb_pipe_unregister(&ctrl_pipe, &hc_conn);
     359        usb_hc_release_default_address(connection);
    324360
    325361leave_release_free_address:
    326         usb_hc_unregister_device(&hc_conn, dev_addr);
    327 
    328         usb_hc_connection_close(&hc_conn);
     362        usb_hc_unregister_device(connection, dev_addr);
    329363
    330364        return rc;
Note: See TracChangeset for help on using the changeset viewer.