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

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 95658c9 was fafb8e5, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Mechanically lowercase IPC_SET_*/IPC_GET_*

  • 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
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,
[239eea41]52 IPC_M_USB_TRANSFER,
[41df71f9]53} usbhc_iface_funcs_t;
54
55/** Reserve default USB address.
56 * @param[in] exch IPC communication exchange
57 * @return Error code.
58 */
[5c69377]59errno_t usbhc_reserve_default_address(async_exch_t *exch)
[41df71f9]60{
61 if (!exch)
62 return EBADMEM;
[4603b35]63 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, true);
[41df71f9]64}
65
66/** Release default USB address.
67 *
68 * @param[in] exch IPC communication exchange
69 *
70 * @return Error code.
71 */
[5c69377]72errno_t usbhc_release_default_address(async_exch_t *exch)
[41df71f9]73{
74 if (!exch)
75 return EBADMEM;
[4603b35]76 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, false);
[41df71f9]77}
78
[eeca8a6]79/**
80 * Trigger USB device enumeration
[41df71f9]81 *
[eeca8a6]82 * @param[in] exch IPC communication exchange
83 * @param[in] port Port number at which the device is attached
84 * @param[in] speed Communication speed of the newly attached device
[41df71f9]85 *
86 * @return Error code.
87 */
[5c69377]88errno_t usbhc_device_enumerate(async_exch_t *exch, unsigned port, usb_speed_t speed)
[41df71f9]89{
90 if (!exch)
91 return EBADMEM;
[5c69377]92 const errno_t ret = async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
[eeca8a6]93 IPC_M_USB_DEVICE_ENUMERATE, port, speed);
[41df71f9]94 return ret;
95}
96
97/** Trigger USB device enumeration
98 *
99 * @param[in] exch IPC communication exchange
100 * @param[in] handle Identifier of the device
101 *
102 * @return Error code.
103 *
104 */
[5a6cc679]105errno_t usbhc_device_remove(async_exch_t *exch, unsigned port)
[41df71f9]106{
107 if (!exch)
108 return EBADMEM;
109 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
110 IPC_M_USB_DEVICE_REMOVE, port);
111}
112
[5a6cc679]113errno_t usbhc_register_endpoint(async_exch_t *exch, usb_pipe_desc_t *pipe_desc,
[9efad54]114 const usb_endpoint_descriptors_t *desc)
[41df71f9]115{
116 if (!exch)
117 return EBADMEM;
118
[9efad54]119 if (!desc)
120 return EINVAL;
121
[41df71f9]122 aid_t opening_request = async_send_1(exch,
123 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_REGISTER_ENDPOINT, NULL);
124
125 if (opening_request == 0) {
126 return ENOMEM;
127 }
128
[5c69377]129 errno_t ret = async_data_write_start(exch, desc, sizeof(*desc));
[41df71f9]130 if (ret != EOK) {
131 async_forget(opening_request);
132 return ret;
133 }
134
135 /* Wait for the answer. */
[5c69377]136 errno_t opening_request_rc;
[41df71f9]137 async_wait_for(opening_request, &opening_request_rc);
138
[9efad54]139 if (opening_request_rc)
[5c69377]140 return (errno_t) opening_request_rc;
[9efad54]141
142 usb_pipe_desc_t dest;
143 ret = async_data_read_start(exch, &dest, sizeof(dest));
144 if (ret != EOK) {
145 return ret;
146 }
147
148 if (pipe_desc)
149 *pipe_desc = dest;
150
151 return EOK;
[41df71f9]152}
153
[5a6cc679]154errno_t usbhc_unregister_endpoint(async_exch_t *exch, const usb_pipe_desc_t *pipe_desc)
[41df71f9]155{
156 if (!exch)
157 return EBADMEM;
158
159 aid_t opening_request = async_send_1(exch,
[3bacee1]160 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_UNREGISTER_ENDPOINT, NULL);
[41df71f9]161
162 if (opening_request == 0) {
163 return ENOMEM;
164 }
165
[5c69377]166 const errno_t ret = async_data_write_start(exch, pipe_desc, sizeof(*pipe_desc));
[41df71f9]167 if (ret != EOK) {
168 async_forget(opening_request);
169 return ret;
170 }
171
172 /* Wait for the answer. */
[5c69377]173 errno_t opening_request_rc;
[41df71f9]174 async_wait_for(opening_request, &opening_request_rc);
175
[5c69377]176 return (errno_t) opening_request_rc;
[41df71f9]177}
178
[5595841]179/**
180 * Issue a USB transfer with a data contained in memory area. That area is
181 * temporarily shared with the HC.
182 */
[239eea41]183errno_t usbhc_transfer(async_exch_t *exch,
184 const usbhc_iface_transfer_request_t *req, size_t *transferred)
[41df71f9]185{
[5595841]186 if (transferred)
187 *transferred = 0;
188
[41df71f9]189 if (!exch)
190 return EBADMEM;
191
[5595841]192 ipc_call_t call;
[41df71f9]193
[239eea41]194 aid_t opening_request = async_send_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
195 IPC_M_USB_TRANSFER, &call);
[41df71f9]196
[5595841]197 if (opening_request == 0)
[41df71f9]198 return ENOMEM;
199
[239eea41]200 const errno_t ret = async_data_write_start(exch, req, sizeof(*req));
201 if (ret != EOK) {
202 async_forget(opening_request);
203 return ret;
204 }
205
206 /* Share the data, if any. */
207 if (req->size > 0) {
[3bacee1]208 unsigned flags = (req->dir == USB_DIRECTION_IN) ?
209 AS_AREA_WRITE : AS_AREA_READ;
[5595841]210
[1d758fc]211 const errno_t ret = async_share_out_start(exch, req->buffer.virt, flags);
[41df71f9]212 if (ret != EOK) {
213 async_forget(opening_request);
214 return ret;
215 }
216 }
217
218 /* Wait for the answer. */
[5a6cc679]219 errno_t opening_request_rc;
[41df71f9]220 async_wait_for(opening_request, &opening_request_rc);
221
[5595841]222 if (transferred)
[fafb8e5]223 *transferred = ipc_get_arg1(&call);
[5595841]224
[5a6cc679]225 return (errno_t) opening_request_rc;
[41df71f9]226}
227
[984a9ba]228static void remote_usbhc_default_address_reservation(ddf_fun_t *, void *, ipc_call_t *);
229static void remote_usbhc_device_enumerate(ddf_fun_t *, void *, ipc_call_t *);
230static void remote_usbhc_device_remove(ddf_fun_t *, void *, ipc_call_t *);
231static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_call_t *);
232static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_call_t *);
233static void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_call_t *call);
[41df71f9]234
235/** Remote USB interface operations. */
236static const remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
[4603b35]237 [IPC_M_USB_DEFAULT_ADDRESS_RESERVATION] = remote_usbhc_default_address_reservation,
[41df71f9]238 [IPC_M_USB_DEVICE_ENUMERATE] = remote_usbhc_device_enumerate,
239 [IPC_M_USB_DEVICE_REMOVE] = remote_usbhc_device_remove,
240 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
241 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint,
[239eea41]242 [IPC_M_USB_TRANSFER] = remote_usbhc_transfer,
[41df71f9]243};
244
245/** Remote USB interface structure.
246 */
247const remote_iface_t remote_usbhc_iface = {
248 .method_count = ARRAY_SIZE(remote_usbhc_iface_ops),
249 .methods = remote_usbhc_iface_ops,
250};
251
252typedef struct {
[984a9ba]253 ipc_call_t call;
[239eea41]254 usbhc_iface_transfer_request_t request;
[41df71f9]255} async_transaction_t;
256
[4603b35]257void remote_usbhc_default_address_reservation(ddf_fun_t *fun, void *iface,
[984a9ba]258 ipc_call_t *call)
[41df71f9]259{
260 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
261
[4603b35]262 if (usbhc_iface->default_address_reservation == NULL) {
[984a9ba]263 async_answer_0(call, ENOTSUP);
[41df71f9]264 return;
265 }
266
[fafb8e5]267 const bool reserve = ipc_get_arg2(call);
[5c69377]268 const errno_t ret = usbhc_iface->default_address_reservation(fun, reserve);
[984a9ba]269 async_answer_0(call, ret);
[41df71f9]270}
271
272static void remote_usbhc_device_enumerate(ddf_fun_t *fun, void *iface,
[984a9ba]273 ipc_call_t *call)
[41df71f9]274{
275 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
276
277 if (usbhc_iface->device_enumerate == NULL) {
[984a9ba]278 async_answer_0(call, ENOTSUP);
[41df71f9]279 return;
280 }
281
282 const unsigned port = DEV_IPC_GET_ARG1(*call);
[eeca8a6]283 usb_speed_t speed = DEV_IPC_GET_ARG2(*call);
[5c69377]284 const errno_t ret = usbhc_iface->device_enumerate(fun, port, speed);
[984a9ba]285 async_answer_0(call, ret);
[41df71f9]286}
287
288static void remote_usbhc_device_remove(ddf_fun_t *fun, void *iface,
[984a9ba]289 ipc_call_t *call)
[41df71f9]290{
291 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
292
293 if (usbhc_iface->device_remove == NULL) {
[984a9ba]294 async_answer_0(call, ENOTSUP);
[41df71f9]295 return;
296 }
297
298 const unsigned port = DEV_IPC_GET_ARG1(*call);
[5c69377]299 const errno_t ret = usbhc_iface->device_remove(fun, port);
[984a9ba]300 async_answer_0(call, ret);
[41df71f9]301}
302
303static void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
[984a9ba]304 ipc_call_t *call)
[41df71f9]305{
306 assert(fun);
307 assert(iface);
308 assert(call);
309
310 const usbhc_iface_t *usbhc_iface = iface;
311
312 if (!usbhc_iface->register_endpoint) {
[984a9ba]313 async_answer_0(call, ENOTSUP);
[41df71f9]314 return;
315 }
316
[9efad54]317 usb_endpoint_descriptors_t ep_desc;
[984a9ba]318 ipc_call_t data;
[9efad54]319 size_t len;
[41df71f9]320
[984a9ba]321 if (!async_data_write_receive(&data, &len) ||
[3bacee1]322 len != sizeof(ep_desc)) {
[984a9ba]323 async_answer_0(call, EINVAL);
[41df71f9]324 return;
325 }
[984a9ba]326
327 async_data_write_finalize(&data, &ep_desc, sizeof(ep_desc));
[41df71f9]328
[9efad54]329 usb_pipe_desc_t pipe_desc;
[41df71f9]330
[5c69377]331 const errno_t rc = usbhc_iface->register_endpoint(fun, &pipe_desc, &ep_desc);
[984a9ba]332 async_answer_0(call, rc);
[9efad54]333
[984a9ba]334 if (!async_data_read_receive(&data, &len) ||
[3bacee1]335 len != sizeof(pipe_desc)) {
[9efad54]336 return;
337 }
[984a9ba]338 async_data_read_finalize(&data, &pipe_desc, sizeof(pipe_desc));
[41df71f9]339}
340
341static void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
[984a9ba]342 ipc_call_t *call)
[41df71f9]343{
344 assert(fun);
345 assert(iface);
346 assert(call);
347
348 const usbhc_iface_t *usbhc_iface = iface;
349
350 if (!usbhc_iface->unregister_endpoint) {
[984a9ba]351 async_answer_0(call, ENOTSUP);
[41df71f9]352 return;
353 }
354
[9efad54]355 usb_pipe_desc_t pipe_desc;
[984a9ba]356 ipc_call_t data;
[9efad54]357 size_t len;
[41df71f9]358
[984a9ba]359 if (!async_data_write_receive(&data, &len) ||
[3bacee1]360 len != sizeof(pipe_desc)) {
[984a9ba]361 async_answer_0(call, EINVAL);
[41df71f9]362 return;
363 }
[984a9ba]364 async_data_write_finalize(&data, &pipe_desc, sizeof(pipe_desc));
[41df71f9]365
[5c69377]366 const errno_t rc = usbhc_iface->unregister_endpoint(fun, &pipe_desc);
[984a9ba]367 async_answer_0(call, rc);
[41df71f9]368}
369
370static void async_transaction_destroy(async_transaction_t *trans)
371{
372 if (trans == NULL) {
373 return;
374 }
[1d758fc]375 if (trans->request.buffer.virt != NULL) {
376 as_area_destroy(trans->request.buffer.virt);
[41df71f9]377 }
378
379 free(trans);
380}
381
[984a9ba]382static async_transaction_t *async_transaction_create(ipc_call_t *call)
[41df71f9]383{
[239eea41]384 async_transaction_t *trans = calloc(1, sizeof(async_transaction_t));
[41df71f9]385
[239eea41]386 if (trans != NULL)
[984a9ba]387 trans->call = *call;
[41df71f9]388
389 return trans;
390}
391
[5c69377]392static errno_t transfer_finished(void *arg, errno_t error, size_t transferred_size)
[41df71f9]393{
[272f46f8]394 async_transaction_t *trans = arg;
[984a9ba]395 const errno_t err = async_answer_1(&trans->call, error, transferred_size);
[41df71f9]396 async_transaction_destroy(trans);
397 return err;
398}
399
[239eea41]400static errno_t receive_memory_buffer(async_transaction_t *trans)
[41df71f9]401{
[5595841]402 assert(trans);
[239eea41]403 assert(trans->request.size > 0);
404
405 const size_t required_size = trans->request.offset + trans->request.size;
406 const unsigned required_flags =
[3bacee1]407 (trans->request.dir == USB_DIRECTION_IN) ?
408 AS_AREA_WRITE : AS_AREA_READ;
[41df71f9]409
[5595841]410 errno_t err;
[984a9ba]411 ipc_call_t data;
[5595841]412 size_t size;
413 unsigned flags;
[41df71f9]414
[984a9ba]415 if (!async_share_out_receive(&data, &size, &flags))
[5595841]416 return EPARTY;
[41df71f9]417
[5595841]418 if (size < required_size || (flags & required_flags) != required_flags) {
[984a9ba]419 async_answer_0(&data, EINVAL);
[5595841]420 return EINVAL;
[41df71f9]421 }
422
[984a9ba]423 if ((err = async_share_out_finalize(&data, &trans->request.buffer.virt)))
[5595841]424 return err;
[41df71f9]425
[c21e6a5]426 /*
[1d758fc]427 * As we're going to get physical addresses of the mapping, we must make
428 * sure the memory is actually mapped. We must do it right now, because
429 * the area might be read-only or write-only, and we may be unsure
430 * later.
[c21e6a5]431 */
432 if (flags & AS_AREA_READ) {
433 char foo = 0;
[1d758fc]434 volatile const char *buf = trans->request.buffer.virt + trans->request.offset;
[c21e6a5]435 for (size_t i = 0; i < size; i += PAGE_SIZE)
436 foo += buf[i];
437 } else {
[1d758fc]438 volatile char *buf = trans->request.buffer.virt + trans->request.offset;
[c21e6a5]439 for (size_t i = 0; i < size; i += PAGE_SIZE)
440 buf[i] = 0xff;
441 }
442
[5595841]443 return EOK;
[41df71f9]444}
445
[984a9ba]446void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_call_t *call)
[41df71f9]447{
448 assert(fun);
449 assert(iface);
450 assert(call);
451
452 const usbhc_iface_t *usbhc_iface = iface;
453
[5595841]454 if (!usbhc_iface->transfer) {
[984a9ba]455 async_answer_0(call, ENOTSUP);
[41df71f9]456 return;
457 }
458
[984a9ba]459 async_transaction_t *trans =
460 async_transaction_create(call);
[41df71f9]461 if (trans == NULL) {
[984a9ba]462 async_answer_0(call, ENOMEM);
[41df71f9]463 return;
464 }
465
[239eea41]466 errno_t err = EPARTY;
[41df71f9]467
[984a9ba]468 ipc_call_t data;
[239eea41]469 size_t len;
[984a9ba]470 if (!async_data_write_receive(&data, &len) ||
[3bacee1]471 len != sizeof(trans->request)) {
[984a9ba]472 async_answer_0(&data, EINVAL);
[239eea41]473 goto err;
[41df71f9]474 }
475
[984a9ba]476 if ((err = async_data_write_finalize(&data,
[3bacee1]477 &trans->request, sizeof(trans->request))))
[239eea41]478 goto err;
[41df71f9]479
[239eea41]480 if (trans->request.size > 0) {
481 if ((err = receive_memory_buffer(trans)))
482 goto err;
483 } else {
484 /* The value was valid on the other side, for us, its garbage. */
[1d758fc]485 trans->request.buffer.virt = NULL;
[41df71f9]486 }
[239eea41]487
488 if ((err = usbhc_iface->transfer(fun, &trans->request,
489 &transfer_finished, trans)))
490 goto err;
491
492 /* The call will be answered asynchronously by the callback. */
493 return;
494
495err:
[984a9ba]496 async_answer_0(call, err);
[239eea41]497 async_transaction_destroy(trans);
[41df71f9]498}
[5595841]499
[41df71f9]500/**
501 * @}
502 */
Note: See TracBrowser for help on using the repository browser.