Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/drv/generic/remote_usb.c

    r7f80313 r4e732f1a  
    3535
    3636#include <async.h>
     37#include <macros.h>
    3738#include <errno.h>
    38 #include <macros.h>
     39#include <devman.h>
    3940
    4041#include "usb_iface.h"
    4142#include "ddf/driver.h"
    4243
     44
     45usb_dev_session_t *usb_dev_connect(devman_handle_t handle)
     46{
     47        return devman_device_connect(EXCHANGE_PARALLEL, handle, IPC_FLAG_BLOCKING);
     48}
     49
     50usb_dev_session_t *usb_dev_connect_to_self(ddf_dev_t *dev)
     51{
     52        // TODO All usb requests are atomic so this is safe,
     53        // it will need to change once USING EXCHANGE PARALLEL is safe with
     54        // devman_parent_device_connect
     55        return devman_parent_device_connect(EXCHANGE_ATOMIC,
     56            ddf_dev_get_handle(dev), IPC_FLAG_BLOCKING);
     57}
     58
     59void usb_dev_disconnect(usb_dev_session_t *sess)
     60{
     61        if (sess)
     62                async_hangup(sess);
     63}
     64
    4365typedef enum {
    44         IPC_M_USB_GET_MY_ADDRESS,
    4566        IPC_M_USB_GET_MY_INTERFACE,
    46         IPC_M_USB_GET_HOST_CONTROLLER_HANDLE,
     67        IPC_M_USB_GET_MY_DEVICE_HANDLE,
     68        IPC_M_USB_RESERVE_DEFAULT_ADDRESS,
     69        IPC_M_USB_RELEASE_DEFAULT_ADDRESS,
     70        IPC_M_USB_DEVICE_ENUMERATE,
     71        IPC_M_USB_DEVICE_REMOVE,
     72        IPC_M_USB_REGISTER_ENDPOINT,
     73        IPC_M_USB_UNREGISTER_ENDPOINT,
     74        IPC_M_USB_READ,
     75        IPC_M_USB_WRITE,
    4776} usb_iface_funcs_t;
    48 
    49 /** Tell USB address assigned to device.
    50  * @param exch Vaid IPC exchange
    51  * @param address Pointer to address storage place.
    52  * @return Error code.
    53  *
    54  * Exch param is an open communication to device implementing usb_iface.
    55  */
    56 int usb_get_my_address(async_exch_t *exch, usb_address_t *address)
    57 {
    58         if (!exch)
    59                 return EBADMEM;
    60         sysarg_t addr;
    61         const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    62             IPC_M_USB_GET_MY_ADDRESS, &addr);
    63 
    64         if (ret == EOK && address != NULL)
    65                 *address = (usb_address_t) addr;
    66         return ret;
    67 }
    6877
    6978/** Tell interface number given device can use.
     
    8594}
    8695
    87 /** Tell devman handle of device host controller.
     96/** Tell devman handle of the usb device function.
    8897 * @param[in] exch IPC communication exchange
    89  * @param[out] hc_handle devman handle of the HC used by the target device.
     98 * @param[out] handle devman handle of the HC used by the target device.
    9099 * @return Error code.
    91100 */
    92 int usb_get_hc_handle(async_exch_t *exch, devman_handle_t *hc_handle)
    93 {
    94         if (!exch)
    95                 return EBADMEM;
    96         devman_handle_t h;
     101int usb_get_my_device_handle(async_exch_t *exch, devman_handle_t *handle)
     102{
     103        devman_handle_t h = 0;
    97104        const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    98             IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
    99         if (ret == EOK && hc_handle)
    100                 *hc_handle = (devman_handle_t)h;
     105            IPC_M_USB_GET_MY_DEVICE_HANDLE, &h);
     106        if (ret == EOK && handle)
     107                *handle = (devman_handle_t)h;
    101108        return ret;
    102109}
    103110
    104 
    105 static void remote_usb_get_my_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     111/** Reserve default USB address.
     112 * @param[in] exch IPC communication exchange
     113 * @param[in] speed Communication speed of the newly attached device
     114 * @return Error code.
     115 */
     116int usb_reserve_default_address(async_exch_t *exch, usb_speed_t speed)
     117{
     118        if (!exch)
     119                return EBADMEM;
     120        return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     121            IPC_M_USB_RESERVE_DEFAULT_ADDRESS, speed);
     122}
     123
     124/** Release default USB address.
     125 * @param[in] exch IPC communication exchange
     126 * @return Error code.
     127 */
     128int usb_release_default_address(async_exch_t *exch)
     129{
     130        if (!exch)
     131                return EBADMEM;
     132        return async_req_1_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     133            IPC_M_USB_RELEASE_DEFAULT_ADDRESS);
     134}
     135
     136/** Trigger USB device enumeration
     137 * @param[in] exch IPC communication exchange
     138 * @param[out] handle Identifier of the newly added device (if successful)
     139 * @return Error code.
     140 */
     141int usb_device_enumerate(async_exch_t *exch, unsigned port)
     142{
     143        if (!exch)
     144                return EBADMEM;
     145        const int ret = async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     146            IPC_M_USB_DEVICE_ENUMERATE, port);
     147        return ret;
     148}
     149
     150/** Trigger USB device enumeration
     151 * @param[in] exch IPC communication exchange
     152 * @param[in] handle Identifier of the device
     153 * @return Error code.
     154 */
     155int usb_device_remove(async_exch_t *exch, unsigned port)
     156{
     157        if (!exch)
     158                return EBADMEM;
     159        return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     160            IPC_M_USB_DEVICE_REMOVE, port);
     161}
     162
     163int static_assert[sizeof(sysarg_t) >= 4 ? 1 : -1];
     164typedef union {
     165        uint8_t arr[sizeof(sysarg_t)];
     166        sysarg_t arg;
     167} pack8_t;
     168
     169int usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
     170    usb_transfer_type_t type, usb_direction_t direction,
     171    size_t mps, unsigned packets, unsigned interval)
     172{
     173        if (!exch)
     174                return EBADMEM;
     175        pack8_t pack;
     176        pack.arr[0] = type;
     177        pack.arr[1] = direction;
     178        pack.arr[2] = interval;
     179        pack.arr[3] = packets;
     180
     181        return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     182            IPC_M_USB_REGISTER_ENDPOINT, endpoint, pack.arg, mps);
     183
     184}
     185
     186int usb_unregister_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
     187    usb_direction_t direction)
     188{
     189        if (!exch)
     190                return EBADMEM;
     191        return async_req_3_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     192            IPC_M_USB_UNREGISTER_ENDPOINT, endpoint, direction);
     193}
     194
     195int usb_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
     196    void *data, size_t size, size_t *rec_size)
     197{
     198        if (!exch)
     199                return EBADMEM;
     200
     201        if (size == 0 && setup == 0)
     202                return EOK;
     203
     204        /* Make call identifying target USB device and type of transfer. */
     205        aid_t opening_request = async_send_4(exch,
     206            DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_READ, endpoint,
     207            (setup & UINT32_MAX), (setup >> 32), NULL);
     208
     209        if (opening_request == 0) {
     210                return ENOMEM;
     211        }
     212
     213        /* Retrieve the data. */
     214        ipc_call_t data_request_call;
     215        aid_t data_request =
     216            async_data_read(exch, data, size, &data_request_call);
     217
     218        if (data_request == 0) {
     219                // FIXME: How to let the other side know that we want to abort?
     220                async_forget(opening_request);
     221                return ENOMEM;
     222        }
     223
     224        /* Wait for the answer. */
     225        sysarg_t data_request_rc;
     226        sysarg_t opening_request_rc;
     227        async_wait_for(data_request, &data_request_rc);
     228        async_wait_for(opening_request, &opening_request_rc);
     229
     230        if (data_request_rc != EOK) {
     231                /* Prefer the return code of the opening request. */
     232                if (opening_request_rc != EOK) {
     233                        return (int) opening_request_rc;
     234                } else {
     235                        return (int) data_request_rc;
     236                }
     237        }
     238        if (opening_request_rc != EOK) {
     239                return (int) opening_request_rc;
     240        }
     241
     242        *rec_size = IPC_GET_ARG2(data_request_call);
     243        return EOK;
     244}
     245
     246int usb_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
     247    const void *data, size_t size)
     248{
     249        if (!exch)
     250                return EBADMEM;
     251
     252        if (size == 0 && setup == 0)
     253                return EOK;
     254
     255        aid_t opening_request = async_send_5(exch,
     256            DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size,
     257            (setup & UINT32_MAX), (setup >> 32), NULL);
     258
     259        if (opening_request == 0) {
     260                return ENOMEM;
     261        }
     262
     263        /* Send the data if any. */
     264        if (size > 0) {
     265                const int ret = async_data_write_start(exch, data, size);
     266                if (ret != EOK) {
     267                        async_forget(opening_request);
     268                        return ret;
     269                }
     270        }
     271
     272        /* Wait for the answer. */
     273        sysarg_t opening_request_rc;
     274        async_wait_for(opening_request, &opening_request_rc);
     275
     276        return (int) opening_request_rc;
     277}
     278
    106279static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    107 static void remote_usb_get_hc_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     280static void remote_usb_get_my_device_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     281static void remote_usb_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     282static void remote_usb_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     283static void remote_usb_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     284static void remote_usb_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     285static void remote_usb_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     286static void remote_usb_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     287static void remote_usb_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
     288static void remote_usb_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
    108289
    109290/** Remote USB interface operations. */
    110291static const remote_iface_func_ptr_t remote_usb_iface_ops [] = {
    111         [IPC_M_USB_GET_MY_ADDRESS] = remote_usb_get_my_address,
    112292        [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface,
    113         [IPC_M_USB_GET_HOST_CONTROLLER_HANDLE] = remote_usb_get_hc_handle,
     293        [IPC_M_USB_GET_MY_DEVICE_HANDLE] = remote_usb_get_my_device_handle,
     294        [IPC_M_USB_RESERVE_DEFAULT_ADDRESS] = remote_usb_reserve_default_address,
     295        [IPC_M_USB_RELEASE_DEFAULT_ADDRESS] = remote_usb_release_default_address,
     296        [IPC_M_USB_DEVICE_ENUMERATE] = remote_usb_device_enumerate,
     297        [IPC_M_USB_DEVICE_REMOVE] = remote_usb_device_remove,
     298        [IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint,
     299        [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint,
     300        [IPC_M_USB_READ] = remote_usb_read,
     301        [IPC_M_USB_WRITE] = remote_usb_write,
    114302};
    115303
     
    118306const remote_iface_t remote_usb_iface = {
    119307        .method_count = ARRAY_SIZE(remote_usb_iface_ops),
    120         .methods = remote_usb_iface_ops
     308        .methods = remote_usb_iface_ops,
    121309};
    122 
    123 
    124 void remote_usb_get_my_address(ddf_fun_t *fun, void *iface,
    125     ipc_callid_t callid, ipc_call_t *call)
    126 {
    127         const usb_iface_t *usb_iface = (usb_iface_t *) iface;
    128 
    129         if (usb_iface->get_my_address == NULL) {
    130                 async_answer_0(callid, ENOTSUP);
    131                 return;
    132         }
    133 
    134         usb_address_t address;
    135         const int ret = usb_iface->get_my_address(fun, &address);
    136         if (ret != EOK) {
    137                 async_answer_0(callid, ret);
    138         } else {
    139                 async_answer_1(callid, EOK, address);
    140         }
    141 }
    142310
    143311void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface,
     
    160328}
    161329
    162 void remote_usb_get_hc_handle(ddf_fun_t *fun, void *iface,
     330void remote_usb_get_my_device_handle(ddf_fun_t *fun, void *iface,
    163331    ipc_callid_t callid, ipc_call_t *call)
    164332{
    165333        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
    166334
    167         if (usb_iface->get_hc_handle == NULL) {
     335        if (usb_iface->get_my_device_handle == NULL) {
    168336                async_answer_0(callid, ENOTSUP);
    169337                return;
     
    171339
    172340        devman_handle_t handle;
    173         const int ret = usb_iface->get_hc_handle(fun, &handle);
     341        const int ret = usb_iface->get_my_device_handle(fun, &handle);
    174342        if (ret != EOK) {
    175343                async_answer_0(callid, ret);
     
    178346        async_answer_1(callid, EOK, (sysarg_t) handle);
    179347}
     348
     349void remote_usb_reserve_default_address(ddf_fun_t *fun, void *iface,
     350    ipc_callid_t callid, ipc_call_t *call)
     351{
     352        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     353
     354        if (usb_iface->reserve_default_address == NULL) {
     355                async_answer_0(callid, ENOTSUP);
     356                return;
     357        }
     358
     359        usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
     360        const int ret = usb_iface->reserve_default_address(fun, speed);
     361        async_answer_0(callid, ret);
     362}
     363
     364void remote_usb_release_default_address(ddf_fun_t *fun, void *iface,
     365    ipc_callid_t callid, ipc_call_t *call)
     366{
     367        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     368
     369        if (usb_iface->release_default_address == NULL) {
     370                async_answer_0(callid, ENOTSUP);
     371                return;
     372        }
     373
     374        const int ret = usb_iface->release_default_address(fun);
     375        async_answer_0(callid, ret);
     376}
     377
     378static void remote_usb_device_enumerate(ddf_fun_t *fun, void *iface,
     379    ipc_callid_t callid, ipc_call_t *call)
     380{
     381        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     382
     383        if (usb_iface->device_enumerate == NULL) {
     384                async_answer_0(callid, ENOTSUP);
     385                return;
     386        }
     387
     388        const unsigned port = DEV_IPC_GET_ARG1(*call);
     389        const int ret = usb_iface->device_enumerate(fun, port);
     390        async_answer_0(callid, ret);
     391}
     392
     393static void remote_usb_device_remove(ddf_fun_t *fun, void *iface,
     394    ipc_callid_t callid, ipc_call_t *call)
     395{
     396        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     397
     398        if (usb_iface->device_remove == NULL) {
     399                async_answer_0(callid, ENOTSUP);
     400                return;
     401        }
     402
     403        const unsigned port = DEV_IPC_GET_ARG1(*call);
     404        const int ret = usb_iface->device_remove(fun, port);
     405        async_answer_0(callid, ret);
     406}
     407
     408static void remote_usb_register_endpoint(ddf_fun_t *fun, void *iface,
     409    ipc_callid_t callid, ipc_call_t *call)
     410{
     411        usb_iface_t *usb_iface = (usb_iface_t *) iface;
     412
     413        if (!usb_iface->register_endpoint) {
     414                async_answer_0(callid, ENOTSUP);
     415                return;
     416        }
     417
     418        const usb_endpoint_t endpoint = DEV_IPC_GET_ARG1(*call);
     419        const pack8_t pack = { .arg = DEV_IPC_GET_ARG2(*call)};
     420        const size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
     421
     422        const usb_transfer_type_t transfer_type = pack.arr[0];
     423        const usb_direction_t direction = pack.arr[1];
     424        unsigned packets = pack.arr[2];
     425        unsigned interval = pack.arr[3];
     426
     427        const int ret = usb_iface->register_endpoint(fun, endpoint,
     428            transfer_type, direction, max_packet_size, packets, interval);
     429
     430        async_answer_0(callid, ret);
     431}
     432
     433static void remote_usb_unregister_endpoint(ddf_fun_t *fun, void *iface,
     434    ipc_callid_t callid, ipc_call_t *call)
     435{
     436        usb_iface_t *usb_iface = (usb_iface_t *) iface;
     437
     438        if (!usb_iface->unregister_endpoint) {
     439                async_answer_0(callid, ENOTSUP);
     440                return;
     441        }
     442
     443        usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG1(*call);
     444        usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG2(*call);
     445
     446        int rc = usb_iface->unregister_endpoint(fun, endpoint, direction);
     447
     448        async_answer_0(callid, rc);
     449}
     450
     451typedef struct {
     452        ipc_callid_t caller;
     453        ipc_callid_t data_caller;
     454        void *buffer;
     455} async_transaction_t;
     456
     457static void async_transaction_destroy(async_transaction_t *trans)
     458{
     459        if (trans == NULL) {
     460                return;
     461        }
     462        if (trans->buffer != NULL) {
     463                free(trans->buffer);
     464        }
     465
     466        free(trans);
     467}
     468
     469static async_transaction_t *async_transaction_create(ipc_callid_t caller)
     470{
     471        async_transaction_t *trans = malloc(sizeof(async_transaction_t));
     472        if (trans == NULL) {
     473                return NULL;
     474        }
     475
     476        trans->caller = caller;
     477        trans->data_caller = 0;
     478        trans->buffer = NULL;
     479
     480        return trans;
     481}
     482
     483static void callback_out(int outcome, void *arg)
     484{
     485        async_transaction_t *trans = arg;
     486
     487        async_answer_0(trans->caller, outcome);
     488
     489        async_transaction_destroy(trans);
     490}
     491
     492static void callback_in(int outcome, size_t actual_size, void *arg)
     493{
     494        async_transaction_t *trans = (async_transaction_t *)arg;
     495
     496        if (outcome != EOK) {
     497                async_answer_0(trans->caller, outcome);
     498                if (trans->data_caller) {
     499                        async_answer_0(trans->data_caller, EINTR);
     500                }
     501                async_transaction_destroy(trans);
     502                return;
     503        }
     504
     505        if (trans->data_caller) {
     506                async_data_read_finalize(trans->data_caller,
     507                    trans->buffer, actual_size);
     508        }
     509
     510        async_answer_0(trans->caller, EOK);
     511
     512        async_transaction_destroy(trans);
     513}
     514
     515void remote_usb_read(
     516    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     517{
     518        assert(fun);
     519        assert(iface);
     520        assert(call);
     521
     522        const usb_iface_t *usb_iface = iface;
     523
     524        if (!usb_iface->read) {
     525                async_answer_0(callid, ENOTSUP);
     526                return;
     527        }
     528
     529        const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
     530        const uint64_t setup =
     531            ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
     532            (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
     533
     534        async_transaction_t *trans = async_transaction_create(callid);
     535        if (trans == NULL) {
     536                async_answer_0(callid, ENOMEM);
     537                return;
     538        }
     539
     540        size_t size = 0;
     541        if (!async_data_read_receive(&trans->data_caller, &size)) {
     542                async_answer_0(callid, EPARTY);
     543                return;
     544        }
     545
     546        trans->buffer = malloc(size);
     547        if (trans->buffer == NULL) {
     548                async_answer_0(trans->data_caller, ENOMEM);
     549                async_answer_0(callid, ENOMEM);
     550                async_transaction_destroy(trans);
     551        }
     552
     553        const int rc = usb_iface->read(
     554            fun, ep, setup, trans->buffer, size, callback_in, trans);
     555
     556        if (rc != EOK) {
     557                async_answer_0(trans->data_caller, rc);
     558                async_answer_0(callid, rc);
     559                async_transaction_destroy(trans);
     560        }
     561}
     562
     563void remote_usb_write(
     564    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     565{
     566        assert(fun);
     567        assert(iface);
     568        assert(call);
     569
     570        const usb_iface_t *usb_iface = iface;
     571
     572        if (!usb_iface->write) {
     573                async_answer_0(callid, ENOTSUP);
     574                return;
     575        }
     576
     577        const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
     578        const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
     579        const uint64_t setup =
     580            ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
     581            (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
     582
     583        async_transaction_t *trans = async_transaction_create(callid);
     584        if (trans == NULL) {
     585                async_answer_0(callid, ENOMEM);
     586                return;
     587        }
     588
     589        size_t size = 0;
     590        if (data_buffer_len > 0) {
     591                const int rc = async_data_write_accept(&trans->buffer, false,
     592                    1, data_buffer_len, 0, &size);
     593
     594                if (rc != EOK) {
     595                        async_answer_0(callid, rc);
     596                        async_transaction_destroy(trans);
     597                        return;
     598                }
     599        }
     600
     601        const int rc = usb_iface->write(
     602            fun, ep, setup, trans->buffer, size, callback_out, trans);
     603
     604        if (rc != EOK) {
     605                async_answer_0(callid, rc);
     606                async_transaction_destroy(trans);
     607        }
     608}
    180609/**
    181610 * @}
Note: See TracChangeset for help on using the changeset viewer.