Changeset b4b534ac in mainline for uspace/lib/drv/generic/remote_usb.c


Ignore:
Timestamp:
2016-07-22T08:24:47Z (8 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f76d2c2
Parents:
5b18137 (diff), 8351f9a4 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge from lp:~jan.vesely/helenos/usb

File:
1 edited

Legend:

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

    r5b18137 rb4b534ac  
    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(handle, IPC_FLAG_BLOCKING);
     48}
     49
     50usb_dev_session_t *usb_dev_connect_to_self(ddf_dev_t *dev)
     51{
     52        return devman_parent_device_connect(ddf_dev_get_handle(dev), IPC_FLAG_BLOCKING);
     53}
     54
     55void usb_dev_disconnect(usb_dev_session_t *sess)
     56{
     57        if (sess)
     58                async_hangup(sess);
     59}
     60
    4361typedef enum {
    44         IPC_M_USB_GET_MY_ADDRESS,
    4562        IPC_M_USB_GET_MY_INTERFACE,
    46         IPC_M_USB_GET_HOST_CONTROLLER_HANDLE,
     63        IPC_M_USB_GET_MY_DEVICE_HANDLE,
     64        IPC_M_USB_RESERVE_DEFAULT_ADDRESS,
     65        IPC_M_USB_RELEASE_DEFAULT_ADDRESS,
     66        IPC_M_USB_DEVICE_ENUMERATE,
     67        IPC_M_USB_DEVICE_REMOVE,
     68        IPC_M_USB_REGISTER_ENDPOINT,
     69        IPC_M_USB_UNREGISTER_ENDPOINT,
     70        IPC_M_USB_READ,
     71        IPC_M_USB_WRITE,
    4772} 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 }
    6873
    6974/** Tell interface number given device can use.
     
    8590}
    8691
    87 /** Tell devman handle of device host controller.
     92/** Tell devman handle of the usb device function.
    8893 * @param[in] exch IPC communication exchange
    89  * @param[out] hc_handle devman handle of the HC used by the target device.
     94 * @param[out] handle devman handle of the HC used by the target device.
    9095 * @return Error code.
    9196 */
    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;
     97int usb_get_my_device_handle(async_exch_t *exch, devman_handle_t *handle)
     98{
     99        devman_handle_t h = 0;
    97100        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;
     101            IPC_M_USB_GET_MY_DEVICE_HANDLE, &h);
     102        if (ret == EOK && handle)
     103                *handle = (devman_handle_t)h;
    101104        return ret;
    102105}
    103106
    104 
    105 static void remote_usb_get_my_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     107/** Reserve default USB address.
     108 * @param[in] exch IPC communication exchange
     109 * @param[in] speed Communication speed of the newly attached device
     110 * @return Error code.
     111 */
     112int usb_reserve_default_address(async_exch_t *exch, usb_speed_t speed)
     113{
     114        if (!exch)
     115                return EBADMEM;
     116        return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     117            IPC_M_USB_RESERVE_DEFAULT_ADDRESS, speed);
     118}
     119
     120/** Release default USB address.
     121 * @param[in] exch IPC communication exchange
     122 * @return Error code.
     123 */
     124int usb_release_default_address(async_exch_t *exch)
     125{
     126        if (!exch)
     127                return EBADMEM;
     128        return async_req_1_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     129            IPC_M_USB_RELEASE_DEFAULT_ADDRESS);
     130}
     131
     132/** Trigger USB device enumeration
     133 * @param[in] exch IPC communication exchange
     134 * @param[out] handle Identifier of the newly added device (if successful)
     135 * @return Error code.
     136 */
     137int usb_device_enumerate(async_exch_t *exch, unsigned port)
     138{
     139        if (!exch)
     140                return EBADMEM;
     141        const int ret = async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     142            IPC_M_USB_DEVICE_ENUMERATE, port);
     143        return ret;
     144}
     145
     146/** Trigger USB device enumeration
     147 * @param[in] exch IPC communication exchange
     148 * @param[in] handle Identifier of the device
     149 * @return Error code.
     150 */
     151int usb_device_remove(async_exch_t *exch, unsigned port)
     152{
     153        if (!exch)
     154                return EBADMEM;
     155        return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     156            IPC_M_USB_DEVICE_REMOVE, port);
     157}
     158
     159int static_assert[sizeof(sysarg_t) >= 4 ? 1 : -1];
     160typedef union {
     161        uint8_t arr[sizeof(sysarg_t)];
     162        sysarg_t arg;
     163} pack8_t;
     164
     165int usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
     166    usb_transfer_type_t type, usb_direction_t direction,
     167    size_t mps, unsigned packets, unsigned interval)
     168{
     169        if (!exch)
     170                return EBADMEM;
     171        pack8_t pack;
     172        pack.arr[0] = type;
     173        pack.arr[1] = direction;
     174        pack.arr[2] = interval;
     175        pack.arr[3] = packets;
     176
     177        return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     178            IPC_M_USB_REGISTER_ENDPOINT, endpoint, pack.arg, mps);
     179
     180}
     181
     182int usb_unregister_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
     183    usb_direction_t direction)
     184{
     185        if (!exch)
     186                return EBADMEM;
     187        return async_req_3_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     188            IPC_M_USB_UNREGISTER_ENDPOINT, endpoint, direction);
     189}
     190
     191int usb_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
     192    void *data, size_t size, size_t *rec_size)
     193{
     194        if (!exch)
     195                return EBADMEM;
     196
     197        if (size == 0 && setup == 0)
     198                return EOK;
     199
     200        /* Make call identifying target USB device and type of transfer. */
     201        aid_t opening_request = async_send_4(exch,
     202            DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_READ, endpoint,
     203            (setup & UINT32_MAX), (setup >> 32), NULL);
     204
     205        if (opening_request == 0) {
     206                return ENOMEM;
     207        }
     208
     209        /* Retrieve the data. */
     210        ipc_call_t data_request_call;
     211        aid_t data_request =
     212            async_data_read(exch, data, size, &data_request_call);
     213
     214        if (data_request == 0) {
     215                // FIXME: How to let the other side know that we want to abort?
     216                async_forget(opening_request);
     217                return ENOMEM;
     218        }
     219
     220        /* Wait for the answer. */
     221        sysarg_t data_request_rc;
     222        sysarg_t opening_request_rc;
     223        async_wait_for(data_request, &data_request_rc);
     224        async_wait_for(opening_request, &opening_request_rc);
     225
     226        if (data_request_rc != EOK) {
     227                /* Prefer the return code of the opening request. */
     228                if (opening_request_rc != EOK) {
     229                        return (int) opening_request_rc;
     230                } else {
     231                        return (int) data_request_rc;
     232                }
     233        }
     234        if (opening_request_rc != EOK) {
     235                return (int) opening_request_rc;
     236        }
     237
     238        *rec_size = IPC_GET_ARG2(data_request_call);
     239        return EOK;
     240}
     241
     242int usb_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
     243    const void *data, size_t size)
     244{
     245        if (!exch)
     246                return EBADMEM;
     247
     248        if (size == 0 && setup == 0)
     249                return EOK;
     250
     251        aid_t opening_request = async_send_5(exch,
     252            DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size,
     253            (setup & UINT32_MAX), (setup >> 32), NULL);
     254
     255        if (opening_request == 0) {
     256                return ENOMEM;
     257        }
     258
     259        /* Send the data if any. */
     260        if (size > 0) {
     261                const int ret = async_data_write_start(exch, data, size);
     262                if (ret != EOK) {
     263                        async_forget(opening_request);
     264                        return ret;
     265                }
     266        }
     267
     268        /* Wait for the answer. */
     269        sysarg_t opening_request_rc;
     270        async_wait_for(opening_request, &opening_request_rc);
     271
     272        return (int) opening_request_rc;
     273}
     274
    106275static 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 *);
     276static void remote_usb_get_my_device_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     277static void remote_usb_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     278static void remote_usb_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     279static void remote_usb_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     280static void remote_usb_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     281static void remote_usb_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     282static void remote_usb_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     283static void remote_usb_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
     284static void remote_usb_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
    108285
    109286/** Remote USB interface operations. */
    110287static const remote_iface_func_ptr_t remote_usb_iface_ops [] = {
    111         [IPC_M_USB_GET_MY_ADDRESS] = remote_usb_get_my_address,
    112288        [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface,
    113         [IPC_M_USB_GET_HOST_CONTROLLER_HANDLE] = remote_usb_get_hc_handle,
     289        [IPC_M_USB_GET_MY_DEVICE_HANDLE] = remote_usb_get_my_device_handle,
     290        [IPC_M_USB_RESERVE_DEFAULT_ADDRESS] = remote_usb_reserve_default_address,
     291        [IPC_M_USB_RELEASE_DEFAULT_ADDRESS] = remote_usb_release_default_address,
     292        [IPC_M_USB_DEVICE_ENUMERATE] = remote_usb_device_enumerate,
     293        [IPC_M_USB_DEVICE_REMOVE] = remote_usb_device_remove,
     294        [IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint,
     295        [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint,
     296        [IPC_M_USB_READ] = remote_usb_read,
     297        [IPC_M_USB_WRITE] = remote_usb_write,
    114298};
    115299
     
    118302const remote_iface_t remote_usb_iface = {
    119303        .method_count = ARRAY_SIZE(remote_usb_iface_ops),
    120         .methods = remote_usb_iface_ops
     304        .methods = remote_usb_iface_ops,
    121305};
    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 }
    142306
    143307void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface,
     
    160324}
    161325
    162 void remote_usb_get_hc_handle(ddf_fun_t *fun, void *iface,
     326void remote_usb_get_my_device_handle(ddf_fun_t *fun, void *iface,
    163327    ipc_callid_t callid, ipc_call_t *call)
    164328{
    165329        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
    166330
    167         if (usb_iface->get_hc_handle == NULL) {
     331        if (usb_iface->get_my_device_handle == NULL) {
    168332                async_answer_0(callid, ENOTSUP);
    169333                return;
     
    171335
    172336        devman_handle_t handle;
    173         const int ret = usb_iface->get_hc_handle(fun, &handle);
     337        const int ret = usb_iface->get_my_device_handle(fun, &handle);
    174338        if (ret != EOK) {
    175339                async_answer_0(callid, ret);
     
    178342        async_answer_1(callid, EOK, (sysarg_t) handle);
    179343}
     344
     345void remote_usb_reserve_default_address(ddf_fun_t *fun, void *iface,
     346    ipc_callid_t callid, ipc_call_t *call)
     347{
     348        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     349
     350        if (usb_iface->reserve_default_address == NULL) {
     351                async_answer_0(callid, ENOTSUP);
     352                return;
     353        }
     354
     355        usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
     356        const int ret = usb_iface->reserve_default_address(fun, speed);
     357        async_answer_0(callid, ret);
     358}
     359
     360void remote_usb_release_default_address(ddf_fun_t *fun, void *iface,
     361    ipc_callid_t callid, ipc_call_t *call)
     362{
     363        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     364
     365        if (usb_iface->release_default_address == NULL) {
     366                async_answer_0(callid, ENOTSUP);
     367                return;
     368        }
     369
     370        const int ret = usb_iface->release_default_address(fun);
     371        async_answer_0(callid, ret);
     372}
     373
     374static void remote_usb_device_enumerate(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->device_enumerate == NULL) {
     380                async_answer_0(callid, ENOTSUP);
     381                return;
     382        }
     383
     384        const unsigned port = DEV_IPC_GET_ARG1(*call);
     385        const int ret = usb_iface->device_enumerate(fun, port);
     386        async_answer_0(callid, ret);
     387}
     388
     389static void remote_usb_device_remove(ddf_fun_t *fun, void *iface,
     390    ipc_callid_t callid, ipc_call_t *call)
     391{
     392        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     393
     394        if (usb_iface->device_remove == NULL) {
     395                async_answer_0(callid, ENOTSUP);
     396                return;
     397        }
     398
     399        const unsigned port = DEV_IPC_GET_ARG1(*call);
     400        const int ret = usb_iface->device_remove(fun, port);
     401        async_answer_0(callid, ret);
     402}
     403
     404static void remote_usb_register_endpoint(ddf_fun_t *fun, void *iface,
     405    ipc_callid_t callid, ipc_call_t *call)
     406{
     407        usb_iface_t *usb_iface = (usb_iface_t *) iface;
     408
     409        if (!usb_iface->register_endpoint) {
     410                async_answer_0(callid, ENOTSUP);
     411                return;
     412        }
     413
     414        const usb_endpoint_t endpoint = DEV_IPC_GET_ARG1(*call);
     415        const pack8_t pack = { .arg = DEV_IPC_GET_ARG2(*call)};
     416        const size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
     417
     418        const usb_transfer_type_t transfer_type = pack.arr[0];
     419        const usb_direction_t direction = pack.arr[1];
     420        unsigned packets = pack.arr[2];
     421        unsigned interval = pack.arr[3];
     422
     423        const int ret = usb_iface->register_endpoint(fun, endpoint,
     424            transfer_type, direction, max_packet_size, packets, interval);
     425
     426        async_answer_0(callid, ret);
     427}
     428
     429static void remote_usb_unregister_endpoint(ddf_fun_t *fun, void *iface,
     430    ipc_callid_t callid, ipc_call_t *call)
     431{
     432        usb_iface_t *usb_iface = (usb_iface_t *) iface;
     433
     434        if (!usb_iface->unregister_endpoint) {
     435                async_answer_0(callid, ENOTSUP);
     436                return;
     437        }
     438
     439        usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG1(*call);
     440        usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG2(*call);
     441
     442        int rc = usb_iface->unregister_endpoint(fun, endpoint, direction);
     443
     444        async_answer_0(callid, rc);
     445}
     446
     447typedef struct {
     448        ipc_callid_t caller;
     449        ipc_callid_t data_caller;
     450        void *buffer;
     451} async_transaction_t;
     452
     453static void async_transaction_destroy(async_transaction_t *trans)
     454{
     455        if (trans == NULL) {
     456                return;
     457        }
     458        if (trans->buffer != NULL) {
     459                free(trans->buffer);
     460        }
     461
     462        free(trans);
     463}
     464
     465static async_transaction_t *async_transaction_create(ipc_callid_t caller)
     466{
     467        async_transaction_t *trans = malloc(sizeof(async_transaction_t));
     468        if (trans == NULL) {
     469                return NULL;
     470        }
     471
     472        trans->caller = caller;
     473        trans->data_caller = 0;
     474        trans->buffer = NULL;
     475
     476        return trans;
     477}
     478
     479static void callback_out(int outcome, void *arg)
     480{
     481        async_transaction_t *trans = arg;
     482
     483        async_answer_0(trans->caller, outcome);
     484
     485        async_transaction_destroy(trans);
     486}
     487
     488static void callback_in(int outcome, size_t actual_size, void *arg)
     489{
     490        async_transaction_t *trans = (async_transaction_t *)arg;
     491
     492        if (outcome != EOK) {
     493                async_answer_0(trans->caller, outcome);
     494                if (trans->data_caller) {
     495                        async_answer_0(trans->data_caller, EINTR);
     496                }
     497                async_transaction_destroy(trans);
     498                return;
     499        }
     500
     501        if (trans->data_caller) {
     502                async_data_read_finalize(trans->data_caller,
     503                    trans->buffer, actual_size);
     504        }
     505
     506        async_answer_0(trans->caller, EOK);
     507
     508        async_transaction_destroy(trans);
     509}
     510
     511void remote_usb_read(
     512    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     513{
     514        assert(fun);
     515        assert(iface);
     516        assert(call);
     517
     518        const usb_iface_t *usb_iface = iface;
     519
     520        if (!usb_iface->read) {
     521                async_answer_0(callid, ENOTSUP);
     522                return;
     523        }
     524
     525        const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
     526        const uint64_t setup =
     527            ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
     528            (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
     529
     530        async_transaction_t *trans = async_transaction_create(callid);
     531        if (trans == NULL) {
     532                async_answer_0(callid, ENOMEM);
     533                return;
     534        }
     535
     536        size_t size = 0;
     537        if (!async_data_read_receive(&trans->data_caller, &size)) {
     538                async_answer_0(callid, EPARTY);
     539                return;
     540        }
     541
     542        trans->buffer = malloc(size);
     543        if (trans->buffer == NULL) {
     544                async_answer_0(trans->data_caller, ENOMEM);
     545                async_answer_0(callid, ENOMEM);
     546                async_transaction_destroy(trans);
     547        }
     548
     549        const int rc = usb_iface->read(
     550            fun, ep, setup, trans->buffer, size, callback_in, trans);
     551
     552        if (rc != EOK) {
     553                async_answer_0(trans->data_caller, rc);
     554                async_answer_0(callid, rc);
     555                async_transaction_destroy(trans);
     556        }
     557}
     558
     559void remote_usb_write(
     560    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     561{
     562        assert(fun);
     563        assert(iface);
     564        assert(call);
     565
     566        const usb_iface_t *usb_iface = iface;
     567
     568        if (!usb_iface->write) {
     569                async_answer_0(callid, ENOTSUP);
     570                return;
     571        }
     572
     573        const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
     574        const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
     575        const uint64_t setup =
     576            ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
     577            (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
     578
     579        async_transaction_t *trans = async_transaction_create(callid);
     580        if (trans == NULL) {
     581                async_answer_0(callid, ENOMEM);
     582                return;
     583        }
     584
     585        size_t size = 0;
     586        if (data_buffer_len > 0) {
     587                const int rc = async_data_write_accept(&trans->buffer, false,
     588                    1, data_buffer_len, 0, &size);
     589
     590                if (rc != EOK) {
     591                        async_answer_0(callid, rc);
     592                        async_transaction_destroy(trans);
     593                        return;
     594                }
     595        }
     596
     597        const int rc = usb_iface->write(
     598            fun, ep, setup, trans->buffer, size, callback_out, trans);
     599
     600        if (rc != EOK) {
     601                async_answer_0(callid, rc);
     602                async_transaction_destroy(trans);
     603        }
     604}
    180605/**
    181606 * @}
Note: See TracChangeset for help on using the changeset viewer.