Ignore:
File:
1 edited

Legend:

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

    rc4f7bf6 r181c32f  
    3636 */
    3737
    38 #include <inttypes.h>
    3938#include <assert.h>
    4039#include <ipc/services.h>
     
    4342#include <stdio.h>
    4443#include <errno.h>
    45 #include <str_error.h>
    4644#include <stdbool.h>
    4745#include <fibril_synch.h>
    4846#include <stdlib.h>
    4947#include <str.h>
    50 #include <dirent.h>
    51 #include <fcntl.h>
    52 #include <sys/stat.h>
    5348#include <ctype.h>
    5449#include <io/log.h>
    5550#include <ipc/devman.h>
    5651#include <ipc/driver.h>
    57 #include <thread.h>
    5852#include <loc.h>
    5953
     54#include "client_conn.h"
     55#include "dev.h"
    6056#include "devman.h"
     57#include "devtree.h"
     58#include "drv_conn.h"
     59#include "driver.h"
     60#include "fun.h"
     61#include "loc.h"
    6162
    6263#define DRIVER_DEFAULT_STORE  "/drv"
    6364
    64 static driver_list_t drivers_list;
    65 static dev_tree_t device_tree;
    66 
    67 static int init_running_drv(void *drv);
    68 
    69 /** Register running driver. */
    70 static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call)
    71 {
    72         driver_t *driver = NULL;
    73         char *drv_name = NULL;
    74 
    75         log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_driver_register");
    76        
    77         /* Get driver name. */
    78         int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
    79         if (rc != EOK) {
    80                 async_answer_0(callid, rc);
    81                 return NULL;
    82         }
    83 
    84         log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s' driver is trying to register.",
    85             drv_name);
    86        
    87         /* Find driver structure. */
    88         driver = find_driver(&drivers_list, drv_name);
    89         if (driver == NULL) {
    90                 log_msg(LOG_DEFAULT, LVL_ERROR, "No driver named `%s' was found.", drv_name);
    91                 free(drv_name);
    92                 drv_name = NULL;
    93                 async_answer_0(callid, ENOENT);
    94                 return NULL;
    95         }
    96        
    97         free(drv_name);
    98         drv_name = NULL;
    99        
    100         fibril_mutex_lock(&driver->driver_mutex);
    101        
    102         if (driver->sess) {
    103                 /* We already have a connection to the driver. */
    104                 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver '%s' already started.\n",
    105                     driver->name);
    106                 fibril_mutex_unlock(&driver->driver_mutex);
    107                 async_answer_0(callid, EEXISTS);
    108                 return NULL;
    109         }
    110        
    111         switch (driver->state) {
    112         case DRIVER_NOT_STARTED:
    113                 /* Somebody started the driver manually. */
    114                 log_msg(LOG_DEFAULT, LVL_NOTE, "Driver '%s' started manually.\n",
    115                     driver->name);
    116                 driver->state = DRIVER_STARTING;
    117                 break;
    118         case DRIVER_STARTING:
    119                 /* The expected case */
    120                 break;
    121         case DRIVER_RUNNING:
    122                 /* Should not happen since we do not have a connected session */
    123                 assert(false);
    124         }
    125        
    126         /* Create connection to the driver. */
    127         log_msg(LOG_DEFAULT, LVL_DEBUG, "Creating connection to the `%s' driver.",
    128             driver->name);
    129         driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
    130         if (!driver->sess) {
    131                 fibril_mutex_unlock(&driver->driver_mutex);
    132                 async_answer_0(callid, ENOTSUP);
    133                 return NULL;
    134         }
    135         /* FIXME: Work around problem with callback sessions */
    136         async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);
    137        
    138         log_msg(LOG_DEFAULT, LVL_NOTE,
    139             "The `%s' driver was successfully registered as running.",
    140             driver->name);
    141        
    142         /*
    143          * Initialize the driver as running (e.g. pass assigned devices to it)
    144          * in a separate fibril; the separate fibril is used to enable the
    145          * driver to use devman service during the driver's initialization.
    146          */
    147         fid_t fid = fibril_create(init_running_drv, driver);
    148         if (fid == 0) {
    149                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create initialization fibril " \
    150                     "for driver `%s'.", driver->name);
    151                 fibril_mutex_unlock(&driver->driver_mutex);
    152                 async_answer_0(callid, ENOMEM);
    153                 return NULL;
    154         }
    155        
    156         fibril_add_ready(fid);
    157         fibril_mutex_unlock(&driver->driver_mutex);
    158        
    159         async_answer_0(callid, EOK);
    160         return driver;
    161 }
    162 
    163 /** Receive device match ID from the device's parent driver and add it to the
    164  * list of devices match ids.
    165  *
    166  * @param match_ids     The list of the device's match ids.
    167  * @return              Zero on success, negative error code otherwise.
    168  */
    169 static int devman_receive_match_id(match_id_list_t *match_ids)
    170 {
    171         match_id_t *match_id = create_match_id();
    172         ipc_callid_t callid;
    173         ipc_call_t call;
    174         int rc = 0;
    175        
    176         callid = async_get_call(&call);
    177         if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
    178                 log_msg(LOG_DEFAULT, LVL_ERROR,
    179                     "Invalid protocol when trying to receive match id.");
    180                 async_answer_0(callid, EINVAL);
    181                 delete_match_id(match_id);
    182                 return EINVAL;
    183         }
    184        
    185         if (match_id == NULL) {
    186                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate match id.");
    187                 async_answer_0(callid, ENOMEM);
    188                 return ENOMEM;
    189         }
    190        
    191         async_answer_0(callid, EOK);
    192        
    193         match_id->score = IPC_GET_ARG1(call);
    194        
    195         char *match_id_str;
    196         rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0);
    197         match_id->id = match_id_str;
    198         if (rc != EOK) {
    199                 delete_match_id(match_id);
    200                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to receive match id string: %s.",
    201                     str_error(rc));
    202                 return rc;
    203         }
    204        
    205         list_append(&match_id->link, &match_ids->ids);
    206        
    207         log_msg(LOG_DEFAULT, LVL_DEBUG, "Received match id `%s', score %d.",
    208             match_id->id, match_id->score);
    209         return rc;
    210 }
    211 
    212 /** Receive device match IDs from the device's parent driver and add them to the
    213  * list of devices match ids.
    214  *
    215  * @param match_count   The number of device's match ids to be received.
    216  * @param match_ids     The list of the device's match ids.
    217  * @return              Zero on success, negative error code otherwise.
    218  */
    219 static int devman_receive_match_ids(sysarg_t match_count,
    220     match_id_list_t *match_ids)
    221 {
    222         int ret = EOK;
    223         size_t i;
    224        
    225         for (i = 0; i < match_count; i++) {
    226                 if (EOK != (ret = devman_receive_match_id(match_ids)))
    227                         return ret;
    228         }
    229         return ret;
    230 }
    231 
    232 static int assign_driver_fibril(void *arg)
    233 {
    234         dev_node_t *dev_node = (dev_node_t *) arg;
    235         assign_driver(dev_node, &drivers_list, &device_tree);
    236 
    237         /* Delete one reference we got from the caller. */
    238         dev_del_ref(dev_node);
    239         return EOK;
    240 }
    241 
    242 static int online_function(fun_node_t *fun)
    243 {
    244         dev_node_t *dev;
    245        
    246         fibril_rwlock_write_lock(&device_tree.rwlock);
    247        
    248         if (fun->state == FUN_ON_LINE) {
    249                 fibril_rwlock_write_unlock(&device_tree.rwlock);
    250                 log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already on line.",
    251                     fun->pathname);
    252                 return EOK;
    253         }
    254        
    255         if (fun->ftype == fun_inner) {
    256                 dev = create_dev_node();
    257                 if (dev == NULL) {
    258                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    259                         return ENOMEM;
    260                 }
    261                
    262                 insert_dev_node(&device_tree, dev, fun);
    263                 dev_add_ref(dev);
    264         }
    265        
    266         log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
    267        
    268         if (fun->ftype == fun_inner) {
    269                 dev = fun->child;
    270                 assert(dev != NULL);
    271                
    272                 /* Give one reference over to assign_driver_fibril(). */
    273                 dev_add_ref(dev);
    274                
    275                 /*
    276                  * Try to find a suitable driver and assign it to the device.  We do
    277                  * not want to block the current fibril that is used for processing
    278                  * incoming calls: we will launch a separate fibril to handle the
    279                  * driver assigning. That is because assign_driver can actually include
    280                  * task spawning which could take some time.
    281                  */
    282                 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
    283                 if (assign_fibril == 0) {
    284                         log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create fibril for "
    285                             "assigning driver.");
    286                         /* XXX Cleanup */
    287                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    288                         return ENOMEM;
    289                 }
    290                 fibril_add_ready(assign_fibril);
    291         } else
    292                 loc_register_tree_function(fun, &device_tree);
    293        
    294         fibril_rwlock_write_unlock(&device_tree.rwlock);
    295        
    296         return EOK;
    297 }
    298 
    299 static int offline_function(fun_node_t *fun)
    300 {
    301         int rc;
    302        
    303         fibril_rwlock_write_lock(&device_tree.rwlock);
    304        
    305         if (fun->state == FUN_OFF_LINE) {
    306                 fibril_rwlock_write_unlock(&device_tree.rwlock);
    307                 log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already off line.",
    308                     fun->pathname);
    309                 return EOK;
    310         }
    311        
    312         if (fun->ftype == fun_inner) {
    313                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Offlining inner function %s.",
    314                     fun->pathname);
    315                
    316                 if (fun->child != NULL) {
    317                         dev_node_t *dev = fun->child;
    318                         device_state_t dev_state;
    319                        
    320                         dev_add_ref(dev);
    321                         dev_state = dev->state;
    322                        
    323                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    324 
    325                         /* If device is owned by driver, ask driver to give it up. */
    326                         if (dev_state == DEVICE_USABLE) {
    327                                 rc = driver_dev_remove(&device_tree, dev);
    328                                 if (rc != EOK) {
    329                                         dev_del_ref(dev);
    330                                         return ENOTSUP;
    331                                 }
    332                         }
    333                        
    334                         /* Verify that driver removed all functions */
    335                         fibril_rwlock_read_lock(&device_tree.rwlock);
    336                         if (!list_empty(&dev->functions)) {
    337                                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    338                                 dev_del_ref(dev);
    339                                 return EIO;
    340                         }
    341                        
    342                         driver_t *driver = dev->drv;
    343                         fibril_rwlock_read_unlock(&device_tree.rwlock);
    344                        
    345                         if (driver)
    346                                 detach_driver(&device_tree, dev);
    347                        
    348                         fibril_rwlock_write_lock(&device_tree.rwlock);
    349                         remove_dev_node(&device_tree, dev);
    350                        
    351                         /* Delete ref created when node was inserted */
    352                         dev_del_ref(dev);
    353                         /* Delete ref created by dev_add_ref(dev) above */
    354                         dev_del_ref(dev);
    355                 }
    356         } else {
    357                 /* Unregister from location service */
    358                 rc = loc_service_unregister(fun->service_id);
    359                 if (rc != EOK) {
    360                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    361                         log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree service.");
    362                         return EIO;
    363                 }
    364                
    365                 fun->service_id = 0;
    366         }
    367        
    368         fun->state = FUN_OFF_LINE;
    369         fibril_rwlock_write_unlock(&device_tree.rwlock);
    370        
    371         return EOK;
    372 }
    373 
    374 /** Handle function registration.
    375  *
    376  * Child devices are registered by their parent's device driver.
    377  */
    378 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
    379 {
    380         fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
    381         devman_handle_t dev_handle = IPC_GET_ARG2(*call);
    382         sysarg_t match_count = IPC_GET_ARG3(*call);
    383         dev_tree_t *tree = &device_tree;
    384        
    385         dev_node_t *pdev = find_dev_node(&device_tree, dev_handle);
    386         if (pdev == NULL) {
    387                 async_answer_0(callid, ENOENT);
    388                 return;
    389         }
    390        
    391         if (ftype != fun_inner && ftype != fun_exposed) {
    392                 /* Unknown function type */
    393                 log_msg(LOG_DEFAULT, LVL_ERROR,
    394                     "Unknown function type %d provided by driver.",
    395                     (int) ftype);
    396 
    397                 dev_del_ref(pdev);
    398                 async_answer_0(callid, EINVAL);
    399                 return;
    400         }
    401        
    402         char *fun_name = NULL;
    403         int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
    404         if (rc != EOK) {
    405                 dev_del_ref(pdev);
    406                 async_answer_0(callid, rc);
    407                 return;
    408         }
    409        
    410         fibril_rwlock_write_lock(&tree->rwlock);
    411        
    412         /* Check device state */
    413         if (pdev->state == DEVICE_REMOVED) {
    414                 fibril_rwlock_write_unlock(&tree->rwlock);
    415                 dev_del_ref(pdev);
    416                 async_answer_0(callid, ENOENT);
    417                 return;
    418         }
    419        
    420         /* Check that function with same name is not there already. */
    421         fun_node_t *tfun = find_fun_node_in_device(tree, pdev, fun_name);
    422         if (tfun) {
    423                 fun_del_ref(tfun);      /* drop the new unwanted reference */
    424                 fibril_rwlock_write_unlock(&tree->rwlock);
    425                 dev_del_ref(pdev);
    426                 async_answer_0(callid, EEXISTS);
    427                 printf(NAME ": Warning, driver tried to register `%s' twice.\n",
    428                     fun_name);
    429                 free(fun_name);
    430                 return;
    431         }
    432        
    433         fun_node_t *fun = create_fun_node();
    434         /* One reference for creation, one for us */
    435         fun_add_ref(fun);
    436         fun_add_ref(fun);
    437         fun->ftype = ftype;
    438        
    439         /*
    440          * We can lock the function here even when holding the tree because
    441          * we know it cannot be held by anyone else yet.
    442          */
    443         fun_busy_lock(fun);
    444        
    445         if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
    446                 fibril_rwlock_write_unlock(&tree->rwlock);
    447                 dev_del_ref(pdev);
    448                 fun_busy_unlock(fun);
    449                 fun_del_ref(fun);
    450                 delete_fun_node(fun);
    451                 async_answer_0(callid, ENOMEM);
    452                 return;
    453         }
    454        
    455         fibril_rwlock_write_unlock(&tree->rwlock);
    456         dev_del_ref(pdev);
    457        
    458         devman_receive_match_ids(match_count, &fun->match_ids);
    459        
    460         rc = online_function(fun);
    461         if (rc != EOK) {
    462                 /* XXX Set some failed state? */
    463                 fun_busy_unlock(fun);
    464                 fun_del_ref(fun);
    465                 async_answer_0(callid, rc);
    466                 return;
    467         }
    468        
    469         fun_busy_unlock(fun);
    470         fun_del_ref(fun);
    471        
    472         /* Return device handle to parent's driver. */
    473         async_answer_1(callid, EOK, fun->handle);
    474 }
    475 
    476 static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)
    477 {
    478         devman_handle_t handle = IPC_GET_ARG1(*call);
    479         category_id_t cat_id;
    480         int rc;
    481        
    482         /* Get category name. */
    483         char *cat_name;
    484         rc = async_data_write_accept((void **) &cat_name, true,
    485             0, 0, 0, 0);
    486         if (rc != EOK) {
    487                 async_answer_0(callid, rc);
    488                 return;
    489         }
    490        
    491         fun_node_t *fun = find_fun_node(&device_tree, handle);
    492         if (fun == NULL) {
    493                 async_answer_0(callid, ENOENT);
    494                 return;
    495         }
    496        
    497         fibril_rwlock_read_lock(&device_tree.rwlock);
    498        
    499         /* Check function state */
    500         if (fun->state == FUN_REMOVED) {
    501                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    502                 async_answer_0(callid, ENOENT);
    503                 return;
    504         }
    505        
    506         rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
    507         if (rc == EOK) {
    508                 loc_service_add_to_cat(fun->service_id, cat_id);
    509                 log_msg(LOG_DEFAULT, LVL_NOTE, "Function `%s' added to category `%s'.",
    510                     fun->pathname, cat_name);
    511         } else {
    512                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding function `%s' to category "
    513                     "`%s'.", fun->pathname, cat_name);
    514         }
    515        
    516         fibril_rwlock_read_unlock(&device_tree.rwlock);
    517         fun_del_ref(fun);
    518        
    519         async_answer_0(callid, rc);
    520 }
    521 
    522 /** Online function by driver request.
    523  *
    524  */
    525 static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
    526     driver_t *drv)
    527 {
    528         fun_node_t *fun;
    529         int rc;
    530        
    531         log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_drv_fun_online()");
    532        
    533         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    534         if (fun == NULL) {
    535                 async_answer_0(iid, ENOENT);
    536                 return;
    537         }
    538        
    539         fun_busy_lock(fun);
    540        
    541         fibril_rwlock_read_lock(&device_tree.rwlock);
    542         if (fun->dev == NULL || fun->dev->drv != drv) {
    543                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    544                 fun_busy_unlock(fun);
    545                 fun_del_ref(fun);
    546                 async_answer_0(iid, ENOENT);
    547                 return;
    548         }
    549         fibril_rwlock_read_unlock(&device_tree.rwlock);
    550        
    551         rc = online_function(fun);
    552         if (rc != EOK) {
    553                 fun_busy_unlock(fun);
    554                 fun_del_ref(fun);
    555                 async_answer_0(iid, (sysarg_t) rc);
    556                 return;
    557         }
    558        
    559         fun_busy_unlock(fun);
    560         fun_del_ref(fun);
    561        
    562         async_answer_0(iid, (sysarg_t) EOK);
    563 }
    564 
    565 
    566 /** Offline function by driver request.
    567  *
    568  */
    569 static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
    570     driver_t *drv)
    571 {
    572         fun_node_t *fun;
    573         int rc;
    574 
    575         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    576         if (fun == NULL) {
    577                 async_answer_0(iid, ENOENT);
    578                 return;
    579         }
    580        
    581         fun_busy_lock(fun);
    582        
    583         fibril_rwlock_write_lock(&device_tree.rwlock);
    584         if (fun->dev == NULL || fun->dev->drv != drv) {
    585                 fun_busy_unlock(fun);
    586                 fun_del_ref(fun);
    587                 async_answer_0(iid, ENOENT);
    588                 return;
    589         }
    590         fibril_rwlock_write_unlock(&device_tree.rwlock);
    591        
    592         rc = offline_function(fun);
    593         if (rc != EOK) {
    594                 fun_busy_unlock(fun);
    595                 fun_del_ref(fun);
    596                 async_answer_0(iid, (sysarg_t) rc);
    597                 return;
    598         }
    599        
    600         fun_busy_unlock(fun);
    601         fun_del_ref(fun);
    602         async_answer_0(iid, (sysarg_t) EOK);
    603 }
    604 
    605 /** Remove function. */
    606 static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
    607 {
    608         devman_handle_t fun_handle = IPC_GET_ARG1(*call);
    609         dev_tree_t *tree = &device_tree;
    610         int rc;
    611        
    612         fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
    613         if (fun == NULL) {
    614                 async_answer_0(callid, ENOENT);
    615                 return;
    616         }
    617        
    618         fun_busy_lock(fun);
    619        
    620         fibril_rwlock_write_lock(&tree->rwlock);
    621        
    622         log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
    623        
    624         /* Check function state */
    625         if (fun->state == FUN_REMOVED) {
    626                 fibril_rwlock_write_unlock(&tree->rwlock);
    627                 fun_busy_unlock(fun);
    628                 fun_del_ref(fun);
    629                 async_answer_0(callid, ENOENT);
    630                 return;
    631         }
    632        
    633         if (fun->ftype == fun_inner) {
    634                 /* This is a surprise removal. Handle possible descendants */
    635                 if (fun->child != NULL) {
    636                         dev_node_t *dev = fun->child;
    637                         device_state_t dev_state;
    638                         int gone_rc;
    639                        
    640                         dev_add_ref(dev);
    641                         dev_state = dev->state;
    642                        
    643                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    644                        
    645                         /* If device is owned by driver, inform driver it is gone. */
    646                         if (dev_state == DEVICE_USABLE)
    647                                 gone_rc = driver_dev_gone(&device_tree, dev);
    648                         else
    649                                 gone_rc = EOK;
    650                        
    651                         fibril_rwlock_read_lock(&device_tree.rwlock);
    652                        
    653                         /* Verify that driver succeeded and removed all functions */
    654                         if (gone_rc != EOK || !list_empty(&dev->functions)) {
    655                                 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver did not remove "
    656                                     "functions for device that is gone. "
    657                                     "Device node is now defunct.");
    658                                
    659                                 /*
    660                                  * Not much we can do but mark the device
    661                                  * node as having invalid state. This
    662                                  * is a driver bug.
    663                                  */
    664                                 dev->state = DEVICE_INVALID;
    665                                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    666                                 dev_del_ref(dev);
    667                                 if (gone_rc == EOK)
    668                                         gone_rc = ENOTSUP;
    669                                 fun_busy_unlock(fun);
    670                                 fun_del_ref(fun);
    671                                 async_answer_0(callid, gone_rc);
    672                                 return;
    673                         }
    674                        
    675                         driver_t *driver = dev->drv;
    676                         fibril_rwlock_read_unlock(&device_tree.rwlock);
    677                        
    678                         if (driver)
    679                                 detach_driver(&device_tree, dev);
    680                        
    681                         fibril_rwlock_write_lock(&device_tree.rwlock);
    682                         remove_dev_node(&device_tree, dev);
    683                        
    684                         /* Delete ref created when node was inserted */
    685                         dev_del_ref(dev);
    686                         /* Delete ref created by dev_add_ref(dev) above */
    687                         dev_del_ref(dev);
    688                 }
    689         } else {
    690                 if (fun->service_id != 0) {
    691                         /* Unregister from location service */
    692                         rc = loc_service_unregister(fun->service_id);
    693                         if (rc != EOK) {
    694                                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree "
    695                                     "service.");
    696                                 fibril_rwlock_write_unlock(&tree->rwlock);
    697                                 fun_busy_unlock(fun);
    698                                 fun_del_ref(fun);
    699                                 async_answer_0(callid, EIO);
    700                                 return;
    701                         }
    702                 }
    703         }
    704        
    705         remove_fun_node(&device_tree, fun);
    706         fibril_rwlock_write_unlock(&tree->rwlock);
    707         fun_busy_unlock(fun);
    708        
    709         /* Delete ref added when inserting function into tree */
    710         fun_del_ref(fun);
    711         /* Delete ref added above when looking up function */
    712         fun_del_ref(fun);
    713        
    714         log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function() succeeded.");
    715         async_answer_0(callid, EOK);
    716 }
    717 
    718 /** Initialize driver which has registered itself as running and ready.
    719  *
    720  * The initialization is done in a separate fibril to avoid deadlocks (if the
    721  * driver needed to be served by devman during the driver's initialization).
    722  */
    723 static int init_running_drv(void *drv)
    724 {
    725         driver_t *driver = (driver_t *) drv;
    726        
    727         initialize_running_driver(driver, &device_tree);
    728         log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s` driver was successfully initialized.",
    729             driver->name);
    730         return 0;
    731 }
    732 
    733 /** Function for handling connections from a driver to the device manager. */
    734 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
    735 {
    736         client_t *client;
    737         driver_t *driver = NULL;
    738        
    739         /* Accept the connection. */
    740         async_answer_0(iid, EOK);
    741        
    742         client = async_get_client_data();
    743         if (client == NULL) {
    744                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate client data.");
    745                 return;
    746         }
    747        
    748         while (true) {
    749                 ipc_call_t call;
    750                 ipc_callid_t callid = async_get_call(&call);
    751                
    752                 if (!IPC_GET_IMETHOD(call))
    753                         break;
    754                
    755                 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {
    756                         fibril_mutex_lock(&client->mutex);
    757                         driver = client->driver;
    758                         fibril_mutex_unlock(&client->mutex);
    759                         if (driver == NULL) {
    760                                 /* First call must be to DEVMAN_DRIVER_REGISTER */
    761                                 async_answer_0(callid, ENOTSUP);
    762                                 continue;
    763                         }
    764                 }
    765                
    766                 switch (IPC_GET_IMETHOD(call)) {
    767                 case DEVMAN_DRIVER_REGISTER:
    768                         fibril_mutex_lock(&client->mutex);
    769                         if (client->driver != NULL) {
    770                                 fibril_mutex_unlock(&client->mutex);
    771                                 async_answer_0(callid, EINVAL);
    772                                 continue;
    773                         }
    774                         client->driver = devman_driver_register(callid, &call);
    775                         fibril_mutex_unlock(&client->mutex);
    776                         break;
    777                 case DEVMAN_ADD_FUNCTION:
    778                         devman_add_function(callid, &call);
    779                         break;
    780                 case DEVMAN_ADD_DEVICE_TO_CATEGORY:
    781                         devman_add_function_to_cat(callid, &call);
    782                         break;
    783                 case DEVMAN_DRV_FUN_ONLINE:
    784                         devman_drv_fun_online(callid, &call, driver);
    785                         break;
    786                 case DEVMAN_DRV_FUN_OFFLINE:
    787                         devman_drv_fun_offline(callid, &call, driver);
    788                         break;
    789                 case DEVMAN_REMOVE_FUNCTION:
    790                         devman_remove_function(callid, &call);
    791                         break;
    792                 default:
    793                         async_answer_0(callid, EINVAL);
    794                         break;
    795                 }
    796         }
    797 }
    798 
    799 /** Find handle for the device instance identified by the device's path in the
    800  * device tree. */
    801 static void devman_function_get_handle(ipc_callid_t iid, ipc_call_t *icall)
    802 {
    803         char *pathname;
    804         devman_handle_t handle;
    805        
    806         int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
    807         if (rc != EOK) {
    808                 async_answer_0(iid, rc);
    809                 return;
    810         }
    811        
    812         fun_node_t *fun = find_fun_node_by_path(&device_tree, pathname);
    813        
    814         free(pathname);
    815 
    816         if (fun == NULL) {
    817                 async_answer_0(iid, ENOENT);
    818                 return;
    819         }
    820 
    821         fibril_rwlock_read_lock(&device_tree.rwlock);
    822 
    823         /* Check function state */
    824         if (fun->state == FUN_REMOVED) {
    825                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    826                 async_answer_0(iid, ENOENT);
    827                 return;
    828         }
    829         handle = fun->handle;
    830 
    831         fibril_rwlock_read_unlock(&device_tree.rwlock);
    832 
    833         /* Delete reference created above by find_fun_node_by_path() */
    834         fun_del_ref(fun);
    835 
    836         async_answer_1(iid, EOK, handle);
    837 }
    838 
    839 /** Get device name. */
    840 static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall)
    841 {
    842         devman_handle_t handle = IPC_GET_ARG1(*icall);
    843 
    844         fun_node_t *fun = find_fun_node(&device_tree, handle);
    845         if (fun == NULL) {
    846                 async_answer_0(iid, ENOMEM);
    847                 return;
    848         }
    849 
    850         ipc_callid_t data_callid;
    851         size_t data_len;
    852         if (!async_data_read_receive(&data_callid, &data_len)) {
    853                 async_answer_0(iid, EINVAL);
    854                 fun_del_ref(fun);
    855                 return;
    856         }
    857 
    858         void *buffer = malloc(data_len);
    859         if (buffer == NULL) {
    860                 async_answer_0(data_callid, ENOMEM);
    861                 async_answer_0(iid, ENOMEM);
    862                 fun_del_ref(fun);
    863                 return;
    864         }
    865 
    866         fibril_rwlock_read_lock(&device_tree.rwlock);
    867 
    868         /* Check function state */
    869         if (fun->state == FUN_REMOVED) {
    870                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    871                 free(buffer);
    872 
    873                 async_answer_0(data_callid, ENOENT);
    874                 async_answer_0(iid, ENOENT);
    875                 fun_del_ref(fun);
    876                 return;
    877         }
    878 
    879         size_t sent_length = str_size(fun->name);
    880         if (sent_length > data_len) {
    881                 sent_length = data_len;
    882         }
    883 
    884         async_data_read_finalize(data_callid, fun->name, sent_length);
    885         async_answer_0(iid, EOK);
    886 
    887         fibril_rwlock_read_unlock(&device_tree.rwlock);
    888         fun_del_ref(fun);
    889         free(buffer);
    890 }
    891 
    892 /** Get function driver name. */
    893 static void devman_fun_get_driver_name(ipc_callid_t iid, ipc_call_t *icall)
    894 {
    895         devman_handle_t handle = IPC_GET_ARG1(*icall);
    896 
    897         fun_node_t *fun = find_fun_node(&device_tree, handle);
    898         if (fun == NULL) {
    899                 async_answer_0(iid, ENOMEM);
    900                 return;
    901         }
    902 
    903         ipc_callid_t data_callid;
    904         size_t data_len;
    905         if (!async_data_read_receive(&data_callid, &data_len)) {
    906                 async_answer_0(iid, EINVAL);
    907                 fun_del_ref(fun);
    908                 return;
    909         }
    910 
    911         void *buffer = malloc(data_len);
    912         if (buffer == NULL) {
    913                 async_answer_0(data_callid, ENOMEM);
    914                 async_answer_0(iid, ENOMEM);
    915                 fun_del_ref(fun);
    916                 return;
    917         }
    918 
    919         fibril_rwlock_read_lock(&device_tree.rwlock);
    920 
    921         /* Check function state */
    922         if (fun->state == FUN_REMOVED) {
    923                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    924                 free(buffer);
    925 
    926                 async_answer_0(data_callid, ENOENT);
    927                 async_answer_0(iid, ENOENT);
    928                 fun_del_ref(fun);
    929                 return;
    930         }
    931 
    932         /* Check whether function has a driver */
    933         if (fun->child == NULL || fun->child->drv == NULL) {
    934                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    935                 free(buffer);
    936 
    937                 async_answer_0(data_callid, EINVAL);
    938                 async_answer_0(iid, EINVAL);
    939                 fun_del_ref(fun);
    940                 return;
    941         }
    942 
    943         size_t sent_length = str_size(fun->child->drv->name);
    944         if (sent_length > data_len) {
    945                 sent_length = data_len;
    946         }
    947 
    948         async_data_read_finalize(data_callid, fun->child->drv->name,
    949             sent_length);
    950         async_answer_0(iid, EOK);
    951 
    952         fibril_rwlock_read_unlock(&device_tree.rwlock);
    953         fun_del_ref(fun);
    954         free(buffer);
    955 }
    956 
    957 /** Get device path. */
    958 static void devman_fun_get_path(ipc_callid_t iid, ipc_call_t *icall)
    959 {
    960         devman_handle_t handle = IPC_GET_ARG1(*icall);
    961 
    962         fun_node_t *fun = find_fun_node(&device_tree, handle);
    963         if (fun == NULL) {
    964                 async_answer_0(iid, ENOMEM);
    965                 return;
    966         }
    967 
    968         ipc_callid_t data_callid;
    969         size_t data_len;
    970         if (!async_data_read_receive(&data_callid, &data_len)) {
    971                 async_answer_0(iid, EINVAL);
    972                 fun_del_ref(fun);
    973                 return;
    974         }
    975 
    976         void *buffer = malloc(data_len);
    977         if (buffer == NULL) {
    978                 async_answer_0(data_callid, ENOMEM);
    979                 async_answer_0(iid, ENOMEM);
    980                 fun_del_ref(fun);
    981                 return;
    982         }
    983        
    984         fibril_rwlock_read_lock(&device_tree.rwlock);
    985        
    986         /* Check function state */
    987         if (fun->state == FUN_REMOVED) {
    988                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    989                 free(buffer);
    990 
    991                 async_answer_0(data_callid, ENOENT);
    992                 async_answer_0(iid, ENOENT);
    993                 fun_del_ref(fun);
    994                 return;
    995         }
    996        
    997         size_t sent_length = str_size(fun->pathname);
    998         if (sent_length > data_len) {
    999                 sent_length = data_len;
    1000         }
    1001 
    1002         async_data_read_finalize(data_callid, fun->pathname, sent_length);
    1003         async_answer_0(iid, EOK);
    1004 
    1005         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1006         fun_del_ref(fun);
    1007         free(buffer);
    1008 }
    1009 
    1010 static void devman_dev_get_functions(ipc_callid_t iid, ipc_call_t *icall)
    1011 {
    1012         ipc_callid_t callid;
    1013         size_t size;
    1014         size_t act_size;
    1015         int rc;
    1016        
    1017         if (!async_data_read_receive(&callid, &size)) {
    1018                 async_answer_0(callid, EREFUSED);
    1019                 async_answer_0(iid, EREFUSED);
    1020                 return;
    1021         }
    1022        
    1023         fibril_rwlock_read_lock(&device_tree.rwlock);
    1024        
    1025         dev_node_t *dev = find_dev_node_no_lock(&device_tree,
    1026             IPC_GET_ARG1(*icall));
    1027         if (dev == NULL || dev->state == DEVICE_REMOVED) {
    1028                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1029                 async_answer_0(callid, ENOENT);
    1030                 async_answer_0(iid, ENOENT);
    1031                 return;
    1032         }
    1033        
    1034         devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
    1035         if (hdl_buf == NULL) {
    1036                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1037                 async_answer_0(callid, ENOMEM);
    1038                 async_answer_0(iid, ENOMEM);
    1039                 return;
    1040         }
    1041        
    1042         rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size);
    1043         if (rc != EOK) {
    1044                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1045                 async_answer_0(callid, rc);
    1046                 async_answer_0(iid, rc);
    1047                 return;
    1048         }
    1049        
    1050         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1051        
    1052         sysarg_t retval = async_data_read_finalize(callid, hdl_buf, size);
    1053         free(hdl_buf);
    1054        
    1055         async_answer_1(iid, retval, act_size);
    1056 }
    1057 
    1058 
    1059 /** Get handle for child device of a function. */
    1060 static void devman_fun_get_child(ipc_callid_t iid, ipc_call_t *icall)
    1061 {
    1062         fun_node_t *fun;
    1063        
    1064         fibril_rwlock_read_lock(&device_tree.rwlock);
    1065        
    1066         fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
    1067         if (fun == NULL || fun->state == FUN_REMOVED) {
    1068                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1069                 async_answer_0(iid, ENOENT);
    1070                 return;
    1071         }
    1072        
    1073         if (fun->child == NULL) {
    1074                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1075                 async_answer_0(iid, ENOENT);
    1076                 return;
    1077         }
    1078        
    1079         async_answer_1(iid, EOK, fun->child->handle);
    1080        
    1081         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1082 }
    1083 
    1084 /** Online function.
    1085  *
    1086  * Send a request to online a function to the responsible driver.
    1087  * The driver may offline other functions if necessary (i.e. if the state
    1088  * of this function is linked to state of another function somehow).
    1089  */
    1090 static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)
    1091 {
    1092         fun_node_t *fun;
    1093         int rc;
    1094 
    1095         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    1096         if (fun == NULL) {
    1097                 async_answer_0(iid, ENOENT);
    1098                 return;
    1099         }
    1100        
    1101         rc = driver_fun_online(&device_tree, fun);
    1102         fun_del_ref(fun);
    1103        
    1104         async_answer_0(iid, (sysarg_t) rc);
    1105 }
    1106 
    1107 /** Offline function.
    1108  *
    1109  * Send a request to offline a function to the responsible driver. As
    1110  * a result the subtree rooted at that function should be cleanly
    1111  * detatched. The driver may offline other functions if necessary
    1112  * (i.e. if the state of this function is linked to state of another
    1113  * function somehow).
    1114  */
    1115 static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
    1116 {
    1117         fun_node_t *fun;
    1118         int rc;
    1119 
    1120         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    1121         if (fun == NULL) {
    1122                 async_answer_0(iid, ENOENT);
    1123                 return;
    1124         }
    1125        
    1126         rc = driver_fun_offline(&device_tree, fun);
    1127         fun_del_ref(fun);
    1128        
    1129         async_answer_0(iid, (sysarg_t) rc);
    1130 }
    1131 
    1132 /** Find handle for the function instance identified by its service ID. */
    1133 static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall)
    1134 {
    1135         fun_node_t *fun;
    1136 
    1137         fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall));
    1138        
    1139         if (fun == NULL) {
    1140                 async_answer_0(iid, ENOENT);
    1141                 return;
    1142         }
    1143 
    1144         fibril_rwlock_read_lock(&device_tree.rwlock);
    1145 
    1146         /* Check function state */
    1147         if (fun->state == FUN_REMOVED) {
    1148                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    1149                 async_answer_0(iid, ENOENT);
    1150                 return;
    1151         }
    1152 
    1153         async_answer_1(iid, EOK, fun->handle);
    1154         fibril_rwlock_read_unlock(&device_tree.rwlock);
    1155         fun_del_ref(fun);
    1156 }
    1157 
    1158 /** Function for handling connections from a client to the device manager. */
    1159 static void devman_connection_client(ipc_callid_t iid, ipc_call_t *icall)
    1160 {
    1161         /* Accept connection. */
    1162         async_answer_0(iid, EOK);
    1163        
    1164         while (true) {
    1165                 ipc_call_t call;
    1166                 ipc_callid_t callid = async_get_call(&call);
    1167                
    1168                 if (!IPC_GET_IMETHOD(call))
    1169                         break;
    1170                
    1171                 switch (IPC_GET_IMETHOD(call)) {
    1172                 case DEVMAN_DEVICE_GET_HANDLE:
    1173                         devman_function_get_handle(callid, &call);
    1174                         break;
    1175                 case DEVMAN_DEV_GET_FUNCTIONS:
    1176                         devman_dev_get_functions(callid, &call);
    1177                         break;
    1178                 case DEVMAN_FUN_GET_CHILD:
    1179                         devman_fun_get_child(callid, &call);
    1180                         break;
    1181                 case DEVMAN_FUN_GET_NAME:
    1182                         devman_fun_get_name(callid, &call);
    1183                         break;
    1184                 case DEVMAN_FUN_GET_DRIVER_NAME:
    1185                         devman_fun_get_driver_name(callid, &call);
    1186                         break;
    1187                 case DEVMAN_FUN_GET_PATH:
    1188                         devman_fun_get_path(callid, &call);
    1189                         break;
    1190                 case DEVMAN_FUN_ONLINE:
    1191                         devman_fun_online(callid, &call);
    1192                         break;
    1193                 case DEVMAN_FUN_OFFLINE:
    1194                         devman_fun_offline(callid, &call);
    1195                         break;
    1196                 case DEVMAN_FUN_SID_TO_HANDLE:
    1197                         devman_fun_sid_to_handle(callid, &call);
    1198                         break;
    1199                 default:
    1200                         async_answer_0(callid, ENOENT);
    1201                 }
    1202         }
    1203 }
     65driver_list_t drivers_list;
     66dev_tree_t device_tree;
    120467
    120568static void devman_forward(ipc_callid_t iid, ipc_call_t *icall,
Note: See TracChangeset for help on using the changeset viewer.