Ignore:
File:
1 edited

Legend:

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

    r1d758fc rb7fd2a0  
    11/*
    2  * Copyright (c) 2010 Vojtech Horky
     2 * Copyright (c) 2010-2011 Vojtech Horky
    33 * Copyright (c) 2011 Jan Vesely
    4  * Copyright (c) 2017 Ondrej Hlavaty
    54 * All rights reserved.
    65 *
     
    3635
    3736#include <async.h>
     37#include <errno.h>
     38#include <assert.h>
    3839#include <macros.h>
    39 #include <errno.h>
    40 #include <devman.h>
    41 #include <as.h>
    4240
    4341#include "usbhc_iface.h"
    4442#include "ddf/driver.h"
    4543
    46 
     44#define USB_MAX_PAYLOAD_SIZE 1020
     45
     46/** IPC methods for communication with HC through DDF interface.
     47 *
     48 * Notes for async methods:
     49 *
     50 * Methods for sending data to device (OUT transactions)
     51 * - e.g. IPC_M_USBHC_INTERRUPT_OUT -
     52 * always use the same semantics:
     53 * - first, IPC call with given method is made
     54 *   - argument #1 is target address
     55 *   - argument #2 is target endpoint
     56 *   - argument #3 is max packet size of the endpoint
     57 * - this call is immediately followed by IPC data write (from caller)
     58 * - the initial call (and the whole transaction) is answer after the
     59 *   transaction is scheduled by the HC and acknowledged by the device
     60 *   or immediately after error is detected
     61 * - the answer carries only the error code
     62 *
     63 * Methods for retrieving data from device (IN transactions)
     64 * - e.g. IPC_M_USBHC_INTERRUPT_IN -
     65 * also use the same semantics:
     66 * - first, IPC call with given method is made
     67 *   - argument #1 is target address
     68 *   - argument #2 is target endpoint
     69 * - this call is immediately followed by IPC data read (async version)
     70 * - the call is not answered until the device returns some data (or until
     71 *   error occurs)
     72 *
     73 * Some special methods (NO-DATA transactions) do not send any data. These
     74 * might behave as both OUT or IN transactions because communication parts
     75 * where actual buffers are exchanged are omitted.
     76 **
     77 * For all these methods, wrap functions exists. Important rule: functions
     78 * for IN transactions have (as parameters) buffers where retrieved data
     79 * will be stored. These buffers must be already allocated and shall not be
     80 * touch until the transaction is completed
     81 * (e.g. not before calling usb_wait_for() with appropriate handle).
     82 * OUT transactions buffers can be freed immediately after call is dispatched
     83 * (i.e. after return from wrapping function).
     84 *
     85 */
    4786typedef enum {
    48         IPC_M_USB_DEFAULT_ADDRESS_RESERVATION,
    49         IPC_M_USB_DEVICE_ENUMERATE,
    50         IPC_M_USB_DEVICE_REMOVE,
    51         IPC_M_USB_REGISTER_ENDPOINT,
    52         IPC_M_USB_UNREGISTER_ENDPOINT,
    53         IPC_M_USB_TRANSFER,
     87        /** Get data from device.
     88         * See explanation at usb_iface_funcs_t (IN transaction).
     89         */
     90        IPC_M_USBHC_READ,
     91
     92        /** Send data to device.
     93         * See explanation at usb_iface_funcs_t (OUT transaction).
     94         */
     95        IPC_M_USBHC_WRITE,
    5496} usbhc_iface_funcs_t;
    5597
    56 /** Reserve default USB address.
    57  * @param[in] exch IPC communication exchange
    58  * @return Error code.
    59  */
    60 errno_t usbhc_reserve_default_address(async_exch_t *exch)
     98errno_t usbhc_read(async_exch_t *exch, usb_address_t address,
     99    usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size,
     100    size_t *rec_size)
    61101{
    62102        if (!exch)
    63103                return EBADMEM;
    64         return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, true);
    65 }
    66 
    67 /** Release default USB address.
    68  *
    69  * @param[in] exch IPC communication exchange
    70  *
    71  * @return Error code.
    72  */
    73 errno_t usbhc_release_default_address(async_exch_t *exch)
     104
     105        if (size == 0 && setup == 0)
     106                return EOK;
     107
     108        const usb_target_t target =
     109            {{ .address = address, .endpoint = endpoint }};
     110
     111        /* Make call identifying target USB device and type of transfer. */
     112        aid_t opening_request = async_send_4(exch,
     113            DEV_IFACE_ID(USBHC_DEV_IFACE),
     114            IPC_M_USBHC_READ, target.packed,
     115            (setup & UINT32_MAX), (setup >> 32), NULL);
     116
     117        if (opening_request == 0) {
     118                return ENOMEM;
     119        }
     120
     121        /* Retrieve the data. */
     122        ipc_call_t data_request_call;
     123        aid_t data_request =
     124            async_data_read(exch, data, size, &data_request_call);
     125
     126        if (data_request == 0) {
     127                // FIXME: How to let the other side know that we want to abort?
     128                async_forget(opening_request);
     129                return ENOMEM;
     130        }
     131
     132        /* Wait for the answer. */
     133        errno_t data_request_rc;
     134        errno_t opening_request_rc;
     135        async_wait_for(data_request, &data_request_rc);
     136        async_wait_for(opening_request, &opening_request_rc);
     137
     138        if (data_request_rc != EOK) {
     139                /* Prefer the return code of the opening request. */
     140                if (opening_request_rc != EOK) {
     141                        return (errno_t) opening_request_rc;
     142                } else {
     143                        return (errno_t) data_request_rc;
     144                }
     145        }
     146        if (opening_request_rc != EOK) {
     147                return (errno_t) opening_request_rc;
     148        }
     149
     150        *rec_size = IPC_GET_ARG2(data_request_call);
     151        return EOK;
     152}
     153
     154errno_t usbhc_write(async_exch_t *exch, usb_address_t address,
     155    usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size)
    74156{
    75157        if (!exch)
    76158                return EBADMEM;
    77         return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, false);
    78 }
    79 
    80 /**
    81  * Trigger USB device enumeration
    82  *
    83  * @param[in] exch IPC communication exchange
    84  * @param[in] port Port number at which the device is attached
    85  * @param[in] speed Communication speed of the newly attached device
    86  *
    87  * @return Error code.
    88  */
    89 errno_t usbhc_device_enumerate(async_exch_t *exch, unsigned port, usb_speed_t speed)
    90 {
    91         if (!exch)
    92                 return EBADMEM;
    93         const errno_t ret = async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    94             IPC_M_USB_DEVICE_ENUMERATE, port, speed);
    95         return ret;
    96 }
    97 
    98 /** Trigger USB device enumeration
    99  *
    100  * @param[in] exch   IPC communication exchange
    101  * @param[in] handle Identifier of the device
    102  *
    103  * @return Error code.
    104  *
    105  */
    106 errno_t usbhc_device_remove(async_exch_t *exch, unsigned port)
    107 {
    108         if (!exch)
    109                 return EBADMEM;
    110         return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    111             IPC_M_USB_DEVICE_REMOVE, port);
    112 }
    113 
    114 errno_t usbhc_register_endpoint(async_exch_t *exch, usb_pipe_desc_t *pipe_desc,
    115     const usb_endpoint_descriptors_t *desc)
    116 {
    117         if (!exch)
    118                 return EBADMEM;
    119 
    120         if (!desc)
    121                 return EINVAL;
    122 
    123         aid_t opening_request = async_send_1(exch,
    124             DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_REGISTER_ENDPOINT, NULL);
     159
     160        if (size == 0 && setup == 0)
     161                return EOK;
     162
     163        const usb_target_t target =
     164            {{ .address = address, .endpoint = endpoint }};
     165
     166        aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
     167            IPC_M_USBHC_WRITE, target.packed, size,
     168            (setup & UINT32_MAX), (setup >> 32), NULL);
    125169
    126170        if (opening_request == 0) {
     
    128172        }
    129173
    130         errno_t ret = async_data_write_start(exch, desc, sizeof(*desc));
    131         if (ret != EOK) {
    132                 async_forget(opening_request);
    133                 return ret;
    134         }
    135 
    136         /* Wait for the answer. */
    137         errno_t opening_request_rc;
    138         async_wait_for(opening_request, &opening_request_rc);
    139 
    140         if (opening_request_rc)
    141                 return (errno_t) opening_request_rc;
    142 
    143         usb_pipe_desc_t dest;
    144         ret = async_data_read_start(exch, &dest, sizeof(dest));
    145         if (ret != EOK) {
    146                 return ret;
    147         }
    148 
    149         if (pipe_desc)
    150                 *pipe_desc = dest;
    151 
    152         return EOK;
    153 }
    154 
    155 errno_t usbhc_unregister_endpoint(async_exch_t *exch, const usb_pipe_desc_t *pipe_desc)
    156 {
    157         if (!exch)
    158                 return EBADMEM;
    159 
    160         aid_t opening_request = async_send_1(exch,
    161                 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_UNREGISTER_ENDPOINT, NULL);
    162 
    163         if (opening_request == 0) {
    164                 return ENOMEM;
    165         }
    166 
    167         const errno_t ret = async_data_write_start(exch, pipe_desc, sizeof(*pipe_desc));
    168         if (ret != EOK) {
    169                 async_forget(opening_request);
    170                 return ret;
    171         }
    172 
    173         /* Wait for the answer. */
    174         errno_t opening_request_rc;
    175         async_wait_for(opening_request, &opening_request_rc);
    176 
    177         return (errno_t) opening_request_rc;
    178 }
    179 
    180 /**
    181  * Issue a USB transfer with a data contained in memory area. That area is
    182  * temporarily shared with the HC.
    183  */
    184 errno_t usbhc_transfer(async_exch_t *exch,
    185     const usbhc_iface_transfer_request_t *req, size_t *transferred)
    186 {
    187         if (transferred)
    188                 *transferred = 0;
    189 
    190         if (!exch)
    191                 return EBADMEM;
    192 
    193         ipc_call_t call;
    194 
    195         aid_t opening_request = async_send_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    196             IPC_M_USB_TRANSFER, &call);
    197 
    198         if (opening_request == 0)
    199                 return ENOMEM;
    200 
    201         const errno_t ret = async_data_write_start(exch, req, sizeof(*req));
    202         if (ret != EOK) {
    203                 async_forget(opening_request);
    204                 return ret;
    205         }
    206 
    207         /* Share the data, if any. */
    208         if (req->size > 0) {
    209                 unsigned flags = (req->dir == USB_DIRECTION_IN)
    210                         ? AS_AREA_WRITE : AS_AREA_READ;
    211 
    212                 const errno_t ret = async_share_out_start(exch, req->buffer.virt, flags);
     174        /* Send the data if any. */
     175        if (size > 0) {
     176                const errno_t ret = async_data_write_start(exch, data, size);
    213177                if (ret != EOK) {
    214178                        async_forget(opening_request);
     
    221185        async_wait_for(opening_request, &opening_request_rc);
    222186
    223         if (transferred)
    224                 *transferred = IPC_GET_ARG1(call);
    225 
    226187        return (errno_t) opening_request_rc;
    227188}
    228189
    229 static void remote_usbhc_default_address_reservation(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    230 static void remote_usbhc_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    231 static void remote_usbhc_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    232 static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    233 static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    234 static void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
    235 
    236 /** Remote USB interface operations. */
    237 static const remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
    238         [IPC_M_USB_DEFAULT_ADDRESS_RESERVATION] = remote_usbhc_default_address_reservation,
    239         [IPC_M_USB_DEVICE_ENUMERATE] = remote_usbhc_device_enumerate,
    240         [IPC_M_USB_DEVICE_REMOVE] = remote_usbhc_device_remove,
    241         [IPC_M_USB_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
    242         [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint,
    243         [IPC_M_USB_TRANSFER] = remote_usbhc_transfer,
     190static void remote_usbhc_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     191static void remote_usbhc_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     192
     193/** Remote USB host controller interface operations. */
     194static const remote_iface_func_ptr_t remote_usbhc_iface_ops[] = {
     195        [IPC_M_USBHC_READ] = remote_usbhc_read,
     196        [IPC_M_USBHC_WRITE] = remote_usbhc_write,
    244197};
    245198
    246 /** Remote USB interface structure.
     199/** Remote USB host controller interface structure.
    247200 */
    248201const remote_iface_t remote_usbhc_iface = {
    249202        .method_count = ARRAY_SIZE(remote_usbhc_iface_ops),
    250         .methods = remote_usbhc_iface_ops,
     203        .methods = remote_usbhc_iface_ops
    251204};
    252205
    253206typedef struct {
    254207        ipc_callid_t caller;
    255         usbhc_iface_transfer_request_t request;
     208        ipc_callid_t data_caller;
     209        void *buffer;
    256210} async_transaction_t;
    257211
    258 void remote_usbhc_default_address_reservation(ddf_fun_t *fun, void *iface,
    259     ipc_callid_t callid, ipc_call_t *call)
    260 {
    261         const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
    262 
    263         if (usbhc_iface->default_address_reservation == NULL) {
    264                 async_answer_0(callid, ENOTSUP);
    265                 return;
    266         }
    267 
    268         const bool reserve = IPC_GET_ARG2(*call);
    269         const errno_t ret = usbhc_iface->default_address_reservation(fun, reserve);
    270         async_answer_0(callid, ret);
    271 }
    272 
    273 
    274 static void remote_usbhc_device_enumerate(ddf_fun_t *fun, void *iface,
    275     ipc_callid_t callid, ipc_call_t *call)
    276 {
    277         const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
    278 
    279         if (usbhc_iface->device_enumerate == NULL) {
    280                 async_answer_0(callid, ENOTSUP);
    281                 return;
    282         }
    283 
    284         const unsigned port = DEV_IPC_GET_ARG1(*call);
    285         usb_speed_t speed = DEV_IPC_GET_ARG2(*call);
    286         const errno_t ret = usbhc_iface->device_enumerate(fun, port, speed);
    287         async_answer_0(callid, ret);
    288 }
    289 
    290 static void remote_usbhc_device_remove(ddf_fun_t *fun, void *iface,
    291     ipc_callid_t callid, ipc_call_t *call)
    292 {
    293         const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
    294 
    295         if (usbhc_iface->device_remove == NULL) {
    296                 async_answer_0(callid, ENOTSUP);
    297                 return;
    298         }
    299 
    300         const unsigned port = DEV_IPC_GET_ARG1(*call);
    301         const errno_t ret = usbhc_iface->device_remove(fun, port);
    302         async_answer_0(callid, ret);
    303 }
    304 
    305 static void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
    306     ipc_callid_t callid, ipc_call_t *call)
     212static void async_transaction_destroy(async_transaction_t *trans)
     213{
     214        if (trans == NULL)
     215                return;
     216       
     217        if (trans->buffer != NULL)
     218                free(trans->buffer);
     219       
     220        free(trans);
     221}
     222
     223static async_transaction_t *async_transaction_create(ipc_callid_t caller)
     224{
     225        async_transaction_t *trans = malloc(sizeof(async_transaction_t));
     226        if (trans == NULL) {
     227                return NULL;
     228        }
     229
     230        trans->caller = caller;
     231        trans->data_caller = 0;
     232        trans->buffer = NULL;
     233
     234        return trans;
     235}
     236
     237static void callback_out(errno_t outcome, void *arg)
     238{
     239        async_transaction_t *trans = arg;
     240
     241        async_answer_0(trans->caller, outcome);
     242
     243        async_transaction_destroy(trans);
     244}
     245
     246static void callback_in(errno_t outcome, size_t actual_size, void *arg)
     247{
     248        async_transaction_t *trans = (async_transaction_t *)arg;
     249
     250        if (outcome != EOK) {
     251                async_answer_0(trans->caller, outcome);
     252                if (trans->data_caller) {
     253                        async_answer_0(trans->data_caller, EINTR);
     254                }
     255                async_transaction_destroy(trans);
     256                return;
     257        }
     258
     259        if (trans->data_caller) {
     260                async_data_read_finalize(trans->data_caller,
     261                    trans->buffer, actual_size);
     262        }
     263
     264        async_answer_0(trans->caller, EOK);
     265
     266        async_transaction_destroy(trans);
     267}
     268
     269void remote_usbhc_read(
     270    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
    307271{
    308272        assert(fun);
     
    310274        assert(call);
    311275
    312         const usbhc_iface_t *usbhc_iface = iface;
    313 
    314         if (!usbhc_iface->register_endpoint) {
     276        const usbhc_iface_t *hc_iface = iface;
     277
     278        if (!hc_iface->read) {
    315279                async_answer_0(callid, ENOTSUP);
    316280                return;
    317281        }
    318282
    319         usb_endpoint_descriptors_t ep_desc;
    320         ipc_callid_t data_callid;
    321         size_t len;
    322 
    323         if (!async_data_write_receive(&data_callid, &len)
    324             || len != sizeof(ep_desc)) {
    325                 async_answer_0(callid, EINVAL);
    326                 return;
    327         }
    328         async_data_write_finalize(data_callid, &ep_desc, sizeof(ep_desc));
    329 
    330         usb_pipe_desc_t pipe_desc;
    331 
    332         const errno_t rc = usbhc_iface->register_endpoint(fun, &pipe_desc, &ep_desc);
    333         async_answer_0(callid, rc);
    334 
    335         if (!async_data_read_receive(&data_callid, &len)
    336             || len != sizeof(pipe_desc)) {
    337                 return;
    338         }
    339         async_data_read_finalize(data_callid, &pipe_desc, sizeof(pipe_desc));
    340 }
    341 
    342 static void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
    343     ipc_callid_t callid, ipc_call_t *call)
     283        const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
     284        const uint64_t setup =
     285            ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
     286            (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
     287
     288        async_transaction_t *trans = async_transaction_create(callid);
     289        if (trans == NULL) {
     290                async_answer_0(callid, ENOMEM);
     291                return;
     292        }
     293
     294        size_t size = 0;
     295        if (!async_data_read_receive(&trans->data_caller, &size)) {
     296                async_answer_0(callid, EPARTY);
     297                return;
     298        }
     299
     300        trans->buffer = malloc(size);
     301        if (trans->buffer == NULL) {
     302                async_answer_0(trans->data_caller, ENOMEM);
     303                async_answer_0(callid, ENOMEM);
     304                async_transaction_destroy(trans);
     305                return;
     306        }
     307
     308        const errno_t rc = hc_iface->read(
     309            fun, target, setup, trans->buffer, size, callback_in, trans);
     310
     311        if (rc != EOK) {
     312                async_answer_0(trans->data_caller, rc);
     313                async_answer_0(callid, rc);
     314                async_transaction_destroy(trans);
     315        }
     316}
     317
     318void remote_usbhc_write(
     319    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
    344320{
    345321        assert(fun);
     
    347323        assert(call);
    348324
    349         const usbhc_iface_t *usbhc_iface = iface;
    350 
    351         if (!usbhc_iface->unregister_endpoint) {
     325        const usbhc_iface_t *hc_iface = iface;
     326
     327        if (!hc_iface->write) {
    352328                async_answer_0(callid, ENOTSUP);
    353329                return;
    354330        }
    355331
    356         usb_pipe_desc_t pipe_desc;
    357         ipc_callid_t data_callid;
    358         size_t len;
    359 
    360         if (!async_data_write_receive(&data_callid, &len)
    361             || len != sizeof(pipe_desc)) {
    362                 async_answer_0(callid, EINVAL);
    363                 return;
    364         }
    365         async_data_write_finalize(data_callid, &pipe_desc, sizeof(pipe_desc));
    366 
    367         const errno_t rc = usbhc_iface->unregister_endpoint(fun, &pipe_desc);
    368         async_answer_0(callid, rc);
    369 }
    370 
    371 static void async_transaction_destroy(async_transaction_t *trans)
    372 {
    373         if (trans == NULL) {
    374                 return;
    375         }
    376         if (trans->request.buffer.virt != NULL) {
    377                 as_area_destroy(trans->request.buffer.virt);
    378         }
    379 
    380         free(trans);
    381 }
    382 
    383 static async_transaction_t *async_transaction_create(ipc_callid_t caller)
    384 {
    385         async_transaction_t *trans = calloc(1, sizeof(async_transaction_t));
    386 
    387         if (trans != NULL)
    388                 trans->caller = caller;
    389 
    390         return trans;
    391 }
    392 
    393 static errno_t transfer_finished(void *arg, errno_t error, size_t transferred_size)
    394 {
    395         async_transaction_t *trans = arg;
    396         const errno_t err = async_answer_1(trans->caller, error, transferred_size);
    397         async_transaction_destroy(trans);
    398         return err;
    399 }
    400 
    401 static errno_t receive_memory_buffer(async_transaction_t *trans)
    402 {
    403         assert(trans);
    404         assert(trans->request.size > 0);
    405 
    406         const size_t required_size = trans->request.offset + trans->request.size;
    407         const unsigned required_flags =
    408                 (trans->request.dir == USB_DIRECTION_IN)
    409                 ? AS_AREA_WRITE : AS_AREA_READ;
    410 
    411         errno_t err;
    412         ipc_callid_t data_callid;
    413         size_t size;
    414         unsigned flags;
    415 
    416         if (!async_share_out_receive(&data_callid, &size, &flags))
    417                 return EPARTY;
    418 
    419         if (size < required_size || (flags & required_flags) != required_flags) {
    420                 async_answer_0(data_callid, EINVAL);
    421                 return EINVAL;
    422         }
    423 
    424         if ((err = async_share_out_finalize(data_callid, &trans->request.buffer.virt)))
    425                 return err;
    426 
    427         /*
    428          * As we're going to get physical addresses of the mapping, we must make
    429          * sure the memory is actually mapped. We must do it right now, because
    430          * the area might be read-only or write-only, and we may be unsure
    431          * later.
    432          */
    433         if (flags & AS_AREA_READ) {
    434                 char foo = 0;
    435                 volatile const char *buf = trans->request.buffer.virt + trans->request.offset;
    436                 for (size_t i = 0; i < size; i += PAGE_SIZE)
    437                         foo += buf[i];
    438         } else {
    439                 volatile char *buf = trans->request.buffer.virt + trans->request.offset;
    440                 for (size_t i = 0; i < size; i += PAGE_SIZE)
    441                         buf[i] = 0xff;
    442         }
    443 
    444         return EOK;
    445 }
    446 
    447 void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
    448 {
    449         assert(fun);
    450         assert(iface);
    451         assert(call);
    452 
    453         const usbhc_iface_t *usbhc_iface = iface;
    454 
    455         if (!usbhc_iface->transfer) {
    456                 async_answer_0(callid, ENOTSUP);
    457                 return;
    458         }
     332        const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
     333        const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
     334        const uint64_t setup =
     335            ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
     336            (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
    459337
    460338        async_transaction_t *trans = async_transaction_create(callid);
     
    464342        }
    465343
    466         errno_t err = EPARTY;
    467 
    468         ipc_callid_t data_callid;
    469         size_t len;
    470         if (!async_data_write_receive(&data_callid, &len)
    471             || len != sizeof(trans->request)) {
    472                 async_answer_0(data_callid, EINVAL);
    473                 goto err;
    474         }
    475 
    476         if ((err = async_data_write_finalize(data_callid,
    477                             &trans->request, sizeof(trans->request))))
    478                 goto err;
    479 
    480         if (trans->request.size > 0) {
    481                 if ((err = receive_memory_buffer(trans)))
    482                         goto err;
    483         } else {
    484                 /* The value was valid on the other side, for us, its garbage. */
    485                 trans->request.buffer.virt = NULL;
    486         }
    487 
    488         if ((err = usbhc_iface->transfer(fun, &trans->request,
    489             &transfer_finished, trans)))
    490                 goto err;
    491 
    492         /* The call will be answered asynchronously by the callback. */
    493         return;
    494 
    495 err:
    496         async_answer_0(callid, err);
    497         async_transaction_destroy(trans);
    498 }
    499 
     344        size_t size = 0;
     345        if (data_buffer_len > 0) {
     346                const errno_t rc = async_data_write_accept(&trans->buffer, false,
     347                    1, USB_MAX_PAYLOAD_SIZE,
     348                    0, &size);
     349
     350                if (rc != EOK) {
     351                        async_answer_0(callid, rc);
     352                        async_transaction_destroy(trans);
     353                        return;
     354                }
     355        }
     356
     357        const errno_t rc = hc_iface->write(
     358            fun, target, setup, trans->buffer, size, callback_out, trans);
     359
     360        if (rc != EOK) {
     361                async_answer_0(callid, rc);
     362                async_transaction_destroy(trans);
     363        }
     364}
    500365/**
    501366 * @}
Note: See TracChangeset for help on using the changeset viewer.