Ignore:
File:
1 edited

Legend:

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

    r02fc5c4 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         if (!exch)
    158                 return ENOMEM;
     207        async_exch_t *exch;
     208        EXCH_INIT(connection, exch);
     209
    159210        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 
    195 /** Get host controller handle by its class index.
    196  *
    197  * @param sid Service ID of the HC function.
    198  * @param hc_handle Where to store the HC handle
    199  *      (can be NULL for existence test only).
    200  * @return Error code.
    201  */
    202 int usb_ddf_get_hc_handle_by_sid(service_id_t sid, devman_handle_t *hc_handle)
    203 {
    204         devman_handle_t handle;
    205         int rc;
    206        
    207         rc = devman_fun_sid_to_handle(sid, &handle);
    208         if (hc_handle != NULL)
    209                 *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);
    238 
     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);
    239278        return ret;
    240279}
Note: See TracChangeset for help on using the changeset viewer.