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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 10cb47e was 58563585, checked in by Martin Decky <martin@…>, 9 years ago

code review and cstyle cleanup (no change in functionality)

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