Ignore:
File:
1 edited

Legend:

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

    re40b9f00 r6d8c5725  
    3434 */
    3535#include <usb/hub.h>
     36#include <usb/pipes.h>
     37#include <usb/request.h>
     38#include <usb/recognise.h>
    3639#include <usbhc_iface.h>
    3740#include <errno.h>
     
    5558 * @return Error code.
    5659 */
    57 int usb_hc_reserve_default_address(usb_hc_connection_t *connection)
     60int usb_hc_reserve_default_address(usb_hc_connection_t *connection,
     61    usb_speed_t speed)
     62{
     63        CHECK_CONNECTION(connection);
     64
     65        return async_req_2_0(connection->hc_phone,
     66            DEV_IFACE_ID(USBHC_DEV_IFACE),
     67            IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS, speed);
     68}
     69
     70/** Tell host controller to release default address.
     71 *
     72 * @param connection Opened connection to host controller.
     73 * @return Error code.
     74 */
     75int usb_hc_release_default_address(usb_hc_connection_t *connection)
    5876{
    5977        CHECK_CONNECTION(connection);
     
    6179        return async_req_1_0(connection->hc_phone,
    6280            DEV_IFACE_ID(USBHC_DEV_IFACE),
    63             IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS);
    64 }
    65 
    66 /** Tell host controller to release default address.
    67  *
    68  * @param connection Opened connection to host controller.
    69  * @return Error code.
    70  */
    71 int usb_hc_release_default_address(usb_hc_connection_t *connection)
    72 {
    73         CHECK_CONNECTION(connection);
    74 
    75         return async_req_1_0(connection->hc_phone,
    76             DEV_IFACE_ID(USBHC_DEV_IFACE),
    7781            IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS);
    7882}
     
    8387 * @return Assigned USB address or negative error code.
    8488 */
    85 usb_address_t usb_hc_request_address(usb_hc_connection_t *connection)
     89usb_address_t usb_hc_request_address(usb_hc_connection_t *connection,
     90    usb_speed_t speed)
    8691{
    8792        CHECK_CONNECTION(connection);
    8893
    8994        sysarg_t address;
    90         int rc = async_req_1_1(connection->hc_phone,
    91             DEV_IFACE_ID(USBHC_DEV_IFACE),
    92             IPC_M_USBHC_REQUEST_ADDRESS, &address);
     95        int rc = async_req_2_1(connection->hc_phone,
     96            DEV_IFACE_ID(USBHC_DEV_IFACE),
     97            IPC_M_USBHC_REQUEST_ADDRESS, speed,
     98            &address);
    9399        if (rc != EOK) {
    94100                return (usb_address_t) rc;
     
    135141
    136142
     143/** Wrapper for registering attached device to the hub.
     144 *
     145 * The @p enable_port function is expected to enable singalling on given
     146 * port.
     147 * The two arguments to it can have arbitrary meaning
     148 * (the @p port_no is only a suggestion)
     149 * and are not touched at all by this function
     150 * (they are passed as is to the @p enable_port function).
     151 *
     152 * If the @p enable_port fails (i.e. does not return EOK), the device
     153 * addition is cancelled.
     154 * The return value is then returned (it is good idea to use different
     155 * error codes than those listed as return codes by this function itself).
     156 *
     157 * @param parent Parent device (i.e. the hub device).
     158 * @param connection Opened connection to host controller.
     159 * @param dev_speed New device speed.
     160 * @param enable_port Function for enabling signalling through the port the
     161 *      device is attached to.
     162 * @param port_no Port number (passed through to @p enable_port).
     163 * @param arg Any data argument to @p enable_port.
     164 * @param[out] assigned_address USB address of the device.
     165 * @param[out] assigned_handle Devman handle of the new device.
     166 * @return Error code.
     167 * @retval ENOENT Connection to HC not opened.
     168 * @retval EADDRNOTAVAIL Failed retrieving free address from host controller.
     169 * @retval EBUSY Failed reserving default USB address.
     170 * @retval ENOTCONN Problem connecting to the host controller via USB pipe.
     171 * @retval ESTALL Problem communication with device (either SET_ADDRESS
     172 *      request or requests for descriptors when creating match ids).
     173 */
     174int usb_hc_new_device_wrapper(device_t *parent, usb_hc_connection_t *connection,
     175    usb_speed_t dev_speed,
     176    int (*enable_port)(int port_no, void *arg), int port_no, void *arg,
     177    usb_address_t *assigned_address, devman_handle_t *assigned_handle)
     178{
     179        CHECK_CONNECTION(connection);
     180
     181        /*
     182         * Request new address.
     183         */
     184        usb_address_t dev_addr = usb_hc_request_address(connection, dev_speed);
     185        if (dev_addr < 0) {
     186                return EADDRNOTAVAIL;
     187        }
     188
     189        int rc;
     190
     191        /*
     192         * Reserve the default address.
     193         */
     194        rc = usb_hc_reserve_default_address(connection, dev_speed);
     195        if (rc != EOK) {
     196                rc = EBUSY;
     197                goto leave_release_free_address;
     198        }
     199
     200        /*
     201         * Enable the port (i.e. allow signalling through this port).
     202         */
     203        rc = enable_port(port_no, arg);
     204        if (rc != EOK) {
     205                goto leave_release_default_address;
     206        }
     207
     208        /*
     209         * Change the address from default to the free one.
     210         * We need to create a new control pipe for that.
     211         */
     212        usb_device_connection_t dev_conn;
     213        rc = usb_device_connection_initialize_on_default_address(&dev_conn,
     214            connection);
     215        if (rc != EOK) {
     216                rc = ENOTCONN;
     217                goto leave_release_default_address;
     218        }
     219
     220        usb_endpoint_pipe_t ctrl_pipe;
     221        rc = usb_endpoint_pipe_initialize_default_control(&ctrl_pipe,
     222            &dev_conn);
     223        if (rc != EOK) {
     224                rc = ENOTCONN;
     225                goto leave_release_default_address;
     226        }
     227
     228        rc = usb_endpoint_pipe_start_session(&ctrl_pipe);
     229        if (rc != EOK) {
     230                rc = ENOTCONN;
     231                goto leave_release_default_address;
     232        }
     233
     234        rc = usb_request_set_address(&ctrl_pipe, dev_addr);
     235        if (rc != EOK) {
     236                rc = ESTALL;
     237                goto leave_stop_session;
     238        }
     239
     240        usb_endpoint_pipe_end_session(&ctrl_pipe);
     241
     242        /*
     243         * Once the address is changed, we can return the default address.
     244         */
     245        usb_hc_release_default_address(connection);
     246
     247        /*
     248         * It is time to register the device with devman.
     249         */
     250        /* FIXME: create device_register that will get opened ctrl pipe. */
     251        devman_handle_t child_handle;
     252        rc = usb_device_register_child_in_devman(dev_addr, dev_conn.hc_handle,
     253            parent, &child_handle);
     254        if (rc != EOK) {
     255                rc = ESTALL;
     256                goto leave_release_free_address;
     257        }
     258
     259        /*
     260         * And now inform the host controller about the handle.
     261         */
     262        usb_hc_attached_device_t new_device = {
     263                .address = dev_addr,
     264                .handle = child_handle
     265        };
     266        rc = usb_hc_register_device(connection, &new_device);
     267        if (rc != EOK) {
     268                rc = EDESTADDRREQ;
     269                goto leave_release_free_address;
     270        }
     271
     272        /*
     273         * And we are done.
     274         */
     275        if (assigned_address != NULL) {
     276                *assigned_address = dev_addr;
     277        }
     278        if (assigned_handle != NULL) {
     279                *assigned_handle = child_handle;
     280        }
     281
     282        return EOK;
     283
     284
     285
     286        /*
     287         * Error handling (like nested exceptions) starts here.
     288         * Completely ignoring errors here.
     289         */
     290
     291leave_stop_session:
     292        usb_endpoint_pipe_end_session(&ctrl_pipe);
     293
     294leave_release_default_address:
     295        usb_hc_release_default_address(connection);
     296
     297leave_release_free_address:
     298        usb_hc_unregister_device(connection, dev_addr);
     299
     300        return rc;
     301}
     302
     303
    137304/**
    138305 * @}
Note: See TracChangeset for help on using the changeset viewer.