Ignore:
Timestamp:
2011-03-01T22:20:56Z (15 years ago)
Author:
Matej Klonfar <maklf@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
e24e7b1
Parents:
976f546 (diff), ac8285d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge with the current development

File:
1 edited

Legend:

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

    r976f546 r19a1800  
    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>
     37#include <assert.h>
    3838
    3939#include "usbhc_iface.h"
    40 #include "driver.h"
     40#include "ddf/driver.h"
    4141
    4242#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 *);
    46 static void remote_usbhc_interrupt_out(device_t *, void *, ipc_callid_t, ipc_call_t *);
    47 static 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 *);
    54 static void remote_usbhc_reserve_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
    55 static void remote_usbhc_release_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
    56 static void remote_usbhc_request_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
    57 static void remote_usbhc_bind_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
    58 static void remote_usbhc_release_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
    59 //static void remote_usbhc(device_t *, void *, ipc_callid_t, ipc_call_t *);
     43#define HACK_MAX_PACKET_SIZE 8
     44#define HACK_MAX_PACKET_SIZE_INTERRUPT_IN 4
     45
     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 *);
     57//static void remote_usbhc(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    6058
    6159/** Remote USB host controller interface operations. */
    6260static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
    63         remote_usbhc_get_address,
    64 
    65         remote_usbhc_get_buffer,
    66 
    6761        remote_usbhc_reserve_default_address,
    6862        remote_usbhc_release_default_address,
     
    7569        remote_usbhc_interrupt_in,
    7670
    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
     71        remote_usbhc_bulk_out,
     72        remote_usbhc_bulk_in,
     73
     74        remote_usbhc_control_write,
     75        remote_usbhc_control_read
    8476};
    8577
     
    9486typedef struct {
    9587        ipc_callid_t caller;
     88        ipc_callid_t data_caller;
    9689        void *buffer;
     90        void *setup_packet;
    9791        size_t size;
    9892} async_transaction_t;
    9993
    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);
     94static void async_transaction_destroy(async_transaction_t *trans)
     95{
     96        if (trans == NULL) {
     97                return;
     98        }
     99
     100        if (trans->setup_packet != NULL) {
     101                free(trans->setup_packet);
     102        }
     103        if (trans->buffer != NULL) {
     104                free(trans->buffer);
     105        }
     106
     107        free(trans);
     108}
     109
     110static async_transaction_t *async_transaction_create(ipc_callid_t caller)
     111{
     112        async_transaction_t *trans = malloc(sizeof(async_transaction_t));
     113        if (trans == NULL) {
     114                return NULL;
     115        }
     116
     117        trans->caller = caller;
     118        trans->data_caller = 0;
     119        trans->buffer = NULL;
     120        trans->setup_packet = NULL;
     121        trans->size = 0;
     122
     123        return trans;
     124}
     125
     126void remote_usbhc_reserve_default_address(ddf_fun_t *fun, void *iface,
     127    ipc_callid_t callid, ipc_call_t *call)
     128{
     129        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     130
     131        if (!usb_iface->reserve_default_address) {
     132                async_answer_0(callid, ENOTSUP);
     133                return;
     134        }
     135       
     136        usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
     137       
     138        int rc = usb_iface->reserve_default_address(fun, speed);
     139
     140        async_answer_0(callid, rc);
     141}
     142
     143void remote_usbhc_release_default_address(ddf_fun_t *fun, void *iface,
     144    ipc_callid_t callid, ipc_call_t *call)
     145{
     146        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     147
     148        if (!usb_iface->release_default_address) {
     149                async_answer_0(callid, ENOTSUP);
     150                return;
     151        }
     152
     153        int rc = usb_iface->release_default_address(fun);
     154
     155        async_answer_0(callid, rc);
     156}
     157
     158void remote_usbhc_request_address(ddf_fun_t *fun, void *iface,
     159    ipc_callid_t callid, ipc_call_t *call)
     160{
     161        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     162
     163        if (!usb_iface->request_address) {
     164                async_answer_0(callid, ENOTSUP);
     165                return;
     166        }
     167       
     168        usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
    111169
    112170        usb_address_t address;
    113         int rc = usb_iface->tell_address(device, handle, &address);
    114         if (rc != EOK) {
    115                 ipc_answer_0(callid, rc);
     171        int rc = usb_iface->request_address(fun, speed, &address);
     172        if (rc != EOK) {
     173                async_answer_0(callid, rc);
    116174        } 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);
    200         }
    201 }
    202 
    203 void remote_usbhc_bind_address(device_t *device, void *iface,
     175                async_answer_1(callid, EOK, (sysarg_t) address);
     176        }
     177}
     178
     179void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface,
    204180    ipc_callid_t callid, ipc_call_t *call)
    205181{
     
    207183
    208184        if (!usb_iface->bind_address) {
    209                 ipc_answer_0(callid, ENOTSUP);
     185                async_answer_0(callid, ENOTSUP);
    210186                return;
    211187        }
     
    214190        devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
    215191
    216         int rc = usb_iface->bind_address(device, address, handle);
    217 
    218         ipc_answer_0(callid, rc);
    219 }
    220 
    221 void remote_usbhc_release_address(device_t *device, void *iface,
     192        int rc = usb_iface->bind_address(fun, address, handle);
     193
     194        async_answer_0(callid, rc);
     195}
     196
     197void remote_usbhc_release_address(ddf_fun_t *fun, void *iface,
    222198    ipc_callid_t callid, ipc_call_t *call)
    223199{
     
    225201
    226202        if (!usb_iface->release_address) {
    227                 ipc_answer_0(callid, ENOTSUP);
     203                async_answer_0(callid, ENOTSUP);
    228204                return;
    229205        }
     
    231207        usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
    232208
    233         int rc = usb_iface->release_address(device, address);
    234 
    235         ipc_answer_0(callid, rc);
    236 }
    237 
    238 
    239 static void callback_out(device_t *device,
    240     usb_transaction_outcome_t outcome, void *arg)
     209        int rc = usb_iface->release_address(fun, address);
     210
     211        async_answer_0(callid, rc);
     212}
     213
     214
     215static void callback_out(ddf_fun_t *fun,
     216    int outcome, void *arg)
    241217{
    242218        async_transaction_t *trans = (async_transaction_t *)arg;
    243219
    244         // FIXME - answer according to outcome
    245         ipc_answer_0(trans->caller, EOK);
    246 
    247         free(trans);
    248 }
    249 
    250 static void callback_in(device_t *device,
    251     usb_transaction_outcome_t outcome, size_t actual_size, void *arg)
     220        async_answer_0(trans->caller, outcome);
     221
     222        async_transaction_destroy(trans);
     223}
     224
     225static void callback_in(ddf_fun_t *fun,
     226    int outcome, size_t actual_size, void *arg)
    252227{
    253228        async_transaction_t *trans = (async_transaction_t *)arg;
    254229
    255         // FIXME - answer according to outcome
    256         ipc_answer_1(trans->caller, EOK, (sysarg_t)trans);
     230        if (outcome != EOK) {
     231                async_answer_0(trans->caller, outcome);
     232                if (trans->data_caller) {
     233                        async_answer_0(trans->data_caller, EINTR);
     234                }
     235                async_transaction_destroy(trans);
     236                return;
     237        }
    257238
    258239        trans->size = actual_size;
     240
     241        if (trans->data_caller) {
     242                async_data_read_finalize(trans->data_caller,
     243                    trans->buffer, actual_size);
     244        }
     245
     246        async_answer_0(trans->caller, EOK);
     247
     248        async_transaction_destroy(trans);
    259249}
    260250
     
    266256 * @param transfer_func Transfer function (might be NULL).
    267257 */
    268 static void remote_usbhc_out_transfer(device_t *device,
     258static void remote_usbhc_out_transfer(ddf_fun_t *fun,
    269259    ipc_callid_t callid, ipc_call_t *call,
    270260    usbhc_iface_transfer_out_t transfer_func)
    271261{
    272262        if (!transfer_func) {
    273                 ipc_answer_0(callid, ENOTSUP);
    274                 return;
    275         }
    276 
    277         size_t expected_len = DEV_IPC_GET_ARG3(*call);
     263                async_answer_0(callid, ENOTSUP);
     264                return;
     265        }
     266
     267        size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
    278268        usb_target_t target = {
    279269                .address = DEV_IPC_GET_ARG1(*call),
     
    283273        size_t len = 0;
    284274        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);
     275
     276        int rc = async_data_write_accept(&buffer, false,
     277            1, USB_MAX_PAYLOAD_SIZE,
     278            0, &len);
     279
     280        if (rc != EOK) {
     281                async_answer_0(callid, rc);
     282                return;
     283        }
     284
     285        async_transaction_t *trans = async_transaction_create(callid);
     286        if (trans == NULL) {
    306287                if (buffer != NULL) {
    307288                        free(buffer);
    308289                }
    309                 free(trans);
     290                async_answer_0(callid, ENOMEM);
     291                return;
     292        }
     293
     294        trans->buffer = buffer;
     295        trans->size = len;
     296
     297        rc = transfer_func(fun, target, max_packet_size,
     298            buffer, len,
     299            callback_out, trans);
     300
     301        if (rc != EOK) {
     302                async_answer_0(callid, rc);
     303                async_transaction_destroy(trans);
    310304        }
    311305}
     
    318312 * @param transfer_func Transfer function (might be NULL).
    319313 */
    320 static void remote_usbhc_in_transfer(device_t *device,
     314static void remote_usbhc_in_transfer(ddf_fun_t *fun,
    321315    ipc_callid_t callid, ipc_call_t *call,
    322316    usbhc_iface_transfer_in_t transfer_func)
    323317{
    324318        if (!transfer_func) {
    325                 ipc_answer_0(callid, ENOTSUP);
    326                 return;
    327         }
    328 
    329         size_t len = DEV_IPC_GET_ARG3(*call);
     319                async_answer_0(callid, ENOTSUP);
     320                return;
     321        }
     322
     323        size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
    330324        usb_target_t target = {
    331325                .address = DEV_IPC_GET_ARG1(*call),
     
    333327        };
    334328
    335         async_transaction_t *trans = malloc(sizeof(async_transaction_t));
    336         trans->caller = callid;
     329        size_t len;
     330        ipc_callid_t data_callid;
     331        if (!async_data_read_receive(&data_callid, &len)) {
     332                async_answer_0(callid, EPARTY);
     333                return;
     334        }
     335
     336        async_transaction_t *trans = async_transaction_create(callid);
     337        if (trans == NULL) {
     338                async_answer_0(callid, ENOMEM);
     339                return;
     340        }
     341        trans->data_caller = data_callid;
    337342        trans->buffer = malloc(len);
    338343        trans->size = len;
    339344
    340         int rc = transfer_func(device, target, trans->buffer, len,
     345        int rc = transfer_func(fun, target, max_packet_size,
     346            trans->buffer, len,
    341347            callback_in, trans);
    342348
    343349        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;
     350                async_answer_0(callid, rc);
     351                async_transaction_destroy(trans);
     352        }
     353}
     354
     355void remote_usbhc_interrupt_out(ddf_fun_t *fun, void *iface,
     356    ipc_callid_t callid, ipc_call_t *call)
     357{
     358        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     359        assert(usb_iface != NULL);
     360
     361        return remote_usbhc_out_transfer(fun, callid, call,
     362            usb_iface->interrupt_out);
     363}
     364
     365void remote_usbhc_interrupt_in(ddf_fun_t *fun, void *iface,
     366    ipc_callid_t callid, ipc_call_t *call)
     367{
     368        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     369        assert(usb_iface != NULL);
     370
     371        return remote_usbhc_in_transfer(fun, callid, call,
     372            usb_iface->interrupt_in);
     373}
     374
     375void remote_usbhc_bulk_out(ddf_fun_t *fun, void *iface,
     376    ipc_callid_t callid, ipc_call_t *call)
     377{
     378        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     379        assert(usb_iface != NULL);
     380
     381        return remote_usbhc_out_transfer(fun, callid, call,
     382            usb_iface->bulk_out);
     383}
     384
     385void remote_usbhc_bulk_in(ddf_fun_t *fun, void *iface,
     386    ipc_callid_t callid, ipc_call_t *call)
     387{
     388        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     389        assert(usb_iface != NULL);
     390
     391        return remote_usbhc_in_transfer(fun, callid, call,
     392            usb_iface->bulk_in);
     393}
     394
     395void remote_usbhc_control_write(ddf_fun_t *fun, void *iface,
     396ipc_callid_t callid, ipc_call_t *call)
     397{
     398        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     399        assert(usb_iface != NULL);
     400
     401        if (!usb_iface->control_write) {
     402                async_answer_0(callid, ENOTSUP);
     403                return;
    383404        }
    384405
     
    387408                .endpoint = DEV_IPC_GET_ARG2(*call)
    388409        };
    389 
    390         async_transaction_t *trans = malloc(sizeof(async_transaction_t));
    391         trans->caller = callid;
    392         trans->buffer = NULL;
    393         trans->size = 0;
     410        size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
     411        size_t max_packet_size = DEV_IPC_GET_ARG4(*call);
    394412
    395413        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)
     414
     415        void *setup_packet = NULL;
     416        void *data_buffer = NULL;
     417        size_t setup_packet_len = 0;
     418
     419        rc = async_data_write_accept(&setup_packet, false,
     420            1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
     421        if (rc != EOK) {
     422                async_answer_0(callid, rc);
     423                return;
     424        }
     425
     426        if (data_buffer_len > 0) {
     427                rc = async_data_write_accept(&data_buffer, false,
     428                    1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
     429                if (rc != EOK) {
     430                        async_answer_0(callid, rc);
     431                        free(setup_packet);
     432                        return;
     433                }
     434        }
     435
     436        async_transaction_t *trans = async_transaction_create(callid);
     437        if (trans == NULL) {
     438                async_answer_0(callid, ENOMEM);
     439                free(setup_packet);
     440                free(data_buffer);
     441                return;
     442        }
     443        trans->setup_packet = setup_packet;
     444        trans->buffer = data_buffer;
     445        trans->size = data_buffer_len;
     446
     447        rc = usb_iface->control_write(fun, target, max_packet_size,
     448            setup_packet, setup_packet_len,
     449            data_buffer, data_buffer_len,
     450            callback_out, trans);
     451
     452        if (rc != EOK) {
     453                async_answer_0(callid, rc);
     454                async_transaction_destroy(trans);
     455        }
     456}
     457
     458
     459void remote_usbhc_control_read(ddf_fun_t *fun, void *iface,
     460ipc_callid_t callid, ipc_call_t *call)
    420461{
    421462        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    422463        assert(usb_iface != NULL);
    423464
    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);
     465        if (!usb_iface->control_read) {
     466                async_answer_0(callid, ENOTSUP);
     467                return;
     468        }
     469
     470        usb_target_t target = {
     471                .address = DEV_IPC_GET_ARG1(*call),
     472                .endpoint = DEV_IPC_GET_ARG2(*call)
     473        };
     474        size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
     475
     476        int rc;
     477
     478        void *setup_packet = NULL;
     479        size_t setup_packet_len = 0;
     480        size_t data_len = 0;
     481
     482        rc = async_data_write_accept(&setup_packet, false,
     483            1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
     484        if (rc != EOK) {
     485                async_answer_0(callid, rc);
     486                return;
     487        }
     488
     489        ipc_callid_t data_callid;
     490        if (!async_data_read_receive(&data_callid, &data_len)) {
     491                async_answer_0(callid, EPARTY);
     492                free(setup_packet);
     493                return;
     494        }
     495
     496        async_transaction_t *trans = async_transaction_create(callid);
     497        if (trans == NULL) {
     498                async_answer_0(callid, ENOMEM);
     499                free(setup_packet);
     500                return;
     501        }
     502        trans->data_caller = data_callid;
     503        trans->setup_packet = setup_packet;
     504        trans->size = data_len;
     505        trans->buffer = malloc(data_len);
     506        if (trans->buffer == NULL) {
     507                async_answer_0(callid, ENOMEM);
     508                async_transaction_destroy(trans);
     509                return;
     510        }
     511
     512        rc = usb_iface->control_read(fun, target, max_packet_size,
     513            setup_packet, setup_packet_len,
     514            trans->buffer, trans->size,
     515            callback_in, trans);
     516
     517        if (rc != EOK) {
     518                async_answer_0(callid, rc);
     519                async_transaction_destroy(trans);
     520        }
    496521}
    497522
Note: See TracChangeset for help on using the changeset viewer.