Ignore:
File:
1 edited

Legend:

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

    r29e479f r02fc5c4  
    11/*
    22 * Copyright (c) 2011 Vojtech Horky
    3  * Copyright (c) 2011 Jan Vesely
    43 * All rights reserved.
    54 *
     
    2726 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2827 */
     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>
     39#include <usbhc_iface.h>
     40#include <usb/hc.h>
    3541#include <usb/debug.h>
    36 
     42#include <errno.h>
    3743#include <assert.h>
    38 #include <errno.h>
    39 #include <usbhc_iface.h>
    40 #include <usb/dev.h>
    41 #include <usb/hc.h>
    42 
    43 static 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 /*----------------------------------------------------------------------------*/
    62 static 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) \
    78 do { \
    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) \
    93 if (exch) { \
    94         async_exchange_end(exch); \
    95         usb_hc_connection_del_ref(connection); \
    96 } else (void)0
    9744
    9845/** Initialize connection to USB host controller.
     
    11259
    11360        devman_handle_t 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         }
     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);
    11867
    11968        return rc;
    12069}
    121 /*----------------------------------------------------------------------------*/
     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 */
     77int 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
    12288/** Open connection to host controller.
    12389 *
     
    12793int usb_hc_connection_open(usb_hc_connection_t *connection)
    12894{
    129         return usb_hc_connection_add_ref(connection);
    130 }
    131 /*----------------------------------------------------------------------------*/
     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.
     110 *
     111 * @param connection Connection to the host controller.
     112 * @return Whether connection is opened.
     113 */
     114bool usb_hc_connection_is_opened(const usb_hc_connection_t *connection)
     115{
     116        assert(connection);
     117        return (connection->hc_sess != NULL);
     118}
     119
    132120/** Close connection to the host controller.
    133121 *
     
    137125int usb_hc_connection_close(usb_hc_connection_t *connection)
    138126{
    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  */
    151 usb_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 /*----------------------------------------------------------------------------*/
    164 int 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 /*----------------------------------------------------------------------------*/
     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
    176143/** Get handle of USB device with given address.
    177144 *
     
    184151    usb_address_t address, devman_handle_t *handle)
    185152{
    186         async_exch_t *exch;
    187         EXCH_INIT(connection, exch);
    188 
     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;
    189159        const int ret = usbhc_get_handle(exch, address, handle);
    190 
    191         EXCH_FINI(connection, exch);
     160        async_exchange_end(exch);
    192161        return ret;
    193162}
    194 /*----------------------------------------------------------------------------*/
    195 int 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 /*----------------------------------------------------------------------------*/
    207 int 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 /*----------------------------------------------------------------------------*/
    221 int 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 /*----------------------------------------------------------------------------*/
    234 int 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 /*----------------------------------------------------------------------------*/
    248 int 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 /*----------------------------------------------------------------------------*/
     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 */
     169usb_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
    260195/** Get host controller handle by its class index.
    261196 *
     
    268203{
    269204        devman_handle_t handle;
    270 
    271         const int ret = devman_fun_sid_to_handle(sid, &handle);
    272         if (ret == EOK && hc_handle != NULL)
     205        int rc;
     206       
     207        rc = devman_fun_sid_to_handle(sid, &handle);
     208        if (hc_handle != NULL)
    273209                *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 */
     221int 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);
    274238
    275239        return ret;
Note: See TracChangeset for help on using the changeset viewer.