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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since cde999a was 25a179e, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

IPC return values are always errno constants. Adjust types to reflect that.

In principle, IPC server is not allowed to return non-errno values via
the "main" return value, because kernel interprets it (e.g. EHANGUP).
It's still possible to return arbitrary additional return values alongside EOK,
which are not interpreted in normal communication.

  • Property mode set to 100644
File size: 16.2 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. */
[25a179e]235 int data_request_rc;
236 int opening_request_rc;
[64e1fb2]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. */
[25a179e]283 int opening_request_rc;
[64e1fb2]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.