Ignore:
Timestamp:
2018-02-28T16:37:50Z (6 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
1b20da0
Parents:
f5e5f73 (diff), b2dca8de (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.
git-author:
Jakub Jermar <jakub@…> (2018-02-28 16:06:42)
git-committer:
Jakub Jermar <jakub@…> (2018-02-28 16:37:50)
Message:

Merge github.com:helenos-xhci-team/helenos

This commit merges support for USB 3 and generally refactors, fixes,
extends and cleans up the existing USB framework.

Notable additions and features:

  • new host controller driver has been implemented to control various xHC models (among others, NEC Renesas uPD720200)
  • isochronous data transfer mode
  • support for explicit USB device removal
  • USB tablet driver
File:
1 edited

Legend:

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

    rf5e5f73 rdf6ded8  
    11/*
    2  * Copyright (c) 2010-2011 Vojtech Horky
     2 * Copyright (c) 2010 Vojtech Horky
    33 * Copyright (c) 2011 Jan Vesely
     4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
    45 * All rights reserved.
    56 *
     
    3536
    3637#include <async.h>
     38#include <macros.h>
    3739#include <errno.h>
    38 #include <assert.h>
    39 #include <macros.h>
     40#include <devman.h>
     41#include <as.h>
    4042
    4143#include "usbhc_iface.h"
    4244#include "ddf/driver.h"
    4345
    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  */
     46
    8647typedef enum {
    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,
     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,
    9654} usbhc_iface_funcs_t;
    9755
    98 errno_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)
    101 {
    102         if (!exch)
    103                 return EBADMEM;
    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);
     56/** Reserve default USB address.
     57 * @param[in] exch IPC communication exchange
     58 * @return Error code.
     59 */
     60errno_t usbhc_reserve_default_address(async_exch_t *exch)
     61{
     62        if (!exch)
     63                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 */
     73errno_t usbhc_release_default_address(async_exch_t *exch)
     74{
     75        if (!exch)
     76                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 */
     89errno_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 */
     106errno_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
     114errno_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);
    116125
    117126        if (opening_request == 0) {
     
    119128        }
    120129
    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?
     130        errno_t ret = async_data_write_start(exch, desc, sizeof(*desc));
     131        if (ret != EOK) {
    128132                async_forget(opening_request);
    129                 return ENOMEM;
     133                return ret;
    130134        }
    131135
    132136        /* Wait for the answer. */
    133         errno_t data_request_rc;
    134137        errno_t opening_request_rc;
    135         async_wait_for(data_request, &data_request_rc);
    136138        async_wait_for(opening_request, &opening_request_rc);
    137139
    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) {
     140        if (opening_request_rc)
    147141                return (errno_t) opening_request_rc;
    148         }
    149 
    150         *rec_size = IPC_GET_ARG2(data_request_call);
     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
    151152        return EOK;
    152153}
    153154
    154 errno_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)
    156 {
    157         if (!exch)
    158                 return EBADMEM;
    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);
     155errno_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);
    169162
    170163        if (opening_request == 0) {
     
    172165        }
    173166
    174         /* Send the data if any. */
    175         if (size > 0) {
    176                 const errno_t ret = async_data_write_start(exch, data, size);
     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 */
     184errno_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);
    177213                if (ret != EOK) {
    178214                        async_forget(opening_request);
     
    185221        async_wait_for(opening_request, &opening_request_rc);
    186222
     223        if (transferred)
     224                *transferred = IPC_GET_ARG1(call);
     225
    187226        return (errno_t) opening_request_rc;
    188227}
    189228
    190 static void remote_usbhc_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    191 static void remote_usbhc_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    192 
    193 /** Remote USB host controller interface operations. */
    194 static 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,
     229static void remote_usbhc_default_address_reservation(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     230static void remote_usbhc_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     231static void remote_usbhc_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     232static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     233static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     234static void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
     235
     236/** Remote USB interface operations. */
     237static 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,
    197244};
    198245
    199 /** Remote USB host controller interface structure.
     246/** Remote USB interface structure.
    200247 */
    201248const remote_iface_t remote_usbhc_iface = {
    202249        .method_count = ARRAY_SIZE(remote_usbhc_iface_ops),
    203         .methods = remote_usbhc_iface_ops
     250        .methods = remote_usbhc_iface_ops,
    204251};
    205252
    206253typedef struct {
    207254        ipc_callid_t caller;
    208         ipc_callid_t data_caller;
    209         void *buffer;
     255        usbhc_iface_transfer_request_t request;
    210256} async_transaction_t;
    211257
    212 static 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 
    223 static 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 
    237 static 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 
    246 static 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 
    269 void remote_usbhc_read(
    270     ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     258void 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
     274static 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
     290static 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
     305static void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
     306    ipc_callid_t callid, ipc_call_t *call)
    271307{
    272308        assert(fun);
     
    274310        assert(call);
    275311
    276         const usbhc_iface_t *hc_iface = iface;
    277 
    278         if (!hc_iface->read) {
     312        const usbhc_iface_t *usbhc_iface = iface;
     313
     314        if (!usbhc_iface->register_endpoint) {
    279315                async_answer_0(callid, ENOTSUP);
    280316                return;
    281317        }
    282318
    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);
     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
     342static void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
     343    ipc_callid_t callid, ipc_call_t *call)
     344{
     345        assert(fun);
     346        assert(iface);
     347        assert(call);
     348
     349        const usbhc_iface_t *usbhc_iface = iface;
     350
     351        if (!usbhc_iface->unregister_endpoint) {
     352                async_answer_0(callid, ENOTSUP);
     353                return;
     354        }
     355
     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
     371static 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
     383static 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
     393static 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
     401static 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
     447void 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        }
    287459
    288460        async_transaction_t *trans = async_transaction_create(callid);
     
    292464        }
    293465
    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 
    318 void remote_usbhc_write(
    319     ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
    320 {
    321         assert(fun);
    322         assert(iface);
    323         assert(call);
    324 
    325         const usbhc_iface_t *hc_iface = iface;
    326 
    327         if (!hc_iface->write) {
    328                 async_answer_0(callid, ENOTSUP);
    329                 return;
    330         }
    331 
    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);
    337 
    338         async_transaction_t *trans = async_transaction_create(callid);
    339         if (trans == NULL) {
    340                 async_answer_0(callid, ENOMEM);
    341                 return;
    342         }
    343 
    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 }
     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
     495err:
     496        async_answer_0(callid, err);
     497        async_transaction_destroy(trans);
     498}
     499
    365500/**
    366501 * @}
Note: See TracChangeset for help on using the changeset viewer.