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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4b8ecff was 64e1fb2, checked in by Jan Vesely <jano.vesely@…>, 12 years ago

libdrv: Add data communication to usb iface.

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