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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 05882233 was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 12.7 KB
RevLine 
[41df71f9]1/*
2 * Copyright (c) 2010 Vojtech Horky
3 * Copyright (c) 2011 Jan Vesely
[e0a5d4c]4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
[41df71f9]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>
[5595841]41#include <as.h>
[41df71f9]42
43#include "usbhc_iface.h"
44#include "ddf/driver.h"
45
46
47typedef enum {
[4603b35]48 IPC_M_USB_DEFAULT_ADDRESS_RESERVATION,
[41df71f9]49 IPC_M_USB_DEVICE_ENUMERATE,
50 IPC_M_USB_DEVICE_REMOVE,
51 IPC_M_USB_REGISTER_ENDPOINT,
52 IPC_M_USB_UNREGISTER_ENDPOINT,
[239eea41]53 IPC_M_USB_TRANSFER,
[41df71f9]54} usbhc_iface_funcs_t;
55
56/** Reserve default USB address.
57 * @param[in] exch IPC communication exchange
58 * @return Error code.
59 */
[5c69377]60errno_t 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 */
[5c69377]73errno_t usbhc_release_default_address(async_exch_t *exch)
[41df71f9]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 */
[5c69377]89errno_t usbhc_device_enumerate(async_exch_t *exch, unsigned port, usb_speed_t speed)
[41df71f9]90{
91 if (!exch)
92 return EBADMEM;
[5c69377]93 const errno_t ret = async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
[eeca8a6]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 */
[5a6cc679]106errno_t usbhc_device_remove(async_exch_t *exch, unsigned port)
[41df71f9]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
[5a6cc679]114errno_t usbhc_register_endpoint(async_exch_t *exch, usb_pipe_desc_t *pipe_desc,
[9efad54]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
[5c69377]130 errno_t 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. */
[5c69377]137 errno_t opening_request_rc;
[41df71f9]138 async_wait_for(opening_request, &opening_request_rc);
139
[9efad54]140 if (opening_request_rc)
[5c69377]141 return (errno_t) opening_request_rc;
[9efad54]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
[5a6cc679]155errno_t 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,
[3bacee1]161 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_UNREGISTER_ENDPOINT, NULL);
[41df71f9]162
163 if (opening_request == 0) {
164 return ENOMEM;
165 }
166
[5c69377]167 const errno_t 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. */
[5c69377]174 errno_t opening_request_rc;
[41df71f9]175 async_wait_for(opening_request, &opening_request_rc);
176
[5c69377]177 return (errno_t) opening_request_rc;
[41df71f9]178}
179
[5595841]180/**
181 * Issue a USB transfer with a data contained in memory area. That area is
182 * temporarily shared with the HC.
183 */
[239eea41]184errno_t usbhc_transfer(async_exch_t *exch,
185 const usbhc_iface_transfer_request_t *req, size_t *transferred)
[41df71f9]186{
[5595841]187 if (transferred)
188 *transferred = 0;
189
[41df71f9]190 if (!exch)
191 return EBADMEM;
192
[5595841]193 ipc_call_t call;
[41df71f9]194
[239eea41]195 aid_t opening_request = async_send_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
196 IPC_M_USB_TRANSFER, &call);
[41df71f9]197
[5595841]198 if (opening_request == 0)
[41df71f9]199 return ENOMEM;
200
[239eea41]201 const errno_t ret = async_data_write_start(exch, req, sizeof(*req));
202 if (ret != EOK) {
203 async_forget(opening_request);
204 return ret;
205 }
206
207 /* Share the data, if any. */
208 if (req->size > 0) {
[3bacee1]209 unsigned flags = (req->dir == USB_DIRECTION_IN) ?
210 AS_AREA_WRITE : AS_AREA_READ;
[5595841]211
[1d758fc]212 const errno_t ret = async_share_out_start(exch, req->buffer.virt, flags);
[41df71f9]213 if (ret != EOK) {
214 async_forget(opening_request);
215 return ret;
216 }
217 }
218
219 /* Wait for the answer. */
[5a6cc679]220 errno_t opening_request_rc;
[41df71f9]221 async_wait_for(opening_request, &opening_request_rc);
222
[5595841]223 if (transferred)
224 *transferred = IPC_GET_ARG1(call);
225
[5a6cc679]226 return (errno_t) opening_request_rc;
[41df71f9]227}
228
[984a9ba]229static void remote_usbhc_default_address_reservation(ddf_fun_t *, void *, ipc_call_t *);
230static void remote_usbhc_device_enumerate(ddf_fun_t *, void *, ipc_call_t *);
231static void remote_usbhc_device_remove(ddf_fun_t *, void *, ipc_call_t *);
232static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_call_t *);
233static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_call_t *);
234static void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_call_t *call);
[41df71f9]235
236/** Remote USB interface operations. */
237static const remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
[4603b35]238 [IPC_M_USB_DEFAULT_ADDRESS_RESERVATION] = remote_usbhc_default_address_reservation,
[41df71f9]239 [IPC_M_USB_DEVICE_ENUMERATE] = remote_usbhc_device_enumerate,
240 [IPC_M_USB_DEVICE_REMOVE] = remote_usbhc_device_remove,
241 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
242 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint,
[239eea41]243 [IPC_M_USB_TRANSFER] = remote_usbhc_transfer,
[41df71f9]244};
245
246/** Remote USB interface structure.
247 */
248const remote_iface_t remote_usbhc_iface = {
249 .method_count = ARRAY_SIZE(remote_usbhc_iface_ops),
250 .methods = remote_usbhc_iface_ops,
251};
252
253typedef struct {
[984a9ba]254 ipc_call_t call;
[239eea41]255 usbhc_iface_transfer_request_t request;
[41df71f9]256} async_transaction_t;
257
[4603b35]258void remote_usbhc_default_address_reservation(ddf_fun_t *fun, void *iface,
[984a9ba]259 ipc_call_t *call)
[41df71f9]260{
261 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
262
[4603b35]263 if (usbhc_iface->default_address_reservation == NULL) {
[984a9ba]264 async_answer_0(call, ENOTSUP);
[41df71f9]265 return;
266 }
267
[4603b35]268 const bool reserve = IPC_GET_ARG2(*call);
[5c69377]269 const errno_t ret = usbhc_iface->default_address_reservation(fun, reserve);
[984a9ba]270 async_answer_0(call, ret);
[41df71f9]271}
272
273
274static void remote_usbhc_device_enumerate(ddf_fun_t *fun, void *iface,
[984a9ba]275 ipc_call_t *call)
[41df71f9]276{
277 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
278
279 if (usbhc_iface->device_enumerate == NULL) {
[984a9ba]280 async_answer_0(call, ENOTSUP);
[41df71f9]281 return;
282 }
283
284 const unsigned port = DEV_IPC_GET_ARG1(*call);
[eeca8a6]285 usb_speed_t speed = DEV_IPC_GET_ARG2(*call);
[5c69377]286 const errno_t ret = usbhc_iface->device_enumerate(fun, port, speed);
[984a9ba]287 async_answer_0(call, ret);
[41df71f9]288}
289
290static void remote_usbhc_device_remove(ddf_fun_t *fun, void *iface,
[984a9ba]291 ipc_call_t *call)
[41df71f9]292{
293 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
294
295 if (usbhc_iface->device_remove == NULL) {
[984a9ba]296 async_answer_0(call, ENOTSUP);
[41df71f9]297 return;
298 }
299
300 const unsigned port = DEV_IPC_GET_ARG1(*call);
[5c69377]301 const errno_t ret = usbhc_iface->device_remove(fun, port);
[984a9ba]302 async_answer_0(call, ret);
[41df71f9]303}
304
305static void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
[984a9ba]306 ipc_call_t *call)
[41df71f9]307{
308 assert(fun);
309 assert(iface);
310 assert(call);
311
312 const usbhc_iface_t *usbhc_iface = iface;
313
314 if (!usbhc_iface->register_endpoint) {
[984a9ba]315 async_answer_0(call, ENOTSUP);
[41df71f9]316 return;
317 }
318
[9efad54]319 usb_endpoint_descriptors_t ep_desc;
[984a9ba]320 ipc_call_t data;
[9efad54]321 size_t len;
[41df71f9]322
[984a9ba]323 if (!async_data_write_receive(&data, &len) ||
[3bacee1]324 len != sizeof(ep_desc)) {
[984a9ba]325 async_answer_0(call, EINVAL);
[41df71f9]326 return;
327 }
[984a9ba]328
329 async_data_write_finalize(&data, &ep_desc, sizeof(ep_desc));
[41df71f9]330
[9efad54]331 usb_pipe_desc_t pipe_desc;
[41df71f9]332
[5c69377]333 const errno_t rc = usbhc_iface->register_endpoint(fun, &pipe_desc, &ep_desc);
[984a9ba]334 async_answer_0(call, rc);
[9efad54]335
[984a9ba]336 if (!async_data_read_receive(&data, &len) ||
[3bacee1]337 len != sizeof(pipe_desc)) {
[9efad54]338 return;
339 }
[984a9ba]340 async_data_read_finalize(&data, &pipe_desc, sizeof(pipe_desc));
[41df71f9]341}
342
343static void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
[984a9ba]344 ipc_call_t *call)
[41df71f9]345{
346 assert(fun);
347 assert(iface);
348 assert(call);
349
350 const usbhc_iface_t *usbhc_iface = iface;
351
352 if (!usbhc_iface->unregister_endpoint) {
[984a9ba]353 async_answer_0(call, ENOTSUP);
[41df71f9]354 return;
355 }
356
[9efad54]357 usb_pipe_desc_t pipe_desc;
[984a9ba]358 ipc_call_t data;
[9efad54]359 size_t len;
[41df71f9]360
[984a9ba]361 if (!async_data_write_receive(&data, &len) ||
[3bacee1]362 len != sizeof(pipe_desc)) {
[984a9ba]363 async_answer_0(call, EINVAL);
[41df71f9]364 return;
365 }
[984a9ba]366 async_data_write_finalize(&data, &pipe_desc, sizeof(pipe_desc));
[41df71f9]367
[5c69377]368 const errno_t rc = usbhc_iface->unregister_endpoint(fun, &pipe_desc);
[984a9ba]369 async_answer_0(call, rc);
[41df71f9]370}
371
372static void async_transaction_destroy(async_transaction_t *trans)
373{
374 if (trans == NULL) {
375 return;
376 }
[1d758fc]377 if (trans->request.buffer.virt != NULL) {
378 as_area_destroy(trans->request.buffer.virt);
[41df71f9]379 }
380
381 free(trans);
382}
383
[984a9ba]384static async_transaction_t *async_transaction_create(ipc_call_t *call)
[41df71f9]385{
[239eea41]386 async_transaction_t *trans = calloc(1, sizeof(async_transaction_t));
[41df71f9]387
[239eea41]388 if (trans != NULL)
[984a9ba]389 trans->call = *call;
[41df71f9]390
391 return trans;
392}
393
[5c69377]394static errno_t transfer_finished(void *arg, errno_t error, size_t transferred_size)
[41df71f9]395{
[272f46f8]396 async_transaction_t *trans = arg;
[984a9ba]397 const errno_t err = async_answer_1(&trans->call, error, transferred_size);
[41df71f9]398 async_transaction_destroy(trans);
399 return err;
400}
401
[239eea41]402static errno_t receive_memory_buffer(async_transaction_t *trans)
[41df71f9]403{
[5595841]404 assert(trans);
[239eea41]405 assert(trans->request.size > 0);
406
407 const size_t required_size = trans->request.offset + trans->request.size;
408 const unsigned required_flags =
[3bacee1]409 (trans->request.dir == USB_DIRECTION_IN) ?
410 AS_AREA_WRITE : AS_AREA_READ;
[41df71f9]411
[5595841]412 errno_t err;
[984a9ba]413 ipc_call_t data;
[5595841]414 size_t size;
415 unsigned flags;
[41df71f9]416
[984a9ba]417 if (!async_share_out_receive(&data, &size, &flags))
[5595841]418 return EPARTY;
[41df71f9]419
[5595841]420 if (size < required_size || (flags & required_flags) != required_flags) {
[984a9ba]421 async_answer_0(&data, EINVAL);
[5595841]422 return EINVAL;
[41df71f9]423 }
424
[984a9ba]425 if ((err = async_share_out_finalize(&data, &trans->request.buffer.virt)))
[5595841]426 return err;
[41df71f9]427
[c21e6a5]428 /*
[1d758fc]429 * As we're going to get physical addresses of the mapping, we must make
430 * sure the memory is actually mapped. We must do it right now, because
431 * the area might be read-only or write-only, and we may be unsure
432 * later.
[c21e6a5]433 */
434 if (flags & AS_AREA_READ) {
435 char foo = 0;
[1d758fc]436 volatile const char *buf = trans->request.buffer.virt + trans->request.offset;
[c21e6a5]437 for (size_t i = 0; i < size; i += PAGE_SIZE)
438 foo += buf[i];
439 } else {
[1d758fc]440 volatile char *buf = trans->request.buffer.virt + trans->request.offset;
[c21e6a5]441 for (size_t i = 0; i < size; i += PAGE_SIZE)
442 buf[i] = 0xff;
443 }
444
[5595841]445 return EOK;
[41df71f9]446}
447
[984a9ba]448void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_call_t *call)
[41df71f9]449{
450 assert(fun);
451 assert(iface);
452 assert(call);
453
454 const usbhc_iface_t *usbhc_iface = iface;
455
[5595841]456 if (!usbhc_iface->transfer) {
[984a9ba]457 async_answer_0(call, ENOTSUP);
[41df71f9]458 return;
459 }
460
[984a9ba]461 async_transaction_t *trans =
462 async_transaction_create(call);
[41df71f9]463 if (trans == NULL) {
[984a9ba]464 async_answer_0(call, ENOMEM);
[41df71f9]465 return;
466 }
467
[239eea41]468 errno_t err = EPARTY;
[41df71f9]469
[984a9ba]470 ipc_call_t data;
[239eea41]471 size_t len;
[984a9ba]472 if (!async_data_write_receive(&data, &len) ||
[3bacee1]473 len != sizeof(trans->request)) {
[984a9ba]474 async_answer_0(&data, EINVAL);
[239eea41]475 goto err;
[41df71f9]476 }
477
[984a9ba]478 if ((err = async_data_write_finalize(&data,
[3bacee1]479 &trans->request, sizeof(trans->request))))
[239eea41]480 goto err;
[41df71f9]481
[239eea41]482 if (trans->request.size > 0) {
483 if ((err = receive_memory_buffer(trans)))
484 goto err;
485 } else {
486 /* The value was valid on the other side, for us, its garbage. */
[1d758fc]487 trans->request.buffer.virt = NULL;
[41df71f9]488 }
[239eea41]489
490 if ((err = usbhc_iface->transfer(fun, &trans->request,
491 &transfer_finished, trans)))
492 goto err;
493
494 /* The call will be answered asynchronously by the callback. */
495 return;
496
497err:
[984a9ba]498 async_answer_0(call, err);
[239eea41]499 async_transaction_destroy(trans);
[41df71f9]500}
[5595841]501
[41df71f9]502/**
503 * @}
504 */
Note: See TracBrowser for help on using the repository browser.