Ignore:
File:
1 edited

Legend:

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

    r6edd494 r357a302  
    11/*
    2  * Copyright (c) 2010 Vojtech Horky
     2 * Copyright (c) 2010-2011 Vojtech Horky
    33 * All rights reserved.
    44 *
     
    3333 */
    3434
    35 #include <ipc/ipc.h>
    3635#include <async.h>
    3736#include <errno.h>
     
    4140
    4241#define USB_MAX_PAYLOAD_SIZE 1020
    43 
    44 static void remote_usbhc_get_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
    45 static void remote_usbhc_get_buffer(device_t *, void *, ipc_callid_t, ipc_call_t *);
     42#define HACK_MAX_PACKET_SIZE 8
     43#define HACK_MAX_PACKET_SIZE_INTERRUPT_IN 4
     44
    4645static void remote_usbhc_interrupt_out(device_t *, void *, ipc_callid_t, ipc_call_t *);
    4746static void remote_usbhc_interrupt_in(device_t *, void *, ipc_callid_t, ipc_call_t *);
    48 static void remote_usbhc_control_write_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
    49 static void remote_usbhc_control_write_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
    50 static void remote_usbhc_control_write_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
    51 static void remote_usbhc_control_read_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
    52 static void remote_usbhc_control_read_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
    53 static void remote_usbhc_control_read_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
     47static void remote_usbhc_bulk_out(device_t *, void *, ipc_callid_t, ipc_call_t *);
     48static void remote_usbhc_bulk_in(device_t *, void *, ipc_callid_t, ipc_call_t *);
     49static void remote_usbhc_control_write(device_t *, void *, ipc_callid_t, ipc_call_t *);
     50static void remote_usbhc_control_read(device_t *, void *, ipc_callid_t, ipc_call_t *);
    5451static void remote_usbhc_reserve_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
    5552static void remote_usbhc_release_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
     
    6158/** Remote USB host controller interface operations. */
    6259static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
    63         remote_usbhc_get_address,
    64 
    65         remote_usbhc_get_buffer,
    66 
    6760        remote_usbhc_reserve_default_address,
    6861        remote_usbhc_release_default_address,
     
    7568        remote_usbhc_interrupt_in,
    7669
    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
     70        remote_usbhc_bulk_out,
     71        remote_usbhc_bulk_in,
     72
     73        remote_usbhc_control_write,
     74        remote_usbhc_control_read
    8475};
    8576
     
    9485typedef struct {
    9586        ipc_callid_t caller;
     87        ipc_callid_t data_caller;
    9688        void *buffer;
     89        void *setup_packet;
    9790        size_t size;
    9891} async_transaction_t;
    9992
    100 void 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);
     93static void async_transaction_destroy(async_transaction_t *trans)
     94{
     95        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
     106        free(trans);
     107}
     108
     109static 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
     125void remote_usbhc_reserve_default_address(device_t *device, void *iface,
     126    ipc_callid_t callid, ipc_call_t *call)
     127{
     128        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     129
     130        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);
     140}
     141
     142void remote_usbhc_release_default_address(device_t *device, void *iface,
     143    ipc_callid_t callid, ipc_call_t *call)
     144{
     145        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     146
     147        if (!usb_iface->release_default_address) {
     148                async_answer_0(callid, ENOTSUP);
     149                return;
     150        }
     151
     152        int rc = usb_iface->release_default_address(device);
     153
     154        async_answer_0(callid, rc);
     155}
     156
     157void remote_usbhc_request_address(device_t *device, void *iface,
     158    ipc_callid_t callid, ipc_call_t *call)
     159{
     160        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     161
     162        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);
    111168
    112169        usb_address_t address;
    113         int rc = usb_iface->tell_address(device, handle, &address);
    114         if (rc != EOK) {
    115                 ipc_answer_0(callid, rc);
     170        int rc = usb_iface->request_address(device, speed, &address);
     171        if (rc != EOK) {
     172                async_answer_0(callid, rc);
    116173        } else {
    117                 ipc_answer_1(callid, EOK, address);
    118         }
    119 }
    120 
    121 void 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;
    126         if (trans == NULL) {
    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);
    151         free(trans);
    152 }
    153 
    154 void remote_usbhc_reserve_default_address(device_t *device, void *iface,
    155     ipc_callid_t callid, ipc_call_t *call)
    156 {
    157         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    158 
    159         if (!usb_iface->reserve_default_address) {
    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);
    167 }
    168 
    169 void remote_usbhc_release_default_address(device_t *device, void *iface,
    170     ipc_callid_t callid, ipc_call_t *call)
    171 {
    172         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    173 
    174         if (!usb_iface->release_default_address) {
    175                 ipc_answer_0(callid, ENOTSUP);
    176                 return;
    177         }
    178 
    179         int rc = usb_iface->release_default_address(device);
    180 
    181         ipc_answer_0(callid, rc);
    182 }
    183 
    184 void remote_usbhc_request_address(device_t *device, void *iface,
    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->request_address) {
    190                 ipc_answer_0(callid, ENOTSUP);
    191                 return;
    192         }
    193 
    194         usb_address_t address;
    195         int rc = usb_iface->request_address(device, &address);
    196         if (rc != EOK) {
    197                 ipc_answer_0(callid, rc);
    198         } else {
    199                 ipc_answer_1(callid, EOK, (sysarg_t) address);
     174                async_answer_1(callid, EOK, (sysarg_t) address);
    200175        }
    201176}
     
    207182
    208183        if (!usb_iface->bind_address) {
    209                 ipc_answer_0(callid, ENOTSUP);
     184                async_answer_0(callid, ENOTSUP);
    210185                return;
    211186        }
     
    216191        int rc = usb_iface->bind_address(device, address, handle);
    217192
    218         ipc_answer_0(callid, rc);
     193        async_answer_0(callid, rc);
    219194}
    220195
     
    225200
    226201        if (!usb_iface->release_address) {
    227                 ipc_answer_0(callid, ENOTSUP);
     202                async_answer_0(callid, ENOTSUP);
    228203                return;
    229204        }
     
    233208        int rc = usb_iface->release_address(device, address);
    234209
    235         ipc_answer_0(callid, rc);
     210        async_answer_0(callid, rc);
    236211}
    237212
    238213
    239214static void callback_out(device_t *device,
    240     usb_transaction_outcome_t outcome, void *arg)
     215    int outcome, void *arg)
    241216{
    242217        async_transaction_t *trans = (async_transaction_t *)arg;
    243218
    244         // FIXME - answer according to outcome
    245         ipc_answer_0(trans->caller, EOK);
    246 
    247         free(trans);
     219        async_answer_0(trans->caller, outcome);
     220
     221        async_transaction_destroy(trans);
    248222}
    249223
    250224static void callback_in(device_t *device,
    251     usb_transaction_outcome_t outcome, size_t actual_size, void *arg)
     225    int outcome, size_t actual_size, void *arg)
    252226{
    253227        async_transaction_t *trans = (async_transaction_t *)arg;
    254228
    255         // FIXME - answer according to outcome
    256         ipc_answer_1(trans->caller, EOK, (sysarg_t)trans);
     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        }
    257237
    258238        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);
    259248}
    260249
     
    271260{
    272261        if (!transfer_func) {
    273                 ipc_answer_0(callid, ENOTSUP);
    274                 return;
    275         }
    276 
    277         size_t expected_len = DEV_IPC_GET_ARG3(*call);
     262                async_answer_0(callid, ENOTSUP);
     263                return;
     264        }
     265
     266        size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
    278267        usb_target_t target = {
    279268                .address = DEV_IPC_GET_ARG1(*call),
     
    283272        size_t len = 0;
    284273        void *buffer = NULL;
    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);
    303 
    304         if (rc != EOK) {
    305                 ipc_answer_0(callid, rc);
     274
     275        int rc = async_data_write_accept(&buffer, false,
     276            1, USB_MAX_PAYLOAD_SIZE,
     277            0, &len);
     278
     279        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) {
    306286                if (buffer != NULL) {
    307287                        free(buffer);
    308288                }
    309                 free(trans);
     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);
    310303        }
    311304}
     
    323316{
    324317        if (!transfer_func) {
    325                 ipc_answer_0(callid, ENOTSUP);
    326                 return;
    327         }
    328 
    329         size_t len = DEV_IPC_GET_ARG3(*call);
     318                async_answer_0(callid, ENOTSUP);
     319                return;
     320        }
     321
     322        size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
    330323        usb_target_t target = {
    331324                .address = DEV_IPC_GET_ARG1(*call),
     
    333326        };
    334327
    335         async_transaction_t *trans = malloc(sizeof(async_transaction_t));
    336         trans->caller = callid;
     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;
    337341        trans->buffer = malloc(len);
    338342        trans->size = len;
    339343
    340         int rc = transfer_func(device, target, trans->buffer, len,
     344        int rc = transfer_func(device, target, max_packet_size,
     345            trans->buffer, len,
    341346            callback_in, trans);
    342347
    343348        if (rc != EOK) {
    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  */
    359 static 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;
     349                async_answer_0(callid, rc);
     350                async_transaction_destroy(trans);
     351        }
     352}
     353
     354void 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
     364void 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
     374void 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
     384void 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
     394void remote_usbhc_control_write(device_t *device, void *iface,
     395ipc_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;
    383403        }
    384404
     
    387407                .endpoint = DEV_IPC_GET_ARG2(*call)
    388408        };
    389 
    390         async_transaction_t *trans = malloc(sizeof(async_transaction_t));
    391         trans->caller = callid;
    392         trans->buffer = NULL;
    393         trans->size = 0;
     409        size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
     410        size_t max_packet_size = DEV_IPC_GET_ARG4(*call);
    394411
    395412        int rc;
    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 
    410         if (rc != EOK) {
    411                 ipc_answer_0(callid, rc);
    412                 free(trans);
    413         }
    414         return;
    415 }
    416 
    417 
    418 void remote_usbhc_interrupt_out(device_t *device, void *iface,
    419     ipc_callid_t callid, ipc_call_t *call)
     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);
     420        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
     458void remote_usbhc_control_read(device_t *device, void *iface,
     459ipc_callid_t callid, ipc_call_t *call)
    420460{
    421461        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    422462        assert(usb_iface != NULL);
    423463
    424         return remote_usbhc_out_transfer(device, callid, call,
    425             usb_iface->interrupt_out);
    426 }
    427 
    428 void 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 
    438 void 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 
    448 void 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 
    458 void 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 
    468 void 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 
    478 void 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 
    488 void 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);
     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        }
    496520}
    497521
Note: See TracChangeset for help on using the changeset viewer.