Changeset 747ef72 in mainline for uspace/lib/usbdev/src/hub.c


Ignore:
Timestamp:
2011-11-10T11:29:10Z (13 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
54464f6a, c2245a3, c6f189f7
Parents:
2e1b9dc (diff), 2d1ba51 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge USB changes.

Interface changes:

  • GET_ADDRESS has been renamed to GET_MY_ADDRESS and the handle parameter was dropped. Tis call no longer cascades up to the root hub, but it is answered in the first place the information is available (nearest hub)
  • Reintroduced address reservation for USB_DEFAULT_ADDRESS. The interface now enables device drivers to request specific address on initialization and either insists on that address or accept any other if the address is not available. Note that it is not possible to get the default address if the driver does not insist.
  • Any endpoint registered is removed when address is released and a warning is produced if there were any such endpoints.
  • It is no longer necessary or possible to pass device speed information when registering endpoints.

Driver fixes: memory leaks and crashes (not only) in error paths.
Fixes or removes flaky device_remove implementation in device drivers.

File:
1 edited

Legend:

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

    r2e1b9dc r747ef72  
    6666 *
    6767 * @param connection Opened connection to host controller.
     68 * @param preferred Preferred SUB address.
     69 * @param strict Fail if the preferred address is not avialable.
    6870 * @param speed Speed of the new device (device that will be assigned
    6971 *    the returned address).
     
    7173 */
    7274usb_address_t usb_hc_request_address(usb_hc_connection_t *connection,
    73     usb_speed_t speed)
     75    usb_address_t preferred, bool strict, usb_speed_t speed)
    7476{
    7577        CHECK_CONNECTION(connection);
     
    7880       
    7981        sysarg_t address;
    80         int rc = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    81             IPC_M_USBHC_REQUEST_ADDRESS, speed,
    82             &address);
     82        int rc = async_req_4_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
     83            IPC_M_USBHC_REQUEST_ADDRESS, preferred, strict, speed, &address);
    8384       
    8485        async_exchange_end(exch);
     
    132133}
    133134
    134 
    135 static void unregister_control_endpoint_on_default_address(
    136     usb_hc_connection_t *connection)
     135/** Change address of connected device.
     136 * This function automatically updates the backing connection to point to
     137 * the new address. It also unregisterrs the old endpoint and registers
     138 * a new one.
     139 * This creates whole bunch of problems:
     140 *  1. All pipes using this wire are broken because they are not
     141 *     registered for new address
     142 *  2. All other pipes for this device are using wrong address,
     143 *     possibly targeting completely different device
     144 *
     145 * @param pipe Control endpoint pipe (session must be already started).
     146 * @param new_address New USB address to be set (in native endianness).
     147 * @return Error code.
     148 */
     149static int usb_request_set_address(usb_pipe_t *pipe, usb_address_t new_address,
     150    usb_hc_connection_t *hc_conn)
    137151{
    138         usb_device_connection_t dev_conn;
    139         int rc = usb_device_connection_initialize_on_default_address(&dev_conn,
    140             connection);
    141         if (rc != EOK) {
    142                 return;
    143         }
    144 
    145         usb_pipe_t ctrl_pipe;
    146         rc = usb_pipe_initialize_default_control(&ctrl_pipe, &dev_conn);
    147         if (rc != EOK) {
    148                 return;
    149         }
    150 
    151         usb_pipe_unregister(&ctrl_pipe, connection);
     152        if ((new_address < 0) || (new_address >= USB11_ADDRESS_MAX)) {
     153                return EINVAL;
     154        }
     155        assert(pipe);
     156        assert(hc_conn);
     157        assert(pipe->wire != NULL);
     158
     159        const uint16_t addr = uint16_host2usb((uint16_t)new_address);
     160
     161        int rc = usb_control_request_set(pipe,
     162            USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_DEVICE,
     163            USB_DEVREQ_SET_ADDRESS, addr, 0, NULL, 0);
     164
     165        if (rc != EOK) {
     166                return rc;
     167        }
     168
     169        /* TODO: prevent others from accessing the wire now. */
     170        if (usb_pipe_unregister(pipe, hc_conn) != EOK) {
     171                usb_log_warning(
     172                    "Failed to unregister the old pipe on address change.\n");
     173        }
     174        /* The address is already changed so set it in the wire */
     175        pipe->wire->address = new_address;
     176        rc = usb_pipe_register(pipe, 0, hc_conn);
     177        if (rc != EOK)
     178                return EADDRNOTAVAIL;
     179
     180        return EOK;
    152181}
    153182
     
    171200 *
    172201 * @param[in] parent Parent device (i.e. the hub device).
    173  * @param[in] connection Connection to host controller.
     202 * @param[in] connection Connection to host controller. Must be non-null.
    174203 * @param[in] dev_speed New device speed.
    175204 * @param[in] enable_port Function for enabling signaling through the port the
     
    177206 * @param[in] arg Any data argument to @p enable_port.
    178207 * @param[out] assigned_address USB address of the device.
    179  * @param[in] dev_ops Child device ops.
     208 * @param[in] dev_ops Child device ops. Will use default if not provided.
    180209 * @param[in] new_dev_data Arbitrary pointer to be stored in the child
    181  *      as @c driver_data.
     210 *      as @c driver_data. Will allocate and assign usb_hub_attached_device_t
     211 *      structure if NULL.
    182212 * @param[out] new_fun Storage where pointer to allocated child function
    183  *      will be written.
     213 *      will be written. Must be non-null.
    184214 * @return Error code.
     215 * @retval EINVAL Either connection or new_fun is a NULL pointer.
    185216 * @retval ENOENT Connection to HC not opened.
    186217 * @retval EADDRNOTAVAIL Failed retrieving free address from host controller.
     
    195226    ddf_dev_ops_t *dev_ops, void *new_dev_data, ddf_fun_t **new_fun)
    196227{
    197         assert(connection != NULL);
     228        if (new_fun == NULL || connection == NULL)
     229                return EINVAL;
     230
    198231        // FIXME: this is awful, we are accessing directly the structure.
     232        // TODO: Why not use provided connection?
    199233        usb_hc_connection_t hc_conn = {
    200234                .hc_handle = connection->hc_handle,
     
    215249        }
    216250
    217 
    218251        /*
    219252         * Request new address.
    220253         */
    221         usb_address_t dev_addr = usb_hc_request_address(&hc_conn, dev_speed);
     254        usb_address_t dev_addr =
     255            usb_hc_request_address(&hc_conn, 0, false, dev_speed);
    222256        if (dev_addr < 0) {
    223257                rc = EADDRNOTAVAIL;
     
    240274
    241275        usb_pipe_t ctrl_pipe;
    242         rc = usb_pipe_initialize_default_control(&ctrl_pipe,
    243             &dev_conn);
     276        rc = usb_pipe_initialize_default_control(&ctrl_pipe, &dev_conn);
    244277        if (rc != EOK) {
    245278                rc = ENOTCONN;
     
    248281
    249282        do {
    250                 rc = usb_pipe_register_with_speed(&ctrl_pipe, dev_speed, 0,
    251                     &hc_conn);
    252                 if (rc != EOK) {
     283                rc = usb_hc_request_address(&hc_conn, USB_ADDRESS_DEFAULT,
     284                    true, dev_speed);
     285                if (rc == ENOENT) {
    253286                        /* Do not overheat the CPU ;-). */
    254287                        async_usleep(ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC);
    255288                }
    256         } while (rc != EOK);
     289        } while (rc == ENOENT);
     290        if (rc < 0) {
     291                goto leave_release_free_address;
     292        }
     293
     294        /* Register control pipe on default address. */
     295        rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
     296        if (rc != EOK) {
     297                rc = ENOTCONN;
     298                goto leave_release_default_address;
     299        }
     300
    257301        struct timeval end_time;
    258302
     
    267311         * above might use much of this time so we should only wait to fill
    268312         * up the 100ms quota*/
    269         suseconds_t elapsed = tv_sub(&end_time, &start_time);
     313        const suseconds_t elapsed = tv_sub(&end_time, &start_time);
    270314        if (elapsed < 100000) {
    271315                async_usleep(100000 - elapsed);
    272316        }
    273317
    274         /*
    275          * Endpoint is registered. We can enable the port and change
    276          * device address.
    277          */
     318        /* Endpoint is registered. We can enable the port and change address. */
    278319        rc = enable_port(arg);
    279320        if (rc != EOK) {
     
    287328        async_usleep(10000);
    288329
     330        /* Get max_packet_size value. */
    289331        rc = usb_pipe_probe_default_control(&ctrl_pipe);
    290332        if (rc != EOK) {
     
    293335        }
    294336
    295         rc = usb_request_set_address(&ctrl_pipe, dev_addr);
     337        rc = usb_request_set_address(&ctrl_pipe, dev_addr, &hc_conn);
    296338        if (rc != EOK) {
    297339                rc = ESTALL;
     
    299341        }
    300342
    301         /*
    302          * Address changed. We can release the original endpoint, thus
    303          * allowing other to access the default address.
    304          */
    305         unregister_control_endpoint_on_default_address(&hc_conn);
    306 
    307         /*
    308          * Time to register the new endpoint.
    309          */
    310         rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
    311         if (rc != EOK) {
    312                 goto leave_release_free_address;
    313         }
    314 
    315         /*
    316          * It is time to register the device with devman.
    317          */
     343        /* Address changed. We can release the default, thus
     344         * allowing other to access the default address. */
     345        usb_hc_unregister_device(&hc_conn, USB_ADDRESS_DEFAULT);
     346
     347        /* Register the device with devman. */
    318348        /* FIXME: create device_register that will get opened ctrl pipe. */
    319349        ddf_fun_t *child_fun;
    320         rc = usb_device_register_child_in_devman(dev_addr, dev_conn.hc_handle,
     350        rc = usb_device_register_child_in_devman(&ctrl_pipe,
    321351            parent, dev_ops, new_dev_data, &child_fun);
    322352        if (rc != EOK) {
    323                 rc = ESTALL;
    324353                goto leave_release_free_address;
    325354        }
    326355
    327         /*
    328          * And now inform the host controller about the handle.
    329          */
    330         usb_hub_attached_device_t new_device = {
     356        const usb_hub_attached_device_t new_device = {
    331357                .address = dev_addr,
    332358                .fun = child_fun,
    333359        };
     360
     361
     362        /* Inform the host controller about the handle. */
    334363        rc = usb_hc_register_device(&hc_conn, &new_device);
    335364        if (rc != EOK) {
     365                /* We know nothing about that data. */
     366                if (new_dev_data)
     367                        child_fun->driver_data = NULL;
     368                /* The child function is already created. */
     369                ddf_fun_destroy(child_fun);
    336370                rc = EDESTADDRREQ;
    337371                goto leave_release_free_address;
    338372        }
    339373
    340 
    341         /*
    342          * And we are done.
    343          */
    344374        if (assigned_address != NULL) {
    345375                *assigned_address = dev_addr;
    346376        }
    347         if (new_fun != NULL) {
    348                 *new_fun = child_fun;
    349         }
     377
     378        *new_fun = child_fun;
    350379
    351380        rc = EOK;
     
    357386         */
    358387leave_release_default_address:
    359         usb_pipe_unregister(&ctrl_pipe, &hc_conn);
     388        usb_hc_unregister_device(&hc_conn, USB_ADDRESS_DEFAULT);
    360389
    361390leave_release_free_address:
    362         usb_hc_unregister_device(&hc_conn, dev_addr);
     391        /* This might be either 0:0 or dev_addr:0 */
     392        if (usb_pipe_unregister(&ctrl_pipe, &hc_conn) != EOK)
     393                usb_log_warning("%s: Failed to unregister default pipe.\n",
     394                    __FUNCTION__);
     395
     396        if (usb_hc_unregister_device(&hc_conn, dev_addr) != EOK)
     397                usb_log_warning("%s: Failed to unregister device.\n",
     398                    __FUNCTION__);
    363399
    364400close_connection:
    365401        if (usb_hc_connection_close(&hc_conn) != EOK)
    366                 usb_log_warning("usb_hc_new_device_wrapper(): Failed to close "
    367                     "connection.\n");
     402                usb_log_warning("%s: Failed to close hc connection.\n",
     403                    __FUNCTION__);
    368404
    369405        return rc;
Note: See TracChangeset for help on using the changeset viewer.