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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 205261f was ef40434, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

usb: Drop deprecated usb hc interface functions.

  • Property mode set to 100644
File size: 14.6 KB
RevLine 
[91db50ac]1/*
[9753220]2 * Copyright (c) 2010-2011 Vojtech Horky
[02fc5c4]3 * Copyright (c) 2011 Jan Vesely
[91db50ac]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 <errno.h>
[eb1a2f4]38#include <assert.h>
[91db50ac]39
[cb59f787]40#include "usbhc_iface.h"
[eb1a2f4]41#include "ddf/driver.h"
[91db50ac]42
[1b22bd4]43#define USB_MAX_PAYLOAD_SIZE 1020
44
[02fc5c4]45/** IPC methods for communication with HC through DDF interface.
46 *
47 * Notes for async methods:
48 *
49 * Methods for sending data to device (OUT transactions)
50 * - e.g. IPC_M_USBHC_INTERRUPT_OUT -
51 * always use the same semantics:
52 * - first, IPC call with given method is made
53 * - argument #1 is target address
54 * - argument #2 is target endpoint
55 * - argument #3 is max packet size of the endpoint
56 * - this call is immediately followed by IPC data write (from caller)
57 * - the initial call (and the whole transaction) is answer after the
58 * transaction is scheduled by the HC and acknowledged by the device
59 * or immediately after error is detected
60 * - the answer carries only the error code
61 *
62 * Methods for retrieving data from device (IN transactions)
63 * - e.g. IPC_M_USBHC_INTERRUPT_IN -
64 * also use the same semantics:
65 * - first, IPC call with given method is made
66 * - argument #1 is target address
67 * - argument #2 is target endpoint
68 * - this call is immediately followed by IPC data read (async version)
69 * - the call is not answered until the device returns some data (or until
70 * error occurs)
71 *
72 * Some special methods (NO-DATA transactions) do not send any data. These
73 * might behave as both OUT or IN transactions because communication parts
74 * where actual buffers are exchanged are omitted.
75 **
76 * For all these methods, wrap functions exists. Important rule: functions
77 * for IN transactions have (as parameters) buffers where retrieved data
78 * will be stored. These buffers must be already allocated and shall not be
79 * touch until the transaction is completed
80 * (e.g. not before calling usb_wait_for() with appropriate handle).
81 * OUT transactions buffers can be freed immediately after call is dispatched
82 * (i.e. after return from wrapping function).
83 *
84 */
85typedef enum {
86 /** Get handle binded with given USB address.
87 * Parameters
88 * - USB address
89 * Answer:
90 * - EOK - address binded, first parameter is the devman handle
91 * - ENOENT - address is not in use at the moment
92 */
93 IPC_M_USBHC_GET_HANDLE_BY_ADDRESS,
94
95 /** Register endpoint attributes at host controller.
96 * This is used to reserve portion of USB bandwidth.
97 * When speed is invalid, speed of the device is used.
98 * Parameters:
99 * - USB address + endpoint number
100 * - packed as ADDR << 16 + EP
101 * - speed + transfer type + direction
102 * - packed as ( SPEED << 8 + TYPE ) << 8 + DIR
103 * - maximum packet size + interval (in milliseconds)
104 * - packed as MPS << 16 + INT
105 * Answer:
106 * - EOK - reservation successful
107 * - ELIMIT - not enough bandwidth to satisfy the request
108 */
109 IPC_M_USBHC_REGISTER_ENDPOINT,
110
111 /** Revert endpoint registration.
112 * Parameters:
113 * - USB address
114 * - endpoint number
115 * - data direction
116 * Answer:
117 * - EOK - endpoint unregistered
118 * - ENOENT - unknown endpoint
119 */
120 IPC_M_USBHC_UNREGISTER_ENDPOINT,
121
122 /** Get data from device.
123 * See explanation at usb_iface_funcs_t (IN transaction).
124 */
125 IPC_M_USBHC_READ,
126
127 /** Send data to device.
128 * See explanation at usb_iface_funcs_t (OUT transaction).
129 */
130 IPC_M_USBHC_WRITE,
131} usbhc_iface_funcs_t;
132
[a76b01b4]133
134
[02fc5c4]135int usbhc_get_handle(async_exch_t *exch, usb_address_t address,
136 devman_handle_t *handle)
137{
138 if (!exch)
[8afeb04]139 return EBADMEM;
[02fc5c4]140 sysarg_t h;
141 const int ret = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
142 IPC_M_USBHC_GET_HANDLE_BY_ADDRESS, address, &h);
143 if (ret == EOK && handle)
144 *handle = (devman_handle_t)h;
145 return ret;
146}
[a76b01b4]147
[02fc5c4]148int usbhc_register_endpoint(async_exch_t *exch, usb_address_t address,
149 usb_endpoint_t endpoint, usb_transfer_type_t type,
150 usb_direction_t direction, size_t mps, unsigned interval)
151{
152 if (!exch)
[8afeb04]153 return EBADMEM;
[02fc5c4]154 const usb_target_t target =
155 {{ .address = address, .endpoint = endpoint }};
156#define _PACK2(high, low) (((high & 0xffff) << 16) | (low & 0xffff))
157
158 return async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
159 IPC_M_USBHC_REGISTER_ENDPOINT, target.packed,
160 _PACK2(type, direction), _PACK2(mps, interval));
161
162#undef _PACK2
163}
[a76b01b4]164
[02fc5c4]165int usbhc_unregister_endpoint(async_exch_t *exch, usb_address_t address,
166 usb_endpoint_t endpoint, usb_direction_t direction)
167{
168 if (!exch)
[8afeb04]169 return EBADMEM;
[02fc5c4]170 return async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
171 IPC_M_USBHC_UNREGISTER_ENDPOINT, address, endpoint, direction);
172}
[a76b01b4]173
[02fc5c4]174int usbhc_read(async_exch_t *exch, usb_address_t address,
175 usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size,
176 size_t *rec_size)
177{
[8afeb04]178 if (!exch)
179 return EBADMEM;
180
[02fc5c4]181 if (size == 0 && setup == 0)
182 return EOK;
183
184 const usb_target_t target =
185 {{ .address = address, .endpoint = endpoint }};
186
187 /* Make call identifying target USB device and type of transfer. */
188 aid_t opening_request = async_send_4(exch,
189 DEV_IFACE_ID(USBHC_DEV_IFACE),
190 IPC_M_USBHC_READ, target.packed,
191 (setup & UINT32_MAX), (setup >> 32), NULL);
192
193 if (opening_request == 0) {
194 return ENOMEM;
195 }
196
197 /* Retrieve the data. */
198 ipc_call_t data_request_call;
199 aid_t data_request =
200 async_data_read(exch, data, size, &data_request_call);
201
202 if (data_request == 0) {
203 // FIXME: How to let the other side know that we want to abort?
[50b581d]204 async_forget(opening_request);
[02fc5c4]205 return ENOMEM;
206 }
207
208 /* Wait for the answer. */
209 sysarg_t data_request_rc;
210 sysarg_t opening_request_rc;
211 async_wait_for(data_request, &data_request_rc);
212 async_wait_for(opening_request, &opening_request_rc);
213
214 if (data_request_rc != EOK) {
215 /* Prefer the return code of the opening request. */
216 if (opening_request_rc != EOK) {
217 return (int) opening_request_rc;
218 } else {
219 return (int) data_request_rc;
220 }
221 }
222 if (opening_request_rc != EOK) {
223 return (int) opening_request_rc;
224 }
225
226 *rec_size = IPC_GET_ARG2(data_request_call);
227 return EOK;
228}
[a76b01b4]229
[02fc5c4]230int usbhc_write(async_exch_t *exch, usb_address_t address,
231 usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size)
232{
[8afeb04]233 if (!exch)
234 return EBADMEM;
235
[02fc5c4]236 if (size == 0 && setup == 0)
237 return EOK;
238
239 const usb_target_t target =
240 {{ .address = address, .endpoint = endpoint }};
241
242 aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
243 IPC_M_USBHC_WRITE, target.packed, size,
244 (setup & UINT32_MAX), (setup >> 32), NULL);
245
246 if (opening_request == 0) {
247 return ENOMEM;
248 }
249
250 /* Send the data if any. */
251 if (size > 0) {
252 const int ret = async_data_write_start(exch, data, size);
253 if (ret != EOK) {
[50b581d]254 async_forget(opening_request);
[02fc5c4]255 return ret;
256 }
257 }
258
259 /* Wait for the answer. */
260 sysarg_t opening_request_rc;
261 async_wait_for(opening_request, &opening_request_rc);
262
263 return (int) opening_request_rc;
264}
[a76b01b4]265
[02fc5c4]266
267static void remote_usbhc_get_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
[b7d8fd9]268static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
269static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
[bbce2c2]270static void remote_usbhc_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
271static void remote_usbhc_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
[eb1a2f4]272//static void remote_usbhc(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
[91db50ac]273
[6edd494]274/** Remote USB host controller interface operations. */
[ffe3fe1]275static remote_iface_func_ptr_t remote_usbhc_iface_ops[] = {
[02fc5c4]276 [IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_get_handle,
[6f04905]277
[1e647c7d]278 [IPC_M_USBHC_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
279 [IPC_M_USBHC_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint,
[0a46c41e]280
[bbce2c2]281 [IPC_M_USBHC_READ] = remote_usbhc_read,
282 [IPC_M_USBHC_WRITE] = remote_usbhc_write,
[91db50ac]283};
284
[6edd494]285/** Remote USB host controller interface structure.
[91db50ac]286 */
[cb59f787]287remote_iface_t remote_usbhc_iface = {
288 .method_count = sizeof(remote_usbhc_iface_ops) /
289 sizeof(remote_usbhc_iface_ops[0]),
290 .methods = remote_usbhc_iface_ops
[91db50ac]291};
292
[1b22bd4]293typedef struct {
294 ipc_callid_t caller;
[0a6fa9f]295 ipc_callid_t data_caller;
[1b22bd4]296 void *buffer;
297} async_transaction_t;
[91db50ac]298
[93f8da1]299static void async_transaction_destroy(async_transaction_t *trans)
300{
301 if (trans == NULL) {
302 return;
303 }
304 if (trans->buffer != NULL) {
305 free(trans->buffer);
306 }
307
308 free(trans);
309}
310
311static async_transaction_t *async_transaction_create(ipc_callid_t caller)
312{
313 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
314 if (trans == NULL) {
315 return NULL;
316 }
317
318 trans->caller = caller;
[0a6fa9f]319 trans->data_caller = 0;
[93f8da1]320 trans->buffer = NULL;
321
322 return trans;
323}
[a76b01b4]324
325
[02fc5c4]326void remote_usbhc_get_handle(ddf_fun_t *fun, void *iface,
[eb2f7dd]327 ipc_callid_t callid, ipc_call_t *call)
328{
[02fc5c4]329 const usbhc_iface_t *usb_iface = iface;
[eb2f7dd]330
[02fc5c4]331 if (!usb_iface->get_handle) {
[eb2f7dd]332 async_answer_0(callid, ENOTSUP);
333 return;
334 }
335
[02fc5c4]336 const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
[eb2f7dd]337 devman_handle_t handle;
[02fc5c4]338 const int ret = usb_iface->get_handle(fun, address, &handle);
[eb2f7dd]339
[02fc5c4]340 if (ret == EOK) {
341 async_answer_1(callid, ret, handle);
[eb2f7dd]342 } else {
[02fc5c4]343 async_answer_0(callid, ret);
[eb2f7dd]344 }
345}
[a76b01b4]346
347
[8f68913f]348static void callback_out(int outcome, void *arg)
[1b22bd4]349{
[272f46f8]350 async_transaction_t *trans = arg;
[1b22bd4]351
[17aca1c]352 async_answer_0(trans->caller, outcome);
[1b22bd4]353
[93f8da1]354 async_transaction_destroy(trans);
[1b22bd4]355}
[a76b01b4]356
[8f68913f]357static void callback_in(int outcome, size_t actual_size, void *arg)
[1b22bd4]358{
359 async_transaction_t *trans = (async_transaction_t *)arg;
360
[daec5e04]361 if (outcome != EOK) {
[17aca1c]362 async_answer_0(trans->caller, outcome);
[5842493]363 if (trans->data_caller) {
364 async_answer_0(trans->data_caller, EINTR);
365 }
[93f8da1]366 async_transaction_destroy(trans);
367 return;
368 }
[1b22bd4]369
[0a6fa9f]370 if (trans->data_caller) {
371 async_data_read_finalize(trans->data_caller,
372 trans->buffer, actual_size);
373 }
374
[daec5e04]375 async_answer_0(trans->caller, EOK);
[1e64b250]376
377 async_transaction_destroy(trans);
[91db50ac]378}
[a76b01b4]379
[b7d8fd9]380void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
381 ipc_callid_t callid, ipc_call_t *call)
382{
383 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
384
385 if (!usb_iface->register_endpoint) {
386 async_answer_0(callid, ENOTSUP);
387 return;
388 }
389
[1998bcd]390#define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \
[27736cf]391 type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) >> 16)
[1998bcd]392#define _INIT_FROM_LOW_DATA2(type, var, arg_no) \
[27736cf]393 type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) & 0xffff)
[1998bcd]394
[365e29e2]395 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
[1998bcd]396
[27736cf]397 _INIT_FROM_HIGH_DATA2(usb_transfer_type_t, transfer_type, 2);
398 _INIT_FROM_LOW_DATA2(usb_direction_t, direction, 2);
[1998bcd]399
400 _INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3);
401 _INIT_FROM_LOW_DATA2(unsigned int, interval, 3);
402
403#undef _INIT_FROM_HIGH_DATA2
404#undef _INIT_FROM_LOW_DATA2
405
[27736cf]406 int rc = usb_iface->register_endpoint(fun, target.address,
[bdd8ad2f]407 target.endpoint, transfer_type, direction, max_packet_size, interval);
[b7d8fd9]408
409 async_answer_0(callid, rc);
410}
411
412void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
413 ipc_callid_t callid, ipc_call_t *call)
414{
415 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
416
417 if (!usb_iface->unregister_endpoint) {
418 async_answer_0(callid, ENOTSUP);
419 return;
420 }
421
422 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
423 usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG2(*call);
424 usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG3(*call);
425
426 int rc = usb_iface->unregister_endpoint(fun,
427 address, endpoint, direction);
428
429 async_answer_0(callid, rc);
430}
431
[bbce2c2]432void remote_usbhc_read(
[ffe3fe1]433 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
434{
435 assert(fun);
436 assert(iface);
437 assert(call);
438
439 const usbhc_iface_t *hc_iface = iface;
440
441 if (!hc_iface->read) {
442 async_answer_0(callid, ENOTSUP);
443 return;
444 }
445
[365e29e2]446 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
[bdd8ad2f]447 const uint64_t setup =
448 ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
449 (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
[ffe3fe1]450
451 async_transaction_t *trans = async_transaction_create(callid);
452 if (trans == NULL) {
453 async_answer_0(callid, ENOMEM);
454 return;
455 }
456
[272f46f8]457 size_t size = 0;
458 if (!async_data_read_receive(&trans->data_caller, &size)) {
[ffe3fe1]459 async_answer_0(callid, EPARTY);
460 return;
461 }
462
[272f46f8]463 trans->buffer = malloc(size);
[ffe3fe1]464 if (trans->buffer == NULL) {
465 async_answer_0(trans->data_caller, ENOMEM);
466 async_answer_0(callid, ENOMEM);
467 async_transaction_destroy(trans);
468 }
469
470 const int rc = hc_iface->read(
[272f46f8]471 fun, target, setup, trans->buffer, size, callback_in, trans);
[ffe3fe1]472
473 if (rc != EOK) {
474 async_answer_0(trans->data_caller, rc);
475 async_answer_0(callid, rc);
476 async_transaction_destroy(trans);
477 }
478}
[a76b01b4]479
[bbce2c2]480void remote_usbhc_write(
[ffe3fe1]481 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
482{
483 assert(fun);
484 assert(iface);
485 assert(call);
486
487 const usbhc_iface_t *hc_iface = iface;
488
489 if (!hc_iface->write) {
490 async_answer_0(callid, ENOTSUP);
491 return;
492 }
493
[365e29e2]494 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
[bdd8ad2f]495 const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
496 const uint64_t setup =
497 ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
498 (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
[ffe3fe1]499
500 async_transaction_t *trans = async_transaction_create(callid);
501 if (trans == NULL) {
502 async_answer_0(callid, ENOMEM);
503 return;
504 }
505
[272f46f8]506 size_t size = 0;
[bdd8ad2f]507 if (data_buffer_len > 0) {
[272f46f8]508 const int rc = async_data_write_accept(&trans->buffer, false,
[bdd8ad2f]509 1, USB_MAX_PAYLOAD_SIZE,
[272f46f8]510 0, &size);
[ffe3fe1]511
[bdd8ad2f]512 if (rc != EOK) {
513 async_answer_0(callid, rc);
514 async_transaction_destroy(trans);
515 return;
516 }
[ffe3fe1]517 }
518
[272f46f8]519 const int rc = hc_iface->write(
520 fun, target, setup, trans->buffer, size, callback_out, trans);
[ffe3fe1]521
522 if (rc != EOK) {
523 async_answer_0(callid, rc);
524 async_transaction_destroy(trans);
525 }
526}
[91db50ac]527/**
528 * @}
529 */
Note: See TracBrowser for help on using the repository browser.