Changeset bd5f3b7 in mainline for uspace/srv/devman/main.c


Ignore:
Timestamp:
2011-08-21T13:07:35Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
00aece0, f1a9e87
Parents:
86a34d3e (diff), a6480d5 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

File:
1 edited

Legend:

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

    r86a34d3e rbd5f3b7  
    5656#include <ipc/driver.h>
    5757#include <thread.h>
    58 #include <devmap.h>
     58#include <loc.h>
    5959
    6060#include "devman.h"
     
    6464static driver_list_t drivers_list;
    6565static dev_tree_t device_tree;
    66 static class_list_t class_list;
     66
     67static int init_running_drv(void *drv);
    6768
    6869/** Register running driver. */
    69 static driver_t *devman_driver_register(void)
    70 {
    71         ipc_call_t icall;
    72         ipc_callid_t iid;
     70static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call)
     71{
    7372        driver_t *driver = NULL;
     73        char *drv_name = NULL;
    7474
    7575        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        
    83         char *drv_name = NULL;
    8476       
    8577        /* Get driver name. */
    8678        int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
    8779        if (rc != EOK) {
    88                 async_answer_0(iid, rc);
     80                async_answer_0(callid, rc);
    8981                return NULL;
    9082        }
     
    9991                free(drv_name);
    10092                drv_name = NULL;
    101                 async_answer_0(iid, ENOENT);
     93                async_answer_0(callid, ENOENT);
    10294                return NULL;
    10395        }
     
    113105                    driver->name);
    114106                fibril_mutex_unlock(&driver->driver_mutex);
    115                 async_answer_0(iid, EEXISTS);
     107                async_answer_0(callid, EEXISTS);
    116108                return NULL;
    117109        }
     
    135127        log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
    136128            driver->name);
    137         driver->sess = async_callback_receive(EXCHANGE_SERIALIZE);
     129        driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
    138130        if (!driver->sess) {
    139131                fibril_mutex_unlock(&driver->driver_mutex);
    140                 async_answer_0(iid, ENOTSUP);
     132                async_answer_0(callid, ENOTSUP);
    141133                return NULL;
    142134        }
    143        
    144         fibril_mutex_unlock(&driver->driver_mutex);
     135        /* FIXME: Work around problem with callback sessions */
     136        async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);
    145137       
    146138        log_msg(LVL_NOTE,
     
    148140            driver->name);
    149141       
    150         async_answer_0(iid, EOK);
    151        
     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);
    152160        return driver;
    153161}
     
    279287                return;
    280288        }
    281 
     289       
    282290        fun_node_t *fun = create_fun_node();
     291        fun->ftype = ftype;
     292       
    283293        if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
    284294                fibril_rwlock_write_unlock(&tree->rwlock);
     
    326336                }
    327337        } else {
    328                 devmap_register_tree_function(fun, tree);
     338                loc_register_tree_function(fun, tree);
    329339        }
    330340       
     
    333343}
    334344
    335 static 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 
    361 static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call)
     345static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)
    362346{
    363347        devman_handle_t handle = IPC_GET_ARG1(*call);
    364        
    365         /* Get class name. */
    366         char *class_name;
    367         int rc = async_data_write_accept((void **) &class_name, true,
     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,
    368354            0, 0, 0, 0);
    369355        if (rc != EOK) {
     
    378364        }
    379365       
    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 
     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. */
     381static 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.");
    389419        async_answer_0(callid, EOK);
    390420}
     
    408438static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
    409439{
     440        client_t *client;
     441        driver_t *driver;
     442       
    410443        /* Accept the connection. */
    411444        async_answer_0(iid, EOK);
    412445       
    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);
     446        client = async_get_client_data();
     447        if (client == NULL) {
     448                log_msg(LVL_ERROR, "Failed to allocate client data.");
     449                return;
     450        }
    429451       
    430452        while (true) {
     
    435457                        break;
    436458               
     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               
    437470                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;
    438481                case DEVMAN_ADD_FUNCTION:
    439482                        devman_add_function(callid, &call);
    440483                        break;
    441                 case DEVMAN_ADD_DEVICE_TO_CLASS:
    442                         devman_add_function_to_class(callid, &call);
     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);
    443489                        break;
    444490                default:
     
    473519}
    474520
    475 /** Find handle for the device instance identified by device class name. */
    476 static 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. */
    510 static void devman_get_device_path_by_handle(ipc_callid_t iid,
    511     ipc_call_t *icall)
     521/** Get device name. */
     522static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall)
    512523{
    513524        devman_handle_t handle = IPC_GET_ARG1(*icall);
     
    533544        }
    534545
     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. */
     559static 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
    535583        size_t sent_length = str_size(fun->pathname);
    536584        if (sent_length > data_len) {
     
    544592}
    545593
     594static 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. */
     644static 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. */
     669static 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}
    546682
    547683/** Function for handling connections from a client to the device manager. */
     
    562698                        devman_function_get_handle(callid, &call);
    563699                        break;
    564                 case DEVMAN_DEVICE_GET_HANDLE_BY_CLASS:
    565                         devman_function_get_handle_by_class(callid, &call);
    566                         break;
    567                 case DEVMAN_DEVICE_GET_DEVICE_PATH:
    568                         devman_get_device_path_by_handle(callid, &call);
     700                case DEVMAN_DEV_GET_FUNCTIONS:
     701                        devman_dev_get_functions(callid, &call);
     702                        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);
    569714                        break;
    570715                default:
     
    659804}
    660805
    661 /** Function for handling connections from a client forwarded by the device
    662  * mapper to the device manager. */
    663 static void devman_connection_devmapper(ipc_callid_t iid, ipc_call_t *icall)
    664 {
    665         devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall);
     806/** Function for handling connections from a client forwarded by the location
     807 * service to the device manager. */
     808static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall)
     809{
     810        service_id_t service_id = IPC_GET_ARG2(*icall);
    666811        fun_node_t *fun;
    667812        dev_node_t *dev;
    668813
    669         fun = find_devmap_tree_function(&device_tree, devmap_handle);
    670         if (fun == NULL)
    671                 fun = find_devmap_class_function(&class_list, devmap_handle);
     814        fun = find_loc_tree_function(&device_tree, service_id);
    672815       
    673816        if (fun == NULL || fun->dev->drv == NULL) {
     817                log_msg(LVL_WARN, "devman_connection_loc(): function "
     818                    "not found.\n");
    674819                async_answer_0(iid, ENOENT);
    675820                return;
     
    677822       
    678823        dev = fun->dev;
    679        
    680         if ((dev->state != DEVICE_USABLE) || (!dev->drv->sess)) {
    681                 async_answer_0(iid, EINVAL);
    682                 return;
    683         }
    684824       
    685825        async_exch_t *exch = async_exchange_begin(dev->drv->sess);
     
    689829       
    690830        log_msg(LVL_DEBUG,
    691             "Forwarding devmapper request for `%s' function to driver `%s'.",
     831            "Forwarding loc service request for `%s' function to driver `%s'.",
    692832            fun->pathname, dev->drv->name);
    693833}
     
    696836static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    697837{
    698         /* Select interface. */
     838        /* Select port. */
    699839        switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
    700840        case DEVMAN_DRIVER:
     
    708848                devman_forward(iid, icall, false);
    709849                break;
    710         case DEVMAN_CONNECT_FROM_DEVMAP:
    711                 /* Someone connected through devmap node. */
    712                 devman_connection_devmapper(iid, icall);
     850        case DEVMAN_CONNECT_FROM_LOC:
     851                /* Someone connected through loc node. */
     852                devman_connection_loc(iid, icall);
    713853                break;
    714854        case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
     
    722862}
    723863
     864static 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
     876static void devman_client_data_destroy(void *data)
     877{
     878        free(data);
     879}
     880
    724881/** Initialize device manager internal structures. */
    725882static bool devman_init(void)
     
    743900        }
    744901
    745         init_class_list(&class_list);
    746        
    747902        /*
    748          * !!! devman_connection ... as the device manager is not a real devmap
     903         * !!! devman_connection ... as the device manager is not a real loc
    749904         * driver (it uses a completely different ipc protocol than an ordinary
    750          * devmap driver) forwarding a connection from client to the devman by
    751          * devmapper would not work.
     905         * loc driver) forwarding a connection from client to the devman by
     906         * location service would not work.
    752907         */
    753         devmap_driver_register(NAME, devman_connection);
     908        loc_server_register(NAME, devman_connection);
    754909       
    755910        return true;
     
    760915        printf(NAME ": HelenOS Device Manager\n");
    761916
    762         if (log_init(NAME, LVL_ERROR) != EOK) {
     917        if (log_init(NAME, LVL_WARN) != EOK) {
    763918                printf(NAME ": Error initializing logging subsystem.\n");
    764919                return -1;
     
    770925        }
    771926       
    772         /* Set a handler of incomming connections. */
     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);
    773930        async_set_client_connection(devman_connection);
    774931
Note: See TracChangeset for help on using the changeset viewer.