Changeset 00aece0 in mainline for uspace/lib/drv/generic


Ignore:
Timestamp:
2012-02-18T16:47:38Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
4449c6c
Parents:
bd5f3b7 (diff), f943dd3 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

Location:
uspace/lib/drv/generic
Files:
2 added
5 edited

Legend:

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

    rbd5f3b7 r00aece0  
    4141#include "remote_hw_res.h"
    4242#include "remote_char_dev.h"
     43#include "remote_nic.h"
    4344#include "remote_usb.h"
    4445#include "remote_usbhc.h"
     
    4647#include "remote_pci.h"
    4748
    48 #include <stdio.h>
    49 
    5049static iface_dipatch_table_t remote_ifaces = {
    5150        .ifaces = {
    5251                &remote_hw_res_iface,
    5352                &remote_char_dev_iface,
     53                &remote_nic_iface,
    5454                &remote_pci_iface,
    5555                &remote_usb_iface,
     
    6868get_remote_method(remote_iface_t *rem_iface, sysarg_t iface_method_idx)
    6969{
    70         if (iface_method_idx >= rem_iface->method_count) {
     70        if (iface_method_idx >= rem_iface->method_count)
    7171                return NULL;
    72         }
    73 
     72       
    7473        return rem_iface->methods[iface_method_idx];
    7574}
  • uspace/lib/drv/generic/driver.c

    rbd5f3b7 r00aece0  
    6363
    6464/** Devices */
     65LIST_INITIALIZE(devices);
     66FIBRIL_MUTEX_INITIALIZE(devices_mutex);
     67
     68/** Functions */
    6569LIST_INITIALIZE(functions);
    6670FIBRIL_MUTEX_INITIALIZE(functions_mutex);
    6771
    68 /** Interrupts */
    69 static interrupt_context_list_t interrupt_contexts;
    70 
    71 static irq_cmd_t default_cmds[] = {
    72         {
    73                 .cmd = CMD_ACCEPT
    74         }
    75 };
    76 
    77 static irq_code_t default_pseudocode = {
    78         sizeof(default_cmds) / sizeof(irq_cmd_t),
    79         default_cmds
    80 };
    81 
    8272static ddf_dev_t *create_device(void);
    8373static void delete_device(ddf_dev_t *);
     74static void dev_add_ref(ddf_dev_t *);
     75static void dev_del_ref(ddf_dev_t *);
     76static void fun_add_ref(ddf_fun_t *);
     77static void fun_del_ref(ddf_fun_t *);
    8478static remote_handler_t *function_get_default_handler(ddf_fun_t *);
    8579static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
    86 
    87 static void driver_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
    88 {
    89         int id = (int)IPC_GET_IMETHOD(*icall);
    90         interrupt_context_t *ctx;
    91        
    92         ctx = find_interrupt_context_by_id(&interrupt_contexts, id);
    93         if (ctx != NULL && ctx->handler != NULL)
    94                 (*ctx->handler)(ctx->dev, iid, icall);
    95 }
    96 
    97 interrupt_context_t *create_interrupt_context(void)
    98 {
    99         interrupt_context_t *ctx;
    100        
    101         ctx = (interrupt_context_t *) malloc(sizeof(interrupt_context_t));
    102         if (ctx != NULL)
    103                 memset(ctx, 0, sizeof(interrupt_context_t));
    104        
    105         return ctx;
    106 }
    107 
    108 void delete_interrupt_context(interrupt_context_t *ctx)
    109 {
    110         if (ctx != NULL)
    111                 free(ctx);
    112 }
    113 
    114 void init_interrupt_context_list(interrupt_context_list_t *list)
    115 {
    116         memset(list, 0, sizeof(interrupt_context_list_t));
    117         fibril_mutex_initialize(&list->mutex);
    118         list_initialize(&list->contexts);
    119 }
    120 
    121 void
    122 add_interrupt_context(interrupt_context_list_t *list, interrupt_context_t *ctx)
    123 {
    124         fibril_mutex_lock(&list->mutex);
    125         ctx->id = list->curr_id++;
    126         list_append(&ctx->link, &list->contexts);
    127         fibril_mutex_unlock(&list->mutex);
    128 }
    129 
    130 void remove_interrupt_context(interrupt_context_list_t *list,
    131     interrupt_context_t *ctx)
    132 {
    133         fibril_mutex_lock(&list->mutex);
    134         list_remove(&ctx->link);
    135         fibril_mutex_unlock(&list->mutex);
    136 }
    137 
    138 interrupt_context_t *
    139 find_interrupt_context_by_id(interrupt_context_list_t *list, int id)
    140 {
    141         interrupt_context_t *ctx;
    142        
    143         fibril_mutex_lock(&list->mutex);
    144        
    145         list_foreach(list->contexts, link) {
    146                 ctx = list_get_instance(link, interrupt_context_t, link);
    147                 if (ctx->id == id) {
    148                         fibril_mutex_unlock(&list->mutex);
    149                         return ctx;
    150                 }
    151         }
    152        
    153         fibril_mutex_unlock(&list->mutex);
    154         return NULL;
    155 }
    156 
    157 interrupt_context_t *
    158 find_interrupt_context(interrupt_context_list_t *list, ddf_dev_t *dev, int irq)
    159 {
    160         interrupt_context_t *ctx;
    161        
    162         fibril_mutex_lock(&list->mutex);
    163        
    164         list_foreach(list->contexts, link) {
    165                 ctx = list_get_instance(link, interrupt_context_t, link);
    166                 if (ctx->irq == irq && ctx->dev == dev) {
    167                         fibril_mutex_unlock(&list->mutex);
    168                         return ctx;
    169                 }
    170         }
    171        
    172         fibril_mutex_unlock(&list->mutex);
    173         return NULL;
    174 }
    175 
    176 
    177 int
    178 register_interrupt_handler(ddf_dev_t *dev, int irq, interrupt_handler_t *handler,
    179     irq_code_t *pseudocode)
    180 {
    181         interrupt_context_t *ctx = create_interrupt_context();
    182        
    183         ctx->dev = dev;
    184         ctx->irq = irq;
    185         ctx->handler = handler;
    186        
    187         add_interrupt_context(&interrupt_contexts, ctx);
    188        
    189         if (pseudocode == NULL)
    190                 pseudocode = &default_pseudocode;
    191        
    192         int res = register_irq(irq, dev->handle, ctx->id, pseudocode);
    193         if (res != EOK) {
    194                 remove_interrupt_context(&interrupt_contexts, ctx);
    195                 delete_interrupt_context(ctx);
    196         }
    197 
    198         return res;
    199 }
    200 
    201 int unregister_interrupt_handler(ddf_dev_t *dev, int irq)
    202 {
    203         interrupt_context_t *ctx = find_interrupt_context(&interrupt_contexts,
    204             dev, irq);
    205         int res = unregister_irq(irq, dev->handle);
    206        
    207         if (ctx != NULL) {
    208                 remove_interrupt_context(&interrupt_contexts, ctx);
    209                 delete_interrupt_context(ctx);
    210         }
    211        
    212         return res;
    213 }
    21480
    21581static void add_to_functions_list(ddf_fun_t *fun)
     
    22793}
    22894
    229 static ddf_fun_t *driver_get_function(list_t *functions, devman_handle_t handle)
     95static ddf_dev_t *driver_get_device(devman_handle_t handle)
     96{
     97        ddf_dev_t *dev = NULL;
     98       
     99        assert(fibril_mutex_is_locked(&devices_mutex));
     100       
     101        list_foreach(devices, link) {
     102                dev = list_get_instance(link, ddf_dev_t, link);
     103                if (dev->handle == handle)
     104                        return dev;
     105        }
     106       
     107        return NULL;
     108}
     109
     110static ddf_fun_t *driver_get_function(devman_handle_t handle)
    230111{
    231112        ddf_fun_t *fun = NULL;
    232113       
    233         fibril_mutex_lock(&functions_mutex);
    234        
    235         list_foreach(*functions, link) {
     114        assert(fibril_mutex_is_locked(&functions_mutex));
     115       
     116        list_foreach(functions, link) {
    236117                fun = list_get_instance(link, ddf_fun_t, link);
    237                 if (fun->handle == handle) {
    238                         fibril_mutex_unlock(&functions_mutex);
     118                if (fun->handle == handle)
    239119                        return fun;
    240                 }
    241         }
    242        
    243         fibril_mutex_unlock(&functions_mutex);
     120        }
    244121       
    245122        return NULL;
    246123}
    247124
    248 static void driver_add_device(ipc_callid_t iid, ipc_call_t *icall)
     125static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall)
    249126{
    250127        char *dev_name = NULL;
     
    252129       
    253130        devman_handle_t dev_handle = IPC_GET_ARG1(*icall);
    254         devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
     131        devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
    255132       
    256133        ddf_dev_t *dev = create_device();
     134
     135        /* Add one reference that will be dropped by driver_dev_remove() */
     136        dev_add_ref(dev);
    257137        dev->handle = dev_handle;
    258138
     
    266146        (void) parent_fun_handle;
    267147       
    268         res = driver->driver_ops->add_device(dev);
    269         if (res != EOK)
    270                 delete_device(dev);
     148        res = driver->driver_ops->dev_add(dev);
     149       
     150        if (res != EOK) {
     151                dev_del_ref(dev);
     152                async_answer_0(iid, res);
     153                return;
     154        }
     155       
     156        fibril_mutex_lock(&devices_mutex);
     157        list_append(&dev->link, &devices);
     158        fibril_mutex_unlock(&devices_mutex);
    271159       
    272160        async_answer_0(iid, res);
     161}
     162
     163static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall)
     164{
     165        devman_handle_t devh;
     166        ddf_dev_t *dev;
     167        int rc;
     168       
     169        devh = IPC_GET_ARG1(*icall);
     170       
     171        fibril_mutex_lock(&devices_mutex);
     172        dev = driver_get_device(devh);
     173        if (dev != NULL)
     174                dev_add_ref(dev);
     175        fibril_mutex_unlock(&devices_mutex);
     176       
     177        if (dev == NULL) {
     178                async_answer_0(iid, ENOENT);
     179                return;
     180        }
     181       
     182        if (driver->driver_ops->dev_remove != NULL)
     183                rc = driver->driver_ops->dev_remove(dev);
     184        else
     185                rc = ENOTSUP;
     186       
     187        if (rc == EOK)
     188                dev_del_ref(dev);
     189       
     190        async_answer_0(iid, (sysarg_t) rc);
     191}
     192
     193static void driver_dev_gone(ipc_callid_t iid, ipc_call_t *icall)
     194{
     195        devman_handle_t devh;
     196        ddf_dev_t *dev;
     197        int rc;
     198       
     199        devh = IPC_GET_ARG1(*icall);
     200       
     201        fibril_mutex_lock(&devices_mutex);
     202        dev = driver_get_device(devh);
     203        if (dev != NULL)
     204                dev_add_ref(dev);
     205        fibril_mutex_unlock(&devices_mutex);
     206       
     207        if (dev == NULL) {
     208                async_answer_0(iid, ENOENT);
     209                return;
     210        }
     211       
     212        if (driver->driver_ops->dev_gone != NULL)
     213                rc = driver->driver_ops->dev_gone(dev);
     214        else
     215                rc = ENOTSUP;
     216       
     217        if (rc == EOK)
     218                dev_del_ref(dev);
     219       
     220        async_answer_0(iid, (sysarg_t) rc);
     221}
     222
     223static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall)
     224{
     225        devman_handle_t funh;
     226        ddf_fun_t *fun;
     227        int rc;
     228       
     229        funh = IPC_GET_ARG1(*icall);
     230       
     231        /*
     232         * Look the function up. Bump reference count so that
     233         * the function continues to exist until we return
     234         * from the driver.
     235         */
     236        fibril_mutex_lock(&functions_mutex);
     237       
     238        fun = driver_get_function(funh);
     239        if (fun != NULL)
     240                fun_add_ref(fun);
     241       
     242        fibril_mutex_unlock(&functions_mutex);
     243       
     244        if (fun == NULL) {
     245                async_answer_0(iid, ENOENT);
     246                return;
     247        }
     248       
     249        /* Call driver entry point */
     250        if (driver->driver_ops->fun_online != NULL)
     251                rc = driver->driver_ops->fun_online(fun);
     252        else
     253                rc = ENOTSUP;
     254       
     255        fun_del_ref(fun);
     256       
     257        async_answer_0(iid, (sysarg_t) rc);
     258}
     259
     260static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
     261{
     262        devman_handle_t funh;
     263        ddf_fun_t *fun;
     264        int rc;
     265       
     266        funh = IPC_GET_ARG1(*icall);
     267       
     268        /*
     269         * Look the function up. Bump reference count so that
     270         * the function continues to exist until we return
     271         * from the driver.
     272         */
     273        fibril_mutex_lock(&functions_mutex);
     274       
     275        fun = driver_get_function(funh);
     276        if (fun != NULL)
     277                fun_add_ref(fun);
     278       
     279        fibril_mutex_unlock(&functions_mutex);
     280       
     281        if (fun == NULL) {
     282                async_answer_0(iid, ENOENT);
     283                return;
     284        }
     285       
     286        /* Call driver entry point */
     287        if (driver->driver_ops->fun_offline != NULL)
     288                rc = driver->driver_ops->fun_offline(fun);
     289        else
     290                rc = ENOTSUP;
     291       
     292        async_answer_0(iid, (sysarg_t) rc);
    273293}
    274294
     
    286306               
    287307                switch (IPC_GET_IMETHOD(call)) {
    288                 case DRIVER_ADD_DEVICE:
    289                         driver_add_device(callid, &call);
     308                case DRIVER_DEV_ADD:
     309                        driver_dev_add(callid, &call);
     310                        break;
     311                case DRIVER_DEV_REMOVE:
     312                        driver_dev_remove(callid, &call);
     313                        break;
     314                case DRIVER_DEV_GONE:
     315                        driver_dev_gone(callid, &call);
     316                        break;
     317                case DRIVER_FUN_ONLINE:
     318                        driver_fun_online(callid, &call);
     319                        break;
     320                case DRIVER_FUN_OFFLINE:
     321                        driver_fun_offline(callid, &call);
    290322                        break;
    291323                default:
    292                         async_answer_0(callid, ENOENT);
     324                        async_answer_0(callid, ENOTSUP);
    293325                }
    294326        }
     
    308340         */
    309341        devman_handle_t handle = IPC_GET_ARG2(*icall);
    310         ddf_fun_t *fun = driver_get_function(&functions, handle);
     342
     343        fibril_mutex_lock(&functions_mutex);
     344        ddf_fun_t *fun = driver_get_function(handle);
     345        fibril_mutex_unlock(&functions_mutex);
     346        /* XXX Need a lock on fun */
    311347       
    312348        if (fun == NULL) {
     
    466502        ddf_dev_t *dev;
    467503
    468         dev = malloc(sizeof(ddf_dev_t));
     504        dev = calloc(1, sizeof(ddf_dev_t));
    469505        if (dev == NULL)
    470506                return NULL;
    471507
    472         memset(dev, 0, sizeof(ddf_dev_t));
    473508        return dev;
    474509}
     
    498533static void delete_device(ddf_dev_t *dev)
    499534{
     535        if (dev->driver_data != NULL)
     536                free(dev->driver_data);
    500537        free(dev);
    501538}
    502539
    503 /** Delete device structure.
     540/** Delete function structure.
    504541 *
    505542 * @param dev           The device structure.
     
    508545{
    509546        clean_match_ids(&fun->match_ids);
     547        if (fun->driver_data != NULL)
     548                free(fun->driver_data);
    510549        if (fun->name != NULL)
    511550                free(fun->name);
     
    513552}
    514553
     554/** Increase device reference count. */
     555static void dev_add_ref(ddf_dev_t *dev)
     556{
     557        atomic_inc(&dev->refcnt);
     558}
     559
     560/** Decrease device reference count.
     561 *
     562 * Free the device structure if the reference count drops to zero.
     563 */
     564static void dev_del_ref(ddf_dev_t *dev)
     565{
     566        if (atomic_predec(&dev->refcnt) == 0)
     567                delete_device(dev);
     568}
     569
     570/** Increase function reference count.
     571 *
     572 * This also increases reference count on the device. The device structure
     573 * will thus not be deallocated while there are some associated function
     574 * structures.
     575 */
     576static void fun_add_ref(ddf_fun_t *fun)
     577{
     578        dev_add_ref(fun->dev);
     579        atomic_inc(&fun->refcnt);
     580}
     581
     582/** Decrease function reference count.
     583 *
     584 * Free the function structure if the reference count drops to zero.
     585 */
     586static void fun_del_ref(ddf_fun_t *fun)
     587{
     588        ddf_dev_t *dev = fun->dev;
     589
     590        if (atomic_predec(&fun->refcnt) == 0)
     591                delete_function(fun);
     592
     593        dev_del_ref(dev);
     594}
     595
     596/** Allocate driver-specific device data. */
     597void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
     598{
     599        void *data;
     600
     601        assert(dev->driver_data == NULL);
     602
     603        data = calloc(1, size);
     604        if (data == NULL)
     605                return NULL;
     606
     607        dev->driver_data = data;
     608        return data;
     609}
     610
    515611/** Create a DDF function node.
    516612 *
     
    544640                return NULL;
    545641
     642        /* Add one reference that will be dropped by ddf_fun_destroy() */
     643        fun->dev = dev;
     644        fun_add_ref(fun);
     645
    546646        fun->bound = false;
    547         fun->dev = dev;
    548647        fun->ftype = ftype;
    549648
     
    557656}
    558657
     658/** Allocate driver-specific function data. */
     659void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
     660{
     661        void *data;
     662
     663        assert(fun->bound == false);
     664        assert(fun->driver_data == NULL);
     665
     666        data = calloc(1, size);
     667        if (data == NULL)
     668                return NULL;
     669
     670        fun->driver_data = data;
     671        return data;
     672}
     673
    559674/** Destroy DDF function node.
    560675 *
     
    567682{
    568683        assert(fun->bound == false);
    569         delete_function(fun);
     684
     685        /*
     686         * Drop the reference added by ddf_fun_create(). This will deallocate
     687         * the function as soon as all other references are dropped (i.e.
     688         * as soon control leaves all driver entry points called in context
     689         * of this function.
     690         */
     691        fun_del_ref(fun);
    570692}
    571693
     
    614736 * the function invisible to the system.
    615737 *
    616  * @param fun           Function to bind
     738 * @param fun           Function to unbind
    617739 * @return              EOK on success or negative error code
    618740 */
     
    623745        assert(fun->bound == true);
    624746       
    625         add_to_functions_list(fun);
    626747        res = devman_remove_function(fun->handle);
    627748        if (res != EOK)
     
    631752       
    632753        fun->bound = false;
     754        return EOK;
     755}
     756
     757/** Online function.
     758 *
     759 * @param fun           Function to online
     760 * @return              EOK on success or negative error code
     761 */
     762int ddf_fun_online(ddf_fun_t *fun)
     763{
     764        int res;
     765       
     766        assert(fun->bound == true);
     767       
     768        res = devman_drv_fun_online(fun->handle);
     769        if (res != EOK)
     770                return res;
     771       
     772        return EOK;
     773}
     774
     775/** Offline function.
     776 *
     777 * @param fun           Function to offline
     778 * @return              EOK on success or negative error code
     779 */
     780int ddf_fun_offline(ddf_fun_t *fun)
     781{
     782        int res;
     783       
     784        assert(fun->bound == true);
     785       
     786        res = devman_drv_fun_offline(fun->handle);
     787        if (res != EOK)
     788                return res;
     789       
    633790        return EOK;
    634791}
     
    657814       
    658815        match_id->id = str_dup(match_id_str);
    659         match_id->score = 90;
     816        match_id->score = match_score;
    660817       
    661818        add_match_id(&fun->match_ids, match_id);
     
    693850        driver = drv;
    694851       
    695         /* Initialize the list of interrupt contexts. */
    696         init_interrupt_context_list(&interrupt_contexts);
    697        
    698         /* Set generic interrupt handler. */
    699         async_set_interrupt_received(driver_irq_handler);
     852        /* Initialize interrupt module */
     853        interrupt_init();
    700854       
    701855        /*
     
    703857         * incoming connections.
    704858         */
    705         rc = devman_driver_register(driver->name, driver_connection);
     859        async_set_client_connection(driver_connection);
     860        rc = devman_driver_register(driver->name);
    706861        if (rc != EOK) {
    707862                printf("Error: Failed to register driver with device manager "
  • uspace/lib/drv/generic/remote_pci.c

    rbd5f3b7 r00aece0  
    3232/** @file
    3333 */
     34
    3435#include <assert.h>
    3536#include <async.h>
  • uspace/lib/drv/generic/remote_usb.c

    rbd5f3b7 r00aece0  
    11/*
    22 * Copyright (c) 2010 Vojtech Horky
     3 * Copyright (c) 2011 Jan Vesely
    34 * All rights reserved.
    45 *
     
    3940#include "ddf/driver.h"
    4041
     42typedef enum {
     43        IPC_M_USB_GET_MY_ADDRESS,
     44        IPC_M_USB_GET_MY_INTERFACE,
     45        IPC_M_USB_GET_HOST_CONTROLLER_HANDLE,
     46} usb_iface_funcs_t;
    4147
    42 static void remote_usb_get_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    43 static void remote_usb_get_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     48/** Tell USB address assigned to device.
     49 * @param exch Vaid IPC exchange
     50 * @param address Pointer to address storage place.
     51 * @return Error code.
     52 *
     53 * Exch param is an open communication to device implementing usb_iface.
     54 */
     55int usb_get_my_address(async_exch_t *exch, usb_address_t *address)
     56{
     57        if (!exch)
     58                return EINVAL;
     59        sysarg_t addr;
     60        const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     61            IPC_M_USB_GET_MY_ADDRESS, &addr);
     62
     63        if (ret == EOK && address != NULL)
     64                *address = (usb_address_t) addr;
     65        return ret;
     66}
     67/*----------------------------------------------------------------------------*/
     68/** Tell interface number given device can use.
     69 * @param[in] exch IPC communication exchange
     70 * @param[in] handle Id of the device
     71 * @param[out] usb_iface Assigned USB interface
     72 * @return Error code.
     73 */
     74int usb_get_my_interface(async_exch_t *exch, int *usb_iface)
     75{
     76        if (!exch)
     77                return EINVAL;
     78        sysarg_t iface_no;
     79        const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     80            IPC_M_USB_GET_MY_INTERFACE, &iface_no);
     81        if (ret == EOK && usb_iface)
     82                *usb_iface = (int)iface_no;
     83        return ret;
     84}
     85/*----------------------------------------------------------------------------*/
     86/** Tell devman handle of device host controller.
     87 * @param[in] exch IPC communication exchange
     88 * @param[out] hc_handle devman handle of the HC used by the target device.
     89 * @return Error code.
     90 */
     91int usb_get_hc_handle(async_exch_t *exch, devman_handle_t *hc_handle)
     92{
     93        if (!exch)
     94                return EINVAL;
     95        devman_handle_t h;
     96        const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
     97            IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
     98        if (ret == EOK && hc_handle)
     99                *hc_handle = (devman_handle_t)h;
     100        return ret;
     101}
     102
     103
     104static void remote_usb_get_my_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     105static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    44106static void remote_usb_get_hc_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    45 //static void remote_usb(device_t *, void *, ipc_callid_t, ipc_call_t *);
    46107
    47108/** Remote USB interface operations. */
    48109static remote_iface_func_ptr_t remote_usb_iface_ops [] = {
    49         remote_usb_get_address,
    50         remote_usb_get_interface,
    51         remote_usb_get_hc_handle
     110        [IPC_M_USB_GET_MY_ADDRESS] = remote_usb_get_my_address,
     111        [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface,
     112        [IPC_M_USB_GET_HOST_CONTROLLER_HANDLE] = remote_usb_get_hc_handle,
    52113};
    53114
     
    60121};
    61122
    62 
    63 void remote_usb_get_address(ddf_fun_t *fun, void *iface,
     123/*----------------------------------------------------------------------------*/
     124void remote_usb_get_my_address(ddf_fun_t *fun, void *iface,
    64125    ipc_callid_t callid, ipc_call_t *call)
    65126{
    66         usb_iface_t *usb_iface = (usb_iface_t *) iface;
     127        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
    67128
    68         if (usb_iface->get_address == NULL) {
     129        if (usb_iface->get_my_address == NULL) {
    69130                async_answer_0(callid, ENOTSUP);
    70131                return;
    71132        }
    72133
    73         devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
    74 
    75134        usb_address_t address;
    76         int rc = usb_iface->get_address(fun, handle, &address);
    77         if (rc != EOK) {
    78                 async_answer_0(callid, rc);
     135        const int ret = usb_iface->get_my_address(fun, &address);
     136        if (ret != EOK) {
     137                async_answer_0(callid, ret);
    79138        } else {
    80139                async_answer_1(callid, EOK, address);
    81140        }
    82141}
    83 
    84 void remote_usb_get_interface(ddf_fun_t *fun, void *iface,
     142/*----------------------------------------------------------------------------*/
     143void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface,
    85144    ipc_callid_t callid, ipc_call_t *call)
    86145{
    87         usb_iface_t *usb_iface = (usb_iface_t *) iface;
     146        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
    88147
    89         if (usb_iface->get_interface == NULL) {
     148        if (usb_iface->get_my_interface == NULL) {
    90149                async_answer_0(callid, ENOTSUP);
    91150                return;
    92151        }
    93152
    94         devman_handle_t handle = DEV_IPC_GET_ARG1(*call);
    95 
    96153        int iface_no;
    97         int rc = usb_iface->get_interface(fun, handle, &iface_no);
    98         if (rc != EOK) {
    99                 async_answer_0(callid, rc);
     154        const int ret = usb_iface->get_my_interface(fun, &iface_no);
     155        if (ret != EOK) {
     156                async_answer_0(callid, ret);
    100157        } else {
    101158                async_answer_1(callid, EOK, iface_no);
    102159        }
    103160}
    104 
     161/*----------------------------------------------------------------------------*/
    105162void remote_usb_get_hc_handle(ddf_fun_t *fun, void *iface,
    106163    ipc_callid_t callid, ipc_call_t *call)
    107164{
    108         usb_iface_t *usb_iface = (usb_iface_t *) iface;
     165        const usb_iface_t *usb_iface = (usb_iface_t *) iface;
    109166
    110167        if (usb_iface->get_hc_handle == NULL) {
     
    114171
    115172        devman_handle_t handle;
    116         int rc = usb_iface->get_hc_handle(fun, &handle);
    117         if (rc != EOK) {
    118                 async_answer_0(callid, rc);
     173        const int ret = usb_iface->get_hc_handle(fun, &handle);
     174        if (ret != EOK) {
     175                async_answer_0(callid, ret);
    119176        }
    120177
    121178        async_answer_1(callid, EOK, (sysarg_t) handle);
    122179}
    123 
    124 
    125 
    126180/**
    127181 * @}
  • uspace/lib/drv/generic/remote_usbhc.c

    rbd5f3b7 r00aece0  
    11/*
    22 * Copyright (c) 2010-2011 Vojtech Horky
     3 * Copyright (c) 2011 Jan Vesely
    34 * All rights reserved.
    45 *
     
    4142
    4243#define USB_MAX_PAYLOAD_SIZE 1020
    43 #define HACK_MAX_PACKET_SIZE 8
    44 #define HACK_MAX_PACKET_SIZE_INTERRUPT_IN 4
    45 
    46 static void remote_usbhc_interrupt_out(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    47 static void remote_usbhc_interrupt_in(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    48 static void remote_usbhc_bulk_out(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    49 static void remote_usbhc_bulk_in(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    50 static void remote_usbhc_control_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    51 static void remote_usbhc_control_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     44
     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
    52323static void remote_usbhc_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    53324static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    54 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 *);
    55326static void remote_usbhc_release_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    56327static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    57328static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     329static void remote_usbhc_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
     330static void remote_usbhc_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    58331//static void remote_usbhc(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
    59332
    60333/** Remote USB host controller interface operations. */
    61 static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
    62         remote_usbhc_request_address,
    63         remote_usbhc_bind_address,
    64         remote_usbhc_find_by_address,
    65         remote_usbhc_release_address,
    66 
    67         remote_usbhc_interrupt_out,
    68         remote_usbhc_interrupt_in,
    69 
    70         remote_usbhc_bulk_out,
    71         remote_usbhc_bulk_in,
    72 
    73         remote_usbhc_control_write,
    74         remote_usbhc_control_read,
    75 
    76         remote_usbhc_register_endpoint,
    77         remote_usbhc_unregister_endpoint
     334static remote_iface_func_ptr_t remote_usbhc_iface_ops[] = {
     335        [IPC_M_USBHC_REQUEST_ADDRESS] = remote_usbhc_request_address,
     336        [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,
     339
     340        [IPC_M_USBHC_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint,
     341        [IPC_M_USBHC_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint,
     342
     343        [IPC_M_USBHC_READ] = remote_usbhc_read,
     344        [IPC_M_USBHC_WRITE] = remote_usbhc_write,
    78345};
    79346
     
    90357        ipc_callid_t data_caller;
    91358        void *buffer;
    92         void *setup_packet;
    93         size_t size;
    94359} async_transaction_t;
    95360
     
    98363        if (trans == NULL) {
    99364                return;
    100         }
    101 
    102         if (trans->setup_packet != NULL) {
    103                 free(trans->setup_packet);
    104365        }
    105366        if (trans->buffer != NULL) {
     
    120381        trans->data_caller = 0;
    121382        trans->buffer = NULL;
    122         trans->setup_packet = NULL;
    123         trans->size = 0;
    124383
    125384        return trans;
    126385}
    127 
     386/*----------------------------------------------------------------------------*/
    128387void remote_usbhc_request_address(ddf_fun_t *fun, void *iface,
    129388    ipc_callid_t callid, ipc_call_t *call)
    130389{
    131         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     390        const usbhc_iface_t *usb_iface = iface;
    132391
    133392        if (!usb_iface->request_address) {
     
    135394                return;
    136395        }
    137        
    138         usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
    139 
    140         usb_address_t address;
    141         int rc = usb_iface->request_address(fun, speed, &address);
     396
     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);
    142402        if (rc != EOK) {
    143403                async_answer_0(callid, rc);
     
    146406        }
    147407}
    148 
     408/*----------------------------------------------------------------------------*/
    149409void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface,
    150410    ipc_callid_t callid, ipc_call_t *call)
    151411{
    152         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     412        const usbhc_iface_t *usb_iface = iface;
    153413
    154414        if (!usb_iface->bind_address) {
     
    157417        }
    158418
    159         usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
    160         devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
    161 
    162         int rc = usb_iface->bind_address(fun, address, handle);
    163 
    164         async_answer_0(callid, rc);
    165 }
    166 
    167 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,
    168427    ipc_callid_t callid, ipc_call_t *call)
    169428{
    170         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    171 
    172         if (!usb_iface->find_by_address) {
    173                 async_answer_0(callid, ENOTSUP);
    174                 return;
    175         }
    176 
    177         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);
    178437        devman_handle_t handle;
    179         int rc = usb_iface->find_by_address(fun, address, &handle);
    180 
    181         if (rc == EOK) {
    182                 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);
    183442        } else {
    184                 async_answer_0(callid, rc);
    185         }
    186 }
    187 
     443                async_answer_0(callid, ret);
     444        }
     445}
     446/*----------------------------------------------------------------------------*/
    188447void remote_usbhc_release_address(ddf_fun_t *fun, void *iface,
    189448    ipc_callid_t callid, ipc_call_t *call)
    190449{
    191         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     450        const usbhc_iface_t *usb_iface = iface;
    192451
    193452        if (!usb_iface->release_address) {
     
    196455        }
    197456
    198         usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
    199 
    200         int rc = usb_iface->release_address(fun, address);
    201 
    202         async_answer_0(callid, rc);
    203 }
    204 
    205 
     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/*----------------------------------------------------------------------------*/
    206463static void callback_out(ddf_fun_t *fun,
    207464    int outcome, void *arg)
    208465{
    209         async_transaction_t *trans = (async_transaction_t *)arg;
     466        async_transaction_t *trans = arg;
    210467
    211468        async_answer_0(trans->caller, outcome);
     
    213470        async_transaction_destroy(trans);
    214471}
    215 
     472/*----------------------------------------------------------------------------*/
    216473static void callback_in(ddf_fun_t *fun,
    217474    int outcome, size_t actual_size, void *arg)
     
    228485        }
    229486
    230         trans->size = actual_size;
    231 
    232487        if (trans->data_caller) {
    233488                async_data_read_finalize(trans->data_caller,
     
    239494        async_transaction_destroy(trans);
    240495}
    241 
    242 /** Process an outgoing transfer (both OUT and SETUP).
    243  *
    244  * @param device Target device.
    245  * @param callid Initiating caller.
    246  * @param call Initiating call.
    247  * @param transfer_func Transfer function (might be NULL).
    248  */
    249 static void remote_usbhc_out_transfer(ddf_fun_t *fun,
    250     ipc_callid_t callid, ipc_call_t *call,
    251     usbhc_iface_transfer_out_t transfer_func)
    252 {
    253         if (!transfer_func) {
    254                 async_answer_0(callid, ENOTSUP);
    255                 return;
    256         }
    257 
    258         usb_target_t target = {
    259                 .address = DEV_IPC_GET_ARG1(*call),
    260                 .endpoint = DEV_IPC_GET_ARG2(*call)
    261         };
    262 
    263         size_t len = 0;
    264         void *buffer = NULL;
    265 
    266         int rc = async_data_write_accept(&buffer, false,
    267             1, USB_MAX_PAYLOAD_SIZE,
    268             0, &len);
    269 
    270         if (rc != EOK) {
    271                 async_answer_0(callid, rc);
    272                 return;
    273         }
     496/*----------------------------------------------------------------------------*/
     497void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
     498    ipc_callid_t callid, ipc_call_t *call)
     499{
     500        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     501
     502        if (!usb_iface->register_endpoint) {
     503                async_answer_0(callid, ENOTSUP);
     504                return;
     505        }
     506
     507#define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \
     508        type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) >> 16)
     509#define _INIT_FROM_LOW_DATA2(type, var, arg_no) \
     510        type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) & 0xffff)
     511
     512        const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
     513
     514        _INIT_FROM_HIGH_DATA2(usb_transfer_type_t, transfer_type, 2);
     515        _INIT_FROM_LOW_DATA2(usb_direction_t, direction, 2);
     516
     517        _INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3);
     518        _INIT_FROM_LOW_DATA2(unsigned int, interval, 3);
     519
     520#undef _INIT_FROM_HIGH_DATA2
     521#undef _INIT_FROM_LOW_DATA2
     522
     523        int rc = usb_iface->register_endpoint(fun, target.address,
     524            target.endpoint, transfer_type, direction, max_packet_size, interval);
     525
     526        async_answer_0(callid, rc);
     527}
     528
     529void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
     530    ipc_callid_t callid, ipc_call_t *call)
     531{
     532        usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
     533
     534        if (!usb_iface->unregister_endpoint) {
     535                async_answer_0(callid, ENOTSUP);
     536                return;
     537        }
     538
     539        usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
     540        usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG2(*call);
     541        usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG3(*call);
     542
     543        int rc = usb_iface->unregister_endpoint(fun,
     544            address, endpoint, direction);
     545
     546        async_answer_0(callid, rc);
     547}
     548
     549void remote_usbhc_read(
     550    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     551{
     552        assert(fun);
     553        assert(iface);
     554        assert(call);
     555
     556        const usbhc_iface_t *hc_iface = iface;
     557
     558        if (!hc_iface->read) {
     559                async_answer_0(callid, ENOTSUP);
     560                return;
     561        }
     562
     563        const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
     564        const uint64_t setup =
     565            ((uint64_t)DEV_IPC_GET_ARG2(*call)) |
     566            (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);
    274567
    275568        async_transaction_t *trans = async_transaction_create(callid);
    276569        if (trans == NULL) {
    277                 if (buffer != NULL) {
    278                         free(buffer);
     570                async_answer_0(callid, ENOMEM);
     571                return;
     572        }
     573
     574        size_t size = 0;
     575        if (!async_data_read_receive(&trans->data_caller, &size)) {
     576                async_answer_0(callid, EPARTY);
     577                return;
     578        }
     579
     580        trans->buffer = malloc(size);
     581        if (trans->buffer == NULL) {
     582                async_answer_0(trans->data_caller, ENOMEM);
     583                async_answer_0(callid, ENOMEM);
     584                async_transaction_destroy(trans);
     585        }
     586
     587        const int rc = hc_iface->read(
     588            fun, target, setup, trans->buffer, size, callback_in, trans);
     589
     590        if (rc != EOK) {
     591                async_answer_0(trans->data_caller, rc);
     592                async_answer_0(callid, rc);
     593                async_transaction_destroy(trans);
     594        }
     595}
     596/*----------------------------------------------------------------------------*/
     597void remote_usbhc_write(
     598    ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)
     599{
     600        assert(fun);
     601        assert(iface);
     602        assert(call);
     603
     604        const usbhc_iface_t *hc_iface = iface;
     605
     606        if (!hc_iface->write) {
     607                async_answer_0(callid, ENOTSUP);
     608                return;
     609        }
     610
     611        const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) };
     612        const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);
     613        const uint64_t setup =
     614            ((uint64_t)DEV_IPC_GET_ARG3(*call)) |
     615            (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);
     616
     617        async_transaction_t *trans = async_transaction_create(callid);
     618        if (trans == NULL) {
     619                async_answer_0(callid, ENOMEM);
     620                return;
     621        }
     622
     623        size_t size = 0;
     624        if (data_buffer_len > 0) {
     625                const int rc = async_data_write_accept(&trans->buffer, false,
     626                    1, USB_MAX_PAYLOAD_SIZE,
     627                    0, &size);
     628
     629                if (rc != EOK) {
     630                        async_answer_0(callid, rc);
     631                        async_transaction_destroy(trans);
     632                        return;
    279633                }
    280                 async_answer_0(callid, ENOMEM);
    281                 return;
    282         }
    283 
    284         trans->buffer = buffer;
    285         trans->size = len;
    286 
    287         rc = transfer_func(fun, target,
    288             buffer, len,
    289             callback_out, trans);
     634        }
     635
     636        const int rc = hc_iface->write(
     637            fun, target, setup, trans->buffer, size, callback_out, trans);
    290638
    291639        if (rc != EOK) {
     
    294642        }
    295643}
    296 
    297 /** Process an incoming transfer.
    298  *
    299  * @param device Target device.
    300  * @param callid Initiating caller.
    301  * @param call Initiating call.
    302  * @param transfer_func Transfer function (might be NULL).
    303  */
    304 static void remote_usbhc_in_transfer(ddf_fun_t *fun,
    305     ipc_callid_t callid, ipc_call_t *call,
    306     usbhc_iface_transfer_in_t transfer_func)
    307 {
    308         if (!transfer_func) {
    309                 async_answer_0(callid, ENOTSUP);
    310                 return;
    311         }
    312 
    313         usb_target_t target = {
    314                 .address = DEV_IPC_GET_ARG1(*call),
    315                 .endpoint = DEV_IPC_GET_ARG2(*call)
    316         };
    317 
    318         size_t len;
    319         ipc_callid_t data_callid;
    320         if (!async_data_read_receive(&data_callid, &len)) {
    321                 async_answer_0(callid, EPARTY);
    322                 return;
    323         }
    324 
    325         async_transaction_t *trans = async_transaction_create(callid);
    326         if (trans == NULL) {
    327                 async_answer_0(data_callid, ENOMEM);
    328                 async_answer_0(callid, ENOMEM);
    329                 return;
    330         }
    331         trans->data_caller = data_callid;
    332         trans->buffer = malloc(len);
    333         trans->size = len;
    334 
    335         int rc = transfer_func(fun, target,
    336             trans->buffer, len,
    337             callback_in, trans);
    338 
    339         if (rc != EOK) {
    340                 async_answer_0(data_callid, rc);
    341                 async_answer_0(callid, rc);
    342                 async_transaction_destroy(trans);
    343         }
    344 }
    345 
    346 void remote_usbhc_interrupt_out(ddf_fun_t *fun, void *iface,
    347     ipc_callid_t callid, ipc_call_t *call)
    348 {
    349         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    350         assert(usb_iface != NULL);
    351 
    352         return remote_usbhc_out_transfer(fun, callid, call,
    353             usb_iface->interrupt_out);
    354 }
    355 
    356 void remote_usbhc_interrupt_in(ddf_fun_t *fun, void *iface,
    357     ipc_callid_t callid, ipc_call_t *call)
    358 {
    359         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    360         assert(usb_iface != NULL);
    361 
    362         return remote_usbhc_in_transfer(fun, callid, call,
    363             usb_iface->interrupt_in);
    364 }
    365 
    366 void remote_usbhc_bulk_out(ddf_fun_t *fun, void *iface,
    367     ipc_callid_t callid, ipc_call_t *call)
    368 {
    369         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    370         assert(usb_iface != NULL);
    371 
    372         return remote_usbhc_out_transfer(fun, callid, call,
    373             usb_iface->bulk_out);
    374 }
    375 
    376 void remote_usbhc_bulk_in(ddf_fun_t *fun, void *iface,
    377     ipc_callid_t callid, ipc_call_t *call)
    378 {
    379         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    380         assert(usb_iface != NULL);
    381 
    382         return remote_usbhc_in_transfer(fun, callid, call,
    383             usb_iface->bulk_in);
    384 }
    385 
    386 void remote_usbhc_control_write(ddf_fun_t *fun, void *iface,
    387 ipc_callid_t callid, ipc_call_t *call)
    388 {
    389         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    390         assert(usb_iface != NULL);
    391 
    392         if (!usb_iface->control_write) {
    393                 async_answer_0(callid, ENOTSUP);
    394                 return;
    395         }
    396 
    397         usb_target_t target = {
    398                 .address = DEV_IPC_GET_ARG1(*call),
    399                 .endpoint = DEV_IPC_GET_ARG2(*call)
    400         };
    401         size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
    402 
    403         int rc;
    404 
    405         void *setup_packet = NULL;
    406         void *data_buffer = NULL;
    407         size_t setup_packet_len = 0;
    408 
    409         rc = async_data_write_accept(&setup_packet, false,
    410             1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
    411         if (rc != EOK) {
    412                 async_answer_0(callid, rc);
    413                 return;
    414         }
    415 
    416         if (data_buffer_len > 0) {
    417                 rc = async_data_write_accept(&data_buffer, false,
    418                     1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
    419                 if (rc != EOK) {
    420                         async_answer_0(callid, rc);
    421                         free(setup_packet);
    422                         return;
    423                 }
    424         }
    425 
    426         async_transaction_t *trans = async_transaction_create(callid);
    427         if (trans == NULL) {
    428                 async_answer_0(callid, ENOMEM);
    429                 free(setup_packet);
    430                 free(data_buffer);
    431                 return;
    432         }
    433         trans->setup_packet = setup_packet;
    434         trans->buffer = data_buffer;
    435         trans->size = data_buffer_len;
    436 
    437         rc = usb_iface->control_write(fun, target,
    438             setup_packet, setup_packet_len,
    439             data_buffer, data_buffer_len,
    440             callback_out, trans);
    441 
    442         if (rc != EOK) {
    443                 async_answer_0(callid, rc);
    444                 async_transaction_destroy(trans);
    445         }
    446 }
    447 
    448 
    449 void remote_usbhc_control_read(ddf_fun_t *fun, void *iface,
    450 ipc_callid_t callid, ipc_call_t *call)
    451 {
    452         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    453         assert(usb_iface != NULL);
    454 
    455         if (!usb_iface->control_read) {
    456                 async_answer_0(callid, ENOTSUP);
    457                 return;
    458         }
    459 
    460         usb_target_t target = {
    461                 .address = DEV_IPC_GET_ARG1(*call),
    462                 .endpoint = DEV_IPC_GET_ARG2(*call)
    463         };
    464 
    465         int rc;
    466 
    467         void *setup_packet = NULL;
    468         size_t setup_packet_len = 0;
    469         size_t data_len = 0;
    470 
    471         rc = async_data_write_accept(&setup_packet, false,
    472             1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
    473         if (rc != EOK) {
    474                 async_answer_0(callid, rc);
    475                 return;
    476         }
    477 
    478         ipc_callid_t data_callid;
    479         if (!async_data_read_receive(&data_callid, &data_len)) {
    480                 async_answer_0(callid, EPARTY);
    481                 free(setup_packet);
    482                 return;
    483         }
    484 
    485         async_transaction_t *trans = async_transaction_create(callid);
    486         if (trans == NULL) {
    487                 async_answer_0(data_callid, ENOMEM);
    488                 async_answer_0(callid, ENOMEM);
    489                 free(setup_packet);
    490                 return;
    491         }
    492         trans->data_caller = data_callid;
    493         trans->setup_packet = setup_packet;
    494         trans->size = data_len;
    495         trans->buffer = malloc(data_len);
    496         if (trans->buffer == NULL) {
    497                 async_answer_0(data_callid, ENOMEM);
    498                 async_answer_0(callid, ENOMEM);
    499                 async_transaction_destroy(trans);
    500                 return;
    501         }
    502 
    503         rc = usb_iface->control_read(fun, target,
    504             setup_packet, setup_packet_len,
    505             trans->buffer, trans->size,
    506             callback_in, trans);
    507 
    508         if (rc != EOK) {
    509                 async_answer_0(data_callid, rc);
    510                 async_answer_0(callid, rc);
    511                 async_transaction_destroy(trans);
    512         }
    513 }
    514 
    515 
    516 void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface,
    517     ipc_callid_t callid, ipc_call_t *call)
    518 {
    519         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    520 
    521         if (!usb_iface->register_endpoint) {
    522                 async_answer_0(callid, ENOTSUP);
    523                 return;
    524         }
    525 
    526 #define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \
    527         type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
    528 #define _INIT_FROM_LOW_DATA2(type, var, arg_no) \
    529         type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 16)
    530 #define _INIT_FROM_HIGH_DATA3(type, var, arg_no) \
    531         type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16)
    532 #define _INIT_FROM_MIDDLE_DATA3(type, var, arg_no) \
    533         type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) / (1 << 8)) % (1 << 8)
    534 #define _INIT_FROM_LOW_DATA3(type, var, arg_no) \
    535         type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 8)
    536 
    537         _INIT_FROM_HIGH_DATA2(usb_address_t, address, 1);
    538         _INIT_FROM_LOW_DATA2(usb_endpoint_t, endpoint, 1);
    539 
    540         _INIT_FROM_HIGH_DATA3(usb_speed_t, speed, 2);
    541         _INIT_FROM_MIDDLE_DATA3(usb_transfer_type_t, transfer_type, 2);
    542         _INIT_FROM_LOW_DATA3(usb_direction_t, direction, 2);
    543 
    544         _INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3);
    545         _INIT_FROM_LOW_DATA2(unsigned int, interval, 3);
    546 
    547 #undef _INIT_FROM_HIGH_DATA2
    548 #undef _INIT_FROM_LOW_DATA2
    549 #undef _INIT_FROM_HIGH_DATA3
    550 #undef _INIT_FROM_MIDDLE_DATA3
    551 #undef _INIT_FROM_LOW_DATA3
    552 
    553         int rc = usb_iface->register_endpoint(fun, address, speed, endpoint,
    554             transfer_type, direction, max_packet_size, interval);
    555 
    556         async_answer_0(callid, rc);
    557 }
    558 
    559 
    560 void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface,
    561     ipc_callid_t callid, ipc_call_t *call)
    562 {
    563         usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
    564 
    565         if (!usb_iface->unregister_endpoint) {
    566                 async_answer_0(callid, ENOTSUP);
    567                 return;
    568         }
    569 
    570         usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
    571         usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG2(*call);
    572         usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG3(*call);
    573 
    574         int rc = usb_iface->unregister_endpoint(fun,
    575             address, endpoint, direction);
    576 
    577         async_answer_0(callid, rc);
    578 }
    579 
    580 
    581644/**
    582645 * @}
Note: See TracChangeset for help on using the changeset viewer.