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

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

Add IPC layer for endpoint (bandwidth) reservation

No HC driver currently implements this and no device driver uses this.
Some adjustments might be needed later.

  • Property mode set to 100644
File size: 15.0 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>
[eb1a2f4]37#include <assert.h>
[91db50ac]38
[cb59f787]39#include "usbhc_iface.h"
[eb1a2f4]40#include "ddf/driver.h"
[91db50ac]41
[1b22bd4]42#define USB_MAX_PAYLOAD_SIZE 1020
[ec59693]43#define HACK_MAX_PACKET_SIZE 8
44#define HACK_MAX_PACKET_SIZE_INTERRUPT_IN 4
[1b22bd4]45
[eb1a2f4]46static void remote_usbhc_interrupt_out(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
47static void remote_usbhc_interrupt_in(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
48static void remote_usbhc_bulk_out(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
49static void remote_usbhc_bulk_in(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
50static void remote_usbhc_control_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
51static void remote_usbhc_control_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
52static void remote_usbhc_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
53static void remote_usbhc_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
54static void remote_usbhc_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
55static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
56static void remote_usbhc_release_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
[b7d8fd9]57static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
58static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
[eb1a2f4]59//static void remote_usbhc(ddf_fun_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 [] = {
[6f04905]63 remote_usbhc_reserve_default_address,
64 remote_usbhc_release_default_address,
65
66 remote_usbhc_request_address,
[4689d40]67 remote_usbhc_bind_address,
[6f04905]68 remote_usbhc_release_address,
69
[aae339e9]70 remote_usbhc_interrupt_out,
[a3dfb2e]71 remote_usbhc_interrupt_in,
[6f04905]72
[0a46c41e]73 remote_usbhc_bulk_out,
74 remote_usbhc_bulk_in,
75
[9753220]76 remote_usbhc_control_write,
[b7d8fd9]77 remote_usbhc_control_read,
78
79 remote_usbhc_register_endpoint,
80 remote_usbhc_unregister_endpoint
[91db50ac]81};
82
[6edd494]83/** Remote USB host controller interface structure.
[91db50ac]84 */
[cb59f787]85remote_iface_t remote_usbhc_iface = {
86 .method_count = sizeof(remote_usbhc_iface_ops) /
87 sizeof(remote_usbhc_iface_ops[0]),
88 .methods = remote_usbhc_iface_ops
[91db50ac]89};
90
[1b22bd4]91typedef struct {
92 ipc_callid_t caller;
[0a6fa9f]93 ipc_callid_t data_caller;
[1b22bd4]94 void *buffer;
[9753220]95 void *setup_packet;
[1b22bd4]96 size_t size;
97} async_transaction_t;
[91db50ac]98
[93f8da1]99static void async_transaction_destroy(async_transaction_t *trans)
100{
101 if (trans == NULL) {
102 return;
103 }
104
105 if (trans->setup_packet != NULL) {
106 free(trans->setup_packet);
107 }
108 if (trans->buffer != NULL) {
109 free(trans->buffer);
110 }
111
112 free(trans);
113}
114
115static async_transaction_t *async_transaction_create(ipc_callid_t caller)
116{
117 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
118 if (trans == NULL) {
119 return NULL;
120 }
121
122 trans->caller = caller;
[0a6fa9f]123 trans->data_caller = 0;
[93f8da1]124 trans->buffer = NULL;
125 trans->setup_packet = NULL;
126 trans->size = 0;
127
128 return trans;
129}
130
[eb1a2f4]131void remote_usbhc_reserve_default_address(ddf_fun_t *fun, void *iface,
[6f04905]132 ipc_callid_t callid, ipc_call_t *call)
133{
134 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
135
136 if (!usb_iface->reserve_default_address) {
[17aca1c]137 async_answer_0(callid, ENOTSUP);
[6f04905]138 return;
139 }
[6427cf67]140
[fa48ebe]141 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
[6427cf67]142
[eb1a2f4]143 int rc = usb_iface->reserve_default_address(fun, speed);
[6f04905]144
[17aca1c]145 async_answer_0(callid, rc);
[6f04905]146}
147
[eb1a2f4]148void remote_usbhc_release_default_address(ddf_fun_t *fun, void *iface,
[6f04905]149 ipc_callid_t callid, ipc_call_t *call)
150{
151 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
152
153 if (!usb_iface->release_default_address) {
[17aca1c]154 async_answer_0(callid, ENOTSUP);
[6f04905]155 return;
156 }
157
[eb1a2f4]158 int rc = usb_iface->release_default_address(fun);
[6f04905]159
[17aca1c]160 async_answer_0(callid, rc);
[6f04905]161}
162
[eb1a2f4]163void remote_usbhc_request_address(ddf_fun_t *fun, void *iface,
[6f04905]164 ipc_callid_t callid, ipc_call_t *call)
165{
166 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
167
168 if (!usb_iface->request_address) {
[17aca1c]169 async_answer_0(callid, ENOTSUP);
[6f04905]170 return;
171 }
[6427cf67]172
[fa48ebe]173 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
[6f04905]174
175 usb_address_t address;
[eb1a2f4]176 int rc = usb_iface->request_address(fun, speed, &address);
[6f04905]177 if (rc != EOK) {
[17aca1c]178 async_answer_0(callid, rc);
[6f04905]179 } else {
[17aca1c]180 async_answer_1(callid, EOK, (sysarg_t) address);
[6f04905]181 }
182}
183
[eb1a2f4]184void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface,
[4689d40]185 ipc_callid_t callid, ipc_call_t *call)
186{
187 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
188
189 if (!usb_iface->bind_address) {
[17aca1c]190 async_answer_0(callid, ENOTSUP);
[4689d40]191 return;
192 }
193
[eac610e]194 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
195 devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
[4689d40]196
[eb1a2f4]197 int rc = usb_iface->bind_address(fun, address, handle);
[4689d40]198
[17aca1c]199 async_answer_0(callid, rc);
[4689d40]200}
201
[eb1a2f4]202void remote_usbhc_release_address(ddf_fun_t *fun, void *iface,
[6f04905]203 ipc_callid_t callid, ipc_call_t *call)
204{
205 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
206
207 if (!usb_iface->release_address) {
[17aca1c]208 async_answer_0(callid, ENOTSUP);
[6f04905]209 return;
210 }
211
[eac610e]212 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
[6f04905]213
[eb1a2f4]214 int rc = usb_iface->release_address(fun, address);
[6f04905]215
[17aca1c]216 async_answer_0(callid, rc);
[6f04905]217}
218
[1b22bd4]219
[eb1a2f4]220static void callback_out(ddf_fun_t *fun,
[daec5e04]221 int outcome, void *arg)
[1b22bd4]222{
223 async_transaction_t *trans = (async_transaction_t *)arg;
224
[17aca1c]225 async_answer_0(trans->caller, outcome);
[1b22bd4]226
[93f8da1]227 async_transaction_destroy(trans);
[1b22bd4]228}
229
[eb1a2f4]230static void callback_in(ddf_fun_t *fun,
[daec5e04]231 int outcome, size_t actual_size, void *arg)
[1b22bd4]232{
233 async_transaction_t *trans = (async_transaction_t *)arg;
234
[daec5e04]235 if (outcome != EOK) {
[17aca1c]236 async_answer_0(trans->caller, outcome);
[5842493]237 if (trans->data_caller) {
238 async_answer_0(trans->data_caller, EINTR);
239 }
[93f8da1]240 async_transaction_destroy(trans);
241 return;
242 }
[1b22bd4]243
244 trans->size = actual_size;
[0a6fa9f]245
246 if (trans->data_caller) {
247 async_data_read_finalize(trans->data_caller,
248 trans->buffer, actual_size);
249 }
250
[daec5e04]251 async_answer_0(trans->caller, EOK);
[1e64b250]252
253 async_transaction_destroy(trans);
[91db50ac]254}
255
[fb1dca09]256/** Process an outgoing transfer (both OUT and SETUP).
257 *
258 * @param device Target device.
259 * @param callid Initiating caller.
260 * @param call Initiating call.
261 * @param transfer_func Transfer function (might be NULL).
262 */
[eb1a2f4]263static void remote_usbhc_out_transfer(ddf_fun_t *fun,
[fb1dca09]264 ipc_callid_t callid, ipc_call_t *call,
265 usbhc_iface_transfer_out_t transfer_func)
[91db50ac]266{
[fb1dca09]267 if (!transfer_func) {
[17aca1c]268 async_answer_0(callid, ENOTSUP);
[fb1dca09]269 return;
270 }
[1b22bd4]271
[228f251]272 size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
[1b22bd4]273 usb_target_t target = {
[eac610e]274 .address = DEV_IPC_GET_ARG1(*call),
275 .endpoint = DEV_IPC_GET_ARG2(*call)
[1b22bd4]276 };
277
278 size_t len = 0;
279 void *buffer = NULL;
280
[228f251]281 int rc = async_data_write_accept(&buffer, false,
282 1, USB_MAX_PAYLOAD_SIZE,
283 0, &len);
284
285 if (rc != EOK) {
286 async_answer_0(callid, rc);
287 return;
[1b22bd4]288 }
289
[93f8da1]290 async_transaction_t *trans = async_transaction_create(callid);
291 if (trans == NULL) {
292 if (buffer != NULL) {
293 free(buffer);
294 }
[17aca1c]295 async_answer_0(callid, ENOMEM);
[93f8da1]296 return;
297 }
298
[fb1dca09]299 trans->buffer = buffer;
300 trans->size = len;
[1b22bd4]301
[eb1a2f4]302 rc = transfer_func(fun, target, max_packet_size,
[ec59693]303 buffer, len,
[1b22bd4]304 callback_out, trans);
305
306 if (rc != EOK) {
[17aca1c]307 async_answer_0(callid, rc);
[93f8da1]308 async_transaction_destroy(trans);
[1b22bd4]309 }
[91db50ac]310}
311
[fb1dca09]312/** Process an incoming transfer.
313 *
314 * @param device Target device.
315 * @param callid Initiating caller.
316 * @param call Initiating call.
317 * @param transfer_func Transfer function (might be NULL).
318 */
[eb1a2f4]319static void remote_usbhc_in_transfer(ddf_fun_t *fun,
[fb1dca09]320 ipc_callid_t callid, ipc_call_t *call,
321 usbhc_iface_transfer_in_t transfer_func)
[91db50ac]322{
[fb1dca09]323 if (!transfer_func) {
[17aca1c]324 async_answer_0(callid, ENOTSUP);
[fb1dca09]325 return;
326 }
[1b22bd4]327
[228f251]328 size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
[1b22bd4]329 usb_target_t target = {
[eac610e]330 .address = DEV_IPC_GET_ARG1(*call),
331 .endpoint = DEV_IPC_GET_ARG2(*call)
[1b22bd4]332 };
333
[228f251]334 size_t len;
[0a6fa9f]335 ipc_callid_t data_callid;
336 if (!async_data_read_receive(&data_callid, &len)) {
337 async_answer_0(callid, EPARTY);
338 return;
339 }
340
[93f8da1]341 async_transaction_t *trans = async_transaction_create(callid);
342 if (trans == NULL) {
[17aca1c]343 async_answer_0(callid, ENOMEM);
[93f8da1]344 return;
345 }
[0a6fa9f]346 trans->data_caller = data_callid;
[1b22bd4]347 trans->buffer = malloc(len);
348 trans->size = len;
349
[eb1a2f4]350 int rc = transfer_func(fun, target, max_packet_size,
[ec59693]351 trans->buffer, len,
[1b22bd4]352 callback_in, trans);
353
354 if (rc != EOK) {
[17aca1c]355 async_answer_0(callid, rc);
[93f8da1]356 async_transaction_destroy(trans);
[1b22bd4]357 }
[91db50ac]358}
359
[eb1a2f4]360void remote_usbhc_interrupt_out(ddf_fun_t *fun, void *iface,
[fb1dca09]361 ipc_callid_t callid, ipc_call_t *call)
[a3dfb2e]362{
363 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
[fb1dca09]364 assert(usb_iface != NULL);
[a3dfb2e]365
[eb1a2f4]366 return remote_usbhc_out_transfer(fun, callid, call,
[fb1dca09]367 usb_iface->interrupt_out);
368}
[a3dfb2e]369
[eb1a2f4]370void remote_usbhc_interrupt_in(ddf_fun_t *fun, void *iface,
[fb1dca09]371 ipc_callid_t callid, ipc_call_t *call)
372{
373 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
374 assert(usb_iface != NULL);
[a3dfb2e]375
[eb1a2f4]376 return remote_usbhc_in_transfer(fun, callid, call,
[fb1dca09]377 usb_iface->interrupt_in);
378}
[a3dfb2e]379
[eb1a2f4]380void remote_usbhc_bulk_out(ddf_fun_t *fun, void *iface,
[0a46c41e]381 ipc_callid_t callid, ipc_call_t *call)
382{
383 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
384 assert(usb_iface != NULL);
385
[eb1a2f4]386 return remote_usbhc_out_transfer(fun, callid, call,
[0a46c41e]387 usb_iface->bulk_out);
388}
389
[eb1a2f4]390void remote_usbhc_bulk_in(ddf_fun_t *fun, void *iface,
[0a46c41e]391 ipc_callid_t callid, ipc_call_t *call)
392{
393 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
394 assert(usb_iface != NULL);
395
[eb1a2f4]396 return remote_usbhc_in_transfer(fun, callid, call,
[0a46c41e]397 usb_iface->bulk_in);
398}
399
[eb1a2f4]400void remote_usbhc_control_write(ddf_fun_t *fun, void *iface,
[9753220]401ipc_callid_t callid, ipc_call_t *call)
402{
403 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
404 assert(usb_iface != NULL);
405
406 if (!usb_iface->control_write) {
[17aca1c]407 async_answer_0(callid, ENOTSUP);
[9753220]408 return;
409 }
410
411 usb_target_t target = {
412 .address = DEV_IPC_GET_ARG1(*call),
413 .endpoint = DEV_IPC_GET_ARG2(*call)
414 };
[3937bda]415 size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
[228f251]416 size_t max_packet_size = DEV_IPC_GET_ARG4(*call);
[9753220]417
418 int rc;
419
420 void *setup_packet = NULL;
421 void *data_buffer = NULL;
422 size_t setup_packet_len = 0;
423
424 rc = async_data_write_accept(&setup_packet, false,
425 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
426 if (rc != EOK) {
[17aca1c]427 async_answer_0(callid, rc);
[9753220]428 return;
429 }
[3937bda]430
431 if (data_buffer_len > 0) {
432 rc = async_data_write_accept(&data_buffer, false,
433 1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
434 if (rc != EOK) {
435 async_answer_0(callid, rc);
436 free(setup_packet);
437 return;
438 }
[9753220]439 }
440
[93f8da1]441 async_transaction_t *trans = async_transaction_create(callid);
442 if (trans == NULL) {
[17aca1c]443 async_answer_0(callid, ENOMEM);
[93f8da1]444 free(setup_packet);
445 free(data_buffer);
446 return;
447 }
[9753220]448 trans->setup_packet = setup_packet;
449 trans->buffer = data_buffer;
450 trans->size = data_buffer_len;
451
[eb1a2f4]452 rc = usb_iface->control_write(fun, target, max_packet_size,
[9753220]453 setup_packet, setup_packet_len,
454 data_buffer, data_buffer_len,
455 callback_out, trans);
456
457 if (rc != EOK) {
[17aca1c]458 async_answer_0(callid, rc);
[93f8da1]459 async_transaction_destroy(trans);
[9753220]460 }
461}
462
463
[eb1a2f4]464void remote_usbhc_control_read(ddf_fun_t *fun, void *iface,
[9753220]465ipc_callid_t callid, ipc_call_t *call)
466{
467 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
468 assert(usb_iface != NULL);
469
470 if (!usb_iface->control_read) {
[17aca1c]471 async_answer_0(callid, ENOTSUP);
[9753220]472 return;
473 }
474
475 usb_target_t target = {
476 .address = DEV_IPC_GET_ARG1(*call),
477 .endpoint = DEV_IPC_GET_ARG2(*call)
478 };
[228f251]479 size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
[9753220]480
481 int rc;
482
483 void *setup_packet = NULL;
484 size_t setup_packet_len = 0;
[3937bda]485 size_t data_len = 0;
[9753220]486
487 rc = async_data_write_accept(&setup_packet, false,
488 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
489 if (rc != EOK) {
[17aca1c]490 async_answer_0(callid, rc);
[9753220]491 return;
492 }
493
[0a6fa9f]494 ipc_callid_t data_callid;
495 if (!async_data_read_receive(&data_callid, &data_len)) {
496 async_answer_0(callid, EPARTY);
497 free(setup_packet);
498 return;
499 }
500
[93f8da1]501 async_transaction_t *trans = async_transaction_create(callid);
502 if (trans == NULL) {
[17aca1c]503 async_answer_0(callid, ENOMEM);
[93f8da1]504 free(setup_packet);
505 return;
506 }
[0a6fa9f]507 trans->data_caller = data_callid;
[9753220]508 trans->setup_packet = setup_packet;
509 trans->size = data_len;
[93f8da1]510 trans->buffer = malloc(data_len);
511 if (trans->buffer == NULL) {
[17aca1c]512 async_answer_0(callid, ENOMEM);
[93f8da1]513 async_transaction_destroy(trans);
514 return;
515 }
[9753220]516
[eb1a2f4]517 rc = usb_iface->control_read(fun, target, max_packet_size,
[9753220]518 setup_packet, setup_packet_len,
519 trans->buffer, trans->size,
520 callback_in, trans);
521
522 if (rc != EOK) {
[17aca1c]523 async_answer_0(callid, rc);
[93f8da1]524 async_transaction_destroy(trans);
[9753220]525 }
526}
527
[a3dfb2e]528
[b7d8fd9]529void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
530 ipc_callid_t callid, ipc_call_t *call)
531{
532 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
533
534 if (!usb_iface->register_endpoint) {
535 async_answer_0(callid, ENOTSUP);
536 return;
537 }
538
539#define INIT_FROM_HIGH_DATA(type, var, arg_no) \
540 type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / 256
541#define INIT_FROM_LOW_DATA(type, var, arg_no) \
542 type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % 256
543
544 INIT_FROM_HIGH_DATA(usb_address_t, address, 1);
545 INIT_FROM_LOW_DATA(usb_endpoint_t, endpoint, 1);
546 INIT_FROM_HIGH_DATA(usb_transfer_type_t, transfer_type, 2);
547 INIT_FROM_LOW_DATA(usb_direction_t, direction, 2);
548
549#undef INIT_FROM_HIGH_DATA
550#undef INIT_FROM_LOW_DATA
551
552 size_t max_packet_size = (size_t) DEV_IPC_GET_ARG3(*call);
553 unsigned int interval = (unsigned int) DEV_IPC_GET_ARG4(*call);
554
555 int rc = usb_iface->register_endpoint(fun, address, endpoint,
556 transfer_type, direction, max_packet_size, interval);
557
558 async_answer_0(callid, rc);
559}
560
561
562void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
563 ipc_callid_t callid, ipc_call_t *call)
564{
565 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
566
567 if (!usb_iface->unregister_endpoint) {
568 async_answer_0(callid, ENOTSUP);
569 return;
570 }
571
572 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
573 usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG2(*call);
574 usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG3(*call);
575
576 int rc = usb_iface->unregister_endpoint(fun,
577 address, endpoint, direction);
578
579 async_answer_0(callid, rc);
580}
581
[1b22bd4]582
[91db50ac]583/**
584 * @}
585 */
Note: See TracBrowser for help on using the repository browser.