Ignore:
File:
1 edited

Legend:

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

    r5a6cc679 rb7fd2a0  
    6161
    6262typedef enum {
    63         IPC_M_USB_GET_MY_DESCRIPTION,
     63        IPC_M_USB_GET_MY_INTERFACE,
     64        IPC_M_USB_GET_MY_DEVICE_HANDLE,
     65        IPC_M_USB_RESERVE_DEFAULT_ADDRESS,
     66        IPC_M_USB_RELEASE_DEFAULT_ADDRESS,
     67        IPC_M_USB_DEVICE_ENUMERATE,
     68        IPC_M_USB_DEVICE_REMOVE,
     69        IPC_M_USB_REGISTER_ENDPOINT,
     70        IPC_M_USB_UNREGISTER_ENDPOINT,
     71        IPC_M_USB_READ,
     72        IPC_M_USB_WRITE,
    6473} usb_iface_funcs_t;
    6574
     
    7079 * @return Error code.
    7180 */
    72 errno_t usb_get_my_description(async_exch_t *exch, usb_device_desc_t *desc)
    73 {
    74         if (!exch)
    75                 return EBADMEM;
    76 
    77         usb_device_desc_t tmp_desc;
    78 
    79         const errno_t ret = async_req_1_5(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    80             IPC_M_USB_GET_MY_DESCRIPTION,
    81             (sysarg_t *) &tmp_desc.address,
    82             (sysarg_t *) &tmp_desc.depth,
    83             (sysarg_t *) &tmp_desc.speed,
    84             &tmp_desc.handle,
    85             (sysarg_t *) &tmp_desc.iface);
    86         if (ret == EOK && desc)
    87                 *desc = tmp_desc;
     81errno_t usb_get_my_interface(async_exch_t *exch, int *usb_iface)
     82{
     83        if (!exch)
     84                return EBADMEM;
     85        sysarg_t iface_no;
     86        const errno_t ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     87            IPC_M_USB_GET_MY_INTERFACE, &iface_no);
     88        if (ret == EOK && usb_iface)
     89                *usb_iface = (int)iface_no;
    8890        return ret;
    8991}
    9092
    91 static void remote_usb_get_my_description(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     93/** Tell devman handle of the usb device function.
     94 *
     95 * @param[in]  exch   IPC communication exchange
     96 * @param[out] handle devman handle of the HC used by the target device.
     97 *
     98 * @return Error code.
     99 *
     100 */
     101errno_t usb_get_my_device_handle(async_exch_t *exch, devman_handle_t *handle)
     102{
     103        devman_handle_t h = 0;
     104        const errno_t ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     105            IPC_M_USB_GET_MY_DEVICE_HANDLE, &h);
     106        if (ret == EOK && handle)
     107                *handle = (devman_handle_t)h;
     108        return ret;
     109}
     110
     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 */
     116errno_t 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 *
     126 * @param[in] exch IPC communication exchange
     127 *
     128 * @return Error code.
     129 *
     130 */
     131errno_t usb_release_default_address(async_exch_t *exch)
     132{
     133        if (!exch)
     134                return EBADMEM;
     135        return async_req_1_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     136            IPC_M_USB_RELEASE_DEFAULT_ADDRESS);
     137}
     138
     139/** Trigger USB device enumeration
     140 *
     141 * @param[in]  exch   IPC communication exchange
     142 * @param[out] handle Identifier of the newly added device (if successful)
     143 *
     144 * @return Error code.
     145 *
     146 */
     147errno_t usb_device_enumerate(async_exch_t *exch, unsigned port)
     148{
     149        if (!exch)
     150                return EBADMEM;
     151        const errno_t ret = async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     152            IPC_M_USB_DEVICE_ENUMERATE, port);
     153        return ret;
     154}
     155
     156/** Trigger USB device enumeration
     157 *
     158 * @param[in] exch   IPC communication exchange
     159 * @param[in] handle Identifier of the device
     160 *
     161 * @return Error code.
     162 *
     163 */
     164errno_t usb_device_remove(async_exch_t *exch, unsigned port)
     165{
     166        if (!exch)
     167                return EBADMEM;
     168        return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     169            IPC_M_USB_DEVICE_REMOVE, port);
     170}
     171
     172static_assert(sizeof(sysarg_t) >= 4);
     173
     174typedef union {
     175        uint8_t arr[sizeof(sysarg_t)];
     176        sysarg_t arg;
     177} pack8_t;
     178
     179errno_t usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
     180    usb_transfer_type_t type, usb_direction_t direction,
     181    size_t mps, unsigned packets, unsigned interval)
     182{
     183        if (!exch)
     184                return EBADMEM;
     185        pack8_t pack;
     186        pack.arr[0] = type;
     187        pack.arr[1] = direction;
     188        pack.arr[2] = interval;
     189        pack.arr[3] = packets;
     190
     191        return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     192            IPC_M_USB_REGISTER_ENDPOINT, endpoint, pack.arg, mps);
     193
     194}
     195
     196errno_t usb_unregister_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
     197    usb_direction_t direction)
     198{
     199        if (!exch)
     200                return EBADMEM;
     201        return async_req_3_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     202            IPC_M_USB_UNREGISTER_ENDPOINT, endpoint, direction);
     203}
     204
     205errno_t usb_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
     206    void *data, size_t size, size_t *rec_size)
     207{
     208        if (!exch)
     209                return EBADMEM;
     210
     211        if (size == 0 && setup == 0)
     212                return EOK;
     213
     214        /* Make call identifying target USB device and type of transfer. */
     215        aid_t opening_request = async_send_4(exch,
     216            DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_READ, endpoint,
     217            (setup & UINT32_MAX), (setup >> 32), NULL);
     218
     219        if (opening_request == 0) {
     220                return ENOMEM;
     221        }
     222
     223        /* Retrieve the data. */
     224        ipc_call_t data_request_call;
     225        aid_t data_request =
     226            async_data_read(exch, data, size, &data_request_call);
     227
     228        if (data_request == 0) {
     229                // FIXME: How to let the other side know that we want to abort?
     230                async_forget(opening_request);
     231                return ENOMEM;
     232        }
     233
     234        /* Wait for the answer. */
     235        errno_t data_request_rc;
     236        errno_t opening_request_rc;
     237        async_wait_for(data_request, &data_request_rc);
     238        async_wait_for(opening_request, &opening_request_rc);
     239
     240        if (data_request_rc != EOK) {
     241                /* Prefer the return code of the opening request. */
     242                if (opening_request_rc != EOK) {
     243                        return (errno_t) opening_request_rc;
     244                } else {
     245                        return (errno_t) data_request_rc;
     246                }
     247        }
     248        if (opening_request_rc != EOK) {
     249                return (errno_t) opening_request_rc;
     250        }
     251
     252        *rec_size = IPC_GET_ARG2(data_request_call);
     253        return EOK;
     254}
     255
     256errno_t usb_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
     257    const void *data, size_t size)
     258{
     259        if (!exch)
     260                return EBADMEM;
     261
     262        if (size == 0 && setup == 0)
     263                return EOK;
     264
     265        aid_t opening_request = async_send_5(exch,
     266            DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size,
     267            (setup & UINT32_MAX), (setup >> 32), NULL);
     268
     269        if (opening_request == 0) {
     270                return ENOMEM;
     271        }
     272
     273        /* Send the data if any. */
     274        if (size > 0) {
     275                const errno_t ret = async_data_write_start(exch, data, size);
     276                if (ret != EOK) {
     277                        async_forget(opening_request);
     278                        return ret;
     279                }
     280        }
     281
     282        /* Wait for the answer. */
     283        errno_t opening_request_rc;
     284        async_wait_for(opening_request, &opening_request_rc);
     285
     286        return (errno_t) opening_request_rc;
     287}
     288
     289static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     290static void remote_usb_get_my_device_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     291static void remote_usb_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     292static void remote_usb_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     293static void remote_usb_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     294static void remote_usb_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     295static void remote_usb_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     296static void remote_usb_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     297static void remote_usb_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
     298static void remote_usb_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
    92299
    93300/** Remote USB interface operations. */
    94301static const remote_iface_func_ptr_t remote_usb_iface_ops [] = {
    95         [IPC_M_USB_GET_MY_DESCRIPTION] = remote_usb_get_my_description,
     302        [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface,
     303        [IPC_M_USB_GET_MY_DEVICE_HANDLE] = remote_usb_get_my_device_handle,
     304        [IPC_M_USB_RESERVE_DEFAULT_ADDRESS] = remote_usb_reserve_default_address,
     305        [IPC_M_USB_RELEASE_DEFAULT_ADDRESS] = remote_usb_release_default_address,
     306        [IPC_M_USB_DEVICE_ENUMERATE] = remote_usb_device_enumerate,
     307        [IPC_M_USB_DEVICE_REMOVE] = remote_usb_device_remove,
     308        [IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint,
     309        [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint,
     310        [IPC_M_USB_READ] = remote_usb_read,
     311        [IPC_M_USB_WRITE] = remote_usb_write,
    96312};
    97313
     
    103319};
    104320
    105 void remote_usb_get_my_description(ddf_fun_t *fun, void *iface,
     321void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface,
    106322    ipc_callid_t callid, ipc_call_t *call)
    107323{
    108324        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
    109325
    110         if (usb_iface->get_my_description == NULL) {
    111                 async_answer_0(callid, ENOTSUP);
    112                 return;
    113         }
    114 
    115         usb_device_desc_t desc;
    116         const errno_t ret = usb_iface->get_my_description(fun, &desc);
     326        if (usb_iface->get_my_interface == NULL) {
     327                async_answer_0(callid, ENOTSUP);
     328                return;
     329        }
     330
     331        int iface_no;
     332        const errno_t ret = usb_iface->get_my_interface(fun, &iface_no);
    117333        if (ret != EOK) {
    118334                async_answer_0(callid, ret);
    119335        } else {
    120                 async_answer_5(callid, EOK,
    121                     (sysarg_t) desc.address,
    122                     (sysarg_t) desc.depth,
    123                     (sysarg_t) desc.speed,
    124                     desc.handle,
    125                     desc.iface);
    126         }
    127 }
    128 
     336                async_answer_1(callid, EOK, iface_no);
     337        }
     338}
     339
     340void remote_usb_get_my_device_handle(ddf_fun_t *fun, void *iface,
     341    ipc_callid_t callid, ipc_call_t *call)
     342{
     343        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     344
     345        if (usb_iface->get_my_device_handle == NULL) {
     346                async_answer_0(callid, ENOTSUP);
     347                return;
     348        }
     349
     350        devman_handle_t handle;
     351        const errno_t ret = usb_iface->get_my_device_handle(fun, &handle);
     352        if (ret != EOK) {
     353                async_answer_0(callid, ret);
     354        }
     355
     356        async_answer_1(callid, EOK, (sysarg_t) handle);
     357}
     358
     359void remote_usb_reserve_default_address(ddf_fun_t *fun, void *iface,
     360    ipc_callid_t callid, ipc_call_t *call)
     361{
     362        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     363
     364        if (usb_iface->reserve_default_address == NULL) {
     365                async_answer_0(callid, ENOTSUP);
     366                return;
     367        }
     368
     369        usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
     370        const errno_t ret = usb_iface->reserve_default_address(fun, speed);
     371        async_answer_0(callid, ret);
     372}
     373
     374void remote_usb_release_default_address(ddf_fun_t *fun, void *iface,
     375    ipc_callid_t callid, ipc_call_t *call)
     376{
     377        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     378
     379        if (usb_iface->release_default_address == NULL) {
     380                async_answer_0(callid, ENOTSUP);
     381                return;
     382        }
     383
     384        const errno_t ret = usb_iface->release_default_address(fun);
     385        async_answer_0(callid, ret);
     386}
     387
     388static void remote_usb_device_enumerate(ddf_fun_t *fun, void *iface,
     389    ipc_callid_t callid, ipc_call_t *call)
     390{
     391        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     392
     393        if (usb_iface->device_enumerate == NULL) {
     394                async_answer_0(callid, ENOTSUP);
     395                return;
     396        }
     397
     398        const unsigned port = DEV_IPC_GET_ARG1(*call);
     399        const errno_t ret = usb_iface->device_enumerate(fun, port);
     400        async_answer_0(callid, ret);
     401}
     402
     403static void remote_usb_device_remove(ddf_fun_t *fun, void *iface,
     404    ipc_callid_t callid, ipc_call_t *call)
     405{
     406        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     407
     408        if (usb_iface->device_remove == NULL) {
     409                async_answer_0(callid, ENOTSUP);
     410                return;
     411        }
     412
     413        const unsigned port = DEV_IPC_GET_ARG1(*call);
     414        const errno_t ret = usb_iface->device_remove(fun, port);
     415        async_answer_0(callid, ret);
     416}
     417
     418static void remote_usb_register_endpoint(ddf_fun_t *fun, void *iface,
     419    ipc_callid_t callid, ipc_call_t *call)
     420{
     421        usb_iface_t *usb_iface = (usb_iface_t *) iface;
     422
     423        if (!usb_iface->register_endpoint) {
     424                async_answer_0(callid, ENOTSUP);
     425                return;
     426        }
     427
     428        const usb_endpoint_t endpoint = DEV_IPC_GET_ARG1(*call);
     429        const pack8_t pack = { .arg = DEV_IPC_GET_ARG2(*call)};
     430        const size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
     431
     432        const usb_transfer_type_t transfer_type = pack.arr[0];
     433        const usb_direction_t direction = pack.arr[1];
     434        unsigned packets = pack.arr[2];
     435        unsigned interval = pack.arr[3];
     436
     437        const errno_t ret = usb_iface->register_endpoint(fun, endpoint,
     438            transfer_type, direction, max_packet_size, packets, interval);
     439
     440        async_answer_0(callid, ret);
     441}
     442
     443static void remote_usb_unregister_endpoint(ddf_fun_t *fun, void *iface,
     444    ipc_callid_t callid, ipc_call_t *call)
     445{
     446        usb_iface_t *usb_iface = (usb_iface_t *) iface;
     447
     448        if (!usb_iface->unregister_endpoint) {
     449                async_answer_0(callid, ENOTSUP);
     450                return;
     451        }
     452
     453        usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG1(*call);
     454        usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG2(*call);
     455
     456        errno_t rc = usb_iface->unregister_endpoint(fun, endpoint, direction);
     457
     458        async_answer_0(callid, rc);
     459}
     460
     461typedef struct {
     462        ipc_callid_t caller;
     463        ipc_callid_t data_caller;
     464        void *buffer;
     465} async_transaction_t;
     466
     467static void async_transaction_destroy(async_transaction_t *trans)
     468{
     469        if (trans == NULL) {
     470                return;
     471        }
     472        if (trans->buffer != NULL) {
     473                free(trans->buffer);
     474        }
     475
     476        free(trans);
     477}
     478
     479static async_transaction_t *async_transaction_create(ipc_callid_t caller)
     480{
     481        async_transaction_t *trans = malloc(sizeof(async_transaction_t));
     482        if (trans == NULL) {
     483                return NULL;
     484        }
     485
     486        trans->caller = caller;
     487        trans->data_caller = 0;
     488        trans->buffer = NULL;
     489
     490        return trans;
     491}
     492
     493static void callback_out(errno_t outcome, void *arg)
     494{
     495        async_transaction_t *trans = arg;
     496
     497        async_answer_0(trans->caller, outcome);
     498
     499        async_transaction_destroy(trans);
     500}
     501
     502static void callback_in(errno_t outcome, size_t actual_size, void *arg)
     503{
     504        async_transaction_t *trans = (async_transaction_t *)arg;
     505
     506        if (outcome != EOK) {
     507                async_answer_0(trans->caller, outcome);
     508                if (trans->data_caller) {
     509                        async_answer_0(trans->data_caller, EINTR);
     510                }
     511                async_transaction_destroy(trans);
     512                return;
     513        }
     514
     515        if (trans->data_caller) {
     516                async_data_read_finalize(trans->data_caller,
     517                    trans->buffer, actual_size);
     518        }
     519
     520        async_answer_0(trans->caller, EOK);
     521
     522        async_transaction_destroy(trans);
     523}
     524
     525void remote_usb_read(
     526    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     527{
     528        assert(fun);
     529        assert(iface);
     530        assert(call);
     531
     532        const usb_iface_t *usb_iface = iface;
     533
     534        if (!usb_iface->read) {
     535                async_answer_0(callid, ENOTSUP);
     536                return;
     537        }
     538
     539        const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
     540        const uint64_t setup =
     541            ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
     542            (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
     543
     544        async_transaction_t *trans = async_transaction_create(callid);
     545        if (trans == NULL) {
     546                async_answer_0(callid, ENOMEM);
     547                return;
     548        }
     549
     550        size_t size = 0;
     551        if (!async_data_read_receive(&trans->data_caller, &size)) {
     552                async_answer_0(callid, EPARTY);
     553                async_transaction_destroy(trans);
     554                return;
     555        }
     556
     557        trans->buffer = malloc(size);
     558        if (trans->buffer == NULL) {
     559                async_answer_0(trans->data_caller, ENOMEM);
     560                async_answer_0(callid, ENOMEM);
     561                async_transaction_destroy(trans);
     562                return;
     563        }
     564
     565        const errno_t rc = usb_iface->read(
     566            fun, ep, setup, trans->buffer, size, callback_in, trans);
     567
     568        if (rc != EOK) {
     569                async_answer_0(trans->data_caller, rc);
     570                async_answer_0(callid, rc);
     571                async_transaction_destroy(trans);
     572        }
     573}
     574
     575void remote_usb_write(
     576    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     577{
     578        assert(fun);
     579        assert(iface);
     580        assert(call);
     581
     582        const usb_iface_t *usb_iface = iface;
     583
     584        if (!usb_iface->write) {
     585                async_answer_0(callid, ENOTSUP);
     586                return;
     587        }
     588
     589        const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
     590        const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
     591        const uint64_t setup =
     592            ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
     593            (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
     594
     595        async_transaction_t *trans = async_transaction_create(callid);
     596        if (trans == NULL) {
     597                async_answer_0(callid, ENOMEM);
     598                return;
     599        }
     600
     601        size_t size = 0;
     602        if (data_buffer_len > 0) {
     603                const errno_t rc = async_data_write_accept(&trans->buffer, false,
     604                    1, data_buffer_len, 0, &size);
     605
     606                if (rc != EOK) {
     607                        async_answer_0(callid, rc);
     608                        async_transaction_destroy(trans);
     609                        return;
     610                }
     611        }
     612
     613        const errno_t rc = usb_iface->write(
     614            fun, ep, setup, trans->buffer, size, callback_out, trans);
     615
     616        if (rc != EOK) {
     617                async_answer_0(callid, rc);
     618                async_transaction_destroy(trans);
     619        }
     620}
    129621/**
    130622 * @}
Note: See TracChangeset for help on using the changeset viewer.