Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/devman/main.c

    rf9b2cb4c r005ac3c  
    4949#include <io/log.h>
    5050#include <ipc/devman.h>
     51#include <ipc/driver.h>
    5152#include <loc.h>
    5253
     
    6566dev_tree_t device_tree;
    6667
    67 static void devman_connection_device(ipc_callid_t iid, ipc_call_t *icall,
    68     void *arg)
     68static void devman_forward(ipc_callid_t iid, ipc_call_t *icall,
     69    bool drv_to_parent)
    6970{
    7071        devman_handle_t handle = IPC_GET_ARG2(*icall);
     72        devman_handle_t fwd_h;
     73        fun_node_t *fun = NULL;
    7174        dev_node_t *dev = NULL;
    7275       
    73         fun_node_t *fun = find_fun_node(&device_tree, handle);
    74         if (fun == NULL) {
     76        fun = find_fun_node(&device_tree, handle);
     77        if (fun == NULL)
    7578                dev = find_dev_node(&device_tree, handle);
    76         } else {
     79        else {
    7780                fibril_rwlock_read_lock(&device_tree.rwlock);
    78                
    7981                dev = fun->dev;
    8082                if (dev != NULL)
    8183                        dev_add_ref(dev);
    82                
    8384                fibril_rwlock_read_unlock(&device_tree.rwlock);
    8485        }
    85        
     86
    8687        /*
    8788         * For a valid function to connect to we need a device. The root
     
    9697                goto cleanup;
    9798        }
    98        
    99         if (fun == NULL) {
     99
     100        if (fun == NULL && !drv_to_parent) {
    100101                log_msg(LOG_DEFAULT, LVL_ERROR, NAME ": devman_forward error - cannot "
    101102                    "connect to handle %" PRIun ", refers to a device.",
     
    105106        }
    106107       
     108        driver_t *driver = NULL;
     109       
    107110        fibril_rwlock_read_lock(&device_tree.rwlock);
    108111       
    109         /* Connect to the specified function */
    110         driver_t *driver = dev->drv;
     112        if (drv_to_parent) {
     113                /* Connect to parent function of a device (or device function). */
     114                if (dev->pfun->dev != NULL)
     115                        driver = dev->pfun->dev->drv;
     116               
     117                fwd_h = dev->pfun->handle;
     118        } else {
     119                /* Connect to the specified function */
     120                driver = dev->drv;
     121                fwd_h = handle;
     122        }
    111123       
    112124        fibril_rwlock_read_unlock(&device_tree.rwlock);
     
    118130                goto cleanup;
    119131        }
     132       
     133        int method;
     134        if (drv_to_parent)
     135                method = DRIVER_DRIVER;
     136        else
     137                method = DRIVER_CLIENT;
    120138       
    121139        if (!driver->sess) {
     
    125143                goto cleanup;
    126144        }
    127        
     145
    128146        if (fun != NULL) {
    129147                log_msg(LOG_DEFAULT, LVL_DEBUG,
     
    137155       
    138156        async_exch_t *exch = async_exchange_begin(driver->sess);
    139         async_forward_fast(iid, exch, INTERFACE_DDF_CLIENT, handle, 0, IPC_FF_NONE);
     157        async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
    140158        async_exchange_end(exch);
    141159       
     
    148166}
    149167
    150 static void devman_connection_parent(ipc_callid_t iid, ipc_call_t *icall,
    151     void *arg)
    152 {
    153         devman_handle_t handle = IPC_GET_ARG2(*icall);
    154         dev_node_t *dev = NULL;
    155        
    156         fun_node_t *fun = find_fun_node(&device_tree, handle);
    157         if (fun == NULL) {
    158                 dev = find_dev_node(&device_tree, handle);
    159         } else {
    160                 fibril_rwlock_read_lock(&device_tree.rwlock);
    161                
    162                 dev = fun->dev;
    163                 if (dev != NULL)
    164                         dev_add_ref(dev);
    165                
    166                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    167         }
    168        
    169         /*
    170          * For a valid function to connect to we need a device. The root
    171          * function, for example, has no device and cannot be connected to.
    172          * This means @c dev needs to be valid regardless whether we are
    173          * connecting to a device or to a function.
    174          */
    175         if (dev == NULL) {
    176                 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding failed - no device or "
    177                     "function with handle %" PRIun " was found.", handle);
    178                 async_answer_0(iid, ENOENT);
    179                 goto cleanup;
    180         }
    181        
    182         driver_t *driver = NULL;
     168/** Function for handling connections from a client forwarded by the location
     169 * service to the device manager. */
     170static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall)
     171{
     172        service_id_t service_id = IPC_GET_ARG2(*icall);
     173        fun_node_t *fun;
     174        dev_node_t *dev;
     175        devman_handle_t handle;
     176        driver_t *driver;
     177
     178        fun = find_loc_tree_function(&device_tree, service_id);
    183179       
    184180        fibril_rwlock_read_lock(&device_tree.rwlock);
    185181       
    186         /* Connect to parent function of a device (or device function). */
    187         if (dev->pfun->dev != NULL)
    188                 driver = dev->pfun->dev->drv;
    189        
    190         devman_handle_t fun_handle = dev->pfun->handle;
    191        
    192         fibril_rwlock_read_unlock(&device_tree.rwlock);
    193        
    194         if (driver == NULL) {
    195                 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding refused - " \
    196                     "the device %" PRIun " is not in usable state.", handle);
    197                 async_answer_0(iid, ENOENT);
    198                 goto cleanup;
    199         }
    200        
    201         if (!driver->sess) {
    202                 log_msg(LOG_DEFAULT, LVL_ERROR,
    203                     "Could not forward to driver `%s'.", driver->name);
    204                 async_answer_0(iid, EINVAL);
    205                 goto cleanup;
    206         }
    207        
    208         if (fun != NULL) {
    209                 log_msg(LOG_DEFAULT, LVL_DEBUG,
    210                     "Forwarding request for `%s' function to driver `%s'.",
    211                     fun->pathname, driver->name);
    212         } else {
    213                 log_msg(LOG_DEFAULT, LVL_DEBUG,
    214                     "Forwarding request for `%s' device to driver `%s'.",
    215                     dev->pfun->pathname, driver->name);
    216         }
    217        
    218         async_exch_t *exch = async_exchange_begin(driver->sess);
    219         async_forward_fast(iid, exch, INTERFACE_DDF_DRIVER, fun_handle, 0, IPC_FF_NONE);
    220         async_exchange_end(exch);
    221        
    222 cleanup:
    223         if (dev != NULL)
    224                 dev_del_ref(dev);
    225        
    226         if (fun != NULL)
    227                 fun_del_ref(fun);
    228 }
    229 
    230 static void devman_forward(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    231 {
    232         iface_t iface = IPC_GET_ARG1(*icall);
    233         service_id_t service_id = IPC_GET_ARG2(*icall);
    234        
    235         fun_node_t *fun = find_loc_tree_function(&device_tree, service_id);
    236        
    237         fibril_rwlock_read_lock(&device_tree.rwlock);
    238        
    239         if ((fun == NULL) || (fun->dev == NULL) || (fun->dev->drv == NULL)) {
    240                 log_msg(LOG_DEFAULT, LVL_WARN, "devman_forward(): function "
     182        if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
     183                log_msg(LOG_DEFAULT, LVL_WARN, "devman_connection_loc(): function "
    241184                    "not found.\n");
    242185                fibril_rwlock_read_unlock(&device_tree.rwlock);
     
    245188        }
    246189       
    247         dev_node_t *dev = fun->dev;
    248         driver_t *driver = dev->drv;
    249         devman_handle_t handle = fun->handle;
     190        dev = fun->dev;
     191        driver = dev->drv;
     192        handle = fun->handle;
    250193       
    251194        fibril_rwlock_read_unlock(&device_tree.rwlock);
    252195       
    253196        async_exch_t *exch = async_exchange_begin(driver->sess);
    254         async_forward_fast(iid, exch, iface, handle, 0, IPC_FF_NONE);
     197        async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0,
     198            IPC_FF_NONE);
    255199        async_exchange_end(exch);
    256200       
    257201        log_msg(LOG_DEFAULT, LVL_DEBUG,
    258             "Forwarding service request for `%s' function to driver `%s'.",
     202            "Forwarding loc service request for `%s' function to driver `%s'.",
    259203            fun->pathname, driver->name);
    260        
     204
    261205        fun_del_ref(fun);
     206}
     207
     208/** Function for handling connections to device manager. */
     209static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     210{
     211        /* Select port. */
     212        switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
     213        case DEVMAN_DRIVER:
     214                devman_connection_driver(iid, icall);
     215                break;
     216        case DEVMAN_CLIENT:
     217                devman_connection_client(iid, icall);
     218                break;
     219        case DEVMAN_CONNECT_TO_DEVICE:
     220                /* Connect client to selected device. */
     221                devman_forward(iid, icall, false);
     222                break;
     223        case DEVMAN_CONNECT_FROM_LOC:
     224                /* Someone connected through loc node. */
     225                devman_connection_loc(iid, icall);
     226                break;
     227        case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
     228                /* Connect client to selected device. */
     229                devman_forward(iid, icall, true);
     230                break;
     231        default:
     232                /* No such interface */
     233                async_answer_0(iid, ENOENT);
     234        }
    262235}
    263236
     
    325298        async_set_client_data_constructor(devman_client_data_create);
    326299        async_set_client_data_destructor(devman_client_data_destroy);
    327        
    328         port_id_t port;
    329         rc = async_create_port(INTERFACE_DDF_DRIVER,
    330             devman_connection_driver, NULL, &port);
    331         if (rc != EOK)
    332                 return rc;
    333        
    334         rc = async_create_port(INTERFACE_DDF_CLIENT,
    335             devman_connection_client, NULL, &port);
    336         if (rc != EOK)
    337                 return rc;
    338        
    339         rc = async_create_port(INTERFACE_DEVMAN_DEVICE,
    340             devman_connection_device, NULL, &port);
    341         if (rc != EOK)
    342                 return rc;
    343        
    344         rc = async_create_port(INTERFACE_DEVMAN_PARENT,
    345             devman_connection_parent, NULL, &port);
    346         if (rc != EOK)
    347                 return rc;
    348        
    349         async_set_fallback_port_handler(devman_forward, NULL);
     300        async_set_client_connection(devman_connection);
    350301       
    351302        if (!devman_init()) {
Note: See TracChangeset for help on using the changeset viewer.