Ignore:
File:
1 edited

Legend:

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

    rdb51a6a6 r25a179e  
    11/*
    2  * Copyright (c) 2010 Vojtech Horky
     2 * Copyright (c) 2010-2011 Vojtech Horky
    33 * Copyright (c) 2011 Jan Vesely
    4  * Copyright (c) 2017 Ondrej Hlavaty
    54 * All rights reserved.
    65 *
     
    3635
    3736#include <async.h>
     37#include <errno.h>
     38#include <assert.h>
    3839#include <macros.h>
    39 #include <errno.h>
    40 #include <devman.h>
    4140
    4241#include "usbhc_iface.h"
    4342#include "ddf/driver.h"
    4443
    45 
     44#define USB_MAX_PAYLOAD_SIZE 1020
     45
     46/** IPC methods for communication with HC through DDF interface.
     47 *
     48 * Notes for async methods:
     49 *
     50 * Methods for sending data to device (OUT transactions)
     51 * - e.g. IPC_M_USBHC_INTERRUPT_OUT -
     52 * always use the same semantics:
     53 * - first, IPC call with given method is made
     54 *   - argument #1 is target address
     55 *   - argument #2 is target endpoint
     56 *   - argument #3 is max packet size of the endpoint
     57 * - this call is immediately followed by IPC data write (from caller)
     58 * - the initial call (and the whole transaction) is answer after the
     59 *   transaction is scheduled by the HC and acknowledged by the device
     60 *   or immediately after error is detected
     61 * - the answer carries only the error code
     62 *
     63 * Methods for retrieving data from device (IN transactions)
     64 * - e.g. IPC_M_USBHC_INTERRUPT_IN -
     65 * also use the same semantics:
     66 * - first, IPC call with given method is made
     67 *   - argument #1 is target address
     68 *   - argument #2 is target endpoint
     69 * - this call is immediately followed by IPC data read (async version)
     70 * - the call is not answered until the device returns some data (or until
     71 *   error occurs)
     72 *
     73 * Some special methods (NO-DATA transactions) do not send any data. These
     74 * might behave as both OUT or IN transactions because communication parts
     75 * where actual buffers are exchanged are omitted.
     76 **
     77 * For all these methods, wrap functions exists. Important rule: functions
     78 * for IN transactions have (as parameters) buffers where retrieved data
     79 * will be stored. These buffers must be already allocated and shall not be
     80 * touch until the transaction is completed
     81 * (e.g. not before calling usb_wait_for() with appropriate handle).
     82 * OUT transactions buffers can be freed immediately after call is dispatched
     83 * (i.e. after return from wrapping function).
     84 *
     85 */
    4686typedef enum {
    47         IPC_M_USB_DEFAULT_ADDRESS_RESERVATION,
    48         IPC_M_USB_DEVICE_ENUMERATE,
    49         IPC_M_USB_DEVICE_REMOVE,
    50         IPC_M_USB_REGISTER_ENDPOINT,
    51         IPC_M_USB_UNREGISTER_ENDPOINT,
    52         IPC_M_USB_READ,
    53         IPC_M_USB_WRITE,
     87        /** Get data from device.
     88         * See explanation at usb_iface_funcs_t (IN transaction).
     89         */
     90        IPC_M_USBHC_READ,
     91
     92        /** Send data to device.
     93         * See explanation at usb_iface_funcs_t (OUT transaction).
     94         */
     95        IPC_M_USBHC_WRITE,
    5496} usbhc_iface_funcs_t;
    5597
    56 /** Reserve default USB address.
    57  * @param[in] exch IPC communication exchange
    58  * @return Error code.
    59  */
    60 int usbhc_reserve_default_address(async_exch_t *exch)
     98int usbhc_read(async_exch_t *exch, usb_address_t address,
     99    usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size,
     100    size_t *rec_size)
    61101{
    62102        if (!exch)
    63103                return EBADMEM;
    64         return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, true);
    65 }
    66 
    67 /** Release default USB address.
    68  *
    69  * @param[in] exch IPC communication exchange
    70  *
    71  * @return Error code.
    72  */
    73 int usbhc_release_default_address(async_exch_t *exch)
    74 {
    75         if (!exch)
    76                 return EBADMEM;
    77         return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, false);
    78 }
    79 
    80 /**
    81  * Trigger USB device enumeration
    82  *
    83  * @param[in] exch IPC communication exchange
    84  * @param[in] port Port number at which the device is attached
    85  * @param[in] speed Communication speed of the newly attached device
    86  *
    87  * @return Error code.
    88  */
    89 int usbhc_device_enumerate(async_exch_t *exch, unsigned port, usb_speed_t speed)
    90 {
    91         if (!exch)
    92                 return EBADMEM;
    93         const int ret = async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    94             IPC_M_USB_DEVICE_ENUMERATE, port, speed);
    95         return ret;
    96 }
    97 
    98 /** Trigger USB device enumeration
    99  *
    100  * @param[in] exch   IPC communication exchange
    101  * @param[in] handle Identifier of the device
    102  *
    103  * @return Error code.
    104  *
    105  */
    106 int usbhc_device_remove(async_exch_t *exch, unsigned port)
    107 {
    108         if (!exch)
    109                 return EBADMEM;
    110         return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    111             IPC_M_USB_DEVICE_REMOVE, port);
    112 }
    113 
    114 int usbhc_register_endpoint(async_exch_t *exch, usb_pipe_desc_t *pipe_desc,
    115     const usb_endpoint_descriptors_t *desc)
    116 {
    117         if (!exch)
    118                 return EBADMEM;
    119 
    120         if (!desc)
    121                 return EINVAL;
    122 
    123         aid_t opening_request = async_send_1(exch,
    124             DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_REGISTER_ENDPOINT, NULL);
    125 
    126         if (opening_request == 0) {
    127                 return ENOMEM;
    128         }
    129 
    130         int ret = async_data_write_start(exch, desc, sizeof(*desc));
    131         if (ret != EOK) {
    132                 async_forget(opening_request);
    133                 return ret;
    134         }
    135 
    136         /* Wait for the answer. */
    137         sysarg_t opening_request_rc;
    138         async_wait_for(opening_request, &opening_request_rc);
    139 
    140         if (opening_request_rc)
    141                 return (int) opening_request_rc;
    142 
    143         usb_pipe_desc_t dest;
    144         ret = async_data_read_start(exch, &dest, sizeof(dest));
    145         if (ret != EOK) {
    146                 return ret;
    147         }
    148 
    149         if (pipe_desc)
    150                 *pipe_desc = dest;
    151 
    152         return EOK;
    153 }
    154 
    155 int usbhc_unregister_endpoint(async_exch_t *exch, const usb_pipe_desc_t *pipe_desc)
    156 {
    157         if (!exch)
    158                 return EBADMEM;
    159 
    160         aid_t opening_request = async_send_1(exch,
    161                 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_UNREGISTER_ENDPOINT, NULL);
    162 
    163         if (opening_request == 0) {
    164                 return ENOMEM;
    165         }
    166 
    167         const int ret = async_data_write_start(exch, pipe_desc, sizeof(*pipe_desc));
    168         if (ret != EOK) {
    169                 async_forget(opening_request);
    170                 return ret;
    171         }
    172 
    173         /* Wait for the answer. */
    174         sysarg_t opening_request_rc;
    175         async_wait_for(opening_request, &opening_request_rc);
    176 
    177         return (int) opening_request_rc;
    178 }
    179 
    180 int usbhc_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
    181     void *data, size_t size, size_t *rec_size)
    182 {
    183         if (!exch)
    184                 return EBADMEM;
    185104
    186105        if (size == 0 && setup == 0)
    187106                return EOK;
    188107
     108        const usb_target_t target =
     109            {{ .address = address, .endpoint = endpoint }};
     110
    189111        /* Make call identifying target USB device and type of transfer. */
    190112        aid_t opening_request = async_send_4(exch,
    191             DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_READ, endpoint,
     113            DEV_IFACE_ID(USBHC_DEV_IFACE),
     114            IPC_M_USBHC_READ, target.packed,
    192115            (setup & UINT32_MAX), (setup >> 32), NULL);
    193116
     
    208131
    209132        /* Wait for the answer. */
    210         sysarg_t data_request_rc;
    211         sysarg_t opening_request_rc;
     133        int data_request_rc;
     134        int opening_request_rc;
    212135        async_wait_for(data_request, &data_request_rc);
    213136        async_wait_for(opening_request, &opening_request_rc);
     
    229152}
    230153
    231 int usbhc_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,
    232     const void *data, size_t size)
     154int usbhc_write(async_exch_t *exch, usb_address_t address,
     155    usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size)
    233156{
    234157        if (!exch)
     
    238161                return EOK;
    239162
    240         aid_t opening_request = async_send_5(exch,
    241             DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size,
     163        const usb_target_t target =
     164            {{ .address = address, .endpoint = endpoint }};
     165
     166        aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
     167            IPC_M_USBHC_WRITE, target.packed, size,
    242168            (setup & UINT32_MAX), (setup >> 32), NULL);
    243169
     
    256182
    257183        /* Wait for the answer. */
    258         sysarg_t opening_request_rc;
     184        int opening_request_rc;
    259185        async_wait_for(opening_request, &opening_request_rc);
    260186
     
    262188}
    263189
    264 static void remote_usbhc_default_address_reservation(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    265 static void remote_usbhc_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    266 static void remote_usbhc_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    267 static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    268 static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    269 static void remote_usbhc_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
    270 static void remote_usbhc_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call);
    271 
    272 /** Remote USB interface operations. */
    273 static const remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
    274         [IPC_M_USB_DEFAULT_ADDRESS_RESERVATION] = remote_usbhc_default_address_reservation,
    275         [IPC_M_USB_DEVICE_ENUMERATE] = remote_usbhc_device_enumerate,
    276         [IPC_M_USB_DEVICE_REMOVE] = remote_usbhc_device_remove,
    277         [IPC_M_USB_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
    278         [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint,
    279         [IPC_M_USB_READ] = remote_usbhc_read,
    280         [IPC_M_USB_WRITE] = remote_usbhc_write,
     190static void remote_usbhc_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     191static void remote_usbhc_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     192
     193/** Remote USB host controller interface operations. */
     194static const remote_iface_func_ptr_t remote_usbhc_iface_ops[] = {
     195        [IPC_M_USBHC_READ] = remote_usbhc_read,
     196        [IPC_M_USBHC_WRITE] = remote_usbhc_write,
    281197};
    282198
    283 /** Remote USB interface structure.
     199/** Remote USB host controller interface structure.
    284200 */
    285201const remote_iface_t remote_usbhc_iface = {
    286202        .method_count = ARRAY_SIZE(remote_usbhc_iface_ops),
    287         .methods = remote_usbhc_iface_ops,
     203        .methods = remote_usbhc_iface_ops
    288204};
    289205
     
    294210} async_transaction_t;
    295211
    296 void remote_usbhc_default_address_reservation(ddf_fun_t *fun, void *iface,
    297     ipc_callid_t callid, ipc_call_t *call)
    298 {
    299         const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
    300 
    301         if (usbhc_iface->default_address_reservation == NULL) {
    302                 async_answer_0(callid, ENOTSUP);
    303                 return;
    304         }
    305 
    306         const bool reserve = IPC_GET_ARG2(*call);
    307         const int ret = usbhc_iface->default_address_reservation(fun, reserve);
    308         async_answer_0(callid, ret);
    309 }
    310 
    311 
    312 static void remote_usbhc_device_enumerate(ddf_fun_t *fun, void *iface,
    313     ipc_callid_t callid, ipc_call_t *call)
    314 {
    315         const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
    316 
    317         if (usbhc_iface->device_enumerate == NULL) {
    318                 async_answer_0(callid, ENOTSUP);
    319                 return;
    320         }
    321 
    322         const unsigned port = DEV_IPC_GET_ARG1(*call);
    323         usb_speed_t speed = DEV_IPC_GET_ARG2(*call);
    324         const int ret = usbhc_iface->device_enumerate(fun, port, speed);
    325         async_answer_0(callid, ret);
    326 }
    327 
    328 static void remote_usbhc_device_remove(ddf_fun_t *fun, void *iface,
    329     ipc_callid_t callid, ipc_call_t *call)
    330 {
    331         const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface;
    332 
    333         if (usbhc_iface->device_remove == NULL) {
    334                 async_answer_0(callid, ENOTSUP);
    335                 return;
    336         }
    337 
    338         const unsigned port = DEV_IPC_GET_ARG1(*call);
    339         const int ret = usbhc_iface->device_remove(fun, port);
    340         async_answer_0(callid, ret);
    341 }
    342 
    343 static void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
    344     ipc_callid_t callid, ipc_call_t *call)
     212static void async_transaction_destroy(async_transaction_t *trans)
     213{
     214        if (trans == NULL)
     215                return;
     216       
     217        if (trans->buffer != NULL)
     218                free(trans->buffer);
     219       
     220        free(trans);
     221}
     222
     223static async_transaction_t *async_transaction_create(ipc_callid_t caller)
     224{
     225        async_transaction_t *trans = malloc(sizeof(async_transaction_t));
     226        if (trans == NULL) {
     227                return NULL;
     228        }
     229
     230        trans->caller = caller;
     231        trans->data_caller = 0;
     232        trans->buffer = NULL;
     233
     234        return trans;
     235}
     236
     237static void callback_out(int outcome, void *arg)
     238{
     239        async_transaction_t *trans = arg;
     240
     241        async_answer_0(trans->caller, outcome);
     242
     243        async_transaction_destroy(trans);
     244}
     245
     246static void callback_in(int outcome, size_t actual_size, void *arg)
     247{
     248        async_transaction_t *trans = (async_transaction_t *)arg;
     249
     250        if (outcome != EOK) {
     251                async_answer_0(trans->caller, outcome);
     252                if (trans->data_caller) {
     253                        async_answer_0(trans->data_caller, EINTR);
     254                }
     255                async_transaction_destroy(trans);
     256                return;
     257        }
     258
     259        if (trans->data_caller) {
     260                async_data_read_finalize(trans->data_caller,
     261                    trans->buffer, actual_size);
     262        }
     263
     264        async_answer_0(trans->caller, EOK);
     265
     266        async_transaction_destroy(trans);
     267}
     268
     269void remote_usbhc_read(
     270    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
    345271{
    346272        assert(fun);
     
    348274        assert(call);
    349275
    350         const usbhc_iface_t *usbhc_iface = iface;
    351 
    352         if (!usbhc_iface->register_endpoint) {
     276        const usbhc_iface_t *hc_iface = iface;
     277
     278        if (!hc_iface->read) {
    353279                async_answer_0(callid, ENOTSUP);
    354280                return;
    355281        }
    356282
    357         usb_endpoint_descriptors_t ep_desc;
    358         ipc_callid_t data_callid;
    359         size_t len;
    360 
    361         if (!async_data_write_receive(&data_callid, &len)
    362             || len != sizeof(ep_desc)) {
    363                 async_answer_0(callid, EINVAL);
    364                 return;
    365         }
    366         async_data_write_finalize(data_callid, &ep_desc, sizeof(ep_desc));
    367 
    368         usb_pipe_desc_t pipe_desc;
    369 
    370         const int rc = usbhc_iface->register_endpoint(fun, &pipe_desc, &ep_desc);
    371         async_answer_0(callid, rc);
    372 
    373         if (!async_data_read_receive(&data_callid, &len)
    374             || len != sizeof(pipe_desc)) {
    375                 return;
    376         }
    377         async_data_read_finalize(data_callid, &pipe_desc, sizeof(pipe_desc));
    378 }
    379 
    380 static void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
    381     ipc_callid_t callid, ipc_call_t *call)
    382 {
    383         assert(fun);
    384         assert(iface);
    385         assert(call);
    386 
    387         const usbhc_iface_t *usbhc_iface = iface;
    388 
    389         if (!usbhc_iface->unregister_endpoint) {
    390                 async_answer_0(callid, ENOTSUP);
    391                 return;
    392         }
    393 
    394         usb_pipe_desc_t pipe_desc;
    395         ipc_callid_t data_callid;
    396         size_t len;
    397 
    398         if (!async_data_write_receive(&data_callid, &len)
    399             || len != sizeof(pipe_desc)) {
    400                 async_answer_0(callid, EINVAL);
    401                 return;
    402         }
    403         async_data_write_finalize(data_callid, &pipe_desc, sizeof(pipe_desc));
    404 
    405         const int rc = usbhc_iface->unregister_endpoint(fun, &pipe_desc);
    406         async_answer_0(callid, rc);
    407 }
    408 
    409 static void async_transaction_destroy(async_transaction_t *trans)
    410 {
    411         if (trans == NULL) {
    412                 return;
    413         }
    414         if (trans->buffer != NULL) {
    415                 free(trans->buffer);
    416         }
    417 
    418         free(trans);
    419 }
    420 
    421 static async_transaction_t *async_transaction_create(ipc_callid_t caller)
    422 {
    423         async_transaction_t *trans = malloc(sizeof(async_transaction_t));
    424         if (trans == NULL) {
    425                 return NULL;
    426         }
    427 
    428         trans->caller = caller;
    429         trans->data_caller = 0;
    430         trans->buffer = NULL;
    431 
    432         return trans;
    433 }
    434 
    435 static int callback_out(void *arg, int error, size_t transferred_size)
    436 {
    437         async_transaction_t *trans = arg;
    438 
    439         const int err = async_answer_0(trans->caller, error);
    440 
    441         async_transaction_destroy(trans);
    442 
    443         return err;
    444 }
    445 
    446 static int callback_in(void *arg, int error, size_t transferred_size)
    447 {
    448         async_transaction_t *trans = arg;
    449 
    450         if (trans->data_caller) {
    451                 if (error == EOK) {
    452                         error = async_data_read_finalize(trans->data_caller,
    453                             trans->buffer, transferred_size);
    454                 } else {
    455                         async_answer_0(trans->data_caller, EINTR);
    456                 }
    457         }
    458 
    459         const int err = async_answer_0(trans->caller, error);
    460         async_transaction_destroy(trans);
    461         return err;
    462 }
    463 
    464 void remote_usbhc_read(
    465     ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
    466 {
    467         assert(fun);
    468         assert(iface);
    469         assert(call);
    470 
    471         const usbhc_iface_t *usbhc_iface = iface;
    472 
    473         if (!usbhc_iface->read) {
    474                 async_answer_0(callid, ENOTSUP);
    475                 return;
    476         }
    477 
    478         const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
     283        const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
    479284        const uint64_t setup =
    480285            ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
     
    490295        if (!async_data_read_receive(&trans->data_caller, &size)) {
    491296                async_answer_0(callid, EPARTY);
    492                 async_transaction_destroy(trans);
    493297                return;
    494298        }
     
    502306        }
    503307
    504         const usb_target_t target = {{
    505                 /* .address is initialized by read itself */
    506                 .endpoint = ep,
    507         }};
    508 
    509         const int rc = usbhc_iface->read(
     308        const int rc = hc_iface->read(
    510309            fun, target, setup, trans->buffer, size, callback_in, trans);
    511310
     
    524323        assert(call);
    525324
    526         const usbhc_iface_t *usbhc_iface = iface;
    527 
    528         if (!usbhc_iface->write) {
     325        const usbhc_iface_t *hc_iface = iface;
     326
     327        if (!hc_iface->write) {
    529328                async_answer_0(callid, ENOTSUP);
    530329                return;
    531330        }
    532331
    533         const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);
     332        const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
    534333        const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
    535334        const uint64_t setup =
     
    546345        if (data_buffer_len > 0) {
    547346                const int rc = async_data_write_accept(&trans->buffer, false,
    548                     1, data_buffer_len, 0, &size);
     347                    1, USB_MAX_PAYLOAD_SIZE,
     348                    0, &size);
    549349
    550350                if (rc != EOK) {
     
    555355        }
    556356
    557         const usb_target_t target = {{
    558                 /* .address is initialized by write itself */
    559                 .endpoint = ep,
    560                 /* streams are not given by the API call yet */
    561                 .stream = 0,
    562         }};
    563 
    564         const int rc = usbhc_iface->write(
     357        const int rc = hc_iface->write(
    565358            fun, target, setup, trans->buffer, size, callback_out, trans);
    566359
Note: See TracChangeset for help on using the changeset viewer.