Ignore:
File:
1 edited

Legend:

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

    r27736cf r272f46f8  
    11/*
    22 * Copyright (c) 2010-2011 Vojtech Horky
     3 * Copyright (c) 2011 Jan Vesely
    34 * All rights reserved.
    45 *
     
    4243#define USB_MAX_PAYLOAD_SIZE 1020
    4344
     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 */
     85typedef 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
     163int 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/*----------------------------------------------------------------------------*/
     176int 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/*----------------------------------------------------------------------------*/
     185int 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/*----------------------------------------------------------------------------*/
     198int 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/*----------------------------------------------------------------------------*/
     206int 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/*----------------------------------------------------------------------------*/
     223int 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/*----------------------------------------------------------------------------*/
     232int 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/*----------------------------------------------------------------------------*/
     287int 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
    44323static void remote_usbhc_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    45324static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    46 static void remote_usbhc_find_by_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     325static void remote_usbhc_get_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    47326static void remote_usbhc_release_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    48327static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     
    57336        [IPC_M_USBHC_RELEASE_ADDRESS] = remote_usbhc_release_address,
    58337        [IPC_M_USBHC_BIND_ADDRESS] = remote_usbhc_bind_address,
    59         [IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_find_by_address,
     338        [IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_get_handle,
    60339
    61340        [IPC_M_USBHC_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
     
    78357        ipc_callid_t data_caller;
    79358        void *buffer;
    80         size_t size;
    81359} async_transaction_t;
    82360
     
    103381        trans->data_caller = 0;
    104382        trans->buffer = NULL;
    105         trans->size = 0;
    106383
    107384        return trans;
    108385}
    109 
     386/*----------------------------------------------------------------------------*/
    110387void remote_usbhc_request_address(ddf_fun_t *fun, void *iface,
    111388    ipc_callid_t callid, ipc_call_t *call)
    112389{
    113         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     390        const usbhc_iface_t *usb_iface = iface;
    114391
    115392        if (!usb_iface->request_address) {
     
    129406        }
    130407}
    131 
     408/*----------------------------------------------------------------------------*/
    132409void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface,
    133410    ipc_callid_t callid, ipc_call_t *call)
    134411{
    135         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     412        const usbhc_iface_t *usb_iface = iface;
    136413
    137414        if (!usb_iface->bind_address) {
     
    140417        }
    141418
    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 
    150 void remote_usbhc_find_by_address(ddf_fun_t *fun, void *iface,
     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/*----------------------------------------------------------------------------*/
     426void remote_usbhc_get_handle(ddf_fun_t *fun, void *iface,
    151427    ipc_callid_t callid, ipc_call_t *call)
    152428{
    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);
     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);
    161437        devman_handle_t handle;
    162         int rc = usb_iface->find_by_address(fun, address, &handle);
    163 
    164         if (rc == EOK) {
    165                 async_answer_1(callid, EOK, handle);
     438        const int ret = usb_iface->get_handle(fun, address, &handle);
     439
     440        if (ret == EOK) {
     441                async_answer_1(callid, ret, handle);
    166442        } else {
    167                 async_answer_0(callid, rc);
    168         }
    169 }
    170 
     443                async_answer_0(callid, ret);
     444        }
     445}
     446/*----------------------------------------------------------------------------*/
    171447void remote_usbhc_release_address(ddf_fun_t *fun, void *iface,
    172448    ipc_callid_t callid, ipc_call_t *call)
    173449{
    174         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     450        const usbhc_iface_t *usb_iface = iface;
    175451
    176452        if (!usb_iface->release_address) {
     
    179455        }
    180456
    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 
     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/*----------------------------------------------------------------------------*/
    189463static void callback_out(ddf_fun_t *fun,
    190464    int outcome, void *arg)
    191465{
    192         async_transaction_t *trans = (async_transaction_t *)arg;
     466        async_transaction_t *trans = arg;
    193467
    194468        async_answer_0(trans->caller, outcome);
     
    196470        async_transaction_destroy(trans);
    197471}
    198 
     472/*----------------------------------------------------------------------------*/
    199473static void callback_in(ddf_fun_t *fun,
    200474    int outcome, size_t actual_size, void *arg)
     
    211485        }
    212486
    213         trans->size = actual_size;
    214 
    215487        if (trans->data_caller) {
    216488                async_data_read_finalize(trans->data_caller,
     
    222494        async_transaction_destroy(trans);
    223495}
    224 
     496/*----------------------------------------------------------------------------*/
    225497void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
    226498    ipc_callid_t callid, ipc_call_t *call)
     
    300572        }
    301573
    302         if (!async_data_read_receive(&trans->data_caller, &trans->size)) {
     574        size_t size = 0;
     575        if (!async_data_read_receive(&trans->data_caller, &size)) {
    303576                async_answer_0(callid, EPARTY);
    304577                return;
    305578        }
    306579
    307         trans->buffer = malloc(trans->size);
     580        trans->buffer = malloc(size);
    308581        if (trans->buffer == NULL) {
    309582                async_answer_0(trans->data_caller, ENOMEM);
     
    313586
    314587        const int rc = hc_iface->read(
    315             fun, target, setup, trans->buffer, trans->size, callback_in, trans);
     588            fun, target, setup, trans->buffer, size, callback_in, trans);
    316589
    317590        if (rc != EOK) {
     
    321594        }
    322595}
    323 
     596/*----------------------------------------------------------------------------*/
    324597void remote_usbhc_write(
    325598    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     
    348621        }
    349622
     623        size_t size = 0;
    350624        if (data_buffer_len > 0) {
    351                 int rc = async_data_write_accept(&trans->buffer, false,
     625                const int rc = async_data_write_accept(&trans->buffer, false,
    352626                    1, USB_MAX_PAYLOAD_SIZE,
    353                     0, &trans->size);
     627                    0, &size);
    354628
    355629                if (rc != EOK) {
     
    360634        }
    361635
    362         int rc = hc_iface->write(
    363             fun, target, setup, trans->buffer, trans->size, callback_out, trans);
     636        const int rc = hc_iface->write(
     637            fun, target, setup, trans->buffer, size, callback_out, trans);
    364638
    365639        if (rc != EOK) {
     
    368642        }
    369643}
    370 
    371 
    372644/**
    373645 * @}
Note: See TracChangeset for help on using the changeset viewer.