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

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

Add getting handle by address over USBHC iface

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