Ignore:
File:
1 edited

Legend:

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

    rd0dd7b5 r422722e  
    6565static dev_tree_t device_tree;
    6666
     67static int init_running_drv(void *drv);
     68
    6769/** Register running driver. */
    68 static driver_t *devman_driver_register(void)
    69 {
    70         ipc_call_t icall;
    71         ipc_callid_t iid;
     70static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call)
     71{
    7272        driver_t *driver = NULL;
     73        char *drv_name = NULL;
    7374
    7475        log_msg(LVL_DEBUG, "devman_driver_register");
    75        
    76         iid = async_get_call(&icall);
    77         if (IPC_GET_IMETHOD(icall) != DEVMAN_DRIVER_REGISTER) {
    78                 async_answer_0(iid, EREFUSED);
    79                 return NULL;
    80         }
    81        
    82         char *drv_name = NULL;
    8376       
    8477        /* Get driver name. */
    8578        int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
    8679        if (rc != EOK) {
    87                 async_answer_0(iid, rc);
     80                async_answer_0(callid, rc);
    8881                return NULL;
    8982        }
     
    9891                free(drv_name);
    9992                drv_name = NULL;
    100                 async_answer_0(iid, ENOENT);
     93                async_answer_0(callid, ENOENT);
    10194                return NULL;
    10295        }
     
    112105                    driver->name);
    113106                fibril_mutex_unlock(&driver->driver_mutex);
    114                 async_answer_0(iid, EEXISTS);
     107                async_answer_0(callid, EEXISTS);
    115108                return NULL;
    116109        }
     
    134127        log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
    135128            driver->name);
    136         driver->sess = async_callback_receive(EXCHANGE_SERIALIZE);
     129        driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
    137130        if (!driver->sess) {
    138131                fibril_mutex_unlock(&driver->driver_mutex);
    139                 async_answer_0(iid, ENOTSUP);
     132                async_answer_0(callid, ENOTSUP);
    140133                return NULL;
    141134        }
    142        
    143         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);
    144137       
    145138        log_msg(LVL_NOTE,
     
    147140            driver->name);
    148141       
    149         async_answer_0(iid, EOK);
    150        
     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);
    151160        return driver;
    152161}
     
    429438static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
    430439{
     440        client_t *client;
     441        driver_t *driver;
     442       
    431443        /* Accept the connection. */
    432444        async_answer_0(iid, EOK);
    433445       
    434         driver_t *driver = devman_driver_register();
    435         if (driver == NULL)
    436                 return;
    437        
    438         /*
    439          * Initialize the driver as running (e.g. pass assigned devices to it)
    440          * in a separate fibril; the separate fibril is used to enable the
    441          * driver to use devman service during the driver's initialization.
    442          */
    443         fid_t fid = fibril_create(init_running_drv, driver);
    444         if (fid == 0) {
    445                 log_msg(LVL_ERROR, "Failed to create initialization fibril " \
    446                     "for driver `%s'.", driver->name);
    447                 return;
    448         }
    449         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        }
    450451       
    451452        while (true) {
     
    456457                        break;
    457458               
     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               
    458470                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;
    459481                case DEVMAN_ADD_FUNCTION:
    460482                        devman_add_function(callid, &call);
     
    497519}
    498520
    499 /** Find device path by its handle. */
    500 static void devman_get_device_path_by_handle(ipc_callid_t iid,
    501     ipc_call_t *icall)
     521/** Get device name. */
     522static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall)
    502523{
    503524        devman_handle_t handle = IPC_GET_ARG1(*icall);
     
    523544        }
    524545
     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
    525583        size_t sent_length = str_size(fun->pathname);
    526584        if (sent_length > data_len) {
     
    532590
    533591        free(buffer);
     592}
     593
     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);
    534666}
    535667
     
    566698                        devman_function_get_handle(callid, &call);
    567699                        break;
    568                 case DEVMAN_DEVICE_GET_DEVICE_PATH:
    569                         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);
    570711                        break;
    571712                case DEVMAN_FUN_SID_TO_HANDLE:
     
    695836static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    696837{
    697         /* Select interface. */
     838        /* Select port. */
    698839        switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
    699840        case DEVMAN_DRIVER:
     
    721862}
    722863
     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
    723881/** Initialize device manager internal structures. */
    724882static bool devman_init(void)
     
    767925        }
    768926       
    769         /* 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);
    770930        async_set_client_connection(devman_connection);
    771931
Note: See TracChangeset for help on using the changeset viewer.