Ignore:
File:
1 edited

Legend:

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

    r0918382f r7f80313  
    3535
    3636#include <async.h>
     37#include <errno.h>
    3738#include <macros.h>
    38 #include <errno.h>
    39 #include <devman.h>
    4039
    4140#include "usb_iface.h"
    4241#include "ddf/driver.h"
    4342
     43typedef enum {
     44        IPC_M_USB_GET_MY_ADDRESS,
     45        IPC_M_USB_GET_MY_INTERFACE,
     46        IPC_M_USB_GET_HOST_CONTROLLER_HANDLE,
     47} usb_iface_funcs_t;
    4448
    45 usb_dev_session_t *usb_dev_connect(devman_handle_t handle)
     49/** Tell USB address assigned to device.
     50 * @param exch Vaid IPC exchange
     51 * @param address Pointer to address storage place.
     52 * @return Error code.
     53 *
     54 * Exch param is an open communication to device implementing usb_iface.
     55 */
     56int usb_get_my_address(async_exch_t *exch, usb_address_t *address)
    4657{
    47         return devman_device_connect(EXCHANGE_PARALLEL, handle, IPC_FLAG_BLOCKING);
     58        if (!exch)
     59                return EBADMEM;
     60        sysarg_t addr;
     61        const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     62            IPC_M_USB_GET_MY_ADDRESS, &addr);
     63
     64        if (ret == EOK && address != NULL)
     65                *address = (usb_address_t) addr;
     66        return ret;
    4867}
    49 
    50 usb_dev_session_t *usb_dev_connect_to_self(ddf_dev_t *dev)
    51 {
    52         // TODO All usb requests are atomic so this is safe,
    53         // it will need to change once USING EXCHANGE PARALLEL is safe with
    54         // devman_parent_device_connect
    55         return devman_parent_device_connect(EXCHANGE_ATOMIC,
    56             ddf_dev_get_handle(dev), IPC_FLAG_BLOCKING);
    57 }
    58 
    59 void usb_dev_disconnect(usb_dev_session_t *sess)
    60 {
    61         if (sess)
    62                 async_hangup(sess);
    63 }
    64 
    65 typedef enum {
    66         IPC_M_USB_GET_MY_INTERFACE,
    67         IPC_M_USB_GET_MY_DEVICE_HANDLE,
    68         IPC_M_USB_RESERVE_DEFAULT_ADDRESS,
    69         IPC_M_USB_RELEASE_DEFAULT_ADDRESS,
    70         IPC_M_USB_DEVICE_ENUMERATE,
    71         IPC_M_USB_DEVICE_REMOVE,
    72         IPC_M_USB_REGISTER_ENDPOINT,
    73         IPC_M_USB_UNREGISTER_ENDPOINT,
    74         IPC_M_USB_READ,
    75         IPC_M_USB_WRITE,
    76 } usb_iface_funcs_t;
    7768
    7869/** Tell interface number given device can use.
     
    9485}
    9586
    96 /** Tell devman handle of the usb device function.
     87/** Tell devman handle of device host controller.
    9788 * @param[in] exch IPC communication exchange
    98  * @param[out] handle devman handle of the HC used by the target device.
     89 * @param[out] hc_handle devman handle of the HC used by the target device.
    9990 * @return Error code.
    10091 */
    101 int usb_get_my_device_handle(async_exch_t *exch, devman_handle_t *handle)
     92int usb_get_hc_handle(async_exch_t *exch, devman_handle_t *hc_handle)
    10293{
    103         devman_handle_t h = 0;
     94        if (!exch)
     95                return EBADMEM;
     96        devman_handle_t h;
    10497        const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    105             IPC_M_USB_GET_MY_DEVICE_HANDLE, &h);
    106         if (ret == EOK && handle)
    107                 *handle = (devman_handle_t)h;
     98            IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
     99        if (ret == EOK && hc_handle)
     100                *hc_handle = (devman_handle_t)h;
    108101        return ret;
    109102}
    110103
    111 /** Reserve default USB address.
    112  * @param[in] exch IPC communication exchange
    113  * @param[in] speed Communication speed of the newly attached device
    114  * @return Error code.
    115  */
    116 int usb_reserve_default_address(async_exch_t *exch, usb_speed_t speed)
    117 {
    118         if (!exch)
    119                 return EBADMEM;
    120         return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    121             IPC_M_USB_RESERVE_DEFAULT_ADDRESS, speed);
    122 }
    123104
    124 /** Release default USB address.
    125  * @param[in] exch IPC communication exchange
    126  * @return Error code.
    127  */
    128 int usb_release_default_address(async_exch_t *exch)
    129 {
    130         if (!exch)
    131                 return EBADMEM;
    132         return async_req_1_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    133             IPC_M_USB_RELEASE_DEFAULT_ADDRESS);
    134 }
    135 
    136 /** Trigger USB device enumeration
    137  * @param[in] exch IPC communication exchange
    138  * @param[out] handle Identifier of the newly added device (if successful)
    139  * @return Error code.
    140  */
    141 int usb_device_enumerate(async_exch_t *exch, unsigned port)
    142 {
    143         if (!exch)
    144                 return EBADMEM;
    145         const int ret = async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    146             IPC_M_USB_DEVICE_ENUMERATE, port);
    147         return ret;
    148 }
    149 
    150 /** Trigger USB device enumeration
    151  * @param[in] exch IPC communication exchange
    152  * @param[in] handle Identifier of the device
    153  * @return Error code.
    154  */
    155 int usb_device_remove(async_exch_t *exch, unsigned port)
    156 {
    157         if (!exch)
    158                 return EBADMEM;
    159         return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    160             IPC_M_USB_DEVICE_REMOVE, port);
    161 }
    162 
    163 int usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
    164     usb_transfer_type_t type, usb_direction_t direction,
    165     size_t mps, unsigned interval)
    166 {
    167         if (!exch)
    168                 return EBADMEM;
    169 #define _PACK2(high, low) (((high & 0xffff) << 16) | (low & 0xffff))
    170 
    171         return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    172             IPC_M_USB_REGISTER_ENDPOINT, endpoint,
    173             _PACK2(type, direction), _PACK2(mps, interval));
    174 
    175 #undef _PACK2
    176 }
    177 
    178 int usb_unregister_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
    179     usb_direction_t direction)
    180 {
    181         if (!exch)
    182                 return EBADMEM;
    183         return async_req_3_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
    184             IPC_M_USB_UNREGISTER_ENDPOINT, endpoint, direction);
    185 }
    186 
    187 int usb_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
    188     void *data, size_t size, size_t *rec_size)
    189 {
    190         if (!exch)
    191                 return EBADMEM;
    192 
    193         if (size == 0 && setup == 0)
    194                 return EOK;
    195 
    196         /* Make call identifying target USB device and type of transfer. */
    197         aid_t opening_request = async_send_4(exch,
    198             DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_READ, endpoint,
    199             (setup & UINT32_MAX), (setup >> 32), NULL);
    200 
    201         if (opening_request == 0) {
    202                 return ENOMEM;
    203         }
    204 
    205         /* Retrieve the data. */
    206         ipc_call_t data_request_call;
    207         aid_t data_request =
    208             async_data_read(exch, data, size, &data_request_call);
    209 
    210         if (data_request == 0) {
    211                 // FIXME: How to let the other side know that we want to abort?
    212                 async_forget(opening_request);
    213                 return ENOMEM;
    214         }
    215 
    216         /* Wait for the answer. */
    217         sysarg_t data_request_rc;
    218         sysarg_t opening_request_rc;
    219         async_wait_for(data_request, &data_request_rc);
    220         async_wait_for(opening_request, &opening_request_rc);
    221 
    222         if (data_request_rc != EOK) {
    223                 /* Prefer the return code of the opening request. */
    224                 if (opening_request_rc != EOK) {
    225                         return (int) opening_request_rc;
    226                 } else {
    227                         return (int) data_request_rc;
    228                 }
    229         }
    230         if (opening_request_rc != EOK) {
    231                 return (int) opening_request_rc;
    232         }
    233 
    234         *rec_size = IPC_GET_ARG2(data_request_call);
    235         return EOK;
    236 }
    237 
    238 int usb_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
    239     const void *data, size_t size)
    240 {
    241         if (!exch)
    242                 return EBADMEM;
    243 
    244         if (size == 0 && setup == 0)
    245                 return EOK;
    246 
    247         aid_t opening_request = async_send_5(exch,
    248             DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size,
    249             (setup & UINT32_MAX), (setup >> 32), NULL);
    250 
    251         if (opening_request == 0) {
    252                 return ENOMEM;
    253         }
    254 
    255         /* Send the data if any. */
    256         if (size > 0) {
    257                 const int ret = async_data_write_start(exch, data, size);
    258                 if (ret != EOK) {
    259                         async_forget(opening_request);
    260                         return ret;
    261                 }
    262         }
    263 
    264         /* Wait for the answer. */
    265         sysarg_t opening_request_rc;
    266         async_wait_for(opening_request, &opening_request_rc);
    267 
    268         return (int) opening_request_rc;
    269 }
    270 
     105static void remote_usb_get_my_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    271106static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    272 static void remote_usb_get_my_device_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    273 static void remote_usb_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    274 static void remote_usb_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    275 static void remote_usb_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    276 static void remote_usb_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    277 static void remote_usb_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    278 static void remote_usb_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    279 static void remote_usb_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
    280 static void remote_usb_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
     107static void remote_usb_get_hc_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    281108
    282109/** Remote USB interface operations. */
    283 static remote_iface_func_ptr_t remote_usb_iface_ops [] = {
     110static const remote_iface_func_ptr_t remote_usb_iface_ops [] = {
     111        [IPC_M_USB_GET_MY_ADDRESS] = remote_usb_get_my_address,
    284112        [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface,
    285         [IPC_M_USB_GET_MY_DEVICE_HANDLE] = remote_usb_get_my_device_handle,
    286         [IPC_M_USB_RESERVE_DEFAULT_ADDRESS] = remote_usb_reserve_default_address,
    287         [IPC_M_USB_RELEASE_DEFAULT_ADDRESS] = remote_usb_release_default_address,
    288         [IPC_M_USB_DEVICE_ENUMERATE] = remote_usb_device_enumerate,
    289         [IPC_M_USB_DEVICE_REMOVE] = remote_usb_device_remove,
    290         [IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint,
    291         [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint,
    292         [IPC_M_USB_READ] = remote_usb_read,
    293         [IPC_M_USB_WRITE] = remote_usb_write,
     113        [IPC_M_USB_GET_HOST_CONTROLLER_HANDLE] = remote_usb_get_hc_handle,
    294114};
    295115
    296116/** Remote USB interface structure.
    297117 */
    298 remote_iface_t remote_usb_iface = {
     118const remote_iface_t remote_usb_iface = {
    299119        .method_count = ARRAY_SIZE(remote_usb_iface_ops),
    300         .methods = remote_usb_iface_ops,
     120        .methods = remote_usb_iface_ops
    301121};
     122
     123
     124void remote_usb_get_my_address(ddf_fun_t *fun, void *iface,
     125    ipc_callid_t callid, ipc_call_t *call)
     126{
     127        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
     128
     129        if (usb_iface->get_my_address == NULL) {
     130                async_answer_0(callid, ENOTSUP);
     131                return;
     132        }
     133
     134        usb_address_t address;
     135        const int ret = usb_iface->get_my_address(fun, &address);
     136        if (ret != EOK) {
     137                async_answer_0(callid, ret);
     138        } else {
     139                async_answer_1(callid, EOK, address);
     140        }
     141}
    302142
    303143void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface,
     
    320160}
    321161
    322 void remote_usb_get_my_device_handle(ddf_fun_t *fun, void *iface,
     162void remote_usb_get_hc_handle(ddf_fun_t *fun, void *iface,
    323163    ipc_callid_t callid, ipc_call_t *call)
    324164{
    325165        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
    326166
    327         if (usb_iface->get_my_device_handle == NULL) {
     167        if (usb_iface->get_hc_handle == NULL) {
    328168                async_answer_0(callid, ENOTSUP);
    329169                return;
     
    331171
    332172        devman_handle_t handle;
    333         const int ret = usb_iface->get_my_device_handle(fun, &handle);
     173        const int ret = usb_iface->get_hc_handle(fun, &handle);
    334174        if (ret != EOK) {
    335175                async_answer_0(callid, ret);
     
    338178        async_answer_1(callid, EOK, (sysarg_t) handle);
    339179}
    340 
    341 void remote_usb_reserve_default_address(ddf_fun_t *fun, void *iface,
    342     ipc_callid_t callid, ipc_call_t *call)
    343 {
    344         const usb_iface_t *usb_iface = (usb_iface_t *) iface;
    345 
    346         if (usb_iface->reserve_default_address == NULL) {
    347                 async_answer_0(callid, ENOTSUP);
    348                 return;
    349         }
    350 
    351         usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
    352         const int ret = usb_iface->reserve_default_address(fun, speed);
    353         async_answer_0(callid, ret);
    354 }
    355 
    356 void remote_usb_release_default_address(ddf_fun_t *fun, void *iface,
    357     ipc_callid_t callid, ipc_call_t *call)
    358 {
    359         const usb_iface_t *usb_iface = (usb_iface_t *) iface;
    360 
    361         if (usb_iface->release_default_address == NULL) {
    362                 async_answer_0(callid, ENOTSUP);
    363                 return;
    364         }
    365 
    366         const int ret = usb_iface->release_default_address(fun);
    367         async_answer_0(callid, ret);
    368 }
    369 
    370 static void remote_usb_device_enumerate(ddf_fun_t *fun, void *iface,
    371     ipc_callid_t callid, ipc_call_t *call)
    372 {
    373         const usb_iface_t *usb_iface = (usb_iface_t *) iface;
    374 
    375         if (usb_iface->device_enumerate == NULL) {
    376                 async_answer_0(callid, ENOTSUP);
    377                 return;
    378         }
    379 
    380         const unsigned port = DEV_IPC_GET_ARG1(*call);
    381         const int ret = usb_iface->device_enumerate(fun, port);
    382         async_answer_0(callid, ret);
    383 }
    384 
    385 static void remote_usb_device_remove(ddf_fun_t *fun, void *iface,
    386     ipc_callid_t callid, ipc_call_t *call)
    387 {
    388         const usb_iface_t *usb_iface = (usb_iface_t *) iface;
    389 
    390         if (usb_iface->device_remove == NULL) {
    391                 async_answer_0(callid, ENOTSUP);
    392                 return;
    393         }
    394 
    395         const unsigned port = DEV_IPC_GET_ARG1(*call);
    396         const int ret = usb_iface->device_remove(fun, port);
    397         async_answer_0(callid, ret);
    398 }
    399 
    400 static void remote_usb_register_endpoint(ddf_fun_t *fun, void *iface,
    401     ipc_callid_t callid, ipc_call_t *call)
    402 {
    403         usb_iface_t *usb_iface = (usb_iface_t *) iface;
    404 
    405         if (!usb_iface->register_endpoint) {
    406                 async_answer_0(callid, ENOTSUP);
    407                 return;
    408         }
    409 
    410 #define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \
    411         type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) >> 16)
    412 #define _INIT_FROM_LOW_DATA2(type, var, arg_no) \
    413         type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) & 0xffff)
    414 
    415         const usb_endpoint_t endpoint = DEV_IPC_GET_ARG1(*call);
    416 
    417         _INIT_FROM_HIGH_DATA2(usb_transfer_type_t, transfer_type, 2);
    418         _INIT_FROM_LOW_DATA2(usb_direction_t, direction, 2);
    419 
    420         _INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3);
    421         _INIT_FROM_LOW_DATA2(unsigned int, interval, 3);
    422 
    423 #undef _INIT_FROM_HIGH_DATA2
    424 #undef _INIT_FROM_LOW_DATA2
    425 
    426         const int ret = usb_iface->register_endpoint(fun, endpoint,
    427             transfer_type, direction, max_packet_size, interval);
    428 
    429         async_answer_0(callid, ret);
    430 }
    431 
    432 static void remote_usb_unregister_endpoint(ddf_fun_t *fun, void *iface,
    433     ipc_callid_t callid, ipc_call_t *call)
    434 {
    435         usb_iface_t *usb_iface = (usb_iface_t *) iface;
    436 
    437         if (!usb_iface->unregister_endpoint) {
    438                 async_answer_0(callid, ENOTSUP);
    439                 return;
    440         }
    441 
    442         usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG1(*call);
    443         usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG2(*call);
    444 
    445         int rc = usb_iface->unregister_endpoint(fun, endpoint, direction);
    446 
    447         async_answer_0(callid, rc);
    448 }
    449 
    450 typedef struct {
    451         ipc_callid_t caller;
    452         ipc_callid_t data_caller;
    453         void *buffer;
    454 } async_transaction_t;
    455 
    456 static void async_transaction_destroy(async_transaction_t *trans)
    457 {
    458         if (trans == NULL) {
    459                 return;
    460         }
    461         if (trans->buffer != NULL) {
    462                 free(trans->buffer);
    463         }
    464 
    465         free(trans);
    466 }
    467 
    468 static async_transaction_t *async_transaction_create(ipc_callid_t caller)
    469 {
    470         async_transaction_t *trans = malloc(sizeof(async_transaction_t));
    471         if (trans == NULL) {
    472                 return NULL;
    473         }
    474 
    475         trans->caller = caller;
    476         trans->data_caller = 0;
    477         trans->buffer = NULL;
    478 
    479         return trans;
    480 }
    481 
    482 static void callback_out(int outcome, void *arg)
    483 {
    484         async_transaction_t *trans = arg;
    485 
    486         async_answer_0(trans->caller, outcome);
    487 
    488         async_transaction_destroy(trans);
    489 }
    490 
    491 static void callback_in(int outcome, size_t actual_size, void *arg)
    492 {
    493         async_transaction_t *trans = (async_transaction_t *)arg;
    494 
    495         if (outcome != EOK) {
    496                 async_answer_0(trans->caller, outcome);
    497                 if (trans->data_caller) {
    498                         async_answer_0(trans->data_caller, EINTR);
    499                 }
    500                 async_transaction_destroy(trans);
    501                 return;
    502         }
    503 
    504         if (trans->data_caller) {
    505                 async_data_read_finalize(trans->data_caller,
    506                     trans->buffer, actual_size);
    507         }
    508 
    509         async_answer_0(trans->caller, EOK);
    510 
    511         async_transaction_destroy(trans);
    512 }
    513 
    514 void remote_usb_read(
    515     ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
    516 {
    517         assert(fun);
    518         assert(iface);
    519         assert(call);
    520 
    521         const usb_iface_t *usb_iface = iface;
    522 
    523         if (!usb_iface->read) {
    524                 async_answer_0(callid, ENOTSUP);
    525                 return;
    526         }
    527 
    528         const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
    529         const uint64_t setup =
    530             ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
    531             (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
    532 
    533         async_transaction_t *trans = async_transaction_create(callid);
    534         if (trans == NULL) {
    535                 async_answer_0(callid, ENOMEM);
    536                 return;
    537         }
    538 
    539         size_t size = 0;
    540         if (!async_data_read_receive(&trans->data_caller, &size)) {
    541                 async_answer_0(callid, EPARTY);
    542                 return;
    543         }
    544 
    545         trans->buffer = malloc(size);
    546         if (trans->buffer == NULL) {
    547                 async_answer_0(trans->data_caller, ENOMEM);
    548                 async_answer_0(callid, ENOMEM);
    549                 async_transaction_destroy(trans);
    550         }
    551 
    552         const int rc = usb_iface->read(
    553             fun, ep, setup, trans->buffer, size, callback_in, trans);
    554 
    555         if (rc != EOK) {
    556                 async_answer_0(trans->data_caller, rc);
    557                 async_answer_0(callid, rc);
    558                 async_transaction_destroy(trans);
    559         }
    560 }
    561 
    562 void remote_usb_write(
    563     ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
    564 {
    565         assert(fun);
    566         assert(iface);
    567         assert(call);
    568 
    569         const usb_iface_t *usb_iface = iface;
    570 
    571         if (!usb_iface->write) {
    572                 async_answer_0(callid, ENOTSUP);
    573                 return;
    574         }
    575 
    576         const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
    577         const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
    578         const uint64_t setup =
    579             ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
    580             (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
    581 
    582         async_transaction_t *trans = async_transaction_create(callid);
    583         if (trans == NULL) {
    584                 async_answer_0(callid, ENOMEM);
    585                 return;
    586         }
    587 
    588         size_t size = 0;
    589         if (data_buffer_len > 0) {
    590                 const int rc = async_data_write_accept(&trans->buffer, false,
    591                     1, data_buffer_len, 0, &size);
    592 
    593                 if (rc != EOK) {
    594                         async_answer_0(callid, rc);
    595                         async_transaction_destroy(trans);
    596                         return;
    597                 }
    598         }
    599 
    600         const int rc = usb_iface->write(
    601             fun, ep, setup, trans->buffer, size, callback_out, trans);
    602 
    603         if (rc != EOK) {
    604                 async_answer_0(callid, rc);
    605                 async_transaction_destroy(trans);
    606         }
    607 }
    608180/**
    609181 * @}
Note: See TracChangeset for help on using the changeset viewer.