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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 90c340fb 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
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 <assert.h>
38#include <macros.h>
39#include <errno.h>
40#include <devman.h>
41
42#include "usb_iface.h"
43#include "ddf/driver.h"
44
45
46usb_dev_session_t *usb_dev_connect(devman_handle_t handle)
47{
48 return devman_device_connect(handle, IPC_FLAG_BLOCKING);
49}
50
51usb_dev_session_t *usb_dev_connect_to_self(ddf_dev_t *dev)
52{
53 return devman_parent_device_connect(ddf_dev_get_handle(dev), IPC_FLAG_BLOCKING);
54}
55
56void usb_dev_disconnect(usb_dev_session_t *sess)
57{
58 if (sess)
59 async_hangup(sess);
60}
61
62typedef enum {
63 IPC_M_USB_GET_MY_INTERFACE,
64 IPC_M_USB_GET_MY_DEVICE_HANDLE,
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,
69 IPC_M_USB_REGISTER_ENDPOINT,
70 IPC_M_USB_UNREGISTER_ENDPOINT,
71 IPC_M_USB_READ,
72 IPC_M_USB_WRITE,
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)
84 return EBADMEM;
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}
92
93/** Tell devman handle of the usb device function.
94 *
95 * @param[in] exch IPC communication exchange
96 * @param[out] handle devman handle of the HC used by the target device.
97 *
98 * @return Error code.
99 *
100 */
101int usb_get_my_device_handle(async_exch_t *exch, devman_handle_t *handle)
102{
103 devman_handle_t h = 0;
104 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
105 IPC_M_USB_GET_MY_DEVICE_HANDLE, &h);
106 if (ret == EOK && handle)
107 *handle = (devman_handle_t)h;
108 return ret;
109}
110
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)
117{
118 if (!exch)
119 return EBADMEM;
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.
125 *
126 * @param[in] exch IPC communication exchange
127 *
128 * @return Error code.
129 *
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
140 *
141 * @param[in] exch IPC communication exchange
142 * @param[out] handle Identifier of the newly added device (if successful)
143 *
144 * @return Error code.
145 *
146 */
147int usb_device_enumerate(async_exch_t *exch, unsigned port)
148{
149 if (!exch)
150 return EBADMEM;
151 const int ret = async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
152 IPC_M_USB_DEVICE_ENUMERATE, port);
153 return ret;
154}
155
156/** Trigger USB device enumeration
157 *
158 * @param[in] exch IPC communication exchange
159 * @param[in] handle Identifier of the device
160 *
161 * @return Error code.
162 *
163 */
164int usb_device_remove(async_exch_t *exch, unsigned port)
165{
166 if (!exch)
167 return EBADMEM;
168 return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
169 IPC_M_USB_DEVICE_REMOVE, port);
170}
171
172static_assert(sizeof(sysarg_t) >= 4);
173
174typedef union {
175 uint8_t arr[sizeof(sysarg_t)];
176 sysarg_t arg;
177} pack8_t;
178
179int usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
180 usb_transfer_type_t type, usb_direction_t direction,
181 size_t mps, unsigned packets, unsigned interval)
182{
183 if (!exch)
184 return EBADMEM;
185 pack8_t pack;
186 pack.arr[0] = type;
187 pack.arr[1] = direction;
188 pack.arr[2] = interval;
189 pack.arr[3] = packets;
190
191 return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
192 IPC_M_USB_REGISTER_ENDPOINT, endpoint, pack.arg, mps);
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
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}
288
289static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
290static void remote_usb_get_my_device_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
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 *);
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 *);
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);
299
300/** Remote USB interface operations. */
301static const remote_iface_func_ptr_t remote_usb_iface_ops [] = {
302 [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface,
303 [IPC_M_USB_GET_MY_DEVICE_HANDLE] = remote_usb_get_my_device_handle,
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,
308 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint,
309 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint,
310 [IPC_M_USB_READ] = remote_usb_read,
311 [IPC_M_USB_WRITE] = remote_usb_write,
312};
313
314/** Remote USB interface structure.
315 */
316const remote_iface_t remote_usb_iface = {
317 .method_count = ARRAY_SIZE(remote_usb_iface_ops),
318 .methods = remote_usb_iface_ops,
319};
320
321void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface,
322 ipc_callid_t callid, ipc_call_t *call)
323{
324 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
325
326 if (usb_iface->get_my_interface == NULL) {
327 async_answer_0(callid, ENOTSUP);
328 return;
329 }
330
331 int iface_no;
332 const int ret = usb_iface->get_my_interface(fun, &iface_no);
333 if (ret != EOK) {
334 async_answer_0(callid, ret);
335 } else {
336 async_answer_1(callid, EOK, iface_no);
337 }
338}
339
340void remote_usb_get_my_device_handle(ddf_fun_t *fun, void *iface,
341 ipc_callid_t callid, ipc_call_t *call)
342{
343 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
344
345 if (usb_iface->get_my_device_handle == NULL) {
346 async_answer_0(callid, ENOTSUP);
347 return;
348 }
349
350 devman_handle_t handle;
351 const int ret = usb_iface->get_my_device_handle(fun, &handle);
352 if (ret != EOK) {
353 async_answer_0(callid, ret);
354 }
355
356 async_answer_1(callid, EOK, (sysarg_t) handle);
357}
358
359void remote_usb_reserve_default_address(ddf_fun_t *fun, void *iface,
360 ipc_callid_t callid, ipc_call_t *call)
361{
362 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
363
364 if (usb_iface->reserve_default_address == NULL) {
365 async_answer_0(callid, ENOTSUP);
366 return;
367 }
368
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;
382 }
383
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
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);
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
413 const unsigned port = DEV_IPC_GET_ARG1(*call);
414 const int ret = usb_iface->device_remove(fun, port);
415 async_answer_0(callid, ret);
416}
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);
429 const pack8_t pack = { .arg = DEV_IPC_GET_ARG2(*call)};
430 const size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
431
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];
436
437 const int ret = usb_iface->register_endpoint(fun, endpoint,
438 transfer_type, direction, max_packet_size, packets, interval);
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}
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);
553 async_transaction_destroy(trans);
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);
562 return;
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 }
620}
621/**
622 * @}
623 */
Note: See TracBrowser for help on using the repository browser.