Ignore:
File:
1 edited

Legend:

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

    r27ed734c rda2f1c9e  
    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        if (connection->ref_count == 0) {
     67                /* Closing already closed connection... */
     68                assert(connection->hc_sess = NULL);
     69                fibril_mutex_unlock(&connection->guard);
     70                return EOK;
     71        }
     72        --connection->ref_count;
     73        int ret = EOK;
     74        if (connection->ref_count == 0) {
     75                assert(connection->hc_sess);
     76                ret = async_hangup(connection->hc_sess);
     77                connection->hc_sess = NULL;
     78        }
     79        fibril_mutex_unlock(&connection->guard);
     80        return ret;
     81}
     82
     83#define EXCH_INIT(connection, exch) \
     84do { \
     85        exch = NULL; \
     86        if (!connection) \
     87                return EBADMEM; \
     88        const int ret = usb_hc_connection_add_ref(connection); \
     89        if (ret != EOK) \
     90                return ret; \
     91        exch = async_exchange_begin(connection->hc_sess); \
     92        if (exch == NULL) { \
     93                usb_hc_connection_del_ref(connection); \
     94                return ENOMEM; \
     95        } \
     96} while (0)
     97
     98#define EXCH_FINI(connection, exch) \
     99if (exch) { \
     100        async_exchange_end(exch); \
     101        usb_hc_connection_del_ref(connection); \
     102} else (void)0
    44103
    45104/** Initialize connection to USB host controller.
     
    59118
    60119        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);
     120        const int rc = usb_get_hc_by_handle(device->handle, &hc_handle);
     121        if (rc == EOK) {
     122                usb_hc_connection_initialize(connection, hc_handle);
     123        }
    67124
    68125        return rc;
    69126}
    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 
     127/*----------------------------------------------------------------------------*/
     128void usb_hc_connection_deinitialize(usb_hc_connection_t *connection)
     129{
     130        assert(connection);
     131        fibril_mutex_lock(&connection->guard);
     132        if (connection->ref_count != 0) {
     133                usb_log_warning("%u stale reference(s) to HC connection.\n",
     134                    connection->ref_count);
     135                assert(connection->hc_sess);
     136                async_hangup(connection->hc_sess);
     137                connection->hc_sess = NULL;
     138                connection->ref_count = 0;
     139        }
     140        fibril_mutex_unlock(&connection->guard);
     141}
     142/*----------------------------------------------------------------------------*/
    88143/** Open connection to host controller.
    89144 *
     
    93148int usb_hc_connection_open(usb_hc_connection_t *connection)
    94149{
    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.
     150        return usb_hc_connection_add_ref(connection);
     151}
     152/*----------------------------------------------------------------------------*/
     153/** Close connection to the host controller.
    110154 *
    111155 * @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.
    123156 * @return Error code.
    124157 */
    125158int usb_hc_connection_close(usb_hc_connection_t *connection)
    126159{
    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 
     160        return usb_hc_connection_del_ref(connection);
     161}
     162/*----------------------------------------------------------------------------*/
     163/** Ask host controller for free address assignment.
     164 *
     165 * @param connection Opened connection to host controller.
     166 * @param preferred Preferred SUB address.
     167 * @param strict Fail if the preferred address is not avialable.
     168 * @param speed Speed of the new device (device that will be assigned
     169 *    the returned address).
     170 * @return Assigned USB address or negative error code.
     171 */
     172usb_address_t usb_hc_request_address(usb_hc_connection_t *connection,
     173    usb_address_t preferred, bool strict, usb_speed_t speed)
     174{
     175        async_exch_t *exch;
     176        EXCH_INIT(connection, exch);
     177
     178        usb_address_t address = preferred;
     179        const int ret = usbhc_request_address(exch, &address, strict, speed);
     180
     181        EXCH_FINI(connection, exch);
     182        return ret == EOK ? address : ret;
     183}
     184/*----------------------------------------------------------------------------*/
     185int usb_hc_bind_address(usb_hc_connection_t * connection,
     186    usb_address_t address, devman_handle_t handle)
     187{
     188        async_exch_t *exch;
     189        EXCH_INIT(connection, exch);
     190
     191        const int ret = usbhc_bind_address(exch, address, handle);
     192
     193        EXCH_FINI(connection, exch);
     194        return ret;
     195}
     196/*----------------------------------------------------------------------------*/
    143197/** Get handle of USB device with given address.
    144198 *
     
    151205    usb_address_t address, devman_handle_t *handle)
    152206{
    153         if (!usb_hc_connection_is_opened(connection))
    154                 return ENOENT;
    155        
    156         async_exch_t *exch = async_exchange_begin(connection->hc_sess);
    157        
    158         sysarg_t tmp;
    159         int rc = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    160             IPC_M_USBHC_GET_HANDLE_BY_ADDRESS,
    161             address, &tmp);
    162        
    163         async_exchange_end(exch);
    164        
    165         if ((rc == EOK) && (handle != NULL))
    166                 *handle = tmp;
    167        
    168         return rc;
    169 }
    170 
    171 /** Tell USB address assigned to device with given handle.
    172  *
    173  * @param dev_handle Devman handle of the USB device in question.
    174  * @return USB address or negative error code.
    175  */
    176 usb_address_t usb_get_address_by_handle(devman_handle_t dev_handle)
    177 {
    178         async_sess_t *parent_sess =
    179             devman_parent_device_connect(EXCHANGE_ATOMIC, dev_handle,
    180             IPC_FLAG_BLOCKING);
    181         if (!parent_sess)
    182                 return ENOMEM;
    183        
    184         async_exch_t *exch = async_exchange_begin(parent_sess);
    185        
    186         sysarg_t address;
    187         int rc = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    188             IPC_M_USB_GET_MY_ADDRESS, &address);
    189        
    190         async_exchange_end(exch);
    191         async_hangup(parent_sess);
    192        
    193         if (rc != EOK)
    194                 return rc;
    195        
    196         return (usb_address_t) address;
    197 }
    198 
    199 
    200 /** Get host controller handle by its class index.
    201  *
    202  * @param sid Service ID of the HC function.
    203  * @param hc_handle Where to store the HC handle
    204  *      (can be NULL for existence test only).
    205  * @return Error code.
    206  */
    207 int usb_ddf_get_hc_handle_by_sid(service_id_t sid, devman_handle_t *hc_handle)
    208 {
    209         devman_handle_t handle;
    210         int rc;
    211        
    212         rc = devman_fun_sid_to_handle(sid, &handle);
    213         if (hc_handle != NULL)
    214                 *hc_handle = handle;
    215        
    216         return rc;
    217 }
    218 
    219 /** Find host controller handle that is ancestor of given device.
    220  *
    221  * @param[in] device_handle Device devman handle.
    222  * @param[out] hc_handle Where to store handle of host controller
    223  *      controlling device with @p device_handle handle.
    224  * @return Error code.
    225  */
    226 int usb_hc_find(devman_handle_t device_handle, devman_handle_t *hc_handle)
    227 {
    228         async_sess_t *parent_sess =
    229             devman_parent_device_connect(EXCHANGE_ATOMIC, device_handle,
    230             IPC_FLAG_BLOCKING);
    231         if (!parent_sess)
    232                 return ENOMEM;
    233        
    234         async_exch_t *exch = async_exchange_begin(parent_sess);
    235        
    236         devman_handle_t h;
    237         int rc = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    238             IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
    239        
    240         async_exchange_end(exch);
    241         async_hangup(parent_sess);
    242        
    243         if (rc != EOK)
    244                 return rc;
    245        
    246         if (hc_handle != NULL)
    247                 *hc_handle = h;
    248        
    249         return EOK;
     207        async_exch_t *exch;
     208        EXCH_INIT(connection, exch);
     209
     210        const int ret = usbhc_get_handle(exch, address, handle);
     211
     212        EXCH_FINI(connection, exch);
     213        return ret;
     214}
     215/*----------------------------------------------------------------------------*/
     216int usb_hc_release_address(usb_hc_connection_t *connection,
     217    usb_address_t address)
     218{
     219        async_exch_t *exch;
     220        EXCH_INIT(connection, exch);
     221
     222        const int ret = usbhc_release_address(exch, address);
     223
     224        EXCH_FINI(connection, exch);
     225        return ret;
     226}
     227/*----------------------------------------------------------------------------*/
     228int usb_hc_register_endpoint(usb_hc_connection_t *connection,
     229    usb_address_t address, usb_endpoint_t endpoint, usb_transfer_type_t type,
     230    usb_direction_t direction, size_t packet_size, unsigned interval)
     231{
     232        async_exch_t *exch;
     233        EXCH_INIT(connection, exch);
     234
     235        const int ret = usbhc_register_endpoint(exch, address, endpoint,
     236            type, direction, packet_size, interval);
     237
     238        EXCH_FINI(connection, exch);
     239        return ret;
     240}
     241/*----------------------------------------------------------------------------*/
     242int usb_hc_unregister_endpoint(usb_hc_connection_t *connection,
     243    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
     244{
     245        async_exch_t *exch;
     246        EXCH_INIT(connection, exch);
     247
     248        const int ret =
     249            usbhc_unregister_endpoint(exch, address, endpoint, direction);
     250
     251        EXCH_FINI(connection, exch);
     252        return ret;
     253}
     254/*----------------------------------------------------------------------------*/
     255int usb_hc_read(usb_hc_connection_t *connection, usb_address_t address,
     256    usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size,
     257    size_t *real_size)
     258{
     259        async_exch_t *exch;
     260        EXCH_INIT(connection, exch);
     261
     262        const int ret =
     263            usbhc_read(exch, address, endpoint, setup, data, size, real_size);
     264
     265        EXCH_FINI(connection, exch);
     266        return ret;
     267}
     268/*----------------------------------------------------------------------------*/
     269int usb_hc_write(usb_hc_connection_t *connection, usb_address_t address,
     270    usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size)
     271{
     272        async_exch_t *exch;
     273        EXCH_INIT(connection, exch);
     274
     275        const int ret = usbhc_write(exch, address, endpoint, setup, data, size);
     276
     277        EXCH_FINI(connection, exch);
     278        return ret;
    250279}
    251280
Note: See TracChangeset for help on using the changeset viewer.