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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5c69377 was 5c69377, checked in by Petr Manek <petr.manek@…>, 7 years ago

drv: refactor other usb interfaces to errno_t

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