Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/drv/generic/remote_usbhc.c

    r357a302 r6edd494  
    11/*
    2  * Copyright (c) 2010-2011 Vojtech Horky
     2 * Copyright (c) 2010 Vojtech Horky
    33 * All rights reserved.
    44 *
     
    3333 */
    3434
     35#include <ipc/ipc.h>
    3536#include <async.h>
    3637#include <errno.h>
     
    4041
    4142#define USB_MAX_PAYLOAD_SIZE 1020
    42 #define HACK_MAX_PACKET_SIZE 8
    43 #define HACK_MAX_PACKET_SIZE_INTERRUPT_IN 4
    44 
     43
     44static void remote_usbhc_get_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
     45static void remote_usbhc_get_buffer(device_t *, void *, ipc_callid_t, ipc_call_t *);
    4546static void remote_usbhc_interrupt_out(device_t *, void *, ipc_callid_t, ipc_call_t *);
    4647static void remote_usbhc_interrupt_in(device_t *, void *, ipc_callid_t, ipc_call_t *);
    47 static void remote_usbhc_bulk_out(device_t *, void *, ipc_callid_t, ipc_call_t *);
    48 static void remote_usbhc_bulk_in(device_t *, void *, ipc_callid_t, ipc_call_t *);
    49 static void remote_usbhc_control_write(device_t *, void *, ipc_callid_t, ipc_call_t *);
    50 static void remote_usbhc_control_read(device_t *, void *, ipc_callid_t, ipc_call_t *);
     48static void remote_usbhc_control_write_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
     49static void remote_usbhc_control_write_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
     50static void remote_usbhc_control_write_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
     51static void remote_usbhc_control_read_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
     52static void remote_usbhc_control_read_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
     53static void remote_usbhc_control_read_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
    5154static void remote_usbhc_reserve_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
    5255static void remote_usbhc_release_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
     
    5861/** Remote USB host controller interface operations. */
    5962static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
     63        remote_usbhc_get_address,
     64
     65        remote_usbhc_get_buffer,
     66
    6067        remote_usbhc_reserve_default_address,
    6168        remote_usbhc_release_default_address,
     
    6875        remote_usbhc_interrupt_in,
    6976
    70         remote_usbhc_bulk_out,
    71         remote_usbhc_bulk_in,
    72 
    73         remote_usbhc_control_write,
    74         remote_usbhc_control_read
     77        remote_usbhc_control_write_setup,
     78        remote_usbhc_control_write_data,
     79        remote_usbhc_control_write_status,
     80
     81        remote_usbhc_control_read_setup,
     82        remote_usbhc_control_read_data,
     83        remote_usbhc_control_read_status
    7584};
    7685
     
    8594typedef struct {
    8695        ipc_callid_t caller;
    87         ipc_callid_t data_caller;
    8896        void *buffer;
    89         void *setup_packet;
    9097        size_t size;
    9198} async_transaction_t;
    9299
    93 static void async_transaction_destroy(async_transaction_t *trans)
    94 {
     100void remote_usbhc_get_address(device_t *device, void *iface,
     101    ipc_callid_t callid, ipc_call_t *call)
     102{
     103        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     104
     105        if (!usb_iface->tell_address) {
     106                ipc_answer_0(callid, ENOTSUP);
     107                return;
     108        }
     109
     110        devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
     111
     112        usb_address_t address;
     113        int rc = usb_iface->tell_address(device, handle, &address);
     114        if (rc != EOK) {
     115                ipc_answer_0(callid, rc);
     116        } else {
     117                ipc_answer_1(callid, EOK, address);
     118        }
     119}
     120
     121void remote_usbhc_get_buffer(device_t *device, void *iface,
     122    ipc_callid_t callid, ipc_call_t *call)
     123{
     124        sysarg_t buffer_hash = DEV_IPC_GET_ARG1(*call);
     125        async_transaction_t * trans = (async_transaction_t *)buffer_hash;
    95126        if (trans == NULL) {
    96                 return;
    97         }
    98 
    99         if (trans->setup_packet != NULL) {
    100                 free(trans->setup_packet);
    101         }
    102         if (trans->buffer != NULL) {
    103                 free(trans->buffer);
    104         }
    105 
     127                ipc_answer_0(callid, ENOENT);
     128                return;
     129        }
     130        if (trans->buffer == NULL) {
     131                ipc_answer_0(callid, EINVAL);
     132                free(trans);
     133                return;
     134        }
     135
     136        ipc_callid_t cid;
     137        size_t accepted_size;
     138        if (!async_data_read_receive(&cid, &accepted_size)) {
     139                ipc_answer_0(callid, EINVAL);
     140                return;
     141        }
     142
     143        if (accepted_size > trans->size) {
     144                accepted_size = trans->size;
     145        }
     146        async_data_read_finalize(cid, trans->buffer, accepted_size);
     147
     148        ipc_answer_1(callid, EOK, accepted_size);
     149
     150        free(trans->buffer);
    106151        free(trans);
    107152}
    108153
    109 static async_transaction_t *async_transaction_create(ipc_callid_t caller)
    110 {
    111         async_transaction_t *trans = malloc(sizeof(async_transaction_t));
    112         if (trans == NULL) {
    113                 return NULL;
    114         }
    115 
    116         trans->caller = caller;
    117         trans->data_caller = 0;
    118         trans->buffer = NULL;
    119         trans->setup_packet = NULL;
    120         trans->size = 0;
    121 
    122         return trans;
    123 }
    124 
    125154void remote_usbhc_reserve_default_address(device_t *device, void *iface,
    126155    ipc_callid_t callid, ipc_call_t *call)
     
    129158
    130159        if (!usb_iface->reserve_default_address) {
    131                 async_answer_0(callid, ENOTSUP);
    132                 return;
    133         }
    134        
    135         usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
    136        
    137         int rc = usb_iface->reserve_default_address(device, speed);
    138 
    139         async_answer_0(callid, rc);
     160                ipc_answer_0(callid, ENOTSUP);
     161                return;
     162        }
     163
     164        int rc = usb_iface->reserve_default_address(device);
     165
     166        ipc_answer_0(callid, rc);
    140167}
    141168
     
    146173
    147174        if (!usb_iface->release_default_address) {
    148                 async_answer_0(callid, ENOTSUP);
     175                ipc_answer_0(callid, ENOTSUP);
    149176                return;
    150177        }
     
    152179        int rc = usb_iface->release_default_address(device);
    153180
    154         async_answer_0(callid, rc);
     181        ipc_answer_0(callid, rc);
    155182}
    156183
     
    161188
    162189        if (!usb_iface->request_address) {
    163                 async_answer_0(callid, ENOTSUP);
    164                 return;
    165         }
    166        
    167         usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
     190                ipc_answer_0(callid, ENOTSUP);
     191                return;
     192        }
    168193
    169194        usb_address_t address;
    170         int rc = usb_iface->request_address(device, speed, &address);
     195        int rc = usb_iface->request_address(device, &address);
    171196        if (rc != EOK) {
    172                 async_answer_0(callid, rc);
     197                ipc_answer_0(callid, rc);
    173198        } else {
    174                 async_answer_1(callid, EOK, (sysarg_t) address);
     199                ipc_answer_1(callid, EOK, (sysarg_t) address);
    175200        }
    176201}
     
    182207
    183208        if (!usb_iface->bind_address) {
    184                 async_answer_0(callid, ENOTSUP);
     209                ipc_answer_0(callid, ENOTSUP);
    185210                return;
    186211        }
     
    191216        int rc = usb_iface->bind_address(device, address, handle);
    192217
    193         async_answer_0(callid, rc);
     218        ipc_answer_0(callid, rc);
    194219}
    195220
     
    200225
    201226        if (!usb_iface->release_address) {
    202                 async_answer_0(callid, ENOTSUP);
     227                ipc_answer_0(callid, ENOTSUP);
    203228                return;
    204229        }
     
    208233        int rc = usb_iface->release_address(device, address);
    209234
    210         async_answer_0(callid, rc);
     235        ipc_answer_0(callid, rc);
    211236}
    212237
    213238
    214239static void callback_out(device_t *device,
    215     int outcome, void *arg)
     240    usb_transaction_outcome_t outcome, void *arg)
    216241{
    217242        async_transaction_t *trans = (async_transaction_t *)arg;
    218243
    219         async_answer_0(trans->caller, outcome);
    220 
    221         async_transaction_destroy(trans);
     244        // FIXME - answer according to outcome
     245        ipc_answer_0(trans->caller, EOK);
     246
     247        free(trans);
    222248}
    223249
    224250static void callback_in(device_t *device,
    225     int outcome, size_t actual_size, void *arg)
     251    usb_transaction_outcome_t outcome, size_t actual_size, void *arg)
    226252{
    227253        async_transaction_t *trans = (async_transaction_t *)arg;
    228254
    229         if (outcome != EOK) {
    230                 async_answer_0(trans->caller, outcome);
    231                 if (trans->data_caller) {
    232                         async_answer_0(trans->data_caller, EINTR);
    233                 }
    234                 async_transaction_destroy(trans);
    235                 return;
    236         }
     255        // FIXME - answer according to outcome
     256        ipc_answer_1(trans->caller, EOK, (sysarg_t)trans);
    237257
    238258        trans->size = actual_size;
    239 
    240         if (trans->data_caller) {
    241                 async_data_read_finalize(trans->data_caller,
    242                     trans->buffer, actual_size);
    243         }
    244 
    245         async_answer_0(trans->caller, EOK);
    246 
    247         async_transaction_destroy(trans);
    248259}
    249260
     
    260271{
    261272        if (!transfer_func) {
    262                 async_answer_0(callid, ENOTSUP);
    263                 return;
    264         }
    265 
    266         size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
     273                ipc_answer_0(callid, ENOTSUP);
     274                return;
     275        }
     276
     277        size_t expected_len = DEV_IPC_GET_ARG3(*call);
    267278        usb_target_t target = {
    268279                .address = DEV_IPC_GET_ARG1(*call),
     
    272283        size_t len = 0;
    273284        void *buffer = NULL;
    274 
    275         int rc = async_data_write_accept(&buffer, false,
    276             1, USB_MAX_PAYLOAD_SIZE,
    277             0, &len);
     285        if (expected_len > 0) {
     286                int rc = async_data_write_accept(&buffer, false,
     287                    1, USB_MAX_PAYLOAD_SIZE,
     288                    0, &len);
     289
     290                if (rc != EOK) {
     291                        ipc_answer_0(callid, rc);
     292                        return;
     293                }
     294        }
     295
     296        async_transaction_t *trans = malloc(sizeof(async_transaction_t));
     297        trans->caller = callid;
     298        trans->buffer = buffer;
     299        trans->size = len;
     300
     301        int rc = transfer_func(device, target, buffer, len,
     302            callback_out, trans);
    278303
    279304        if (rc != EOK) {
    280                 async_answer_0(callid, rc);
    281                 return;
    282         }
    283 
    284         async_transaction_t *trans = async_transaction_create(callid);
    285         if (trans == NULL) {
     305                ipc_answer_0(callid, rc);
    286306                if (buffer != NULL) {
    287307                        free(buffer);
    288308                }
    289                 async_answer_0(callid, ENOMEM);
    290                 return;
    291         }
    292 
    293         trans->buffer = buffer;
    294         trans->size = len;
    295 
    296         rc = transfer_func(device, target, max_packet_size,
    297             buffer, len,
    298             callback_out, trans);
    299 
    300         if (rc != EOK) {
    301                 async_answer_0(callid, rc);
    302                 async_transaction_destroy(trans);
     309                free(trans);
    303310        }
    304311}
     
    316323{
    317324        if (!transfer_func) {
    318                 async_answer_0(callid, ENOTSUP);
    319                 return;
    320         }
    321 
    322         size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
     325                ipc_answer_0(callid, ENOTSUP);
     326                return;
     327        }
     328
     329        size_t len = DEV_IPC_GET_ARG3(*call);
    323330        usb_target_t target = {
    324331                .address = DEV_IPC_GET_ARG1(*call),
     
    326333        };
    327334
    328         size_t len;
    329         ipc_callid_t data_callid;
    330         if (!async_data_read_receive(&data_callid, &len)) {
    331                 async_answer_0(callid, EPARTY);
    332                 return;
    333         }
    334 
    335         async_transaction_t *trans = async_transaction_create(callid);
    336         if (trans == NULL) {
    337                 async_answer_0(callid, ENOMEM);
    338                 return;
    339         }
    340         trans->data_caller = data_callid;
     335        async_transaction_t *trans = malloc(sizeof(async_transaction_t));
     336        trans->caller = callid;
    341337        trans->buffer = malloc(len);
    342338        trans->size = len;
    343339
    344         int rc = transfer_func(device, target, max_packet_size,
    345             trans->buffer, len,
     340        int rc = transfer_func(device, target, trans->buffer, len,
    346341            callback_in, trans);
    347342
    348343        if (rc != EOK) {
    349                 async_answer_0(callid, rc);
    350                 async_transaction_destroy(trans);
    351         }
    352 }
    353 
    354 void remote_usbhc_interrupt_out(device_t *device, void *iface,
    355     ipc_callid_t callid, ipc_call_t *call)
    356 {
    357         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    358         assert(usb_iface != NULL);
    359 
    360         return remote_usbhc_out_transfer(device, callid, call,
    361             usb_iface->interrupt_out);
    362 }
    363 
    364 void remote_usbhc_interrupt_in(device_t *device, void *iface,
    365     ipc_callid_t callid, ipc_call_t *call)
    366 {
    367         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    368         assert(usb_iface != NULL);
    369 
    370         return remote_usbhc_in_transfer(device, callid, call,
    371             usb_iface->interrupt_in);
    372 }
    373 
    374 void remote_usbhc_bulk_out(device_t *device, void *iface,
    375     ipc_callid_t callid, ipc_call_t *call)
    376 {
    377         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    378         assert(usb_iface != NULL);
    379 
    380         return remote_usbhc_out_transfer(device, callid, call,
    381             usb_iface->bulk_out);
    382 }
    383 
    384 void remote_usbhc_bulk_in(device_t *device, void *iface,
    385     ipc_callid_t callid, ipc_call_t *call)
    386 {
    387         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    388         assert(usb_iface != NULL);
    389 
    390         return remote_usbhc_in_transfer(device, callid, call,
    391             usb_iface->bulk_in);
    392 }
    393 
    394 void remote_usbhc_control_write(device_t *device, void *iface,
    395 ipc_callid_t callid, ipc_call_t *call)
    396 {
    397         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    398         assert(usb_iface != NULL);
    399 
    400         if (!usb_iface->control_write) {
    401                 async_answer_0(callid, ENOTSUP);
    402                 return;
     344                ipc_answer_0(callid, rc);
     345                free(trans->buffer);
     346                free(trans);
     347        }
     348}
     349
     350/** Process status part of control transfer.
     351 *
     352 * @param device Target device.
     353 * @param callid Initiating caller.
     354 * @param call Initiating call.
     355 * @param direction Transfer direction (read ~ in, write ~ out).
     356 * @param transfer_in_func Transfer function for control read (might be NULL).
     357 * @param transfer_out_func Transfer function for control write (might be NULL).
     358 */
     359static void remote_usbhc_status_transfer(device_t *device,
     360    ipc_callid_t callid, ipc_call_t *call,
     361    usb_direction_t direction,
     362    int (*transfer_in_func)(device_t *, usb_target_t,
     363        usbhc_iface_transfer_in_callback_t, void *),
     364    int (*transfer_out_func)(device_t *, usb_target_t,
     365        usbhc_iface_transfer_out_callback_t, void *))
     366{
     367        switch (direction) {
     368                case USB_DIRECTION_IN:
     369                        if (!transfer_in_func) {
     370                                ipc_answer_0(callid, ENOTSUP);
     371                                return;
     372                        }
     373                        break;
     374                case USB_DIRECTION_OUT:
     375                        if (!transfer_out_func) {
     376                                ipc_answer_0(callid, ENOTSUP);
     377                                return;
     378                        }
     379                        break;
     380                default:
     381                        assert(false && "unreachable code");
     382                        break;
    403383        }
    404384
     
    407387                .endpoint = DEV_IPC_GET_ARG2(*call)
    408388        };
    409         size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
    410         size_t max_packet_size = DEV_IPC_GET_ARG4(*call);
     389
     390        async_transaction_t *trans = malloc(sizeof(async_transaction_t));
     391        trans->caller = callid;
     392        trans->buffer = NULL;
     393        trans->size = 0;
    411394
    412395        int rc;
    413 
    414         void *setup_packet = NULL;
    415         void *data_buffer = NULL;
    416         size_t setup_packet_len = 0;
    417 
    418         rc = async_data_write_accept(&setup_packet, false,
    419             1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
     396        switch (direction) {
     397                case USB_DIRECTION_IN:
     398                        rc = transfer_in_func(device, target,
     399                            callback_in, trans);
     400                        break;
     401                case USB_DIRECTION_OUT:
     402                        rc = transfer_out_func(device, target,
     403                            callback_out, trans);
     404                        break;
     405                default:
     406                        assert(false && "unreachable code");
     407                        break;
     408        }
     409
    420410        if (rc != EOK) {
    421                 async_answer_0(callid, rc);
    422                 return;
    423         }
    424 
    425         if (data_buffer_len > 0) {
    426                 rc = async_data_write_accept(&data_buffer, false,
    427                     1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
    428                 if (rc != EOK) {
    429                         async_answer_0(callid, rc);
    430                         free(setup_packet);
    431                         return;
    432                 }
    433         }
    434 
    435         async_transaction_t *trans = async_transaction_create(callid);
    436         if (trans == NULL) {
    437                 async_answer_0(callid, ENOMEM);
    438                 free(setup_packet);
    439                 free(data_buffer);
    440                 return;
    441         }
    442         trans->setup_packet = setup_packet;
    443         trans->buffer = data_buffer;
    444         trans->size = data_buffer_len;
    445 
    446         rc = usb_iface->control_write(device, target, max_packet_size,
    447             setup_packet, setup_packet_len,
    448             data_buffer, data_buffer_len,
    449             callback_out, trans);
    450 
    451         if (rc != EOK) {
    452                 async_answer_0(callid, rc);
    453                 async_transaction_destroy(trans);
    454         }
    455 }
    456 
    457 
    458 void remote_usbhc_control_read(device_t *device, void *iface,
    459 ipc_callid_t callid, ipc_call_t *call)
    460 {
    461         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    462         assert(usb_iface != NULL);
    463 
    464         if (!usb_iface->control_read) {
    465                 async_answer_0(callid, ENOTSUP);
    466                 return;
    467         }
    468 
    469         usb_target_t target = {
    470                 .address = DEV_IPC_GET_ARG1(*call),
    471                 .endpoint = DEV_IPC_GET_ARG2(*call)
    472         };
    473         size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
    474 
    475         int rc;
    476 
    477         void *setup_packet = NULL;
    478         size_t setup_packet_len = 0;
    479         size_t data_len = 0;
    480 
    481         rc = async_data_write_accept(&setup_packet, false,
    482             1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
    483         if (rc != EOK) {
    484                 async_answer_0(callid, rc);
    485                 return;
    486         }
    487 
    488         ipc_callid_t data_callid;
    489         if (!async_data_read_receive(&data_callid, &data_len)) {
    490                 async_answer_0(callid, EPARTY);
    491                 free(setup_packet);
    492                 return;
    493         }
    494 
    495         async_transaction_t *trans = async_transaction_create(callid);
    496         if (trans == NULL) {
    497                 async_answer_0(callid, ENOMEM);
    498                 free(setup_packet);
    499                 return;
    500         }
    501         trans->data_caller = data_callid;
    502         trans->setup_packet = setup_packet;
    503         trans->size = data_len;
    504         trans->buffer = malloc(data_len);
    505         if (trans->buffer == NULL) {
    506                 async_answer_0(callid, ENOMEM);
    507                 async_transaction_destroy(trans);
    508                 return;
    509         }
    510 
    511         rc = usb_iface->control_read(device, target, max_packet_size,
    512             setup_packet, setup_packet_len,
    513             trans->buffer, trans->size,
    514             callback_in, trans);
    515 
    516         if (rc != EOK) {
    517                 async_answer_0(callid, rc);
    518                 async_transaction_destroy(trans);
    519         }
     411                ipc_answer_0(callid, rc);
     412                free(trans);
     413        }
     414        return;
     415}
     416
     417
     418void remote_usbhc_interrupt_out(device_t *device, void *iface,
     419    ipc_callid_t callid, ipc_call_t *call)
     420{
     421        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     422        assert(usb_iface != NULL);
     423
     424        return remote_usbhc_out_transfer(device, callid, call,
     425            usb_iface->interrupt_out);
     426}
     427
     428void remote_usbhc_interrupt_in(device_t *device, void *iface,
     429    ipc_callid_t callid, ipc_call_t *call)
     430{
     431        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     432        assert(usb_iface != NULL);
     433
     434        return remote_usbhc_in_transfer(device, callid, call,
     435            usb_iface->interrupt_in);
     436}
     437
     438void remote_usbhc_control_write_setup(device_t *device, void *iface,
     439    ipc_callid_t callid, ipc_call_t *call)
     440{
     441        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     442        assert(usb_iface != NULL);
     443
     444        return remote_usbhc_out_transfer(device, callid, call,
     445            usb_iface->control_write_setup);
     446}
     447
     448void remote_usbhc_control_write_data(device_t *device, void *iface,
     449    ipc_callid_t callid, ipc_call_t *call)
     450{
     451        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     452        assert(usb_iface != NULL);
     453
     454        return remote_usbhc_out_transfer(device, callid, call,
     455            usb_iface->control_write_data);
     456}
     457
     458void remote_usbhc_control_write_status(device_t *device, void *iface,
     459    ipc_callid_t callid, ipc_call_t *call)
     460{
     461        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     462        assert(usb_iface != NULL);
     463
     464        return remote_usbhc_status_transfer(device, callid, call,
     465            USB_DIRECTION_IN, usb_iface->control_write_status, NULL);
     466}
     467
     468void remote_usbhc_control_read_setup(device_t *device, void *iface,
     469    ipc_callid_t callid, ipc_call_t *call)
     470{
     471        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     472        assert(usb_iface != NULL);
     473
     474        return remote_usbhc_out_transfer(device, callid, call,
     475            usb_iface->control_read_setup);
     476}
     477
     478void remote_usbhc_control_read_data(device_t *device, void *iface,
     479            ipc_callid_t callid, ipc_call_t *call)
     480{
     481        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     482        assert(usb_iface != NULL);
     483
     484        return remote_usbhc_in_transfer(device, callid, call,
     485            usb_iface->control_read_data);
     486}
     487
     488void remote_usbhc_control_read_status(device_t *device, void *iface,
     489            ipc_callid_t callid, ipc_call_t *call)
     490{
     491        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     492        assert(usb_iface != NULL);
     493
     494        return remote_usbhc_status_transfer(device, callid, call,
     495            USB_DIRECTION_OUT, NULL, usb_iface->control_read_status);
    520496}
    521497
Note: See TracChangeset for help on using the changeset viewer.