Ignore:
File:
1 edited

Legend:

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

    r272f46f8 rbbce2c2  
    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 *);
     
    33455static remote_iface_func_ptr_t remote_usbhc_iface_ops[] = {
    33556        [IPC_M_USBHC_REQUEST_ADDRESS] = remote_usbhc_request_address,
     57        [IPC_M_USBHC_BIND_ADDRESS] = remote_usbhc_bind_address,
     58        [IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_find_by_address,
    33659        [IPC_M_USBHC_RELEASE_ADDRESS] = remote_usbhc_release_address,
    337         [IPC_M_USBHC_BIND_ADDRESS] = remote_usbhc_bind_address,
    338         [IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_get_handle,
    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) {
     
    395118        }
    396119
    397         usb_address_t address = DEV_IPC_GET_ARG1(*call);
    398         const bool strict = DEV_IPC_GET_ARG2(*call);
    399         const usb_speed_t speed = DEV_IPC_GET_ARG3(*call);
    400 
    401         const int rc = usb_iface->request_address(fun, &address, strict, speed);
     120        usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
     121
     122        usb_address_t address;
     123        int rc = usb_iface->request_address(fun, speed, &address);
    402124        if (rc != EOK) {
    403125                async_answer_0(callid, rc);
     
    406128        }
    407129}
    408 /*----------------------------------------------------------------------------*/
     130
    409131void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface,
    410132    ipc_callid_t callid, ipc_call_t *call)
    411133{
    412         const usbhc_iface_t *usb_iface = iface;
     134        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    413135
    414136        if (!usb_iface->bind_address) {
     
    417139        }
    418140
    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);
     141        usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
     142        devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
     143
     144        int rc = usb_iface->bind_address(fun, address, handle);
     145
     146        async_answer_0(callid, rc);
     147}
     148
     149void remote_usbhc_find_by_address(ddf_fun_t *fun, void *iface,
     150    ipc_callid_t callid, ipc_call_t *call)
     151{
     152        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     153
     154        if (!usb_iface->find_by_address) {
     155                async_answer_0(callid, ENOTSUP);
     156                return;
     157        }
     158
     159        usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
    437160        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);
     161        int rc = usb_iface->find_by_address(fun, address, &handle);
     162
     163        if (rc == EOK) {
     164                async_answer_1(callid, EOK, handle);
    442165        } else {
    443                 async_answer_0(callid, ret);
    444         }
    445 }
    446 /*----------------------------------------------------------------------------*/
     166                async_answer_0(callid, rc);
     167        }
     168}
     169
    447170void remote_usbhc_release_address(ddf_fun_t *fun, void *iface,
    448171    ipc_callid_t callid, ipc_call_t *call)
    449172{
    450         const usbhc_iface_t *usb_iface = iface;
     173        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    451174
    452175        if (!usb_iface->release_address) {
     
    455178        }
    456179
    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 /*----------------------------------------------------------------------------*/
     180        usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
     181
     182        int rc = usb_iface->release_address(fun, address);
     183
     184        async_answer_0(callid, rc);
     185}
     186
     187
    463188static void callback_out(ddf_fun_t *fun,
    464189    int outcome, void *arg)
    465190{
    466         async_transaction_t *trans = arg;
     191        async_transaction_t *trans = (async_transaction_t *)arg;
    467192
    468193        async_answer_0(trans->caller, outcome);
     
    470195        async_transaction_destroy(trans);
    471196}
    472 /*----------------------------------------------------------------------------*/
     197
    473198static void callback_in(ddf_fun_t *fun,
    474199    int outcome, size_t actual_size, void *arg)
     
    485210        }
    486211
     212        trans->size = actual_size;
     213
    487214        if (trans->data_caller) {
    488215                async_data_read_finalize(trans->data_caller,
     
    494221        async_transaction_destroy(trans);
    495222}
    496 /*----------------------------------------------------------------------------*/
     223
    497224void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
    498225    ipc_callid_t callid, ipc_call_t *call)
     
    506233
    507234#define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \
    508         type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) >> 16)
     235        type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
    509236#define _INIT_FROM_LOW_DATA2(type, var, arg_no) \
    510         type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) & 0xffff)
     237        type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 16)
     238#define _INIT_FROM_HIGH_DATA3(type, var, arg_no) \
     239        type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
     240#define _INIT_FROM_MIDDLE_DATA3(type, var, arg_no) \
     241        type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) / (1 << 8)) % (1 << 8)
     242#define _INIT_FROM_LOW_DATA3(type, var, arg_no) \
     243        type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 8)
    511244
    512245        const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
    513246
    514         _INIT_FROM_HIGH_DATA2(usb_transfer_type_t, transfer_type, 2);
    515         _INIT_FROM_LOW_DATA2(usb_direction_t, direction, 2);
     247        _INIT_FROM_HIGH_DATA3(usb_speed_t, speed, 2);
     248        _INIT_FROM_MIDDLE_DATA3(usb_transfer_type_t, transfer_type, 2);
     249        _INIT_FROM_LOW_DATA3(usb_direction_t, direction, 2);
    516250
    517251        _INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3);
     
    520254#undef _INIT_FROM_HIGH_DATA2
    521255#undef _INIT_FROM_LOW_DATA2
    522 
    523         int rc = usb_iface->register_endpoint(fun, target.address,
     256#undef _INIT_FROM_HIGH_DATA3
     257#undef _INIT_FROM_MIDDLE_DATA3
     258#undef _INIT_FROM_LOW_DATA3
     259
     260        int rc = usb_iface->register_endpoint(fun, target.address, speed,
    524261            target.endpoint, transfer_type, direction, max_packet_size, interval);
    525262
     
    572309        }
    573310
    574         size_t size = 0;
    575         if (!async_data_read_receive(&trans->data_caller, &size)) {
     311        if (!async_data_read_receive(&trans->data_caller, &trans->size)) {
    576312                async_answer_0(callid, EPARTY);
    577313                return;
    578314        }
    579315
    580         trans->buffer = malloc(size);
     316        trans->buffer = malloc(trans->size);
    581317        if (trans->buffer == NULL) {
    582318                async_answer_0(trans->data_caller, ENOMEM);
     
    586322
    587323        const int rc = hc_iface->read(
    588             fun, target, setup, trans->buffer, size, callback_in, trans);
     324            fun, target, setup, trans->buffer, trans->size, callback_in, trans);
    589325
    590326        if (rc != EOK) {
     
    594330        }
    595331}
    596 /*----------------------------------------------------------------------------*/
     332
    597333void remote_usbhc_write(
    598334    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     
    621357        }
    622358
    623         size_t size = 0;
    624359        if (data_buffer_len > 0) {
    625                 const int rc = async_data_write_accept(&trans->buffer, false,
     360                int rc = async_data_write_accept(&trans->buffer, false,
    626361                    1, USB_MAX_PAYLOAD_SIZE,
    627                     0, &size);
     362                    0, &trans->size);
    628363
    629364                if (rc != EOK) {
     
    634369        }
    635370
    636         const int rc = hc_iface->write(
    637             fun, target, setup, trans->buffer, size, callback_out, trans);
     371        int rc = hc_iface->write(
     372            fun, target, setup, trans->buffer, trans->size, callback_out, trans);
    638373
    639374        if (rc != EOK) {
     
    642377        }
    643378}
     379
     380
    644381/**
    645382 * @}
Note: See TracChangeset for help on using the changeset viewer.