source: mainline/uspace/lib/drv/generic/remote_usb.c@ d4a829e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d4a829e was 90c340fb, checked in by jzr <zarevucky.jiri@…>, 8 years ago

Convert two "old style" static asserts.

  • Property mode set to 100644
File size: 16.3 KB
RevLine 
[56fb3732]1/*
2 * Copyright (c) 2010 Vojtech Horky
[56bdd9a4]3 * Copyright (c) 2011 Jan Vesely
[56fb3732]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libdrv
31 * @{
32 */
33/** @file
34 */
35
36#include <async.h>
[90c340fb]37#include <assert.h>
[9be30cdf]38#include <macros.h>
[56fb3732]39#include <errno.h>
[e938fa6]40#include <devman.h>
[56fb3732]41
42#include "usb_iface.h"
[eb1a2f4]43#include "ddf/driver.h"
[56fb3732]44
[56bdd9a4]45
[94fbf78]46usb_dev_session_t *usb_dev_connect(devman_handle_t handle)
[56bdd9a4]47{
[b4b534ac]48 return devman_device_connect(handle, IPC_FLAG_BLOCKING);
[94fbf78]49}
[56bdd9a4]50
[94fbf78]51usb_dev_session_t *usb_dev_connect_to_self(ddf_dev_t *dev)
[e938fa6]52{
[b4b534ac]53 return devman_parent_device_connect(ddf_dev_get_handle(dev), IPC_FLAG_BLOCKING);
[e938fa6]54}
55
[71384bd3]56void usb_dev_disconnect(usb_dev_session_t *sess)
[e938fa6]57{
58 if (sess)
59 async_hangup(sess);
[56bdd9a4]60}
[a76b01b4]61
[56bdd9a4]62typedef enum {
63 IPC_M_USB_GET_MY_INTERFACE,
[3121b5f]64 IPC_M_USB_GET_MY_DEVICE_HANDLE,
[e938fa6]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,
[70a422b]69 IPC_M_USB_REGISTER_ENDPOINT,
70 IPC_M_USB_UNREGISTER_ENDPOINT,
[64e1fb2]71 IPC_M_USB_READ,
72 IPC_M_USB_WRITE,
[56bdd9a4]73} usb_iface_funcs_t;
74
75/** Tell interface number given device can use.
76 * @param[in] exch IPC communication exchange
77 * @param[in] handle Id of the device
78 * @param[out] usb_iface Assigned USB interface
79 * @return Error code.
80 */
81int usb_get_my_interface(async_exch_t *exch, int *usb_iface)
82{
83 if (!exch)
[8afeb04]84 return EBADMEM;
[56bdd9a4]85 sysarg_t iface_no;
86 const int 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;
90 return ret;
91}
[a76b01b4]92
[9d15d1b]93/** Tell devman handle of the usb device function.
[58563585]94 *
95 * @param[in] exch IPC communication exchange
[9d15d1b]96 * @param[out] handle devman handle of the HC used by the target device.
[58563585]97 *
[56bdd9a4]98 * @return Error code.
[58563585]99 *
[56bdd9a4]100 */
[3121b5f]101int usb_get_my_device_handle(async_exch_t *exch, devman_handle_t *handle)
[9d15d1b]102{
103 devman_handle_t h = 0;
104 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
[3121b5f]105 IPC_M_USB_GET_MY_DEVICE_HANDLE, &h);
[9d15d1b]106 if (ret == EOK && handle)
107 *handle = (devman_handle_t)h;
108 return ret;
109}
110
[e938fa6]111/** Reserve default USB address.
112 * @param[in] exch IPC communication exchange
113 * @param[in] speed Communication speed of the newly attached device
114 * @return Error code.
115 */
116int usb_reserve_default_address(async_exch_t *exch, usb_speed_t speed)
[56bdd9a4]117{
118 if (!exch)
[8afeb04]119 return EBADMEM;
[e938fa6]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.
[58563585]125 *
[e938fa6]126 * @param[in] exch IPC communication exchange
[58563585]127 *
[e938fa6]128 * @return Error code.
[58563585]129 *
[e938fa6]130 */
131int 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
[58563585]140 *
141 * @param[in] exch IPC communication exchange
[e938fa6]142 * @param[out] handle Identifier of the newly added device (if successful)
[58563585]143 *
[e938fa6]144 * @return Error code.
[58563585]145 *
[e938fa6]146 */
[0918382f]147int usb_device_enumerate(async_exch_t *exch, unsigned port)
[e938fa6]148{
[0918382f]149 if (!exch)
[e938fa6]150 return EBADMEM;
[0918382f]151 const int ret = async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
152 IPC_M_USB_DEVICE_ENUMERATE, port);
[56bdd9a4]153 return ret;
154}
155
[e938fa6]156/** Trigger USB device enumeration
[58563585]157 *
158 * @param[in] exch IPC communication exchange
[e938fa6]159 * @param[in] handle Identifier of the device
[58563585]160 *
[e938fa6]161 * @return Error code.
[58563585]162 *
[e938fa6]163 */
[0918382f]164int usb_device_remove(async_exch_t *exch, unsigned port)
[e938fa6]165{
166 if (!exch)
167 return EBADMEM;
168 return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
[0918382f]169 IPC_M_USB_DEVICE_REMOVE, port);
[e938fa6]170}
[56fb3732]171
[90c340fb]172static_assert(sizeof(sysarg_t) >= 4);
173
[4e732f1a]174typedef union {
175 uint8_t arr[sizeof(sysarg_t)];
176 sysarg_t arg;
177} pack8_t;
178
[70a422b]179int usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
180 usb_transfer_type_t type, usb_direction_t direction,
[4e732f1a]181 size_t mps, unsigned packets, unsigned interval)
[70a422b]182{
183 if (!exch)
184 return EBADMEM;
[4e732f1a]185 pack8_t pack;
186 pack.arr[0] = type;
187 pack.arr[1] = direction;
188 pack.arr[2] = interval;
189 pack.arr[3] = packets;
[70a422b]190
191 return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
[4e732f1a]192 IPC_M_USB_REGISTER_ENDPOINT, endpoint, pack.arg, mps);
[70a422b]193
194}
195
196int 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
[64e1fb2]205int 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 sysarg_t data_request_rc;
236 sysarg_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 (int) opening_request_rc;
244 } else {
245 return (int) data_request_rc;
246 }
247 }
248 if (opening_request_rc != EOK) {
249 return (int) opening_request_rc;
250 }
251
252 *rec_size = IPC_GET_ARG2(data_request_call);
253 return EOK;
254}
255
256int 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 int 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 sysarg_t opening_request_rc;
284 async_wait_for(opening_request, &opening_request_rc);
285
286 return (int) opening_request_rc;
287}
[56fb3732]288
[317a463]289static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
[3121b5f]290static void remote_usb_get_my_device_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
[e938fa6]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 *);
[70a422b]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 *);
[64e1fb2]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);
[56fb3732]299
300/** Remote USB interface operations. */
[9be30cdf]301static const remote_iface_func_ptr_t remote_usb_iface_ops [] = {
[317a463]302 [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface,
[3121b5f]303 [IPC_M_USB_GET_MY_DEVICE_HANDLE] = remote_usb_get_my_device_handle,
[e938fa6]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,
[70a422b]308 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint,
309 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint,
[64e1fb2]310 [IPC_M_USB_READ] = remote_usb_read,
311 [IPC_M_USB_WRITE] = remote_usb_write,
[56fb3732]312};
313
314/** Remote USB interface structure.
315 */
[7f80313]316const remote_iface_t remote_usb_iface = {
[9be30cdf]317 .method_count = ARRAY_SIZE(remote_usb_iface_ops),
[e938fa6]318 .methods = remote_usb_iface_ops,
[56fb3732]319};
320
[317a463]321void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface,
[357a302]322 ipc_callid_t callid, ipc_call_t *call)
323{
[56bdd9a4]324 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
[357a302]325
[317a463]326 if (usb_iface->get_my_interface == NULL) {
[357a302]327 async_answer_0(callid, ENOTSUP);
328 return;
329 }
330
[95120c3]331 int iface_no;
[56bdd9a4]332 const int ret = usb_iface->get_my_interface(fun, &iface_no);
333 if (ret != EOK) {
334 async_answer_0(callid, ret);
[357a302]335 } else {
[95120c3]336 async_answer_1(callid, EOK, iface_no);
[357a302]337 }
338}
[a76b01b4]339
[3121b5f]340void remote_usb_get_my_device_handle(ddf_fun_t *fun, void *iface,
[95120c3]341 ipc_callid_t callid, ipc_call_t *call)
342{
[56bdd9a4]343 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
[95120c3]344
[3121b5f]345 if (usb_iface->get_my_device_handle == NULL) {
[95120c3]346 async_answer_0(callid, ENOTSUP);
347 return;
348 }
349
[9d15d1b]350 devman_handle_t handle;
[3121b5f]351 const int ret = usb_iface->get_my_device_handle(fun, &handle);
[56bdd9a4]352 if (ret != EOK) {
353 async_answer_0(callid, ret);
[95120c3]354 }
[9d15d1b]355
356 async_answer_1(callid, EOK, (sysarg_t) handle);
[95120c3]357}
[a76b01b4]358
[e938fa6]359void remote_usb_reserve_default_address(ddf_fun_t *fun, void *iface,
[56fb3732]360 ipc_callid_t callid, ipc_call_t *call)
361{
[56bdd9a4]362 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
[56fb3732]363
[e938fa6]364 if (usb_iface->reserve_default_address == NULL) {
[17aca1c]365 async_answer_0(callid, ENOTSUP);
[56fb3732]366 return;
367 }
368
[e938fa6]369 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
370 const int 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;
[56fb3732]382 }
383
[e938fa6]384 const int 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
[0918382f]398 const unsigned port = DEV_IPC_GET_ARG1(*call);
399 const int ret = usb_iface->device_enumerate(fun, port);
400 async_answer_0(callid, ret);
[e938fa6]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
[0918382f]413 const unsigned port = DEV_IPC_GET_ARG1(*call);
414 const int ret = usb_iface->device_remove(fun, port);
[e938fa6]415 async_answer_0(callid, ret);
416}
[70a422b]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);
[4e732f1a]429 const pack8_t pack = { .arg = DEV_IPC_GET_ARG2(*call)};
430 const size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
[70a422b]431
[4e732f1a]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];
[70a422b]436
437 const int ret = usb_iface->register_endpoint(fun, endpoint,
[4e732f1a]438 transfer_type, direction, max_packet_size, packets, interval);
[70a422b]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 int rc = usb_iface->unregister_endpoint(fun, endpoint, direction);
457
458 async_answer_0(callid, rc);
459}
[64e1fb2]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(int 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(int 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);
[1e5d01b]553 async_transaction_destroy(trans);
[64e1fb2]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);
[c7840e9]562 return;
[64e1fb2]563 }
564
565 const int 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 int 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 int 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 }
[56fb3732]620}
621/**
622 * @}
623 */
Note: See TracBrowser for help on using the repository browser.