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

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

libdrv: Make driver ops structures constant

These are statically initialized and we don't modify them.
Moves cca 1KB (30%) of data from .data (rw) section to ro. (driver binaries, amd64)

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