Changeset 72af8da in mainline for uspace/drv/uhci-rhd/port.c


Ignore:
Timestamp:
2011-03-16T18:50:17Z (14 years ago)
Author:
Matus Dekanek <smekideki@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
42a3a57
Parents:
3e7b7cd (diff), fcf07e6 (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 from usb/development

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/uhci-rhd/port.c

    r3e7b7cd r72af8da  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcirh
    2929 * @{
    3030 */
    3131/** @file
    32  * @brief UHCI driver
    33  */
     32 * @brief UHCI root hub port routines
     33 */
     34#include <libarch/ddi.h> /* pio_read and pio_write */
    3435#include <errno.h>
    3536#include <str_error.h>
     
    3738
    3839#include <usb/usb.h>    /* usb_address_t */
    39 #include <usb/usbdevice.h>
    4040#include <usb/hub.h>
    41 #include <usb/request.h>
    4241#include <usb/debug.h>
    43 #include <usb/recognise.h>
    4442
    4543#include "port.h"
    46 #include "port_status.h"
    47 
    48 static int uhci_port_new_device(uhci_port_t *port, uint16_t status);
     44
     45static int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed);
    4946static int uhci_port_remove_device(uhci_port_t *port);
    5047static int uhci_port_set_enabled(uhci_port_t *port, bool enabled);
    5148static int uhci_port_check(void *port);
    52 static int new_device_enable_port(int portno, void *arg);
    53 
    54 int uhci_port_init(
    55   uhci_port_t *port, port_status_t *address, unsigned number,
    56   unsigned usec, ddf_dev_t *rh)
    57 {
    58         assert(port);
     49static int uhci_port_reset_enable(int portno, void *arg);
     50static void uhci_port_print_status(
     51    uhci_port_t *port, const port_status_t value);
     52
     53/** Register reading helper function.
     54 *
     55 * @param[in] port Structure to use.
     56 * @return Error code. (Always EOK)
     57 */
     58static inline port_status_t uhci_port_read_status(uhci_port_t *port)
     59{
     60        assert(port);
     61        return pio_read_16(port->address);
     62}
     63/*----------------------------------------------------------------------------*/
     64/** Register writing helper function.
     65 *
     66 * @param[in] port Structure to use.
     67 * @param[in] value New register value.
     68 * @return Error code. (Always EOK)
     69 */
     70static inline void uhci_port_write_status(
     71    uhci_port_t *port, port_status_t value)
     72{
     73        assert(port);
     74        pio_write_16(port->address, value);
     75}
     76
     77/*----------------------------------------------------------------------------*/
     78/** Initialize UHCI root hub port instance.
     79 *
     80 * @param[in] port Memory structure to use.
     81 * @param[in] addr Address of I/O register.
     82 * @param[in] number Port number.
     83 * @param[in] usec Polling interval.
     84 * @param[in] rh Pointer to ddf instance fo the root hub driver.
     85 * @return Error code.
     86 *
     87 * Creates and starts the polling fibril.
     88 */
     89int uhci_port_init(uhci_port_t *port,
     90    port_status_t *address, unsigned number, unsigned usec, ddf_dev_t *rh)
     91{
     92        assert(port);
     93        asprintf(&port->id_string, "Port (%p - %d)", port, number);
     94        if (port->id_string == NULL) {
     95                return ENOMEM;
     96        }
     97
    5998        port->address = address;
    6099        port->number = number;
     
    62101        port->attached_device = 0;
    63102        port->rh = rh;
     103
    64104        int rc = usb_hc_connection_initialize_from_device(
    65105            &port->hc_connection, rh);
     
    71111        port->checker = fibril_create(uhci_port_check, port);
    72112        if (port->checker == 0) {
    73                 usb_log_error("Port(%p - %d): failed to launch root hub fibril.",
    74                     port->address, port->number);
     113                usb_log_error("%s: failed to create polling fibril.",
     114                    port->id_string);
    75115                return ENOMEM;
    76116        }
     117
    77118        fibril_add_ready(port->checker);
    78         usb_log_debug("Port(%p - %d): Added fibril. %x\n",
    79             port->address, port->number, port->checker);
    80         return EOK;
    81 }
    82 /*----------------------------------------------------------------------------*/
     119        usb_log_debug("%s: Started polling fibril(%x).\n",
     120            port->id_string, port->checker);
     121        return EOK;
     122}
     123/*----------------------------------------------------------------------------*/
     124/** Cleanup UHCI root hub port instance.
     125 *
     126 * @param[in] port Memory structure to use.
     127 *
     128 * Stops the polling fibril.
     129 */
    83130void uhci_port_fini(uhci_port_t *port)
    84131{
    85 // TODO: destroy fibril
    86 // TODO: hangup phone
    87 //      fibril_teardown(port->checker);
     132        assert(port);
     133        free(port->id_string);
     134        /* TODO: Kill fibril here */
    88135        return;
    89136}
    90137/*----------------------------------------------------------------------------*/
     138/** Periodically checks port status and reports new devices.
     139 *
     140 * @param[in] port Port structure to use.
     141 * @return Error code.
     142 */
    91143int uhci_port_check(void *port)
    92144{
    93         uhci_port_t *port_instance = port;
    94         assert(port_instance);
    95 //      port_status_write(port_instance->address, 0);
    96 
    97         unsigned count = 0;
     145        uhci_port_t *instance = port;
     146        assert(instance);
    98147
    99148        while (1) {
    100                 async_usleep(port_instance->wait_period_usec);
    101 
    102                 /* read register value */
    103                 port_status_t port_status =
    104                         port_status_read(port_instance->address);
    105 
    106                 /* debug print */
    107                 static fibril_mutex_t dbg_mtx = FIBRIL_MUTEX_INITIALIZER(dbg_mtx);
    108                 fibril_mutex_lock(&dbg_mtx);
    109                 usb_log_debug2("Port(%p - %d): Status: %#04x. === %u\n",
    110                   port_instance->address, port_instance->number, port_status, count++);
    111 //              print_port_status(port_status);
    112                 fibril_mutex_unlock(&dbg_mtx);
    113 
    114                 if ((port_status & STATUS_CONNECTED_CHANGED) != 0) {
    115                         usb_log_debug("Port(%p - %d): Connected change detected: %x.\n",
    116                             port_instance->address, port_instance->number, port_status);
    117 
    118 
    119                         int rc = usb_hc_connection_open(
    120                             &port_instance->hc_connection);
    121                         if (rc != EOK) {
    122                                 usb_log_error("Port(%p - %d): Failed to connect to HC.",
    123                                     port_instance->address, port_instance->number);
    124                                 continue;
    125                         }
    126 
    127                         /* remove any old device */
    128                         if (port_instance->attached_device) {
    129                                 usb_log_debug("Port(%p - %d): Removing device.\n",
    130                                     port_instance->address, port_instance->number);
    131                                 uhci_port_remove_device(port_instance);
    132                         }
    133 
    134                         if ((port_status & STATUS_CONNECTED) != 0) {
    135                                 /* new device */
    136                                 uhci_port_new_device(port_instance, port_status);
    137                         } else {
    138                                 /* ack changes by writing one to WC bits */
    139                                 port_status_write(port_instance->address, port_status);
    140                                 usb_log_debug("Port(%p - %d): Change status ACK.\n",
    141                                                 port_instance->address, port_instance->number);
    142                         }
    143 
    144                         rc = usb_hc_connection_close(
    145                             &port_instance->hc_connection);
    146                         if (rc != EOK) {
    147                                 usb_log_error("Port(%p - %d): Failed to disconnect from HC.",
    148                                     port_instance->address, port_instance->number);
    149                         }
     149                async_usleep(instance->wait_period_usec);
     150
     151                /* Read register value */
     152                port_status_t port_status = uhci_port_read_status(instance);
     153
     154                /* Print the value if it's interesting */
     155                if (port_status & ~STATUS_ALWAYS_ONE)
     156                        uhci_port_print_status(instance, port_status);
     157
     158                if ((port_status & STATUS_CONNECTED_CHANGED) == 0)
     159                        continue;
     160
     161                usb_log_debug("%s: Connected change detected: %x.\n",
     162                    instance->id_string, port_status);
     163
     164                int rc =
     165                    usb_hc_connection_open(&instance->hc_connection);
     166                if (rc != EOK) {
     167                        usb_log_error("%s: Failed to connect to HC.",
     168                            instance->id_string);
     169                        continue;
    150170                }
    151         }
    152         return EOK;
    153 }
    154 
     171
     172                /* Remove any old device */
     173                if (instance->attached_device) {
     174                        usb_log_debug2("%s: Removing device.\n",
     175                            instance->id_string);
     176                        uhci_port_remove_device(instance);
     177                }
     178
     179                if ((port_status & STATUS_CONNECTED) != 0) {
     180                        /* New device */
     181                        const usb_speed_t speed =
     182                            ((port_status & STATUS_LOW_SPEED) != 0) ?
     183                            USB_SPEED_LOW : USB_SPEED_FULL;
     184                        uhci_port_new_device(instance, speed);
     185                } else {
     186                        /* Write one to WC bits, to ack changes */
     187                        uhci_port_write_status(instance, port_status);
     188                        usb_log_debug("%s: status change ACK.\n",
     189                            instance->id_string);
     190                }
     191
     192                rc = usb_hc_connection_close(&instance->hc_connection);
     193                if (rc != EOK) {
     194                        usb_log_error("%s: Failed to disconnect.",
     195                            instance->id_string);
     196                }
     197        }
     198        return EOK;
     199}
     200/*----------------------------------------------------------------------------*/
    155201/** Callback for enabling port during adding a new device.
    156202 *
     
    158204 * @param arg Pointer to uhci_port_t of port with the new device.
    159205 * @return Error code.
    160  */
    161 static int new_device_enable_port(int portno, void *arg)
     206 *
     207 * Resets and enables the ub port.
     208 */
     209int uhci_port_reset_enable(int portno, void *arg)
    162210{
    163211        uhci_port_t *port = (uhci_port_t *) arg;
    164212
    165         usb_log_debug2("Port(%p - %d): new_device_enable_port.\n",
    166             port->address, port->number);
     213        usb_log_debug2("%s: new_device_enable_port.\n", port->id_string);
    167214
    168215        /*
     
    172219        async_usleep(100000);
    173220
    174 
    175         /* The hub maintains the reset signal to that port for 10 ms
    176          * (See Section 11.5.1.5)
     221        /*
     222         * Resets from root ports should be nominally 50ms
    177223         */
    178224        {
    179                 usb_log_debug("Port(%p - %d): Reset Signal start.\n",
    180                     port->address, port->number);
    181                 port_status_t port_status =
    182                         port_status_read(port->address);
     225                usb_log_debug("%s: Reset Signal start.\n", port->id_string);
     226                port_status_t port_status = uhci_port_read_status(port);
    183227                port_status |= STATUS_IN_RESET;
    184                 port_status_write(port->address, port_status);
    185                 async_usleep(10000);
    186                 port_status =
    187                         port_status_read(port->address);
     228                uhci_port_write_status(port, port_status);
     229                async_usleep(50000);
     230                port_status = uhci_port_read_status(port);
    188231                port_status &= ~STATUS_IN_RESET;
    189                 port_status_write(port->address, port_status);
    190                 usb_log_debug("Port(%p - %d): Reset Signal stop.\n",
    191                     port->address, port->number);
    192         }
     232                uhci_port_write_status(port, port_status);
     233                usb_log_debug("%s: Reset Signal stop.\n", port->id_string);
     234        }
     235
     236        /* the reset recovery time 10ms */
     237        async_usleep(10000);
    193238
    194239        /* Enable the port. */
     
    197242        return EOK;
    198243}
    199 
    200 /*----------------------------------------------------------------------------*/
    201 static int uhci_port_new_device(uhci_port_t *port, uint16_t status)
     244/*----------------------------------------------------------------------------*/
     245/** Initialize and report connected device.
     246 *
     247 * @param[in] port Port structure to use.
     248 * @param[in] speed Detected speed.
     249 * @return Error code.
     250 *
     251 * Uses libUSB function to do the actual work.
     252 */
     253int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed)
    202254{
    203255        assert(port);
    204256        assert(usb_hc_connection_is_opened(&port->hc_connection));
    205257
    206         usb_log_info("Port(%p-%d): Detected new device.\n",
    207             port->address, port->number);
     258        usb_log_info("%s: Detected new device.\n", port->id_string);
    208259
    209260        usb_address_t dev_addr;
    210261        int rc = usb_hc_new_device_wrapper(port->rh, &port->hc_connection,
    211             ((status & STATUS_LOW_SPEED) != 0) ? USB_SPEED_LOW : USB_SPEED_FULL,
    212             new_device_enable_port, port->number, port,
     262            speed, uhci_port_reset_enable, port->number, port,
    213263            &dev_addr, &port->attached_device, NULL, NULL, NULL);
    214264
    215265        if (rc != EOK) {
    216                 usb_log_error("Port(%p-%d): Failed(%d) adding new device: %s.\n",
    217                     port->address, port->number, rc, str_error(rc));
     266                usb_log_error("%s: Failed(%d) to add device: %s.\n",
     267                    port->id_string, rc, str_error(rc));
    218268                uhci_port_set_enabled(port, false);
    219269                return rc;
    220270        }
    221271
    222         usb_log_info("Port(%p-%d): New device has address %d (handle %zu).\n",
    223             port->address, port->number, dev_addr, port->attached_device);
    224 
    225         return EOK;
    226 }
    227 
    228 /*----------------------------------------------------------------------------*/
    229 static int uhci_port_remove_device(uhci_port_t *port)
    230 {
    231         usb_log_error("Port(%p-%d): Don't know how to remove device %#x.\n",
    232                 port->address, port->number, (unsigned int)port->attached_device);
    233 //      uhci_port_set_enabled(port, false);
    234         return EOK;
    235 }
    236 /*----------------------------------------------------------------------------*/
    237 static int uhci_port_set_enabled(uhci_port_t *port, bool enabled)
    238 {
    239         assert(port);
    240 
    241         /* read register value */
    242         port_status_t port_status
    243                 = port_status_read(port->address);
    244 
    245         /* enable port: register write */
     272        usb_log_info("%s: New device has address %d (handle %zu).\n",
     273            port->id_string, dev_addr, port->attached_device);
     274
     275        return EOK;
     276}
     277/*----------------------------------------------------------------------------*/
     278/** Remove device.
     279 *
     280 * @param[in] port Memory structure to use.
     281 * @return Error code.
     282 *
     283 * Does not work, DDF does not support device removal.
     284 * Does not even free used USB address (it would be dangerous if tis driver
     285 * is still running).
     286 */
     287int uhci_port_remove_device(uhci_port_t *port)
     288{
     289        usb_log_error("%s: Don't know how to remove device %d.\n",
     290            port->id_string, (unsigned int)port->attached_device);
     291        return EOK;
     292}
     293/*----------------------------------------------------------------------------*/
     294/** Enable or disable root hub port.
     295 *
     296 * @param[in] port Port structure to use.
     297 * @param[in] enabled Port status to set.
     298 * @return Error code. (Always EOK)
     299 */
     300int uhci_port_set_enabled(uhci_port_t *port, bool enabled)
     301{
     302        assert(port);
     303
     304        /* Read register value */
     305        port_status_t port_status = uhci_port_read_status(port);
     306
     307        /* Set enabled bit */
    246308        if (enabled) {
    247309                port_status |= STATUS_ENABLED;
     
    249311                port_status &= ~STATUS_ENABLED;
    250312        }
    251         port_status_write(port->address, port_status);
    252 
    253         usb_log_info("Port(%p-%d): %sabled port.\n",
    254                 port->address, port->number, enabled ? "En" : "Dis");
    255         return EOK;
    256 }
    257 /*----------------------------------------------------------------------------*/
     313
     314        /* Write new value. */
     315        uhci_port_write_status(port, port_status);
     316
     317        usb_log_info("%s: %sabled port.\n",
     318                port->id_string, enabled ? "En" : "Dis");
     319        return EOK;
     320}
     321/*----------------------------------------------------------------------------*/
     322/** Print the port status value in a human friendly way
     323 *
     324 * @param[in] port Port structure to use.
     325 * @param[in] value Port register value to print.
     326 * @return Error code. (Always EOK)
     327 */
     328void uhci_port_print_status(uhci_port_t *port, const port_status_t value)
     329{
     330        assert(port);
     331        usb_log_debug2("%s Port status(%#x):%s%s%s%s%s%s%s%s%s%s%s.\n",
     332            port->id_string, value,
     333            (value & STATUS_SUSPEND) ? " SUSPENDED," : "",
     334            (value & STATUS_RESUME) ? " IN RESUME," : "",
     335            (value & STATUS_IN_RESET) ? " IN RESET," : "",
     336            (value & STATUS_LINE_D_MINUS) ? " VD-," : "",
     337            (value & STATUS_LINE_D_PLUS) ? " VD+," : "",
     338            (value & STATUS_LOW_SPEED) ? " LOWSPEED," : "",
     339            (value & STATUS_ENABLED_CHANGED) ? " ENABLED-CHANGE," : "",
     340            (value & STATUS_ENABLED) ? " ENABLED," : "",
     341            (value & STATUS_CONNECTED_CHANGED) ? " CONNECTED-CHANGE," : "",
     342            (value & STATUS_CONNECTED) ? " CONNECTED," : "",
     343            (value & STATUS_ALWAYS_ONE) ? " ALWAYS ONE" : " ERROR: NO ALWAYS ONE"
     344        );
     345}
    258346/**
    259347 * @}
Note: See TracChangeset for help on using the changeset viewer.