Ignore:
File:
1 edited

Legend:

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

    r02fc5c4 r29e479f  
    11/*
    22 * Copyright (c) 2011 Vojtech Horky
     3 * Copyright (c) 2011 Jan Vesely
    34 * All rights reserved.
    45 *
     
    2627 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2728 */
    28 
    2929/** @addtogroup libusb
    3030 * @{
     
    3333 * General communication with host controller driver (implementation).
    3434 */
    35 #include <devman.h>
    36 #include <async.h>
    37 #include <dev_iface.h>
    38 #include <usb_iface.h>
     35#include <usb/debug.h>
     36
     37#include <assert.h>
     38#include <errno.h>
    3939#include <usbhc_iface.h>
     40#include <usb/dev.h>
    4041#include <usb/hc.h>
    41 #include <usb/debug.h>
    42 #include <errno.h>
    43 #include <assert.h>
     42
     43static int usb_hc_connection_add_ref(usb_hc_connection_t *connection)
     44{
     45        assert(connection);
     46        fibril_mutex_lock(&connection->guard);
     47        if (connection->ref_count == 0) {
     48                assert(connection->hc_sess == NULL);
     49                /* Parallel exchange for us */
     50                connection->hc_sess = devman_device_connect(EXCHANGE_PARALLEL,
     51                        connection->hc_handle, 0);
     52                if (!connection->hc_sess) {
     53                        fibril_mutex_unlock(&connection->guard);
     54                        return ENOMEM;
     55                }
     56        }
     57        ++connection->ref_count;
     58        fibril_mutex_unlock(&connection->guard);
     59        return EOK;
     60}
     61/*----------------------------------------------------------------------------*/
     62static int usb_hc_connection_del_ref(usb_hc_connection_t *connection)
     63{
     64        assert(connection);
     65        fibril_mutex_lock(&connection->guard);
     66        --connection->ref_count;
     67        int ret = EOK;
     68        if (connection->ref_count == 0) {
     69                assert(connection->hc_sess);
     70                ret = async_hangup(connection->hc_sess);
     71                connection->hc_sess = NULL;
     72        }
     73        fibril_mutex_unlock(&connection->guard);
     74        return ret;
     75}
     76
     77#define EXCH_INIT(connection, exch) \
     78do { \
     79        exch = NULL; \
     80        if (!connection) \
     81                return EBADMEM; \
     82        const int ret = usb_hc_connection_add_ref(connection); \
     83        if (ret != EOK) \
     84                return ret; \
     85        exch = async_exchange_begin(connection->hc_sess); \
     86        if (exch == NULL) { \
     87                usb_hc_connection_del_ref(connection); \
     88                return ENOMEM; \
     89        } \
     90} while (0)
     91
     92#define EXCH_FINI(connection, exch) \
     93if (exch) { \
     94        async_exchange_end(exch); \
     95        usb_hc_connection_del_ref(connection); \
     96} else (void)0
    4497
    4598/** Initialize connection to USB host controller.
     
    59112
    60113        devman_handle_t hc_handle;
    61         int rc = usb_hc_find(device->handle, &hc_handle);
    62         if (rc != EOK) {
    63                 return rc;
    64         }
    65 
    66         rc = usb_hc_connection_initialize(connection, hc_handle);
     114        const int rc = usb_get_hc_by_handle(device->handle, &hc_handle);
     115        if (rc == EOK) {
     116                usb_hc_connection_initialize(connection, hc_handle);
     117        }
    67118
    68119        return rc;
    69120}
    70 
    71 /** Manually initialize connection to USB host controller.
    72  *
    73  * @param connection Connection to be initialized.
    74  * @param hc_handle Devman handle of the host controller.
    75  * @return Error code.
    76  */
    77 int usb_hc_connection_initialize(usb_hc_connection_t *connection,
    78     devman_handle_t hc_handle)
    79 {
    80         assert(connection);
    81 
    82         connection->hc_handle = hc_handle;
    83         connection->hc_sess = NULL;
    84 
    85         return EOK;
    86 }
    87 
     121/*----------------------------------------------------------------------------*/
    88122/** Open connection to host controller.
    89123 *
     
    93127int usb_hc_connection_open(usb_hc_connection_t *connection)
    94128{
    95         assert(connection);
    96        
    97         if (usb_hc_connection_is_opened(connection))
    98                 return EBUSY;
    99        
    100         async_sess_t *sess = devman_device_connect(EXCHANGE_ATOMIC,
    101             connection->hc_handle, 0);
    102         if (!sess)
    103                 return ENOMEM;
    104        
    105         connection->hc_sess = sess;
    106         return EOK;
    107 }
    108 
    109 /** Tells whether connection to host controller is opened.
     129        return usb_hc_connection_add_ref(connection);
     130}
     131/*----------------------------------------------------------------------------*/
     132/** Close connection to the host controller.
    110133 *
    111134 * @param connection Connection to the host controller.
    112  * @return Whether connection is opened.
    113  */
    114 bool usb_hc_connection_is_opened(const usb_hc_connection_t *connection)
    115 {
    116         assert(connection);
    117         return (connection->hc_sess != NULL);
    118 }
    119 
    120 /** Close connection to the host controller.
    121  *
    122  * @param connection Connection to the host controller.
    123135 * @return Error code.
    124136 */
    125137int usb_hc_connection_close(usb_hc_connection_t *connection)
    126138{
    127         assert(connection);
    128 
    129         if (!usb_hc_connection_is_opened(connection)) {
    130                 return ENOENT;
    131         }
    132 
    133         int rc = async_hangup(connection->hc_sess);
    134         if (rc != EOK) {
    135                 return rc;
    136         }
    137 
    138         connection->hc_sess = NULL;
    139 
    140         return EOK;
    141 }
    142 
     139        return usb_hc_connection_del_ref(connection);
     140}
     141/*----------------------------------------------------------------------------*/
     142/** Ask host controller for free address assignment.
     143 *
     144 * @param connection Opened connection to host controller.
     145 * @param preferred Preferred SUB address.
     146 * @param strict Fail if the preferred address is not avialable.
     147 * @param speed Speed of the new device (device that will be assigned
     148 *    the returned address).
     149 * @return Assigned USB address or negative error code.
     150 */
     151usb_address_t usb_hc_request_address(usb_hc_connection_t *connection,
     152    usb_address_t preferred, bool strict, usb_speed_t speed)
     153{
     154        async_exch_t *exch;
     155        EXCH_INIT(connection, exch);
     156
     157        usb_address_t address = preferred;
     158        const int ret = usbhc_request_address(exch, &address, strict, speed);
     159
     160        EXCH_FINI(connection, exch);
     161        return ret == EOK ? address : ret;
     162}
     163/*----------------------------------------------------------------------------*/
     164int usb_hc_bind_address(usb_hc_connection_t * connection,
     165    usb_address_t address, devman_handle_t handle)
     166{
     167        async_exch_t *exch;
     168        EXCH_INIT(connection, exch);
     169
     170        const int ret = usbhc_bind_address(exch, address, handle);
     171
     172        EXCH_FINI(connection, exch);
     173        return ret;
     174}
     175/*----------------------------------------------------------------------------*/
    143176/** Get handle of USB device with given address.
    144177 *
     
    151184    usb_address_t address, devman_handle_t *handle)
    152185{
    153         if (!usb_hc_connection_is_opened(connection))
    154                 return ENOENT;
    155 
    156         async_exch_t *exch = async_exchange_begin(connection->hc_sess);
    157         if (!exch)
    158                 return ENOMEM;
     186        async_exch_t *exch;
     187        EXCH_INIT(connection, exch);
     188
    159189        const int ret = usbhc_get_handle(exch, address, handle);
    160         async_exchange_end(exch);
    161         return ret;
    162 }
    163 
    164 /** Tell USB address assigned to device with given handle.
    165  *
    166  * @param dev_handle Devman handle of the USB device in question.
    167  * @return USB address or negative error code.
    168  */
    169 usb_address_t usb_get_address_by_handle(devman_handle_t dev_handle)
    170 {
    171         async_sess_t *parent_sess =
    172             devman_parent_device_connect(EXCHANGE_ATOMIC, dev_handle,
    173             IPC_FLAG_BLOCKING);
    174         if (!parent_sess)
    175                 return ENOMEM;
    176 
    177         async_exch_t *exch = async_exchange_begin(parent_sess);
    178         if (!exch) {
    179                 async_hangup(parent_sess);
    180                 return ENOMEM;
    181         }
    182         usb_address_t address;
    183         const int ret = usb_get_my_address(exch, &address);
    184 
    185         async_exchange_end(exch);
    186         async_hangup(parent_sess);
    187 
    188         if (ret != EOK)
    189                 return ret;
    190 
    191         return address;
    192 }
    193 
    194 
     190
     191        EXCH_FINI(connection, exch);
     192        return ret;
     193}
     194/*----------------------------------------------------------------------------*/
     195int usb_hc_release_address(usb_hc_connection_t *connection,
     196    usb_address_t address)
     197{
     198        async_exch_t *exch;
     199        EXCH_INIT(connection, exch);
     200
     201        const int ret = usbhc_release_address(exch, address);
     202
     203        EXCH_FINI(connection, exch);
     204        return ret;
     205}
     206/*----------------------------------------------------------------------------*/
     207int usb_hc_register_endpoint(usb_hc_connection_t *connection,
     208    usb_address_t address, usb_endpoint_t endpoint, usb_transfer_type_t type,
     209    usb_direction_t direction, size_t packet_size, unsigned interval)
     210{
     211        async_exch_t *exch;
     212        EXCH_INIT(connection, exch);
     213
     214        const int ret = usbhc_register_endpoint(exch, address, endpoint,
     215            type, direction, packet_size, interval);
     216
     217        EXCH_FINI(connection, exch);
     218        return ret;
     219}
     220/*----------------------------------------------------------------------------*/
     221int usb_hc_unregister_endpoint(usb_hc_connection_t *connection,
     222    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
     223{
     224        async_exch_t *exch;
     225        EXCH_INIT(connection, exch);
     226
     227        const int ret =
     228            usbhc_unregister_endpoint(exch, address, endpoint, direction);
     229
     230        EXCH_FINI(connection, exch);
     231        return ret;
     232}
     233/*----------------------------------------------------------------------------*/
     234int usb_hc_control_read(usb_hc_connection_t *connection, usb_address_t address,
     235    usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size,
     236    size_t *real_size)
     237{
     238        async_exch_t *exch;
     239        EXCH_INIT(connection, exch);
     240
     241        const int ret =
     242            usbhc_read(exch, address, endpoint, setup, data, size, real_size);
     243
     244        EXCH_FINI(connection, exch);
     245        return ret;
     246}
     247/*----------------------------------------------------------------------------*/
     248int usb_hc_control_write(usb_hc_connection_t *connection, usb_address_t address,
     249    usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size)
     250{
     251        async_exch_t *exch;
     252        EXCH_INIT(connection, exch);
     253
     254        const int ret = usbhc_write(exch, address, endpoint, setup, data, size);
     255
     256        EXCH_FINI(connection, exch);
     257        return ret;
     258}
     259/*----------------------------------------------------------------------------*/
    195260/** Get host controller handle by its class index.
    196261 *
     
    203268{
    204269        devman_handle_t handle;
    205         int rc;
    206        
    207         rc = devman_fun_sid_to_handle(sid, &handle);
    208         if (hc_handle != NULL)
     270
     271        const int ret = devman_fun_sid_to_handle(sid, &handle);
     272        if (ret == EOK && hc_handle != NULL)
    209273                *hc_handle = handle;
    210        
    211         return rc;
    212 }
    213 
    214 /** Find host controller handle that is ancestor of given device.
    215  *
    216  * @param[in] device_handle Device devman handle.
    217  * @param[out] hc_handle Where to store handle of host controller
    218  *      controlling device with @p device_handle handle.
    219  * @return Error code.
    220  */
    221 int usb_hc_find(devman_handle_t device_handle, devman_handle_t *hc_handle)
    222 {
    223         async_sess_t *parent_sess =
    224             devman_parent_device_connect(EXCHANGE_ATOMIC, device_handle,
    225             IPC_FLAG_BLOCKING);
    226         if (!parent_sess)
    227                 return ENOMEM;
    228 
    229         async_exch_t *exch = async_exchange_begin(parent_sess);
    230         if (!exch) {
    231                 async_hangup(parent_sess);
    232                 return ENOMEM;
    233         }
    234         const int ret = usb_get_hc_handle(exch, hc_handle);
    235 
    236         async_exchange_end(exch);
    237         async_hangup(parent_sess);
    238274
    239275        return ret;
Note: See TracChangeset for help on using the changeset viewer.