Ignore:
File:
1 edited

Legend:

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

    r272f46f8 r27736cf  
    11/*
    22 * Copyright (c) 2010-2011 Vojtech Horky
    3  * Copyright (c) 2011 Jan Vesely
    43 * All rights reserved.
    54 *
     
    4342#define USB_MAX_PAYLOAD_SIZE 1020
    4443
    45 /** IPC methods for communication with HC through DDF interface.
    46  *
    47  * Notes for async methods:
    48  *
    49  * Methods for sending data to device (OUT transactions)
    50  * - e.g. IPC_M_USBHC_INTERRUPT_OUT -
    51  * always use the same semantics:
    52  * - first, IPC call with given method is made
    53  *   - argument #1 is target address
    54  *   - argument #2 is target endpoint
    55  *   - argument #3 is max packet size of the endpoint
    56  * - this call is immediately followed by IPC data write (from caller)
    57  * - the initial call (and the whole transaction) is answer after the
    58  *   transaction is scheduled by the HC and acknowledged by the device
    59  *   or immediately after error is detected
    60  * - the answer carries only the error code
    61  *
    62  * Methods for retrieving data from device (IN transactions)
    63  * - e.g. IPC_M_USBHC_INTERRUPT_IN -
    64  * also use the same semantics:
    65  * - first, IPC call with given method is made
    66  *   - argument #1 is target address
    67  *   - argument #2 is target endpoint
    68  * - this call is immediately followed by IPC data read (async version)
    69  * - the call is not answered until the device returns some data (or until
    70  *   error occurs)
    71  *
    72  * Some special methods (NO-DATA transactions) do not send any data. These
    73  * might behave as both OUT or IN transactions because communication parts
    74  * where actual buffers are exchanged are omitted.
    75  **
    76  * For all these methods, wrap functions exists. Important rule: functions
    77  * for IN transactions have (as parameters) buffers where retrieved data
    78  * will be stored. These buffers must be already allocated and shall not be
    79  * touch until the transaction is completed
    80  * (e.g. not before calling usb_wait_for() with appropriate handle).
    81  * OUT transactions buffers can be freed immediately after call is dispatched
    82  * (i.e. after return from wrapping function).
    83  *
    84  */
    85 typedef enum {
    86         /** Asks for address assignment by host controller.
    87          * Answer:
    88          * - ELIMIT - host controller run out of address
    89          * - EOK - address assigned
    90          * Answer arguments:
    91          * - assigned address
    92          *
    93          * The address must be released by via IPC_M_USBHC_RELEASE_ADDRESS.
    94          */
    95         IPC_M_USBHC_REQUEST_ADDRESS,
    96 
    97         /** Bind USB address with devman handle.
    98          * Parameters:
    99          * - USB address
    100          * - devman handle
    101          * Answer:
    102          * - EOK - address binded
    103          * - ENOENT - address is not in use
    104          */
    105         IPC_M_USBHC_BIND_ADDRESS,
    106 
    107         /** Get handle binded with given USB address.
    108          * Parameters
    109          * - USB address
    110          * Answer:
    111          * - EOK - address binded, first parameter is the devman handle
    112          * - ENOENT - address is not in use at the moment
    113          */
    114         IPC_M_USBHC_GET_HANDLE_BY_ADDRESS,
    115 
    116         /** Release address in use.
    117          * Arguments:
    118          * - address to be released
    119          * Answer:
    120          * - ENOENT - address not in use
    121          * - EPERM - trying to release default USB address
    122          */
    123         IPC_M_USBHC_RELEASE_ADDRESS,
    124 
    125         /** Register endpoint attributes at host controller.
    126          * This is used to reserve portion of USB bandwidth.
    127          * When speed is invalid, speed of the device is used.
    128          * Parameters:
    129          * - USB address + endpoint number
    130          *   - packed as ADDR << 16 + EP
    131          * - speed + transfer type + direction
    132          *   - packed as ( SPEED << 8 + TYPE ) << 8 + DIR
    133          * - maximum packet size + interval (in milliseconds)
    134          *   - packed as MPS << 16 + INT
    135          * Answer:
    136          * - EOK - reservation successful
    137          * - ELIMIT - not enough bandwidth to satisfy the request
    138          */
    139         IPC_M_USBHC_REGISTER_ENDPOINT,
    140 
    141         /** Revert endpoint registration.
    142          * Parameters:
    143          * - USB address
    144          * - endpoint number
    145          * - data direction
    146          * Answer:
    147          * - EOK - endpoint unregistered
    148          * - ENOENT - unknown endpoint
    149          */
    150         IPC_M_USBHC_UNREGISTER_ENDPOINT,
    151 
    152         /** Get data from device.
    153          * See explanation at usb_iface_funcs_t (IN transaction).
    154          */
    155         IPC_M_USBHC_READ,
    156 
    157         /** Send data to device.
    158          * See explanation at usb_iface_funcs_t (OUT transaction).
    159          */
    160         IPC_M_USBHC_WRITE,
    161 } usbhc_iface_funcs_t;
    162 
    163 int usbhc_request_address(async_exch_t *exch, usb_address_t *address,
    164     bool strict, usb_speed_t speed)
    165 {
    166         if (!exch || !address)
    167                 return EINVAL;
    168         sysarg_t new_address;
    169         const int ret = async_req_4_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    170             IPC_M_USBHC_REQUEST_ADDRESS, *address, strict, speed, &new_address);
    171         if (ret == EOK)
    172                 *address = (usb_address_t)new_address;
    173         return ret;
    174 }
    175 /*----------------------------------------------------------------------------*/
    176 int usbhc_bind_address(async_exch_t *exch, usb_address_t address,
    177     devman_handle_t handle)
    178 {
    179         if (!exch)
    180                 return EINVAL;
    181         return async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    182             IPC_M_USBHC_BIND_ADDRESS, address, handle);
    183 }
    184 /*----------------------------------------------------------------------------*/
    185 int usbhc_get_handle(async_exch_t *exch, usb_address_t address,
    186     devman_handle_t *handle)
    187 {
    188         if (!exch)
    189                 return EINVAL;
    190         sysarg_t h;
    191         const int ret = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    192             IPC_M_USBHC_GET_HANDLE_BY_ADDRESS, address, &h);
    193         if (ret == EOK && handle)
    194                 *handle = (devman_handle_t)h;
    195         return ret;
    196 }
    197 /*----------------------------------------------------------------------------*/
    198 int usbhc_release_address(async_exch_t *exch, usb_address_t address)
    199 {
    200         if (!exch)
    201                 return EINVAL;
    202         return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    203             IPC_M_USBHC_RELEASE_ADDRESS, address);
    204 }
    205 /*----------------------------------------------------------------------------*/
    206 int usbhc_register_endpoint(async_exch_t *exch, usb_address_t address,
    207     usb_endpoint_t endpoint, usb_transfer_type_t type,
    208     usb_direction_t direction, size_t mps, unsigned interval)
    209 {
    210         if (!exch)
    211                 return EINVAL;
    212         const usb_target_t target =
    213             {{ .address = address, .endpoint = endpoint }};
    214 #define _PACK2(high, low) (((high & 0xffff) << 16) | (low & 0xffff))
    215 
    216         return async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    217             IPC_M_USBHC_REGISTER_ENDPOINT, target.packed,
    218             _PACK2(type, direction), _PACK2(mps, interval));
    219 
    220 #undef _PACK2
    221 }
    222 /*----------------------------------------------------------------------------*/
    223 int usbhc_unregister_endpoint(async_exch_t *exch, usb_address_t address,
    224     usb_endpoint_t endpoint, usb_direction_t direction)
    225 {
    226         if (!exch)
    227                 return EINVAL;
    228         return async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    229             IPC_M_USBHC_UNREGISTER_ENDPOINT, address, endpoint, direction);
    230 }
    231 /*----------------------------------------------------------------------------*/
    232 int usbhc_read(async_exch_t *exch, usb_address_t address,
    233     usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size,
    234     size_t *rec_size)
    235 {
    236         if (size == 0 && setup == 0)
    237                 return EOK;
    238 
    239         if (!exch)
    240                 return EINVAL;
    241         const usb_target_t target =
    242             {{ .address = address, .endpoint = endpoint }};
    243 
    244         /* Make call identifying target USB device and type of transfer. */
    245         aid_t opening_request = async_send_4(exch,
    246             DEV_IFACE_ID(USBHC_DEV_IFACE),
    247             IPC_M_USBHC_READ, target.packed,
    248             (setup & UINT32_MAX), (setup >> 32), NULL);
    249 
    250         if (opening_request == 0) {
    251                 return ENOMEM;
    252         }
    253 
    254         /* Retrieve the data. */
    255         ipc_call_t data_request_call;
    256         aid_t data_request =
    257             async_data_read(exch, data, size, &data_request_call);
    258 
    259         if (data_request == 0) {
    260                 // FIXME: How to let the other side know that we want to abort?
    261                 async_wait_for(opening_request, NULL);
    262                 return ENOMEM;
    263         }
    264 
    265         /* Wait for the answer. */
    266         sysarg_t data_request_rc;
    267         sysarg_t opening_request_rc;
    268         async_wait_for(data_request, &data_request_rc);
    269         async_wait_for(opening_request, &opening_request_rc);
    270 
    271         if (data_request_rc != EOK) {
    272                 /* Prefer the return code of the opening request. */
    273                 if (opening_request_rc != EOK) {
    274                         return (int) opening_request_rc;
    275                 } else {
    276                         return (int) data_request_rc;
    277                 }
    278         }
    279         if (opening_request_rc != EOK) {
    280                 return (int) opening_request_rc;
    281         }
    282 
    283         *rec_size = IPC_GET_ARG2(data_request_call);
    284         return EOK;
    285 }
    286 /*----------------------------------------------------------------------------*/
    287 int usbhc_write(async_exch_t *exch, usb_address_t address,
    288     usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size)
    289 {
    290         if (size == 0 && setup == 0)
    291                 return EOK;
    292 
    293         if (!exch)
    294                 return EINVAL;
    295         const usb_target_t target =
    296             {{ .address = address, .endpoint = endpoint }};
    297 
    298         aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),
    299             IPC_M_USBHC_WRITE, target.packed, size,
    300             (setup & UINT32_MAX), (setup >> 32), NULL);
    301 
    302         if (opening_request == 0) {
    303                 return ENOMEM;
    304         }
    305 
    306         /* Send the data if any. */
    307         if (size > 0) {
    308                 const int ret = async_data_write_start(exch, data, size);
    309                 if (ret != EOK) {
    310                         async_wait_for(opening_request, NULL);
    311                         return ret;
    312                 }
    313         }
    314 
    315         /* Wait for the answer. */
    316         sysarg_t opening_request_rc;
    317         async_wait_for(opening_request, &opening_request_rc);
    318 
    319         return (int) opening_request_rc;
    320 }
    321 /*----------------------------------------------------------------------------*/
    322 
    32344static void remote_usbhc_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    32445static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    325 static void remote_usbhc_get_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     46static void remote_usbhc_find_by_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    32647static void remote_usbhc_release_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    32748static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     
    33657        [IPC_M_USBHC_RELEASE_ADDRESS] = remote_usbhc_release_address,
    33758        [IPC_M_USBHC_BIND_ADDRESS] = remote_usbhc_bind_address,
    338         [IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_get_handle,
     59        [IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_find_by_address,
    33960
    34061        [IPC_M_USBHC_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
     
    35778        ipc_callid_t data_caller;
    35879        void *buffer;
     80        size_t size;
    35981} async_transaction_t;
    36082
     
    381103        trans->data_caller = 0;
    382104        trans->buffer = NULL;
     105        trans->size = 0;
    383106
    384107        return trans;
    385108}
    386 /*----------------------------------------------------------------------------*/
     109
    387110void remote_usbhc_request_address(ddf_fun_t *fun, void *iface,
    388111    ipc_callid_t callid, ipc_call_t *call)
    389112{
    390         const usbhc_iface_t *usb_iface = iface;
     113        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    391114
    392115        if (!usb_iface->request_address) {
     
    406129        }
    407130}
    408 /*----------------------------------------------------------------------------*/
     131
    409132void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface,
    410133    ipc_callid_t callid, ipc_call_t *call)
    411134{
    412         const usbhc_iface_t *usb_iface = iface;
     135        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    413136
    414137        if (!usb_iface->bind_address) {
     
    417140        }
    418141
    419         const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
    420         const devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
    421 
    422         const int ret = usb_iface->bind_address(fun, address, handle);
    423         async_answer_0(callid, ret);
    424 }
    425 /*----------------------------------------------------------------------------*/
    426 void remote_usbhc_get_handle(ddf_fun_t *fun, void *iface,
    427     ipc_callid_t callid, ipc_call_t *call)
    428 {
    429         const usbhc_iface_t *usb_iface = iface;
    430 
    431         if (!usb_iface->get_handle) {
    432                 async_answer_0(callid, ENOTSUP);
    433                 return;
    434         }
    435 
    436         const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
     142        usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
     143        devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
     144
     145        int rc = usb_iface->bind_address(fun, address, handle);
     146
     147        async_answer_0(callid, rc);
     148}
     149
     150void remote_usbhc_find_by_address(ddf_fun_t *fun, void *iface,
     151    ipc_callid_t callid, ipc_call_t *call)
     152{
     153        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     154
     155        if (!usb_iface->find_by_address) {
     156                async_answer_0(callid, ENOTSUP);
     157                return;
     158        }
     159
     160        usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
    437161        devman_handle_t handle;
    438         const int ret = usb_iface->get_handle(fun, address, &handle);
    439 
    440         if (ret == EOK) {
    441                 async_answer_1(callid, ret, handle);
     162        int rc = usb_iface->find_by_address(fun, address, &handle);
     163
     164        if (rc == EOK) {
     165                async_answer_1(callid, EOK, handle);
    442166        } else {
    443                 async_answer_0(callid, ret);
    444         }
    445 }
    446 /*----------------------------------------------------------------------------*/
     167                async_answer_0(callid, rc);
     168        }
     169}
     170
    447171void remote_usbhc_release_address(ddf_fun_t *fun, void *iface,
    448172    ipc_callid_t callid, ipc_call_t *call)
    449173{
    450         const usbhc_iface_t *usb_iface = iface;
     174        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    451175
    452176        if (!usb_iface->release_address) {
     
    455179        }
    456180
    457         const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
    458 
    459         const int ret = usb_iface->release_address(fun, address);
    460         async_answer_0(callid, ret);
    461 }
    462 /*----------------------------------------------------------------------------*/
     181        usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
     182
     183        int rc = usb_iface->release_address(fun, address);
     184
     185        async_answer_0(callid, rc);
     186}
     187
     188
    463189static void callback_out(ddf_fun_t *fun,
    464190    int outcome, void *arg)
    465191{
    466         async_transaction_t *trans = arg;
     192        async_transaction_t *trans = (async_transaction_t *)arg;
    467193
    468194        async_answer_0(trans->caller, outcome);
     
    470196        async_transaction_destroy(trans);
    471197}
    472 /*----------------------------------------------------------------------------*/
     198
    473199static void callback_in(ddf_fun_t *fun,
    474200    int outcome, size_t actual_size, void *arg)
     
    485211        }
    486212
     213        trans->size = actual_size;
     214
    487215        if (trans->data_caller) {
    488216                async_data_read_finalize(trans->data_caller,
     
    494222        async_transaction_destroy(trans);
    495223}
    496 /*----------------------------------------------------------------------------*/
     224
    497225void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
    498226    ipc_callid_t callid, ipc_call_t *call)
     
    572300        }
    573301
    574         size_t size = 0;
    575         if (!async_data_read_receive(&trans->data_caller, &size)) {
     302        if (!async_data_read_receive(&trans->data_caller, &trans->size)) {
    576303                async_answer_0(callid, EPARTY);
    577304                return;
    578305        }
    579306
    580         trans->buffer = malloc(size);
     307        trans->buffer = malloc(trans->size);
    581308        if (trans->buffer == NULL) {
    582309                async_answer_0(trans->data_caller, ENOMEM);
     
    586313
    587314        const int rc = hc_iface->read(
    588             fun, target, setup, trans->buffer, size, callback_in, trans);
     315            fun, target, setup, trans->buffer, trans->size, callback_in, trans);
    589316
    590317        if (rc != EOK) {
     
    594321        }
    595322}
    596 /*----------------------------------------------------------------------------*/
     323
    597324void remote_usbhc_write(
    598325    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     
    621348        }
    622349
    623         size_t size = 0;
    624350        if (data_buffer_len > 0) {
    625                 const int rc = async_data_write_accept(&trans->buffer, false,
     351                int rc = async_data_write_accept(&trans->buffer, false,
    626352                    1, USB_MAX_PAYLOAD_SIZE,
    627                     0, &size);
     353                    0, &trans->size);
    628354
    629355                if (rc != EOK) {
     
    634360        }
    635361
    636         const int rc = hc_iface->write(
    637             fun, target, setup, trans->buffer, size, callback_out, trans);
     362        int rc = hc_iface->write(
     363            fun, target, setup, trans->buffer, trans->size, callback_out, trans);
    638364
    639365        if (rc != EOK) {
     
    642368        }
    643369}
     370
     371
    644372/**
    645373 * @}
Note: See TracChangeset for help on using the changeset viewer.