source: mainline/uspace/lib/drv/generic/remote_usbhc.c@ 4603b35

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4603b35 was 4603b35, checked in by Ondřej Hlavatý <aearsis@…>, 7 years ago

libdrv: merged usbhc default address reservation operations

  • Property mode set to 100644
File size: 14.4 KB
RevLine 
[41df71f9]1/*
2 * Copyright (c) 2010 Vojtech Horky
3 * Copyright (c) 2011 Jan Vesely
4 * Copyright (c) 2017 Ondrej Hlavaty
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/** @addtogroup libdrv
32 * @{
33 */
34/** @file
35 */
36
37#include <async.h>
38#include <macros.h>
39#include <errno.h>
40#include <devman.h>
41
42#include "usbhc_iface.h"
43#include "ddf/driver.h"
44
45
46typedef enum {
[4603b35]47 IPC_M_USB_DEFAULT_ADDRESS_RESERVATION,
[41df71f9]48 IPC_M_USB_DEVICE_ENUMERATE,
49 IPC_M_USB_DEVICE_REMOVE,
50 IPC_M_USB_REGISTER_ENDPOINT,
51 IPC_M_USB_UNREGISTER_ENDPOINT,
52 IPC_M_USB_READ,
53 IPC_M_USB_WRITE,
54} usbhc_iface_funcs_t;
55
56/** Reserve default USB address.
57 * @param[in] exch IPC communication exchange
58 * @return Error code.
59 */
[eeca8a6]60int usbhc_reserve_default_address(async_exch_t *exch)
[41df71f9]61{
62 if (!exch)
63 return EBADMEM;
[4603b35]64 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, true);
[41df71f9]65}
66
67/** Release default USB address.
68 *
69 * @param[in] exch IPC communication exchange
70 *
71 * @return Error code.
72 */
73int usbhc_release_default_address(async_exch_t *exch)
74{
75 if (!exch)
76 return EBADMEM;
[4603b35]77 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, false);
[41df71f9]78}
79
[eeca8a6]80/**
81 * Trigger USB device enumeration
[41df71f9]82 *
[eeca8a6]83 * @param[in] exch IPC communication exchange
84 * @param[in] port Port number at which the device is attached
85 * @param[in] speed Communication speed of the newly attached device
[41df71f9]86 *
87 * @return Error code.
88 */
[eeca8a6]89int usbhc_device_enumerate(async_exch_t *exch, unsigned port, usb_speed_t speed)
[41df71f9]90{
91 if (!exch)
92 return EBADMEM;
[eeca8a6]93 const int ret = async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
94 IPC_M_USB_DEVICE_ENUMERATE, port, speed);
[41df71f9]95 return ret;
96}
97
98/** Trigger USB device enumeration
99 *
100 * @param[in] exch IPC communication exchange
101 * @param[in] handle Identifier of the device
102 *
103 * @return Error code.
104 *
105 */
106int usbhc_device_remove(async_exch_t *exch, unsigned port)
107{
108 if (!exch)
109 return EBADMEM;
110 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
111 IPC_M_USB_DEVICE_REMOVE, port);
112}
113
[9efad54]114int usbhc_register_endpoint(async_exch_t *exch, usb_pipe_desc_t *pipe_desc,
115 const usb_endpoint_descriptors_t *desc)
[41df71f9]116{
117 if (!exch)
118 return EBADMEM;
119
[9efad54]120 if (!desc)
121 return EINVAL;
122
[41df71f9]123 aid_t opening_request = async_send_1(exch,
124 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_REGISTER_ENDPOINT, NULL);
125
126 if (opening_request == 0) {
127 return ENOMEM;
128 }
129
[9efad54]130 int ret = async_data_write_start(exch, desc, sizeof(*desc));
[41df71f9]131 if (ret != EOK) {
132 async_forget(opening_request);
133 return ret;
134 }
135
136 /* Wait for the answer. */
137 sysarg_t opening_request_rc;
138 async_wait_for(opening_request, &opening_request_rc);
139
[9efad54]140 if (opening_request_rc)
141 return (int) opening_request_rc;
142
143 usb_pipe_desc_t dest;
144 ret = async_data_read_start(exch, &dest, sizeof(dest));
145 if (ret != EOK) {
146 return ret;
147 }
148
149 if (pipe_desc)
150 *pipe_desc = dest;
151
152 return EOK;
[41df71f9]153}
154
[9efad54]155int usbhc_unregister_endpoint(async_exch_t *exch, const usb_pipe_desc_t *pipe_desc)
[41df71f9]156{
157 if (!exch)
158 return EBADMEM;
159
160 aid_t opening_request = async_send_1(exch,
161 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_UNREGISTER_ENDPOINT, NULL);
162
163 if (opening_request == 0) {
164 return ENOMEM;
165 }
166
[9efad54]167 const int ret = async_data_write_start(exch, pipe_desc, sizeof(*pipe_desc));
[41df71f9]168 if (ret != EOK) {
169 async_forget(opening_request);
170 return ret;
171 }
172
173 /* Wait for the answer. */
174 sysarg_t opening_request_rc;
175 async_wait_for(opening_request, &opening_request_rc);
176
177 return (int) opening_request_rc;
178}
179
180int usbhc_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
181 void *data, size_t size, size_t *rec_size)
182{
183 if (!exch)
184 return EBADMEM;
185
186 if (size == 0 && setup == 0)
187 return EOK;
188
189 /* Make call identifying target USB device and type of transfer. */
190 aid_t opening_request = async_send_4(exch,
191 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_READ, endpoint,
192 (setup & UINT32_MAX), (setup >> 32), NULL);
193
194 if (opening_request == 0) {
195 return ENOMEM;
196 }
197
198 /* Retrieve the data. */
199 ipc_call_t data_request_call;
200 aid_t data_request =
201 async_data_read(exch, data, size, &data_request_call);
202
203 if (data_request == 0) {
204 // FIXME: How to let the other side know that we want to abort?
205 async_forget(opening_request);
206 return ENOMEM;
207 }
208
209 /* Wait for the answer. */
210 sysarg_t data_request_rc;
211 sysarg_t opening_request_rc;
212 async_wait_for(data_request, &data_request_rc);
213 async_wait_for(opening_request, &opening_request_rc);
214
215 if (data_request_rc != EOK) {
216 /* Prefer the return code of the opening request. */
217 if (opening_request_rc != EOK) {
218 return (int) opening_request_rc;
219 } else {
220 return (int) data_request_rc;
221 }
222 }
223 if (opening_request_rc != EOK) {
224 return (int) opening_request_rc;
225 }
226
227 *rec_size = IPC_GET_ARG2(data_request_call);
228 return EOK;
229}
230
231int usbhc_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
232 const void *data, size_t size)
233{
234 if (!exch)
235 return EBADMEM;
236
237 if (size == 0 && setup == 0)
238 return EOK;
239
240 aid_t opening_request = async_send_5(exch,
241 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size,
242 (setup & UINT32_MAX), (setup >> 32), NULL);
243
244 if (opening_request == 0) {
245 return ENOMEM;
246 }
247
248 /* Send the data if any. */
249 if (size > 0) {
250 const int ret = async_data_write_start(exch, data, size);
251 if (ret != EOK) {
252 async_forget(opening_request);
253 return ret;
254 }
255 }
256
257 /* Wait for the answer. */
258 sysarg_t opening_request_rc;
259 async_wait_for(opening_request, &opening_request_rc);
260
261 return (int) opening_request_rc;
262}
263
[4603b35]264static void remote_usbhc_default_address_reservation(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
[41df71f9]265static void remote_usbhc_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
266static void remote_usbhc_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
267static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
268static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
269static void remote_usbhc_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
270static void remote_usbhc_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
271
272/** Remote USB interface operations. */
273static const remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
[4603b35]274 [IPC_M_USB_DEFAULT_ADDRESS_RESERVATION] = remote_usbhc_default_address_reservation,
[41df71f9]275 [IPC_M_USB_DEVICE_ENUMERATE] = remote_usbhc_device_enumerate,
276 [IPC_M_USB_DEVICE_REMOVE] = remote_usbhc_device_remove,
277 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
278 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint,
279 [IPC_M_USB_READ] = remote_usbhc_read,
280 [IPC_M_USB_WRITE] = remote_usbhc_write,
281};
282
283/** Remote USB interface structure.
284 */
285const remote_iface_t remote_usbhc_iface = {
286 .method_count = ARRAY_SIZE(remote_usbhc_iface_ops),
287 .methods = remote_usbhc_iface_ops,
288};
289
290typedef struct {
291 ipc_callid_t caller;
292 ipc_callid_t data_caller;
293 void *buffer;
294} async_transaction_t;
295
[4603b35]296void remote_usbhc_default_address_reservation(ddf_fun_t *fun, void *iface,
[41df71f9]297 ipc_callid_t callid, ipc_call_t *call)
298{
299 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
300
[4603b35]301 if (usbhc_iface->default_address_reservation == NULL) {
[41df71f9]302 async_answer_0(callid, ENOTSUP);
303 return;
304 }
305
[4603b35]306 const bool reserve = IPC_GET_ARG2(*call);
307 const int ret = usbhc_iface->default_address_reservation(fun, reserve);
[41df71f9]308 async_answer_0(callid, ret);
309}
310
311
312static void remote_usbhc_device_enumerate(ddf_fun_t *fun, void *iface,
313 ipc_callid_t callid, ipc_call_t *call)
314{
315 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
316
317 if (usbhc_iface->device_enumerate == NULL) {
318 async_answer_0(callid, ENOTSUP);
319 return;
320 }
321
322 const unsigned port = DEV_IPC_GET_ARG1(*call);
[eeca8a6]323 usb_speed_t speed = DEV_IPC_GET_ARG2(*call);
324 const int ret = usbhc_iface->device_enumerate(fun, port, speed);
[41df71f9]325 async_answer_0(callid, ret);
326}
327
328static void remote_usbhc_device_remove(ddf_fun_t *fun, void *iface,
329 ipc_callid_t callid, ipc_call_t *call)
330{
331 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
332
333 if (usbhc_iface->device_remove == NULL) {
334 async_answer_0(callid, ENOTSUP);
335 return;
336 }
337
338 const unsigned port = DEV_IPC_GET_ARG1(*call);
339 const int ret = usbhc_iface->device_remove(fun, port);
340 async_answer_0(callid, ret);
341}
342
343static void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
344 ipc_callid_t callid, ipc_call_t *call)
345{
346 assert(fun);
347 assert(iface);
348 assert(call);
349
350 const usbhc_iface_t *usbhc_iface = iface;
351
352 if (!usbhc_iface->register_endpoint) {
353 async_answer_0(callid, ENOTSUP);
354 return;
355 }
356
[9efad54]357 usb_endpoint_descriptors_t ep_desc;
358 ipc_callid_t data_callid;
359 size_t len;
[41df71f9]360
[9efad54]361 if (!async_data_write_receive(&data_callid, &len)
362 || len != sizeof(ep_desc)) {
363 async_answer_0(callid, EINVAL);
[41df71f9]364 return;
365 }
[9efad54]366 async_data_write_finalize(data_callid, &ep_desc, sizeof(ep_desc));
[41df71f9]367
[9efad54]368 usb_pipe_desc_t pipe_desc;
[41df71f9]369
[9efad54]370 const int rc = usbhc_iface->register_endpoint(fun, &pipe_desc, &ep_desc);
[41df71f9]371 async_answer_0(callid, rc);
[9efad54]372
373 if (!async_data_read_receive(&data_callid, &len)
374 || len != sizeof(pipe_desc)) {
375 return;
376 }
377 async_data_read_finalize(data_callid, &pipe_desc, sizeof(pipe_desc));
[41df71f9]378}
379
380static void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
381 ipc_callid_t callid, ipc_call_t *call)
382{
383 assert(fun);
384 assert(iface);
385 assert(call);
386
387 const usbhc_iface_t *usbhc_iface = iface;
388
389 if (!usbhc_iface->unregister_endpoint) {
390 async_answer_0(callid, ENOTSUP);
391 return;
392 }
393
[9efad54]394 usb_pipe_desc_t pipe_desc;
395 ipc_callid_t data_callid;
396 size_t len;
[41df71f9]397
[9efad54]398 if (!async_data_write_receive(&data_callid, &len)
399 || len != sizeof(pipe_desc)) {
400 async_answer_0(callid, EINVAL);
[41df71f9]401 return;
402 }
[9efad54]403 async_data_write_finalize(data_callid, &pipe_desc, sizeof(pipe_desc));
[41df71f9]404
[9efad54]405 const int rc = usbhc_iface->unregister_endpoint(fun, &pipe_desc);
[41df71f9]406 async_answer_0(callid, rc);
407}
408
409static void async_transaction_destroy(async_transaction_t *trans)
410{
411 if (trans == NULL) {
412 return;
413 }
414 if (trans->buffer != NULL) {
415 free(trans->buffer);
416 }
417
418 free(trans);
419}
420
421static async_transaction_t *async_transaction_create(ipc_callid_t caller)
422{
423 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
424 if (trans == NULL) {
425 return NULL;
426 }
427
428 trans->caller = caller;
429 trans->data_caller = 0;
430 trans->buffer = NULL;
431
432 return trans;
433}
434
[f9d0a86]435static int callback_out(void *arg, int error, size_t transfered_size)
[41df71f9]436{
[272f46f8]437 async_transaction_t *trans = arg;
[41df71f9]438
[f9d0a86]439 const int err = async_answer_0(trans->caller, error);
[41df71f9]440
441 async_transaction_destroy(trans);
442
443 return err;
444}
445
[f9d0a86]446static int callback_in(void *arg, int error, size_t transfered_size)
[41df71f9]447{
[f9d0a86]448 async_transaction_t *trans = arg;
[41df71f9]449
450 if (trans->data_caller) {
[f9d0a86]451 if (error == EOK) {
452 error = async_data_read_finalize(trans->data_caller,
453 trans->buffer, transfered_size);
[41df71f9]454 } else {
455 async_answer_0(trans->data_caller, EINTR);
456 }
457 }
458
[f9d0a86]459 const int err = async_answer_0(trans->caller, error);
[41df71f9]460 async_transaction_destroy(trans);
461 return err;
462}
463
464void remote_usbhc_read(
465 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
466{
467 assert(fun);
468 assert(iface);
469 assert(call);
470
471 const usbhc_iface_t *usbhc_iface = iface;
472
473 if (!usbhc_iface->read) {
474 async_answer_0(callid, ENOTSUP);
475 return;
476 }
477
478 const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
479 const uint64_t setup =
480 ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
481 (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
482
483 async_transaction_t *trans = async_transaction_create(callid);
484 if (trans == NULL) {
485 async_answer_0(callid, ENOMEM);
486 return;
487 }
488
489 size_t size = 0;
490 if (!async_data_read_receive(&trans->data_caller, &size)) {
491 async_answer_0(callid, EPARTY);
492 async_transaction_destroy(trans);
493 return;
494 }
495
496 trans->buffer = malloc(size);
497 if (trans->buffer == NULL) {
498 async_answer_0(trans->data_caller, ENOMEM);
499 async_answer_0(callid, ENOMEM);
500 async_transaction_destroy(trans);
501 return;
502 }
503
504 const usb_target_t target = {{
505 /* .address is initialized by read itself */
506 .endpoint = ep,
507 }};
508
509 const int rc = usbhc_iface->read(
510 fun, target, setup, trans->buffer, size, callback_in, trans);
511
512 if (rc != EOK) {
513 async_answer_0(trans->data_caller, rc);
514 async_answer_0(callid, rc);
515 async_transaction_destroy(trans);
516 }
517}
518
519void remote_usbhc_write(
520 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
521{
522 assert(fun);
523 assert(iface);
524 assert(call);
525
526 const usbhc_iface_t *usbhc_iface = iface;
527
528 if (!usbhc_iface->write) {
529 async_answer_0(callid, ENOTSUP);
530 return;
531 }
532
533 const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
534 const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
535 const uint64_t setup =
536 ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
537 (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
538
539 async_transaction_t *trans = async_transaction_create(callid);
540 if (trans == NULL) {
541 async_answer_0(callid, ENOMEM);
542 return;
543 }
544
545 size_t size = 0;
546 if (data_buffer_len > 0) {
547 const int rc = async_data_write_accept(&trans->buffer, false,
548 1, data_buffer_len, 0, &size);
549
550 if (rc != EOK) {
551 async_answer_0(callid, rc);
552 async_transaction_destroy(trans);
553 return;
554 }
555 }
556
557 const usb_target_t target = {{
558 /* .address is initialized by write itself */
559 .endpoint = ep,
560 }};
561
562 const int rc = usbhc_iface->write(
563 fun, target, setup, trans->buffer, size, callback_out, trans);
564
565 if (rc != EOK) {
566 async_answer_0(callid, rc);
567 async_transaction_destroy(trans);
568 }
569}
570/**
571 * @}
572 */
Note: See TracBrowser for help on using the repository browser.