Ignore:
File:
1 edited

Legend:

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

    rda2f1c9e r27ed734c  
    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         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) \
    84 do { \
    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) \
    99 if (exch) { \
    100         async_exchange_end(exch); \
    101         usb_hc_connection_del_ref(connection); \
    102 } else (void)0
    10344
    10445/** Initialize connection to USB host controller.
     
    11859
    11960        devman_handle_t 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         }
     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);
    12467
    12568        return rc;
    12669}
    127 /*----------------------------------------------------------------------------*/
    128 void 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 /*----------------------------------------------------------------------------*/
     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
    14388/** Open connection to host controller.
    14489 *
     
    14893int usb_hc_connection_open(usb_hc_connection_t *connection)
    14994{
    150         return usb_hc_connection_add_ref(connection);
    151 }
    152 /*----------------------------------------------------------------------------*/
     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
    153120/** Close connection to the host controller.
    154121 *
     
    158125int usb_hc_connection_close(usb_hc_connection_t *connection)
    159126{
    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  */
    172 usb_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 /*----------------------------------------------------------------------------*/
    185 int 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 /*----------------------------------------------------------------------------*/
     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
    197143/** Get handle of USB device with given address.
    198144 *
     
    205151    usb_address_t address, devman_handle_t *handle)
    206152{
    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 /*----------------------------------------------------------------------------*/
    216 int 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 /*----------------------------------------------------------------------------*/
    228 int 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 /*----------------------------------------------------------------------------*/
    242 int 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 /*----------------------------------------------------------------------------*/
    255 int 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 /*----------------------------------------------------------------------------*/
    269 int 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;
     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 */
     176usb_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 */
     207int 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 */
     226int 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;
    279250}
    280251
Note: See TracChangeset for help on using the changeset viewer.