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

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