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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5842493 was 5842493, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

Fix call leakage

Data read call is always answered.

  • Property mode set to 100644
File size: 16.9 KB
RevLine 
[91db50ac]1/*
[9753220]2 * Copyright (c) 2010-2011 Vojtech Horky
[91db50ac]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libdrv
30 * @{
31 */
32/** @file
33 */
34
35#include <async.h>
36#include <errno.h>
37
[cb59f787]38#include "usbhc_iface.h"
[91db50ac]39#include "driver.h"
40
[1b22bd4]41#define USB_MAX_PAYLOAD_SIZE 1020
42
[aae339e9]43static void remote_usbhc_get_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
[cb59f787]44static void remote_usbhc_interrupt_out(device_t *, void *, ipc_callid_t, ipc_call_t *);
45static void remote_usbhc_interrupt_in(device_t *, void *, ipc_callid_t, ipc_call_t *);
[a3dfb2e]46static void remote_usbhc_control_write_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
47static void remote_usbhc_control_write_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
48static void remote_usbhc_control_write_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
49static void remote_usbhc_control_read_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
50static void remote_usbhc_control_read_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
51static void remote_usbhc_control_read_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
[9753220]52static void remote_usbhc_control_write(device_t *, void *, ipc_callid_t, ipc_call_t *);
53static void remote_usbhc_control_read(device_t *, void *, ipc_callid_t, ipc_call_t *);
[6f04905]54static void remote_usbhc_reserve_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
55static void remote_usbhc_release_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
56static void remote_usbhc_request_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
[4689d40]57static void remote_usbhc_bind_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
[6f04905]58static void remote_usbhc_release_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
[a3dfb2e]59//static void remote_usbhc(device_t *, void *, ipc_callid_t, ipc_call_t *);
[91db50ac]60
[6edd494]61/** Remote USB host controller interface operations. */
[cb59f787]62static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
[aae339e9]63 remote_usbhc_get_address,
[6f04905]64
65 remote_usbhc_reserve_default_address,
66 remote_usbhc_release_default_address,
67
68 remote_usbhc_request_address,
[4689d40]69 remote_usbhc_bind_address,
[6f04905]70 remote_usbhc_release_address,
71
[aae339e9]72 remote_usbhc_interrupt_out,
[a3dfb2e]73 remote_usbhc_interrupt_in,
[6f04905]74
[a3dfb2e]75 remote_usbhc_control_write_setup,
76 remote_usbhc_control_write_data,
77 remote_usbhc_control_write_status,
[6f04905]78
[a3dfb2e]79 remote_usbhc_control_read_setup,
80 remote_usbhc_control_read_data,
[9753220]81 remote_usbhc_control_read_status,
82
83 remote_usbhc_control_write,
84 remote_usbhc_control_read
[91db50ac]85};
86
[6edd494]87/** Remote USB host controller interface structure.
[91db50ac]88 */
[cb59f787]89remote_iface_t remote_usbhc_iface = {
90 .method_count = sizeof(remote_usbhc_iface_ops) /
91 sizeof(remote_usbhc_iface_ops[0]),
92 .methods = remote_usbhc_iface_ops
[91db50ac]93};
94
[1b22bd4]95typedef struct {
96 ipc_callid_t caller;
[0a6fa9f]97 ipc_callid_t data_caller;
[1b22bd4]98 void *buffer;
[9753220]99 void *setup_packet;
[1b22bd4]100 size_t size;
101} async_transaction_t;
[91db50ac]102
[93f8da1]103static void async_transaction_destroy(async_transaction_t *trans)
104{
105 if (trans == NULL) {
106 return;
107 }
108
109 if (trans->setup_packet != NULL) {
110 free(trans->setup_packet);
111 }
112 if (trans->buffer != NULL) {
113 free(trans->buffer);
114 }
115
116 free(trans);
117}
118
119static async_transaction_t *async_transaction_create(ipc_callid_t caller)
120{
121 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
122 if (trans == NULL) {
123 return NULL;
124 }
125
126 trans->caller = caller;
[0a6fa9f]127 trans->data_caller = 0;
[93f8da1]128 trans->buffer = NULL;
129 trans->setup_packet = NULL;
130 trans->size = 0;
131
132 return trans;
133}
134
[aae339e9]135void remote_usbhc_get_address(device_t *device, void *iface,
136 ipc_callid_t callid, ipc_call_t *call)
137{
138 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
139
140 if (!usb_iface->tell_address) {
[17aca1c]141 async_answer_0(callid, ENOTSUP);
[aae339e9]142 return;
143 }
144
[eac610e]145 devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
[aae339e9]146
147 usb_address_t address;
148 int rc = usb_iface->tell_address(device, handle, &address);
149 if (rc != EOK) {
[17aca1c]150 async_answer_0(callid, rc);
[aae339e9]151 } else {
[17aca1c]152 async_answer_1(callid, EOK, address);
[aae339e9]153 }
154}
[91db50ac]155
[6f04905]156void remote_usbhc_reserve_default_address(device_t *device, void *iface,
157 ipc_callid_t callid, ipc_call_t *call)
158{
159 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
160
161 if (!usb_iface->reserve_default_address) {
[17aca1c]162 async_answer_0(callid, ENOTSUP);
[6f04905]163 return;
164 }
165
166 int rc = usb_iface->reserve_default_address(device);
167
[17aca1c]168 async_answer_0(callid, rc);
[6f04905]169}
170
171void remote_usbhc_release_default_address(device_t *device, void *iface,
172 ipc_callid_t callid, ipc_call_t *call)
173{
174 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
175
176 if (!usb_iface->release_default_address) {
[17aca1c]177 async_answer_0(callid, ENOTSUP);
[6f04905]178 return;
179 }
180
181 int rc = usb_iface->release_default_address(device);
182
[17aca1c]183 async_answer_0(callid, rc);
[6f04905]184}
185
186void remote_usbhc_request_address(device_t *device, void *iface,
187 ipc_callid_t callid, ipc_call_t *call)
188{
189 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
190
191 if (!usb_iface->request_address) {
[17aca1c]192 async_answer_0(callid, ENOTSUP);
[6f04905]193 return;
194 }
195
196 usb_address_t address;
197 int rc = usb_iface->request_address(device, &address);
198 if (rc != EOK) {
[17aca1c]199 async_answer_0(callid, rc);
[6f04905]200 } else {
[17aca1c]201 async_answer_1(callid, EOK, (sysarg_t) address);
[6f04905]202 }
203}
204
[4689d40]205void remote_usbhc_bind_address(device_t *device, void *iface,
206 ipc_callid_t callid, ipc_call_t *call)
207{
208 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
209
210 if (!usb_iface->bind_address) {
[17aca1c]211 async_answer_0(callid, ENOTSUP);
[4689d40]212 return;
213 }
214
[eac610e]215 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
216 devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
[4689d40]217
218 int rc = usb_iface->bind_address(device, address, handle);
219
[17aca1c]220 async_answer_0(callid, rc);
[4689d40]221}
222
[6f04905]223void remote_usbhc_release_address(device_t *device, void *iface,
224 ipc_callid_t callid, ipc_call_t *call)
225{
226 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
227
228 if (!usb_iface->release_address) {
[17aca1c]229 async_answer_0(callid, ENOTSUP);
[6f04905]230 return;
231 }
232
[eac610e]233 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
[6f04905]234
235 int rc = usb_iface->release_address(device, address);
236
[17aca1c]237 async_answer_0(callid, rc);
[6f04905]238}
239
[1b22bd4]240
241static void callback_out(device_t *device,
242 usb_transaction_outcome_t outcome, void *arg)
243{
244 async_transaction_t *trans = (async_transaction_t *)arg;
245
[17aca1c]246 async_answer_0(trans->caller, outcome);
[1b22bd4]247
[93f8da1]248 async_transaction_destroy(trans);
[1b22bd4]249}
250
251static void callback_in(device_t *device,
252 usb_transaction_outcome_t outcome, size_t actual_size, void *arg)
253{
254 async_transaction_t *trans = (async_transaction_t *)arg;
255
[93f8da1]256 if (outcome != USB_OUTCOME_OK) {
[17aca1c]257 async_answer_0(trans->caller, outcome);
[5842493]258 if (trans->data_caller) {
259 async_answer_0(trans->data_caller, EINTR);
260 }
[93f8da1]261 async_transaction_destroy(trans);
262 return;
263 }
[1b22bd4]264
265 trans->size = actual_size;
[0a6fa9f]266
267 if (trans->data_caller) {
268 async_data_read_finalize(trans->data_caller,
269 trans->buffer, actual_size);
270 }
271
272 async_answer_0(trans->caller, USB_OUTCOME_OK);
[1e64b250]273
274 async_transaction_destroy(trans);
[91db50ac]275}
276
[fb1dca09]277/** Process an outgoing transfer (both OUT and SETUP).
278 *
279 * @param device Target device.
280 * @param callid Initiating caller.
281 * @param call Initiating call.
282 * @param transfer_func Transfer function (might be NULL).
283 */
284static void remote_usbhc_out_transfer(device_t *device,
285 ipc_callid_t callid, ipc_call_t *call,
286 usbhc_iface_transfer_out_t transfer_func)
[91db50ac]287{
[fb1dca09]288 if (!transfer_func) {
[17aca1c]289 async_answer_0(callid, ENOTSUP);
[fb1dca09]290 return;
291 }
[1b22bd4]292
[eac610e]293 size_t expected_len = DEV_IPC_GET_ARG3(*call);
[1b22bd4]294 usb_target_t target = {
[eac610e]295 .address = DEV_IPC_GET_ARG1(*call),
296 .endpoint = DEV_IPC_GET_ARG2(*call)
[1b22bd4]297 };
298
299 size_t len = 0;
300 void *buffer = NULL;
301 if (expected_len > 0) {
302 int rc = async_data_write_accept(&buffer, false,
303 1, USB_MAX_PAYLOAD_SIZE,
304 0, &len);
305
306 if (rc != EOK) {
[17aca1c]307 async_answer_0(callid, rc);
[1b22bd4]308 return;
309 }
310 }
311
[93f8da1]312 async_transaction_t *trans = async_transaction_create(callid);
313 if (trans == NULL) {
314 if (buffer != NULL) {
315 free(buffer);
316 }
[17aca1c]317 async_answer_0(callid, ENOMEM);
[93f8da1]318 return;
319 }
320
[fb1dca09]321 trans->buffer = buffer;
322 trans->size = len;
[1b22bd4]323
[fb1dca09]324 int rc = transfer_func(device, target, buffer, len,
[1b22bd4]325 callback_out, trans);
326
327 if (rc != EOK) {
[17aca1c]328 async_answer_0(callid, rc);
[93f8da1]329 async_transaction_destroy(trans);
[1b22bd4]330 }
[91db50ac]331}
332
[fb1dca09]333/** Process an incoming transfer.
334 *
335 * @param device Target device.
336 * @param callid Initiating caller.
337 * @param call Initiating call.
338 * @param transfer_func Transfer function (might be NULL).
339 */
340static void remote_usbhc_in_transfer(device_t *device,
341 ipc_callid_t callid, ipc_call_t *call,
342 usbhc_iface_transfer_in_t transfer_func)
[91db50ac]343{
[fb1dca09]344 if (!transfer_func) {
[17aca1c]345 async_answer_0(callid, ENOTSUP);
[fb1dca09]346 return;
347 }
[1b22bd4]348
[eac610e]349 size_t len = DEV_IPC_GET_ARG3(*call);
[1b22bd4]350 usb_target_t target = {
[eac610e]351 .address = DEV_IPC_GET_ARG1(*call),
352 .endpoint = DEV_IPC_GET_ARG2(*call)
[1b22bd4]353 };
354
[0a6fa9f]355 ipc_callid_t data_callid;
356 if (!async_data_read_receive(&data_callid, &len)) {
357 async_answer_0(callid, EPARTY);
358 return;
359 }
360
[93f8da1]361 async_transaction_t *trans = async_transaction_create(callid);
362 if (trans == NULL) {
[17aca1c]363 async_answer_0(callid, ENOMEM);
[93f8da1]364 return;
365 }
[0a6fa9f]366 trans->data_caller = data_callid;
[1b22bd4]367 trans->buffer = malloc(len);
368 trans->size = len;
369
[fb1dca09]370 int rc = transfer_func(device, target, trans->buffer, len,
[1b22bd4]371 callback_in, trans);
372
373 if (rc != EOK) {
[17aca1c]374 async_answer_0(callid, rc);
[93f8da1]375 async_transaction_destroy(trans);
[1b22bd4]376 }
[91db50ac]377}
378
[fb1dca09]379/** Process status part of control transfer.
380 *
381 * @param device Target device.
382 * @param callid Initiating caller.
383 * @param call Initiating call.
384 * @param direction Transfer direction (read ~ in, write ~ out).
385 * @param transfer_in_func Transfer function for control read (might be NULL).
386 * @param transfer_out_func Transfer function for control write (might be NULL).
387 */
388static void remote_usbhc_status_transfer(device_t *device,
389 ipc_callid_t callid, ipc_call_t *call,
390 usb_direction_t direction,
391 int (*transfer_in_func)(device_t *, usb_target_t,
392 usbhc_iface_transfer_in_callback_t, void *),
393 int (*transfer_out_func)(device_t *, usb_target_t,
394 usbhc_iface_transfer_out_callback_t, void *))
[a3dfb2e]395{
[fb1dca09]396 switch (direction) {
397 case USB_DIRECTION_IN:
398 if (!transfer_in_func) {
[17aca1c]399 async_answer_0(callid, ENOTSUP);
[fb1dca09]400 return;
401 }
402 break;
403 case USB_DIRECTION_OUT:
404 if (!transfer_out_func) {
[17aca1c]405 async_answer_0(callid, ENOTSUP);
[fb1dca09]406 return;
407 }
408 break;
409 default:
410 assert(false && "unreachable code");
411 break;
412 }
[a3dfb2e]413
414 usb_target_t target = {
[eac610e]415 .address = DEV_IPC_GET_ARG1(*call),
416 .endpoint = DEV_IPC_GET_ARG2(*call)
[a3dfb2e]417 };
418
[93f8da1]419 async_transaction_t *trans = async_transaction_create(callid);
420 if (trans == NULL) {
[17aca1c]421 async_answer_0(callid, ENOMEM);
[93f8da1]422 return;
423 }
[a3dfb2e]424
[fb1dca09]425 int rc;
426 switch (direction) {
427 case USB_DIRECTION_IN:
428 rc = transfer_in_func(device, target,
429 callback_in, trans);
430 break;
431 case USB_DIRECTION_OUT:
432 rc = transfer_out_func(device, target,
433 callback_out, trans);
434 break;
435 default:
436 assert(false && "unreachable code");
437 break;
438 }
[a3dfb2e]439
440 if (rc != EOK) {
[17aca1c]441 async_answer_0(callid, rc);
[93f8da1]442 async_transaction_destroy(trans);
[a3dfb2e]443 }
444}
445
[fb1dca09]446
447void remote_usbhc_interrupt_out(device_t *device, void *iface,
448 ipc_callid_t callid, ipc_call_t *call)
[a3dfb2e]449{
450 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
[fb1dca09]451 assert(usb_iface != NULL);
[a3dfb2e]452
[fb1dca09]453 return remote_usbhc_out_transfer(device, callid, call,
454 usb_iface->interrupt_out);
455}
[a3dfb2e]456
[fb1dca09]457void remote_usbhc_interrupt_in(device_t *device, void *iface,
458 ipc_callid_t callid, ipc_call_t *call)
459{
460 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
461 assert(usb_iface != NULL);
[a3dfb2e]462
[fb1dca09]463 return remote_usbhc_in_transfer(device, callid, call,
464 usb_iface->interrupt_in);
465}
[a3dfb2e]466
[fb1dca09]467void remote_usbhc_control_write_setup(device_t *device, void *iface,
468 ipc_callid_t callid, ipc_call_t *call)
469{
470 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
471 assert(usb_iface != NULL);
[a3dfb2e]472
[fb1dca09]473 return remote_usbhc_out_transfer(device, callid, call,
474 usb_iface->control_write_setup);
475}
[a3dfb2e]476
[fb1dca09]477void remote_usbhc_control_write_data(device_t *device, void *iface,
478 ipc_callid_t callid, ipc_call_t *call)
479{
480 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
481 assert(usb_iface != NULL);
[a3dfb2e]482
[fb1dca09]483 return remote_usbhc_out_transfer(device, callid, call,
484 usb_iface->control_write_data);
[a3dfb2e]485}
486
487void remote_usbhc_control_write_status(device_t *device, void *iface,
[fb1dca09]488 ipc_callid_t callid, ipc_call_t *call)
[a3dfb2e]489{
490 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
[fb1dca09]491 assert(usb_iface != NULL);
[a3dfb2e]492
[fb1dca09]493 return remote_usbhc_status_transfer(device, callid, call,
494 USB_DIRECTION_IN, usb_iface->control_write_status, NULL);
[a3dfb2e]495}
496
497void remote_usbhc_control_read_setup(device_t *device, void *iface,
[fb1dca09]498 ipc_callid_t callid, ipc_call_t *call)
[a3dfb2e]499{
500 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
[fb1dca09]501 assert(usb_iface != NULL);
[a3dfb2e]502
[fb1dca09]503 return remote_usbhc_out_transfer(device, callid, call,
504 usb_iface->control_read_setup);
[a3dfb2e]505}
506
507void remote_usbhc_control_read_data(device_t *device, void *iface,
508 ipc_callid_t callid, ipc_call_t *call)
509{
510 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
[fb1dca09]511 assert(usb_iface != NULL);
[a3dfb2e]512
[fb1dca09]513 return remote_usbhc_in_transfer(device, callid, call,
514 usb_iface->control_read_data);
[a3dfb2e]515}
516
517void remote_usbhc_control_read_status(device_t *device, void *iface,
518 ipc_callid_t callid, ipc_call_t *call)
519{
520 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
[fb1dca09]521 assert(usb_iface != NULL);
[a3dfb2e]522
[fb1dca09]523 return remote_usbhc_status_transfer(device, callid, call,
524 USB_DIRECTION_OUT, NULL, usb_iface->control_read_status);
[a3dfb2e]525}
526
[9753220]527void remote_usbhc_control_write(device_t *device, void *iface,
528ipc_callid_t callid, ipc_call_t *call)
529{
530 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
531 assert(usb_iface != NULL);
532
533 if (!usb_iface->control_write) {
[17aca1c]534 async_answer_0(callid, ENOTSUP);
[9753220]535 return;
536 }
537
538 usb_target_t target = {
539 .address = DEV_IPC_GET_ARG1(*call),
540 .endpoint = DEV_IPC_GET_ARG2(*call)
541 };
542
543 int rc;
544
545 void *setup_packet = NULL;
546 void *data_buffer = NULL;
547 size_t setup_packet_len = 0;
548 size_t data_buffer_len = 0;
549
550 rc = async_data_write_accept(&setup_packet, false,
551 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
552 if (rc != EOK) {
[17aca1c]553 async_answer_0(callid, rc);
[9753220]554 return;
555 }
556 rc = async_data_write_accept(&data_buffer, false,
557 1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
558 if (rc != EOK) {
[17aca1c]559 async_answer_0(callid, rc);
[93f8da1]560 free(setup_packet);
[9753220]561 return;
562 }
563
[93f8da1]564 async_transaction_t *trans = async_transaction_create(callid);
565 if (trans == NULL) {
[17aca1c]566 async_answer_0(callid, ENOMEM);
[93f8da1]567 free(setup_packet);
568 free(data_buffer);
569 return;
570 }
[9753220]571 trans->setup_packet = setup_packet;
572 trans->buffer = data_buffer;
573 trans->size = data_buffer_len;
574
575 rc = usb_iface->control_write(device, target,
576 setup_packet, setup_packet_len,
577 data_buffer, data_buffer_len,
578 callback_out, trans);
579
580 if (rc != EOK) {
[17aca1c]581 async_answer_0(callid, rc);
[93f8da1]582 async_transaction_destroy(trans);
[9753220]583 }
584}
585
586
587void remote_usbhc_control_read(device_t *device, void *iface,
588ipc_callid_t callid, ipc_call_t *call)
589{
590 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
591 assert(usb_iface != NULL);
592
593 if (!usb_iface->control_read) {
[17aca1c]594 async_answer_0(callid, ENOTSUP);
[9753220]595 return;
596 }
597
598 size_t data_len = DEV_IPC_GET_ARG3(*call);
599 usb_target_t target = {
600 .address = DEV_IPC_GET_ARG1(*call),
601 .endpoint = DEV_IPC_GET_ARG2(*call)
602 };
603
604 int rc;
605
606 void *setup_packet = NULL;
607 size_t setup_packet_len = 0;
608
609 rc = async_data_write_accept(&setup_packet, false,
610 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
611 if (rc != EOK) {
[17aca1c]612 async_answer_0(callid, rc);
[9753220]613 return;
614 }
615
[0a6fa9f]616 ipc_callid_t data_callid;
617 if (!async_data_read_receive(&data_callid, &data_len)) {
618 async_answer_0(callid, EPARTY);
619 free(setup_packet);
620 return;
621 }
622
[93f8da1]623 async_transaction_t *trans = async_transaction_create(callid);
624 if (trans == NULL) {
[17aca1c]625 async_answer_0(callid, ENOMEM);
[93f8da1]626 free(setup_packet);
627 return;
628 }
[0a6fa9f]629 trans->data_caller = data_callid;
[9753220]630 trans->setup_packet = setup_packet;
631 trans->size = data_len;
[93f8da1]632 trans->buffer = malloc(data_len);
633 if (trans->buffer == NULL) {
[17aca1c]634 async_answer_0(callid, ENOMEM);
[93f8da1]635 async_transaction_destroy(trans);
636 return;
637 }
[9753220]638
639 rc = usb_iface->control_read(device, target,
640 setup_packet, setup_packet_len,
641 trans->buffer, trans->size,
642 callback_in, trans);
643
644 if (rc != EOK) {
[17aca1c]645 async_answer_0(callid, rc);
[93f8da1]646 async_transaction_destroy(trans);
[9753220]647 }
648}
649
[a3dfb2e]650
[1b22bd4]651
[91db50ac]652/**
653 * @}
654 */
Note: See TracBrowser for help on using the repository browser.