Ignore:
File:
1 edited

Legend:

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

    r8e5ce07 r77ad86c  
    11/*
    22 * Copyright (c) 2011 Vojtech Horky
     3 * Copyright (c) 2011 Jan Vesely
    34 * All rights reserved.
    45 *
     
    3334 * General communication with host controller driver (implementation).
    3435 */
    35 #include <devman.h>
    36 #include <async.h>
    37 #include <dev_iface.h>
    38 #include <usb_iface.h>
     36
     37#include <usb/debug.h>
     38
     39#include <assert.h>
     40#include <errno.h>
    3941#include <usbhc_iface.h>
     42#include <usb/dev.h>
    4043#include <usb/hc.h>
    41 #include <usb/debug.h>
    42 #include <errno.h>
    43 #include <assert.h>
     44
     45static int usb_hc_connection_add_ref(usb_hc_connection_t *connection)
     46{
     47        assert(connection);
     48       
     49        fibril_mutex_lock(&connection->guard);
     50        if (connection->ref_count == 0) {
     51                assert(connection->hc_sess == NULL);
     52                /* Parallel exchange for us */
     53                connection->hc_sess = devman_device_connect(EXCHANGE_PARALLEL,
     54                        connection->hc_handle, 0);
     55                if (!connection->hc_sess) {
     56                        fibril_mutex_unlock(&connection->guard);
     57                        return ENOMEM;
     58                }
     59        }
     60       
     61        ++connection->ref_count;
     62        fibril_mutex_unlock(&connection->guard);
     63        return EOK;
     64}
     65
     66static int usb_hc_connection_del_ref(usb_hc_connection_t *connection)
     67{
     68        assert(connection);
     69       
     70        fibril_mutex_lock(&connection->guard);
     71        if (connection->ref_count == 0) {
     72                /* Closing already closed connection... */
     73                assert(connection->hc_sess == NULL);
     74                fibril_mutex_unlock(&connection->guard);
     75                return EOK;
     76        }
     77       
     78        --connection->ref_count;
     79        int ret = EOK;
     80        if (connection->ref_count == 0) {
     81                assert(connection->hc_sess);
     82                ret = async_hangup(connection->hc_sess);
     83                connection->hc_sess = NULL;
     84        }
     85        fibril_mutex_unlock(&connection->guard);
     86        return ret;
     87}
     88
     89#define EXCH_INIT(connection, exch) \
     90do { \
     91        exch = NULL; \
     92        if (!connection) \
     93                return EBADMEM; \
     94        const int ret = usb_hc_connection_add_ref(connection); \
     95        if (ret != EOK) \
     96                return ret; \
     97        exch = async_exchange_begin(connection->hc_sess); \
     98        if (exch == NULL) { \
     99                usb_hc_connection_del_ref(connection); \
     100                return ENOMEM; \
     101        } \
     102} while (0)
     103
     104#define EXCH_FINI(connection, exch) \
     105if (exch) { \
     106        async_exchange_end(exch); \
     107        usb_hc_connection_del_ref(connection); \
     108} else (void)0
    44109
    45110/** Initialize connection to USB host controller.
     
    59124
    60125        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);
     126        const int rc = usb_get_hc_by_handle(device->handle, &hc_handle);
     127        if (rc == EOK) {
     128                usb_hc_connection_initialize(connection, hc_handle);
     129        }
    67130
    68131        return rc;
    69132}
    70133
    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;
     134void usb_hc_connection_deinitialize(usb_hc_connection_t *connection)
     135{
     136        assert(connection);
     137        fibril_mutex_lock(&connection->guard);
     138        if (connection->ref_count != 0) {
     139                usb_log_warning("%u stale reference(s) to HC connection.\n",
     140                    connection->ref_count);
     141                assert(connection->hc_sess);
     142                async_hangup(connection->hc_sess);
     143                connection->hc_sess = NULL;
     144                connection->ref_count = 0;
     145        }
     146        fibril_mutex_unlock(&connection->guard);
    86147}
    87148
     
    93154int usb_hc_connection_open(usb_hc_connection_t *connection)
    94155{
    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.
     156        return usb_hc_connection_add_ref(connection);
     157}
     158
     159/** Close connection to the host controller.
    110160 *
    111161 * @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.
    123162 * @return Error code.
    124163 */
    125164int usb_hc_connection_close(usb_hc_connection_t *connection)
    126165{
    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;
     166        return usb_hc_connection_del_ref(connection);
     167}
     168
     169/** Ask host controller for free address assignment.
     170 *
     171 * @param connection Opened connection to host controller.
     172 * @param preferred Preferred SUB address.
     173 * @param strict Fail if the preferred address is not avialable.
     174 * @param speed Speed of the new device (device that will be assigned
     175 *    the returned address).
     176 * @return Assigned USB address or negative error code.
     177 */
     178usb_address_t usb_hc_request_address(usb_hc_connection_t *connection,
     179    usb_address_t preferred, bool strict, usb_speed_t speed)
     180{
     181        async_exch_t *exch;
     182        EXCH_INIT(connection, exch);
     183
     184        usb_address_t address = preferred;
     185        const int ret = usbhc_request_address(exch, &address, strict, speed);
     186
     187        EXCH_FINI(connection, exch);
     188        return ret == EOK ? address : ret;
     189}
     190
     191int usb_hc_bind_address(usb_hc_connection_t * connection,
     192    usb_address_t address, devman_handle_t handle)
     193{
     194        async_exch_t *exch;
     195        EXCH_INIT(connection, exch);
     196
     197        const int ret = usbhc_bind_address(exch, address, handle);
     198
     199        EXCH_FINI(connection, exch);
     200        return ret;
    141201}
    142202
     
    151211    usb_address_t address, devman_handle_t *handle)
    152212{
    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_hc_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_2_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    188             IPC_M_USB_GET_ADDRESS,
    189             dev_handle, &address);
    190        
    191         async_exchange_end(exch);
    192         async_hangup(parent_sess);
    193        
    194         if (rc != EOK)
    195                 return rc;
    196        
    197         return (usb_address_t) address;
    198 }
    199 
    200 
    201 /** Get host controller handle by its class index.
    202  *
    203  * @param sid Service ID of the HC function.
    204  * @param hc_handle Where to store the HC handle
    205  *      (can be NULL for existence test only).
    206  * @return Error code.
    207  */
    208 int usb_ddf_get_hc_handle_by_sid(service_id_t sid, devman_handle_t *hc_handle)
    209 {
    210         devman_handle_t handle;
    211         int rc;
    212        
    213         rc = devman_fun_sid_to_handle(sid, &handle);
    214         if (hc_handle != NULL)
    215                 *hc_handle = handle;
    216        
    217         return rc;
    218 }
    219 
    220 /** Find host controller handle that is ancestor of given device.
    221  *
    222  * @param[in] device_handle Device devman handle.
    223  * @param[out] hc_handle Where to store handle of host controller
    224  *      controlling device with @p device_handle handle.
    225  * @return Error code.
    226  */
    227 int usb_hc_find(devman_handle_t device_handle, devman_handle_t *hc_handle)
    228 {
    229         async_sess_t *parent_sess =
    230             devman_parent_device_connect(EXCHANGE_ATOMIC, device_handle,
    231             IPC_FLAG_BLOCKING);
    232         if (!parent_sess)
    233                 return ENOMEM;
    234        
    235         async_exch_t *exch = async_exchange_begin(parent_sess);
    236        
    237         devman_handle_t h;
    238         int rc = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    239             IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
    240        
    241         async_exchange_end(exch);
    242         async_hangup(parent_sess);
    243        
    244         if (rc != EOK)
    245                 return rc;
    246        
    247         if (hc_handle != NULL)
    248                 *hc_handle = h;
    249        
    250         return EOK;
     213        async_exch_t *exch;
     214        EXCH_INIT(connection, exch);
     215
     216        const int ret = usbhc_get_handle(exch, address, handle);
     217
     218        EXCH_FINI(connection, exch);
     219        return ret;
     220}
     221
     222int usb_hc_release_address(usb_hc_connection_t *connection,
     223    usb_address_t address)
     224{
     225        async_exch_t *exch;
     226        EXCH_INIT(connection, exch);
     227
     228        const int ret = usbhc_release_address(exch, address);
     229
     230        EXCH_FINI(connection, exch);
     231        return ret;
     232}
     233
     234int usb_hc_register_endpoint(usb_hc_connection_t *connection,
     235    usb_address_t address, usb_endpoint_t endpoint, usb_transfer_type_t type,
     236    usb_direction_t direction, size_t packet_size, unsigned interval)
     237{
     238        async_exch_t *exch;
     239        EXCH_INIT(connection, exch);
     240
     241        const int ret = usbhc_register_endpoint(exch, address, endpoint,
     242            type, direction, packet_size, interval);
     243
     244        EXCH_FINI(connection, exch);
     245        return ret;
     246}
     247
     248int usb_hc_unregister_endpoint(usb_hc_connection_t *connection,
     249    usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
     250{
     251        async_exch_t *exch;
     252        EXCH_INIT(connection, exch);
     253
     254        const int ret =
     255            usbhc_unregister_endpoint(exch, address, endpoint, direction);
     256
     257        EXCH_FINI(connection, exch);
     258        return ret;
     259}
     260
     261int usb_hc_read(usb_hc_connection_t *connection, usb_address_t address,
     262    usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size,
     263    size_t *real_size)
     264{
     265        async_exch_t *exch;
     266        EXCH_INIT(connection, exch);
     267
     268        const int ret =
     269            usbhc_read(exch, address, endpoint, setup, data, size, real_size);
     270
     271        EXCH_FINI(connection, exch);
     272        return ret;
     273}
     274
     275int usb_hc_write(usb_hc_connection_t *connection, usb_address_t address,
     276    usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size)
     277{
     278        async_exch_t *exch;
     279        EXCH_INIT(connection, exch);
     280
     281        const int ret = usbhc_write(exch, address, endpoint, setup, data, size);
     282
     283        EXCH_FINI(connection, exch);
     284        return ret;
    251285}
    252286
Note: See TracChangeset for help on using the changeset viewer.