hub.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Vojtech Horky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00035 #include <usb/dev/hub.h>
00036 #include <usb/dev/pipes.h>
00037 #include <usb/dev/request.h>
00038 #include <usb/dev/recognise.h>
00039 #include <usbhc_iface.h>
00040 #include <errno.h>
00041 #include <assert.h>
00042 #include <usb/debug.h>
00043 #include <time.h>
00044 
00048 #define ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC (1000 * (10 + 2))
00049 
00054 #define CHECK_CONNECTION(conn) \
00055         do { \
00056                 assert((conn)); \
00057                 if (!usb_hc_connection_is_opened((conn))) { \
00058                         return ENOENT; \
00059                 } \
00060         } while (false)
00061 
00069 usb_address_t usb_hc_request_address(usb_hc_connection_t *connection,
00070     usb_speed_t speed)
00071 {
00072         CHECK_CONNECTION(connection);
00073 
00074         sysarg_t address;
00075         int rc = async_req_2_1(connection->hc_phone,
00076             DEV_IFACE_ID(USBHC_DEV_IFACE),
00077             IPC_M_USBHC_REQUEST_ADDRESS, speed,
00078             &address);
00079         if (rc != EOK) {
00080                 return (usb_address_t) rc;
00081         } else {
00082                 return (usb_address_t) address;
00083         }
00084 }
00085 
00092 int usb_hc_register_device(usb_hc_connection_t * connection,
00093     const usb_hc_attached_device_t *attached_device)
00094 {
00095         CHECK_CONNECTION(connection);
00096         if (attached_device == NULL) {
00097                 return EBADMEM;
00098         }
00099 
00100         return async_req_3_0(connection->hc_phone,
00101             DEV_IFACE_ID(USBHC_DEV_IFACE),
00102             IPC_M_USBHC_BIND_ADDRESS,
00103             attached_device->address, attached_device->handle);
00104 }
00105 
00112 int usb_hc_unregister_device(usb_hc_connection_t *connection,
00113     usb_address_t address)
00114 {
00115         CHECK_CONNECTION(connection);
00116 
00117         return async_req_2_0(connection->hc_phone,
00118             DEV_IFACE_ID(USBHC_DEV_IFACE),
00119             IPC_M_USBHC_RELEASE_ADDRESS, address);
00120 }
00121 
00122 
00123 static void unregister_control_endpoint_on_default_address(
00124     usb_hc_connection_t *connection)
00125 {
00126         usb_device_connection_t dev_conn;
00127         int rc = usb_device_connection_initialize_on_default_address(&dev_conn,
00128             connection);
00129         if (rc != EOK) {
00130                 return;
00131         }
00132 
00133         usb_pipe_t ctrl_pipe;
00134         rc = usb_pipe_initialize_default_control(&ctrl_pipe, &dev_conn);
00135         if (rc != EOK) {
00136                 return;
00137         }
00138 
00139         usb_pipe_unregister(&ctrl_pipe, connection);
00140 }
00141 
00142 
00184 int usb_hc_new_device_wrapper(ddf_dev_t *parent, usb_hc_connection_t *connection,
00185     usb_speed_t dev_speed,
00186     int (*enable_port)(int port_no, void *arg), int port_no, void *arg,
00187     usb_address_t *assigned_address, devman_handle_t *assigned_handle,
00188     ddf_dev_ops_t *dev_ops, void *new_dev_data, ddf_fun_t **new_fun)
00189 {
00190         assert(connection != NULL);
00191         // FIXME: this is awful, we are accessing directly the structure.
00192         usb_hc_connection_t hc_conn = {
00193                 .hc_handle = connection->hc_handle,
00194                 .hc_phone = -1
00195         };
00196 
00197         int rc;
00198         struct timeval start_time;
00199 
00200         rc = gettimeofday(&start_time, NULL);
00201         if (rc != EOK) {
00202                 return rc;
00203         }
00204 
00205         rc = usb_hc_connection_open(&hc_conn);
00206         if (rc != EOK) {
00207                 return rc;
00208         }
00209 
00210 
00211         /*
00212          * Request new address.
00213          */
00214         usb_address_t dev_addr = usb_hc_request_address(&hc_conn, dev_speed);
00215         if (dev_addr < 0) {
00216                 usb_hc_connection_close(&hc_conn);
00217                 return EADDRNOTAVAIL;
00218         }
00219 
00220         /*
00221          * We will not register control pipe on default address.
00222          * The registration might fail. That means that someone else already
00223          * registered that endpoint. We will simply wait and try again.
00224          * (Someone else already wants to add a new device.)
00225          */
00226         usb_device_connection_t dev_conn;
00227         rc = usb_device_connection_initialize_on_default_address(&dev_conn,
00228             &hc_conn);
00229         if (rc != EOK) {
00230                 rc = ENOTCONN;
00231                 goto leave_release_free_address;
00232         }
00233 
00234         usb_pipe_t ctrl_pipe;
00235         rc = usb_pipe_initialize_default_control(&ctrl_pipe,
00236             &dev_conn);
00237         if (rc != EOK) {
00238                 rc = ENOTCONN;
00239                 goto leave_release_free_address;
00240         }
00241 
00242         do {
00243                 rc = usb_pipe_register_with_speed(&ctrl_pipe, dev_speed, 0,
00244                     &hc_conn);
00245                 if (rc != EOK) {
00246                         /* Do not overheat the CPU ;-). */
00247                         async_usleep(ENDPOINT_0_0_REGISTER_ATTEMPT_DELAY_USEC);
00248                 }
00249         } while (rc != EOK);
00250         struct timeval end_time;
00251 
00252         rc = gettimeofday(&end_time, NULL);
00253         if (rc != EOK) {
00254                 goto leave_release_default_address;
00255         }
00256 
00257         /* According to the USB spec part 9.1.2 host allows 100ms time for
00258          * the insertion process to complete. According to 7.1.7.1 this is the
00259          * time between attach detected and port reset. However, the setup done
00260          * above might use much of this time so we should only wait to fill
00261          * up the 100ms quota*/
00262         suseconds_t elapsed = tv_sub(&end_time, &start_time);
00263         if (elapsed < 100000) {
00264                 async_usleep(100000 - elapsed);
00265         }
00266 
00267         /*
00268          * Endpoint is registered. We can enable the port and change
00269          * device address.
00270          */
00271         rc = enable_port(port_no, arg);
00272         if (rc != EOK) {
00273                 goto leave_release_default_address;
00274         }
00275         /* USB spec 7.1.7.1: The USB System Software guarantees a minimum of
00276          * 10ms for reset recovery. Device response to any bus transactions
00277          * addressed to the default device address during the reset recovery
00278          * time is undefined.
00279          */
00280         async_usleep(10000);
00281 
00282         rc = usb_pipe_probe_default_control(&ctrl_pipe);
00283         if (rc != EOK) {
00284                 rc = ESTALL;
00285                 goto leave_release_default_address;
00286         }
00287 
00288         rc = usb_request_set_address(&ctrl_pipe, dev_addr);
00289         if (rc != EOK) {
00290                 rc = ESTALL;
00291                 goto leave_release_default_address;
00292         }
00293 
00294         /*
00295          * Address changed. We can release the original endpoint, thus
00296          * allowing other to access the default address.
00297          */
00298         unregister_control_endpoint_on_default_address(&hc_conn);
00299 
00300         /*
00301          * Time to register the new endpoint.
00302          */
00303         rc = usb_pipe_register(&ctrl_pipe, 0, &hc_conn);
00304         if (rc != EOK) {
00305                 goto leave_release_free_address;
00306         }
00307 
00308         /*
00309          * It is time to register the device with devman.
00310          */
00311         /* FIXME: create device_register that will get opened ctrl pipe. */
00312         devman_handle_t child_handle;
00313         rc = usb_device_register_child_in_devman(dev_addr, dev_conn.hc_handle,
00314             parent, &child_handle,
00315             dev_ops, new_dev_data, new_fun);
00316         if (rc != EOK) {
00317                 rc = ESTALL;
00318                 goto leave_release_free_address;
00319         }
00320 
00321         /*
00322          * And now inform the host controller about the handle.
00323          */
00324         usb_hc_attached_device_t new_device = {
00325                 .address = dev_addr,
00326                 .handle = child_handle
00327         };
00328         rc = usb_hc_register_device(&hc_conn, &new_device);
00329         if (rc != EOK) {
00330                 rc = EDESTADDRREQ;
00331                 goto leave_release_free_address;
00332         }
00333         
00334         usb_hc_connection_close(&hc_conn);
00335 
00336         /*
00337          * And we are done.
00338          */
00339         if (assigned_address != NULL) {
00340                 *assigned_address = dev_addr;
00341         }
00342         if (assigned_handle != NULL) {
00343                 *assigned_handle = child_handle;
00344         }
00345 
00346         return EOK;
00347 
00348 
00349 
00350         /*
00351          * Error handling (like nested exceptions) starts here.
00352          * Completely ignoring errors here.
00353          */
00354 leave_release_default_address:
00355         usb_pipe_unregister(&ctrl_pipe, &hc_conn);
00356 
00357 leave_release_free_address:
00358         usb_hc_unregister_device(&hc_conn, dev_addr);
00359 
00360         usb_hc_connection_close(&hc_conn);
00361 
00362         return rc;
00363 }
00364 

Generated on Thu Jun 2 07:45:45 2011 for HelenOS/USB by  doxygen 1.4.7