Ignore:
File:
1 edited

Legend:

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

    r422722e r9934f7d  
    5656#include <ipc/driver.h>
    5757#include <thread.h>
    58 #include <loc.h>
     58#include <devmap.h>
    5959
    6060#include "devman.h"
     
    6464static driver_list_t drivers_list;
    6565static dev_tree_t device_tree;
    66 
    67 static int init_running_drv(void *drv);
     66static class_list_t class_list;
    6867
    6968/** Register running driver. */
    70 static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call)
    71 {
     69static driver_t *devman_driver_register(void)
     70{
     71        ipc_call_t icall;
     72        ipc_callid_t iid;
    7273        driver_t *driver = NULL;
     74
     75        log_msg(LVL_DEBUG, "devman_driver_register");
     76       
     77        iid = async_get_call(&icall);
     78        if (IPC_GET_IMETHOD(icall) != DEVMAN_DRIVER_REGISTER) {
     79                async_answer_0(iid, EREFUSED);
     80                return NULL;
     81        }
     82       
    7383        char *drv_name = NULL;
    74 
    75         log_msg(LVL_DEBUG, "devman_driver_register");
    7684       
    7785        /* Get driver name. */
    7886        int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
    7987        if (rc != EOK) {
    80                 async_answer_0(callid, rc);
     88                async_answer_0(iid, rc);
    8189                return NULL;
    8290        }
     
    9199                free(drv_name);
    92100                drv_name = NULL;
    93                 async_answer_0(callid, ENOENT);
     101                async_answer_0(iid, ENOENT);
    94102                return NULL;
    95103        }
     
    105113                    driver->name);
    106114                fibril_mutex_unlock(&driver->driver_mutex);
    107                 async_answer_0(callid, EEXISTS);
     115                async_answer_0(iid, EEXISTS);
    108116                return NULL;
    109117        }
     
    127135        log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
    128136            driver->name);
    129         driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
     137        driver->sess = async_callback_receive(EXCHANGE_SERIALIZE);
    130138        if (!driver->sess) {
    131139                fibril_mutex_unlock(&driver->driver_mutex);
    132                 async_answer_0(callid, ENOTSUP);
     140                async_answer_0(iid, ENOTSUP);
    133141                return NULL;
    134142        }
    135         /* FIXME: Work around problem with callback sessions */
    136         async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);
     143       
     144        fibril_mutex_unlock(&driver->driver_mutex);
    137145       
    138146        log_msg(LVL_NOTE,
     
    140148            driver->name);
    141149       
    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(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);
     150        async_answer_0(iid, EOK);
     151       
    160152        return driver;
    161153}
     
    287279                return;
    288280        }
    289        
     281
    290282        fun_node_t *fun = create_fun_node();
    291         fun->ftype = ftype;
    292        
    293283        if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
    294284                fibril_rwlock_write_unlock(&tree->rwlock);
     
    336326                }
    337327        } else {
    338                 loc_register_tree_function(fun, tree);
     328                devmap_register_tree_function(fun, tree);
    339329        }
    340330       
     
    343333}
    344334
    345 static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)
     335static void devmap_register_class_dev(dev_class_info_t *cli)
     336{
     337        /* Create devmap path and name for the device. */
     338        char *devmap_pathname = NULL;
     339
     340        asprintf(&devmap_pathname, "%s/%s%c%s", DEVMAP_CLASS_NAMESPACE,
     341            cli->dev_class->name, DEVMAP_SEPARATOR, cli->dev_name);
     342        if (devmap_pathname == NULL)
     343                return;
     344       
     345        /*
     346         * Register the device by the device mapper and remember its devmap
     347         * handle.
     348         */
     349        devmap_device_register_with_iface(devmap_pathname,
     350            &cli->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
     351       
     352        /*
     353         * Add device to the hash map of class devices registered by device
     354         * mapper.
     355         */
     356        class_add_devmap_function(&class_list, cli);
     357       
     358        free(devmap_pathname);
     359}
     360
     361static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call)
    346362{
    347363        devman_handle_t handle = IPC_GET_ARG1(*call);
    348         category_id_t cat_id;
    349         int rc;
    350        
    351         /* Get category name. */
    352         char *cat_name;
    353         rc = async_data_write_accept((void **) &cat_name, true,
     364       
     365        /* Get class name. */
     366        char *class_name;
     367        int rc = async_data_write_accept((void **) &class_name, true,
    354368            0, 0, 0, 0);
    355369        if (rc != EOK) {
     
    364378        }
    365379       
    366         rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
    367         if (rc == EOK) {
    368                 loc_service_add_to_cat(fun->service_id, cat_id);
    369         } else {
    370                 log_msg(LVL_ERROR, "Failed adding function `%s' to category "
    371                     "`%s'.", fun->pathname, cat_name);
    372         }
    373        
    374         log_msg(LVL_NOTE, "Function `%s' added to category `%s'.",
    375             fun->pathname, cat_name);
    376 
    377         async_answer_0(callid, EOK);
    378 }
    379 
    380 /** Remove function. */
    381 static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
    382 {
    383         devman_handle_t fun_handle = IPC_GET_ARG1(*call);
    384         dev_tree_t *tree = &device_tree;
    385         int rc;
    386        
    387         fibril_rwlock_write_lock(&tree->rwlock);
    388        
    389         fun_node_t *fun = find_fun_node_no_lock(&device_tree, fun_handle);
    390         if (fun == NULL) {
    391                 fibril_rwlock_write_unlock(&tree->rwlock);
    392                 async_answer_0(callid, ENOENT);
    393                 return;
    394         }
    395        
    396         log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
    397        
    398         if (fun->ftype == fun_inner) {
    399                 /* Handle possible descendants */
    400                 /* TODO */
    401                 log_msg(LVL_WARN, "devman_remove_function(): not handling "
    402                     "descendants\n");
    403         } else {
    404                 /* Unregister from location service */
    405                 rc = loc_service_unregister(fun->service_id);
    406                 if (rc != EOK) {
    407                         log_msg(LVL_ERROR, "Failed unregistering tree service.");
    408                         fibril_rwlock_write_unlock(&tree->rwlock);
    409                         async_answer_0(callid, EIO);
    410                         return;
    411                 }
    412         }
    413        
    414         remove_fun_node(&device_tree, fun);
    415         fibril_rwlock_write_unlock(&tree->rwlock);
    416         delete_fun_node(fun);
    417        
    418         log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
     380        dev_class_t *cl = get_dev_class(&class_list, class_name);
     381        dev_class_info_t *class_info = add_function_to_class(fun, cl, NULL);
     382       
     383        /* Register the device's class alias by devmapper. */
     384        devmap_register_class_dev(class_info);
     385       
     386        log_msg(LVL_NOTE, "Function `%s' added to class `%s' as `%s'.",
     387            fun->pathname, class_name, class_info->dev_name);
     388
    419389        async_answer_0(callid, EOK);
    420390}
     
    438408static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
    439409{
    440         client_t *client;
    441         driver_t *driver;
    442        
    443410        /* Accept the connection. */
    444411        async_answer_0(iid, EOK);
    445412       
    446         client = async_get_client_data();
    447         if (client == NULL) {
    448                 log_msg(LVL_ERROR, "Failed to allocate client data.");
    449                 return;
    450         }
     413        driver_t *driver = devman_driver_register();
     414        if (driver == NULL)
     415                return;
     416       
     417        /*
     418         * Initialize the driver as running (e.g. pass assigned devices to it)
     419         * in a separate fibril; the separate fibril is used to enable the
     420         * driver to use devman service during the driver's initialization.
     421         */
     422        fid_t fid = fibril_create(init_running_drv, driver);
     423        if (fid == 0) {
     424                log_msg(LVL_ERROR, "Failed to create initialization fibril " \
     425                    "for driver `%s'.", driver->name);
     426                return;
     427        }
     428        fibril_add_ready(fid);
    451429       
    452430        while (true) {
     
    457435                        break;
    458436               
    459                 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {
    460                         fibril_mutex_lock(&client->mutex);
    461                         driver = client->driver;
    462                         fibril_mutex_unlock(&client->mutex);
    463                         if (driver == NULL) {
    464                                 /* First call must be to DEVMAN_DRIVER_REGISTER */
    465                                 async_answer_0(callid, ENOTSUP);
    466                                 continue;
    467                         }
    468                 }
    469                
    470437                switch (IPC_GET_IMETHOD(call)) {
    471                 case DEVMAN_DRIVER_REGISTER:
    472                         fibril_mutex_lock(&client->mutex);
    473                         if (client->driver != NULL) {
    474                                 fibril_mutex_unlock(&client->mutex);
    475                                 async_answer_0(callid, EINVAL);
    476                                 continue;
    477                         }
    478                         client->driver = devman_driver_register(callid, &call);
    479                         fibril_mutex_unlock(&client->mutex);
    480                         break;
    481438                case DEVMAN_ADD_FUNCTION:
    482439                        devman_add_function(callid, &call);
    483440                        break;
    484                 case DEVMAN_ADD_DEVICE_TO_CATEGORY:
    485                         devman_add_function_to_cat(callid, &call);
    486                         break;
    487                 case DEVMAN_REMOVE_FUNCTION:
    488                         devman_remove_function(callid, &call);
     441                case DEVMAN_ADD_DEVICE_TO_CLASS:
     442                        devman_add_function_to_class(callid, &call);
    489443                        break;
    490444                default:
     
    519473}
    520474
    521 /** Get device name. */
    522 static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall)
     475/** Find handle for the device instance identified by device class name. */
     476static void devman_function_get_handle_by_class(ipc_callid_t iid,
     477    ipc_call_t *icall)
     478{
     479        char *classname;
     480        char *devname;
     481
     482        int rc = async_data_write_accept((void **) &classname, true, 0, 0, 0, 0);
     483        if (rc != EOK) {
     484                async_answer_0(iid, rc);
     485                return;
     486        }
     487        rc = async_data_write_accept((void **) &devname, true, 0, 0, 0, 0);
     488        if (rc != EOK) {
     489                free(classname);
     490                async_answer_0(iid, rc);
     491                return;
     492        }
     493
     494
     495        fun_node_t *fun = find_fun_node_by_class(&class_list,
     496            classname, devname);
     497
     498        free(classname);
     499        free(devname);
     500
     501        if (fun == NULL) {
     502                async_answer_0(iid, ENOENT);
     503                return;
     504        }
     505
     506        async_answer_1(iid, EOK, fun->handle);
     507}
     508
     509/** Find device path by its handle. */
     510static void devman_get_device_path_by_handle(ipc_callid_t iid,
     511    ipc_call_t *icall)
    523512{
    524513        devman_handle_t handle = IPC_GET_ARG1(*icall);
     
    544533        }
    545534
    546         size_t sent_length = str_size(fun->name);
    547         if (sent_length > data_len) {
    548                 sent_length = data_len;
    549         }
    550 
    551         async_data_read_finalize(data_callid, fun->name, sent_length);
    552         async_answer_0(iid, EOK);
    553 
    554         free(buffer);
    555 }
    556 
    557 
    558 /** Get device path. */
    559 static void devman_fun_get_path(ipc_callid_t iid, ipc_call_t *icall)
    560 {
    561         devman_handle_t handle = IPC_GET_ARG1(*icall);
    562 
    563         fun_node_t *fun = find_fun_node(&device_tree, handle);
    564         if (fun == NULL) {
    565                 async_answer_0(iid, ENOMEM);
    566                 return;
    567         }
    568 
    569         ipc_callid_t data_callid;
    570         size_t data_len;
    571         if (!async_data_read_receive(&data_callid, &data_len)) {
    572                 async_answer_0(iid, EINVAL);
    573                 return;
    574         }
    575 
    576         void *buffer = malloc(data_len);
    577         if (buffer == NULL) {
    578                 async_answer_0(data_callid, ENOMEM);
    579                 async_answer_0(iid, ENOMEM);
    580                 return;
    581         }
    582 
    583535        size_t sent_length = str_size(fun->pathname);
    584536        if (sent_length > data_len) {
     
    592544}
    593545
    594 static void devman_dev_get_functions(ipc_callid_t iid, ipc_call_t *icall)
    595 {
    596         ipc_callid_t callid;
    597         size_t size;
    598         size_t act_size;
    599         int rc;
    600        
    601         if (!async_data_read_receive(&callid, &size)) {
    602                 async_answer_0(callid, EREFUSED);
    603                 async_answer_0(iid, EREFUSED);
    604                 return;
    605         }
    606        
    607         fibril_rwlock_read_lock(&device_tree.rwlock);
    608        
    609         dev_node_t *dev = find_dev_node_no_lock(&device_tree,
    610             IPC_GET_ARG1(*icall));
    611         if (dev == NULL) {
    612                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    613                 async_answer_0(callid, ENOENT);
    614                 async_answer_0(iid, ENOENT);
    615                 return;
    616         }
    617        
    618         devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
    619         if (hdl_buf == NULL) {
    620                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    621                 async_answer_0(callid, ENOMEM);
    622                 async_answer_0(iid, ENOMEM);
    623                 return;
    624         }
    625        
    626         rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size);
    627         if (rc != EOK) {
    628                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    629                 async_answer_0(callid, rc);
    630                 async_answer_0(iid, rc);
    631                 return;
    632         }
    633        
    634         fibril_rwlock_read_unlock(&device_tree.rwlock);
    635        
    636         sysarg_t retval = async_data_read_finalize(callid, hdl_buf, size);
    637         free(hdl_buf);
    638        
    639         async_answer_1(iid, retval, act_size);
    640 }
    641 
    642 
    643 /** Get handle for child device of a function. */
    644 static void devman_fun_get_child(ipc_callid_t iid, ipc_call_t *icall)
    645 {
    646         fun_node_t *fun;
    647        
    648         fibril_rwlock_read_lock(&device_tree.rwlock);
    649        
    650         fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
    651         if (fun == NULL) {
    652                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    653                 async_answer_0(iid, ENOENT);
    654                 return;
    655         }
    656        
    657         if (fun->child == NULL) {
    658                 fibril_rwlock_read_unlock(&device_tree.rwlock);
    659                 async_answer_0(iid, ENOENT);
    660                 return;
    661         }
    662        
    663         async_answer_1(iid, EOK, fun->child->handle);
    664        
    665         fibril_rwlock_read_unlock(&device_tree.rwlock);
    666 }
    667 
    668 /** Find handle for the function instance identified by its service ID. */
    669 static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall)
    670 {
    671         fun_node_t *fun;
    672 
    673         fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall));
    674        
    675         if (fun == NULL) {
    676                 async_answer_0(iid, ENOENT);
    677                 return;
    678         }
    679 
    680         async_answer_1(iid, EOK, fun->handle);
    681 }
    682546
    683547/** Function for handling connections from a client to the device manager. */
     
    698562                        devman_function_get_handle(callid, &call);
    699563                        break;
    700                 case DEVMAN_DEV_GET_FUNCTIONS:
    701                         devman_dev_get_functions(callid, &call);
     564                case DEVMAN_DEVICE_GET_HANDLE_BY_CLASS:
     565                        devman_function_get_handle_by_class(callid, &call);
    702566                        break;
    703                 case DEVMAN_FUN_GET_CHILD:
    704                         devman_fun_get_child(callid, &call);
    705                         break;
    706                 case DEVMAN_FUN_GET_NAME:
    707                         devman_fun_get_name(callid, &call);
    708                         break;
    709                 case DEVMAN_FUN_GET_PATH:
    710                         devman_fun_get_path(callid, &call);
    711                         break;
    712                 case DEVMAN_FUN_SID_TO_HANDLE:
    713                         devman_fun_sid_to_handle(callid, &call);
     567                case DEVMAN_DEVICE_GET_DEVICE_PATH:
     568                        devman_get_device_path_by_handle(callid, &call);
    714569                        break;
    715570                default:
     
    804659}
    805660
    806 /** Function for handling connections from a client forwarded by the location
    807  * service to the device manager. */
    808 static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall)
    809 {
    810         service_id_t service_id = IPC_GET_ARG2(*icall);
     661/** Function for handling connections from a client forwarded by the device
     662 * mapper to the device manager. */
     663static void devman_connection_devmapper(ipc_callid_t iid, ipc_call_t *icall)
     664{
     665        devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall);
    811666        fun_node_t *fun;
    812667        dev_node_t *dev;
    813668
    814         fun = find_loc_tree_function(&device_tree, service_id);
     669        fun = find_devmap_tree_function(&device_tree, devmap_handle);
     670        if (fun == NULL)
     671                fun = find_devmap_class_function(&class_list, devmap_handle);
    815672       
    816673        if (fun == NULL || fun->dev->drv == NULL) {
    817                 log_msg(LVL_WARN, "devman_connection_loc(): function "
    818                     "not found.\n");
    819674                async_answer_0(iid, ENOENT);
    820675                return;
     
    822677       
    823678        dev = fun->dev;
     679       
     680        if ((dev->state != DEVICE_USABLE) || (!dev->drv->sess)) {
     681                async_answer_0(iid, EINVAL);
     682                return;
     683        }
    824684       
    825685        async_exch_t *exch = async_exchange_begin(dev->drv->sess);
     
    829689       
    830690        log_msg(LVL_DEBUG,
    831             "Forwarding loc service request for `%s' function to driver `%s'.",
     691            "Forwarding devmapper request for `%s' function to driver `%s'.",
    832692            fun->pathname, dev->drv->name);
    833693}
     
    836696static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    837697{
    838         /* Select port. */
     698        /* Select interface. */
    839699        switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
    840700        case DEVMAN_DRIVER:
     
    848708                devman_forward(iid, icall, false);
    849709                break;
    850         case DEVMAN_CONNECT_FROM_LOC:
    851                 /* Someone connected through loc node. */
    852                 devman_connection_loc(iid, icall);
     710        case DEVMAN_CONNECT_FROM_DEVMAP:
     711                /* Someone connected through devmap node. */
     712                devman_connection_devmapper(iid, icall);
    853713                break;
    854714        case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
     
    862722}
    863723
    864 static void *devman_client_data_create(void)
    865 {
    866         client_t *client;
    867        
    868         client = calloc(1, sizeof(client_t));
    869         if (client == NULL)
    870                 return NULL;
    871        
    872         fibril_mutex_initialize(&client->mutex);
    873         return client;
    874 }
    875 
    876 static void devman_client_data_destroy(void *data)
    877 {
    878         free(data);
    879 }
    880 
    881724/** Initialize device manager internal structures. */
    882725static bool devman_init(void)
     
    900743        }
    901744
     745        init_class_list(&class_list);
     746       
    902747        /*
    903          * !!! devman_connection ... as the device manager is not a real loc
     748         * !!! devman_connection ... as the device manager is not a real devmap
    904749         * driver (it uses a completely different ipc protocol than an ordinary
    905          * loc driver) forwarding a connection from client to the devman by
    906          * location service would not work.
     750         * devmap driver) forwarding a connection from client to the devman by
     751         * devmapper would not work.
    907752         */
    908         loc_server_register(NAME, devman_connection);
     753        devmap_driver_register(NAME, devman_connection);
    909754       
    910755        return true;
     
    915760        printf(NAME ": HelenOS Device Manager\n");
    916761
    917         if (log_init(NAME, LVL_WARN) != EOK) {
     762        if (log_init(NAME, LVL_ERROR) != EOK) {
    918763                printf(NAME ": Error initializing logging subsystem.\n");
    919764                return -1;
     
    925770        }
    926771       
    927         /* Set handlers for incoming connections. */
    928         async_set_client_data_constructor(devman_client_data_create);
    929         async_set_client_data_destructor(devman_client_data_destroy);
     772        /* Set a handler of incomming connections. */
    930773        async_set_client_connection(devman_connection);
    931774
Note: See TracChangeset for help on using the changeset viewer.