Changeset 181c32f in mainline


Ignore:
Timestamp:
2013-09-10T21:12:23Z (11 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
02e5e34
Parents:
d80d7a8
Message:

Separate module for devman-driver communication.

Location:
uspace/srv/devman
Files:
2 added
3 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/devman/Makefile

    rd80d7a8 r181c32f  
    3636        dev.c \
    3737        devtree.c \
     38        drv_conn.c \
    3839        driver.c \
    3940        loc.c \
  • uspace/srv/devman/main.c

    rd80d7a8 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
     
    6256#include "devman.h"
    6357#include "devtree.h"
     58#include "drv_conn.h"
    6459#include "driver.h"
    6560#include "fun.h"
     
    6863#define DRIVER_DEFAULT_STORE  "/drv"
    6964
    70 static driver_list_t drivers_list;
     65driver_list_t drivers_list;
    7166dev_tree_t device_tree;
    72 
    73 static int init_running_drv(void *drv);
    74 
    75 /** Register running driver. */
    76 static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call)
    77 {
    78         driver_t *driver = NULL;
    79         char *drv_name = NULL;
    80 
    81         log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_driver_register");
    82        
    83         /* Get driver name. */
    84         int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
    85         if (rc != EOK) {
    86                 async_answer_0(callid, rc);
    87                 return NULL;
    88         }
    89 
    90         log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s' driver is trying to register.",
    91             drv_name);
    92        
    93         /* Find driver structure. */
    94         driver = find_driver(&drivers_list, drv_name);
    95         if (driver == NULL) {
    96                 log_msg(LOG_DEFAULT, LVL_ERROR, "No driver named `%s' was found.", drv_name);
    97                 free(drv_name);
    98                 drv_name = NULL;
    99                 async_answer_0(callid, ENOENT);
    100                 return NULL;
    101         }
    102        
    103         free(drv_name);
    104         drv_name = NULL;
    105        
    106         fibril_mutex_lock(&driver->driver_mutex);
    107        
    108         if (driver->sess) {
    109                 /* We already have a connection to the driver. */
    110                 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver '%s' already started.\n",
    111                     driver->name);
    112                 fibril_mutex_unlock(&driver->driver_mutex);
    113                 async_answer_0(callid, EEXISTS);
    114                 return NULL;
    115         }
    116        
    117         switch (driver->state) {
    118         case DRIVER_NOT_STARTED:
    119                 /* Somebody started the driver manually. */
    120                 log_msg(LOG_DEFAULT, LVL_NOTE, "Driver '%s' started manually.\n",
    121                     driver->name);
    122                 driver->state = DRIVER_STARTING;
    123                 break;
    124         case DRIVER_STARTING:
    125                 /* The expected case */
    126                 break;
    127         case DRIVER_RUNNING:
    128                 /* Should not happen since we do not have a connected session */
    129                 assert(false);
    130         }
    131        
    132         /* Create connection to the driver. */
    133         log_msg(LOG_DEFAULT, LVL_DEBUG, "Creating connection to the `%s' driver.",
    134             driver->name);
    135         driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
    136         if (!driver->sess) {
    137                 fibril_mutex_unlock(&driver->driver_mutex);
    138                 async_answer_0(callid, ENOTSUP);
    139                 return NULL;
    140         }
    141         /* FIXME: Work around problem with callback sessions */
    142         async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);
    143        
    144         log_msg(LOG_DEFAULT, LVL_NOTE,
    145             "The `%s' driver was successfully registered as running.",
    146             driver->name);
    147        
    148         /*
    149          * Initialize the driver as running (e.g. pass assigned devices to it)
    150          * in a separate fibril; the separate fibril is used to enable the
    151          * driver to use devman service during the driver's initialization.
    152          */
    153         fid_t fid = fibril_create(init_running_drv, driver);
    154         if (fid == 0) {
    155                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create initialization fibril " \
    156                     "for driver `%s'.", driver->name);
    157                 fibril_mutex_unlock(&driver->driver_mutex);
    158                 async_answer_0(callid, ENOMEM);
    159                 return NULL;
    160         }
    161        
    162         fibril_add_ready(fid);
    163         fibril_mutex_unlock(&driver->driver_mutex);
    164        
    165         async_answer_0(callid, EOK);
    166         return driver;
    167 }
    168 
    169 /** Receive device match ID from the device's parent driver and add it to the
    170  * list of devices match ids.
    171  *
    172  * @param match_ids     The list of the device's match ids.
    173  * @return              Zero on success, negative error code otherwise.
    174  */
    175 static int devman_receive_match_id(match_id_list_t *match_ids)
    176 {
    177         match_id_t *match_id = create_match_id();
    178         ipc_callid_t callid;
    179         ipc_call_t call;
    180         int rc = 0;
    181        
    182         callid = async_get_call(&call);
    183         if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
    184                 log_msg(LOG_DEFAULT, LVL_ERROR,
    185                     "Invalid protocol when trying to receive match id.");
    186                 async_answer_0(callid, EINVAL);
    187                 delete_match_id(match_id);
    188                 return EINVAL;
    189         }
    190        
    191         if (match_id == NULL) {
    192                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate match id.");
    193                 async_answer_0(callid, ENOMEM);
    194                 return ENOMEM;
    195         }
    196        
    197         async_answer_0(callid, EOK);
    198        
    199         match_id->score = IPC_GET_ARG1(call);
    200        
    201         char *match_id_str;
    202         rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0);
    203         match_id->id = match_id_str;
    204         if (rc != EOK) {
    205                 delete_match_id(match_id);
    206                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to receive match id string: %s.",
    207                     str_error(rc));
    208                 return rc;
    209         }
    210        
    211         list_append(&match_id->link, &match_ids->ids);
    212        
    213         log_msg(LOG_DEFAULT, LVL_DEBUG, "Received match id `%s', score %d.",
    214             match_id->id, match_id->score);
    215         return rc;
    216 }
    217 
    218 /** Receive device match IDs from the device's parent driver and add them to the
    219  * list of devices match ids.
    220  *
    221  * @param match_count   The number of device's match ids to be received.
    222  * @param match_ids     The list of the device's match ids.
    223  * @return              Zero on success, negative error code otherwise.
    224  */
    225 static int devman_receive_match_ids(sysarg_t match_count,
    226     match_id_list_t *match_ids)
    227 {
    228         int ret = EOK;
    229         size_t i;
    230        
    231         for (i = 0; i < match_count; i++) {
    232                 if (EOK != (ret = devman_receive_match_id(match_ids)))
    233                         return ret;
    234         }
    235         return ret;
    236 }
    237 
    238 static int assign_driver_fibril(void *arg)
    239 {
    240         dev_node_t *dev_node = (dev_node_t *) arg;
    241         assign_driver(dev_node, &drivers_list, &device_tree);
    242 
    243         /* Delete one reference we got from the caller. */
    244         dev_del_ref(dev_node);
    245         return EOK;
    246 }
    247 
    248 static int online_function(fun_node_t *fun)
    249 {
    250         dev_node_t *dev;
    251        
    252         fibril_rwlock_write_lock(&device_tree.rwlock);
    253        
    254         if (fun->state == FUN_ON_LINE) {
    255                 fibril_rwlock_write_unlock(&device_tree.rwlock);
    256                 log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already on line.",
    257                     fun->pathname);
    258                 return EOK;
    259         }
    260        
    261         if (fun->ftype == fun_inner) {
    262                 dev = create_dev_node();
    263                 if (dev == NULL) {
    264                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    265                         return ENOMEM;
    266                 }
    267                
    268                 insert_dev_node(&device_tree, dev, fun);
    269                 dev_add_ref(dev);
    270         }
    271        
    272         log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
    273        
    274         if (fun->ftype == fun_inner) {
    275                 dev = fun->child;
    276                 assert(dev != NULL);
    277                
    278                 /* Give one reference over to assign_driver_fibril(). */
    279                 dev_add_ref(dev);
    280                
    281                 /*
    282                  * Try to find a suitable driver and assign it to the device.  We do
    283                  * not want to block the current fibril that is used for processing
    284                  * incoming calls: we will launch a separate fibril to handle the
    285                  * driver assigning. That is because assign_driver can actually include
    286                  * task spawning which could take some time.
    287                  */
    288                 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
    289                 if (assign_fibril == 0) {
    290                         log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create fibril for "
    291                             "assigning driver.");
    292                         /* XXX Cleanup */
    293                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    294                         return ENOMEM;
    295                 }
    296                 fibril_add_ready(assign_fibril);
    297         } else
    298                 loc_register_tree_function(fun, &device_tree);
    299        
    300         fibril_rwlock_write_unlock(&device_tree.rwlock);
    301        
    302         return EOK;
    303 }
    304 
    305 static int offline_function(fun_node_t *fun)
    306 {
    307         int rc;
    308        
    309         fibril_rwlock_write_lock(&device_tree.rwlock);
    310        
    311         if (fun->state == FUN_OFF_LINE) {
    312                 fibril_rwlock_write_unlock(&device_tree.rwlock);
    313                 log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already off line.",
    314                     fun->pathname);
    315                 return EOK;
    316         }
    317        
    318         if (fun->ftype == fun_inner) {
    319                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Offlining inner function %s.",
    320                     fun->pathname);
    321                
    322                 if (fun->child != NULL) {
    323                         dev_node_t *dev = fun->child;
    324                         device_state_t dev_state;
    325                        
    326                         dev_add_ref(dev);
    327                         dev_state = dev->state;
    328                        
    329                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    330 
    331                         /* If device is owned by driver, ask driver to give it up. */
    332                         if (dev_state == DEVICE_USABLE) {
    333                                 rc = driver_dev_remove(&device_tree, dev);
    334                                 if (rc != EOK) {
    335                                         dev_del_ref(dev);
    336                                         return ENOTSUP;
    337                                 }
    338                         }
    339                        
    340                         /* Verify that driver removed all functions */
    341                         fibril_rwlock_read_lock(&device_tree.rwlock);
    342                         if (!list_empty(&dev->functions)) {
    343                                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    344                                 dev_del_ref(dev);
    345                                 return EIO;
    346                         }
    347                        
    348                         driver_t *driver = dev->drv;
    349                         fibril_rwlock_read_unlock(&device_tree.rwlock);
    350                        
    351                         if (driver)
    352                                 detach_driver(&device_tree, dev);
    353                        
    354                         fibril_rwlock_write_lock(&device_tree.rwlock);
    355                         remove_dev_node(&device_tree, dev);
    356                        
    357                         /* Delete ref created when node was inserted */
    358                         dev_del_ref(dev);
    359                         /* Delete ref created by dev_add_ref(dev) above */
    360                         dev_del_ref(dev);
    361                 }
    362         } else {
    363                 /* Unregister from location service */
    364                 rc = loc_service_unregister(fun->service_id);
    365                 if (rc != EOK) {
    366                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    367                         log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree service.");
    368                         return EIO;
    369                 }
    370                
    371                 fun->service_id = 0;
    372         }
    373        
    374         fun->state = FUN_OFF_LINE;
    375         fibril_rwlock_write_unlock(&device_tree.rwlock);
    376        
    377         return EOK;
    378 }
    379 
    380 /** Handle function registration.
    381  *
    382  * Child devices are registered by their parent's device driver.
    383  */
    384 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
    385 {
    386         fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
    387         devman_handle_t dev_handle = IPC_GET_ARG2(*call);
    388         sysarg_t match_count = IPC_GET_ARG3(*call);
    389         dev_tree_t *tree = &device_tree;
    390        
    391         dev_node_t *pdev = find_dev_node(&device_tree, dev_handle);
    392         if (pdev == NULL) {
    393                 async_answer_0(callid, ENOENT);
    394                 return;
    395         }
    396        
    397         if (ftype != fun_inner && ftype != fun_exposed) {
    398                 /* Unknown function type */
    399                 log_msg(LOG_DEFAULT, LVL_ERROR,
    400                     "Unknown function type %d provided by driver.",
    401                     (int) ftype);
    402 
    403                 dev_del_ref(pdev);
    404                 async_answer_0(callid, EINVAL);
    405                 return;
    406         }
    407        
    408         char *fun_name = NULL;
    409         int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
    410         if (rc != EOK) {
    411                 dev_del_ref(pdev);
    412                 async_answer_0(callid, rc);
    413                 return;
    414         }
    415        
    416         fibril_rwlock_write_lock(&tree->rwlock);
    417        
    418         /* Check device state */
    419         if (pdev->state == DEVICE_REMOVED) {
    420                 fibril_rwlock_write_unlock(&tree->rwlock);
    421                 dev_del_ref(pdev);
    422                 async_answer_0(callid, ENOENT);
    423                 return;
    424         }
    425        
    426         /* Check that function with same name is not there already. */
    427         fun_node_t *tfun = find_fun_node_in_device(tree, pdev, fun_name);
    428         if (tfun) {
    429                 fun_del_ref(tfun);      /* drop the new unwanted reference */
    430                 fibril_rwlock_write_unlock(&tree->rwlock);
    431                 dev_del_ref(pdev);
    432                 async_answer_0(callid, EEXISTS);
    433                 printf(NAME ": Warning, driver tried to register `%s' twice.\n",
    434                     fun_name);
    435                 free(fun_name);
    436                 return;
    437         }
    438        
    439         fun_node_t *fun = create_fun_node();
    440         /* One reference for creation, one for us */
    441         fun_add_ref(fun);
    442         fun_add_ref(fun);
    443         fun->ftype = ftype;
    444        
    445         /*
    446          * We can lock the function here even when holding the tree because
    447          * we know it cannot be held by anyone else yet.
    448          */
    449         fun_busy_lock(fun);
    450        
    451         if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
    452                 fibril_rwlock_write_unlock(&tree->rwlock);
    453                 dev_del_ref(pdev);
    454                 fun_busy_unlock(fun);
    455                 fun_del_ref(fun);
    456                 delete_fun_node(fun);
    457                 async_answer_0(callid, ENOMEM);
    458                 return;
    459         }
    460        
    461         fibril_rwlock_write_unlock(&tree->rwlock);
    462         dev_del_ref(pdev);
    463        
    464         devman_receive_match_ids(match_count, &fun->match_ids);
    465        
    466         rc = online_function(fun);
    467         if (rc != EOK) {
    468                 /* XXX Set some failed state? */
    469                 fun_busy_unlock(fun);
    470                 fun_del_ref(fun);
    471                 async_answer_0(callid, rc);
    472                 return;
    473         }
    474        
    475         fun_busy_unlock(fun);
    476         fun_del_ref(fun);
    477        
    478         /* Return device handle to parent's driver. */
    479         async_answer_1(callid, EOK, fun->handle);
    480 }
    481 
    482 static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)
    483 {
    484         devman_handle_t handle = IPC_GET_ARG1(*call);
    485         category_id_t cat_id;
    486         int rc;
    487        
    488         /* Get category name. */
    489         char *cat_name;
    490         rc = async_data_write_accept((void **) &cat_name, true,
    491             0, 0, 0, 0);
    492         if (rc != EOK) {
    493                 async_answer_0(callid, rc);
    494                 return;
    495         }
    496        
    497         fun_node_t *fun = find_fun_node(&device_tree, handle);
    498         if (fun == NULL) {
    499                 async_answer_0(callid, ENOENT);
    500                 return;
    501         }
    502        
    503         fibril_rwlock_read_lock(&device_tree.rwlock);
    504        
    505         /* Check function state */
    506         if (fun->state == FUN_REMOVED) {
    507                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    508                 async_answer_0(callid, ENOENT);
    509                 return;
    510         }
    511        
    512         rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
    513         if (rc == EOK) {
    514                 loc_service_add_to_cat(fun->service_id, cat_id);
    515                 log_msg(LOG_DEFAULT, LVL_NOTE, "Function `%s' added to category `%s'.",
    516                     fun->pathname, cat_name);
    517         } else {
    518                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding function `%s' to category "
    519                     "`%s'.", fun->pathname, cat_name);
    520         }
    521        
    522         fibril_rwlock_read_unlock(&device_tree.rwlock);
    523         fun_del_ref(fun);
    524        
    525         async_answer_0(callid, rc);
    526 }
    527 
    528 /** Online function by driver request.
    529  *
    530  */
    531 static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
    532     driver_t *drv)
    533 {
    534         fun_node_t *fun;
    535         int rc;
    536        
    537         log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_drv_fun_online()");
    538        
    539         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    540         if (fun == NULL) {
    541                 async_answer_0(iid, ENOENT);
    542                 return;
    543         }
    544        
    545         fun_busy_lock(fun);
    546        
    547         fibril_rwlock_read_lock(&device_tree.rwlock);
    548         if (fun->dev == NULL || fun->dev->drv != drv) {
    549                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    550                 fun_busy_unlock(fun);
    551                 fun_del_ref(fun);
    552                 async_answer_0(iid, ENOENT);
    553                 return;
    554         }
    555         fibril_rwlock_read_unlock(&device_tree.rwlock);
    556        
    557         rc = online_function(fun);
    558         if (rc != EOK) {
    559                 fun_busy_unlock(fun);
    560                 fun_del_ref(fun);
    561                 async_answer_0(iid, (sysarg_t) rc);
    562                 return;
    563         }
    564        
    565         fun_busy_unlock(fun);
    566         fun_del_ref(fun);
    567        
    568         async_answer_0(iid, (sysarg_t) EOK);
    569 }
    570 
    571 
    572 /** Offline function by driver request.
    573  *
    574  */
    575 static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
    576     driver_t *drv)
    577 {
    578         fun_node_t *fun;
    579         int rc;
    580 
    581         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    582         if (fun == NULL) {
    583                 async_answer_0(iid, ENOENT);
    584                 return;
    585         }
    586        
    587         fun_busy_lock(fun);
    588        
    589         fibril_rwlock_write_lock(&device_tree.rwlock);
    590         if (fun->dev == NULL || fun->dev->drv != drv) {
    591                 fun_busy_unlock(fun);
    592                 fun_del_ref(fun);
    593                 async_answer_0(iid, ENOENT);
    594                 return;
    595         }
    596         fibril_rwlock_write_unlock(&device_tree.rwlock);
    597        
    598         rc = offline_function(fun);
    599         if (rc != EOK) {
    600                 fun_busy_unlock(fun);
    601                 fun_del_ref(fun);
    602                 async_answer_0(iid, (sysarg_t) rc);
    603                 return;
    604         }
    605        
    606         fun_busy_unlock(fun);
    607         fun_del_ref(fun);
    608         async_answer_0(iid, (sysarg_t) EOK);
    609 }
    610 
    611 /** Remove function. */
    612 static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
    613 {
    614         devman_handle_t fun_handle = IPC_GET_ARG1(*call);
    615         dev_tree_t *tree = &device_tree;
    616         int rc;
    617        
    618         fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
    619         if (fun == NULL) {
    620                 async_answer_0(callid, ENOENT);
    621                 return;
    622         }
    623        
    624         fun_busy_lock(fun);
    625        
    626         fibril_rwlock_write_lock(&tree->rwlock);
    627        
    628         log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
    629        
    630         /* Check function state */
    631         if (fun->state == FUN_REMOVED) {
    632                 fibril_rwlock_write_unlock(&tree->rwlock);
    633                 fun_busy_unlock(fun);
    634                 fun_del_ref(fun);
    635                 async_answer_0(callid, ENOENT);
    636                 return;
    637         }
    638        
    639         if (fun->ftype == fun_inner) {
    640                 /* This is a surprise removal. Handle possible descendants */
    641                 if (fun->child != NULL) {
    642                         dev_node_t *dev = fun->child;
    643                         device_state_t dev_state;
    644                         int gone_rc;
    645                        
    646                         dev_add_ref(dev);
    647                         dev_state = dev->state;
    648                        
    649                         fibril_rwlock_write_unlock(&device_tree.rwlock);
    650                        
    651                         /* If device is owned by driver, inform driver it is gone. */
    652                         if (dev_state == DEVICE_USABLE)
    653                                 gone_rc = driver_dev_gone(&device_tree, dev);
    654                         else
    655                                 gone_rc = EOK;
    656                        
    657                         fibril_rwlock_read_lock(&device_tree.rwlock);
    658                        
    659                         /* Verify that driver succeeded and removed all functions */
    660                         if (gone_rc != EOK || !list_empty(&dev->functions)) {
    661                                 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver did not remove "
    662                                     "functions for device that is gone. "
    663                                     "Device node is now defunct.");
    664                                
    665                                 /*
    666                                  * Not much we can do but mark the device
    667                                  * node as having invalid state. This
    668                                  * is a driver bug.
    669                                  */
    670                                 dev->state = DEVICE_INVALID;
    671                                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    672                                 dev_del_ref(dev);
    673                                 if (gone_rc == EOK)
    674                                         gone_rc = ENOTSUP;
    675                                 fun_busy_unlock(fun);
    676                                 fun_del_ref(fun);
    677                                 async_answer_0(callid, gone_rc);
    678                                 return;
    679                         }
    680                        
    681                         driver_t *driver = dev->drv;
    682                         fibril_rwlock_read_unlock(&device_tree.rwlock);
    683                        
    684                         if (driver)
    685                                 detach_driver(&device_tree, dev);
    686                        
    687                         fibril_rwlock_write_lock(&device_tree.rwlock);
    688                         remove_dev_node(&device_tree, dev);
    689                        
    690                         /* Delete ref created when node was inserted */
    691                         dev_del_ref(dev);
    692                         /* Delete ref created by dev_add_ref(dev) above */
    693                         dev_del_ref(dev);
    694                 }
    695         } else {
    696                 if (fun->service_id != 0) {
    697                         /* Unregister from location service */
    698                         rc = loc_service_unregister(fun->service_id);
    699                         if (rc != EOK) {
    700                                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree "
    701                                     "service.");
    702                                 fibril_rwlock_write_unlock(&tree->rwlock);
    703                                 fun_busy_unlock(fun);
    704                                 fun_del_ref(fun);
    705                                 async_answer_0(callid, EIO);
    706                                 return;
    707                         }
    708                 }
    709         }
    710        
    711         remove_fun_node(&device_tree, fun);
    712         fibril_rwlock_write_unlock(&tree->rwlock);
    713         fun_busy_unlock(fun);
    714        
    715         /* Delete ref added when inserting function into tree */
    716         fun_del_ref(fun);
    717         /* Delete ref added above when looking up function */
    718         fun_del_ref(fun);
    719        
    720         log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function() succeeded.");
    721         async_answer_0(callid, EOK);
    722 }
    723 
    724 /** Initialize driver which has registered itself as running and ready.
    725  *
    726  * The initialization is done in a separate fibril to avoid deadlocks (if the
    727  * driver needed to be served by devman during the driver's initialization).
    728  */
    729 static int init_running_drv(void *drv)
    730 {
    731         driver_t *driver = (driver_t *) drv;
    732        
    733         initialize_running_driver(driver, &device_tree);
    734         log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s` driver was successfully initialized.",
    735             driver->name);
    736         return 0;
    737 }
    738 
    739 /** Function for handling connections from a driver to the device manager. */
    740 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
    741 {
    742         client_t *client;
    743         driver_t *driver = NULL;
    744        
    745         /* Accept the connection. */
    746         async_answer_0(iid, EOK);
    747        
    748         client = async_get_client_data();
    749         if (client == NULL) {
    750                 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate client data.");
    751                 return;
    752         }
    753        
    754         while (true) {
    755                 ipc_call_t call;
    756                 ipc_callid_t callid = async_get_call(&call);
    757                
    758                 if (!IPC_GET_IMETHOD(call))
    759                         break;
    760                
    761                 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {
    762                         fibril_mutex_lock(&client->mutex);
    763                         driver = client->driver;
    764                         fibril_mutex_unlock(&client->mutex);
    765                         if (driver == NULL) {
    766                                 /* First call must be to DEVMAN_DRIVER_REGISTER */
    767                                 async_answer_0(callid, ENOTSUP);
    768                                 continue;
    769                         }
    770                 }
    771                
    772                 switch (IPC_GET_IMETHOD(call)) {
    773                 case DEVMAN_DRIVER_REGISTER:
    774                         fibril_mutex_lock(&client->mutex);
    775                         if (client->driver != NULL) {
    776                                 fibril_mutex_unlock(&client->mutex);
    777                                 async_answer_0(callid, EINVAL);
    778                                 continue;
    779                         }
    780                         client->driver = devman_driver_register(callid, &call);
    781                         fibril_mutex_unlock(&client->mutex);
    782                         break;
    783                 case DEVMAN_ADD_FUNCTION:
    784                         devman_add_function(callid, &call);
    785                         break;
    786                 case DEVMAN_ADD_DEVICE_TO_CATEGORY:
    787                         devman_add_function_to_cat(callid, &call);
    788                         break;
    789                 case DEVMAN_DRV_FUN_ONLINE:
    790                         devman_drv_fun_online(callid, &call, driver);
    791                         break;
    792                 case DEVMAN_DRV_FUN_OFFLINE:
    793                         devman_drv_fun_offline(callid, &call, driver);
    794                         break;
    795                 case DEVMAN_REMOVE_FUNCTION:
    796                         devman_remove_function(callid, &call);
    797                         break;
    798                 default:
    799                         async_answer_0(callid, EINVAL);
    800                         break;
    801                 }
    802         }
    803 }
    80467
    80568static void devman_forward(ipc_callid_t iid, ipc_call_t *icall,
  • uspace/srv/devman/main.h

    rd80d7a8 r181c32f  
    3636#include "devman.h"
    3737
     38extern driver_list_t drivers_list;
    3839extern dev_tree_t device_tree;
    3940
Note: See TracChangeset for help on using the changeset viewer.