HelenOS sources
This source file includes following definitions.
- devman_function_get_handle
- devman_fun_get_match_id
- devman_fun_get_name
- devman_fun_get_driver_name
- devman_fun_get_path
- devman_dev_get_parent
- devman_dev_get_functions
- devman_fun_get_child
- devman_fun_online
- devman_fun_offline
- devman_fun_sid_to_handle
- devman_get_drivers
- devman_driver_get_devices
- devman_driver_get_handle
- devman_driver_get_match_id
- devman_driver_get_name
- devman_driver_get_state
- devman_driver_load
- devman_driver_unload
- devman_connection_client
#include <inttypes.h>
#include <assert.h>
#include <ns.h>
#include <async.h>
#include <stdio.h>
#include <errno.h>
#include <str_error.h>
#include <stdbool.h>
#include <fibril_synch.h>
#include <stdlib.h>
#include <str.h>
#include <ctype.h>
#include <ipc/devman.h>
#include "client_conn.h"
#include "dev.h"
#include "devman.h"
#include "driver.h"
#include "fun.h"
#include "loc.h"
#include "main.h"
static void devman_function_get_handle(ipc_call_t *icall)
{
char *pathname;
devman_handle_t handle;
errno_t rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
if (rc != EOK) {
async_answer_0(icall, rc);
return;
}
fun_node_t *fun = find_fun_node_by_path(&device_tree, pathname);
free(pathname);
if (fun == NULL) {
async_answer_0(icall, ENOENT);
return;
}
fibril_rwlock_read_lock(&device_tree.rwlock);
if (fun->state == FUN_REMOVED) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
async_answer_0(icall, ENOENT);
return;
}
handle = fun->handle;
fibril_rwlock_read_unlock(&device_tree.rwlock);
fun_del_ref(fun);
async_answer_1(icall, EOK, handle);
}
static void devman_fun_get_match_id(ipc_call_t *icall)
{
devman_handle_t handle = ipc_get_arg1(icall);
size_t index = ipc_get_arg2(icall);
void *buffer = NULL;
fun_node_t *fun = find_fun_node(&device_tree, handle);
if (fun == NULL) {
async_answer_0(icall, ENOMEM);
return;
}
ipc_call_t data;
size_t data_len;
if (!async_data_read_receive(&data, &data_len)) {
async_answer_0(icall, EINVAL);
fun_del_ref(fun);
return;
}
buffer = malloc(data_len);
if (buffer == NULL) {
async_answer_0(&data, ENOMEM);
async_answer_0(icall, ENOMEM);
fun_del_ref(fun);
return;
}
fibril_rwlock_read_lock(&device_tree.rwlock);
if (fun->state == FUN_REMOVED)
goto error;
link_t *link = list_nth(&fun->match_ids.ids, index);
if (link == NULL)
goto error;
match_id_t *mid = list_get_instance(link, match_id_t, link);
size_t sent_length = str_size(mid->id);
if (sent_length > data_len) {
sent_length = data_len;
}
async_data_read_finalize(&data, mid->id, sent_length);
async_answer_1(icall, EOK, mid->score);
fibril_rwlock_read_unlock(&device_tree.rwlock);
fun_del_ref(fun);
free(buffer);
return;
error:
fibril_rwlock_read_unlock(&device_tree.rwlock);
free(buffer);
async_answer_0(&data, ENOENT);
async_answer_0(icall, ENOENT);
fun_del_ref(fun);
}
static void devman_fun_get_name(ipc_call_t *icall)
{
devman_handle_t handle = ipc_get_arg1(icall);
fun_node_t *fun = find_fun_node(&device_tree, handle);
if (fun == NULL) {
async_answer_0(icall, ENOMEM);
return;
}
ipc_call_t data;
size_t data_len;
if (!async_data_read_receive(&data, &data_len)) {
async_answer_0(icall, EINVAL);
fun_del_ref(fun);
return;
}
void *buffer = malloc(data_len);
if (buffer == NULL) {
async_answer_0(&data, ENOMEM);
async_answer_0(icall, ENOMEM);
fun_del_ref(fun);
return;
}
fibril_rwlock_read_lock(&device_tree.rwlock);
if (fun->state == FUN_REMOVED) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
free(buffer);
async_answer_0(&data, ENOENT);
async_answer_0(icall, ENOENT);
fun_del_ref(fun);
return;
}
size_t sent_length = str_size(fun->name);
if (sent_length > data_len) {
sent_length = data_len;
}
async_data_read_finalize(&data, fun->name, sent_length);
async_answer_0(icall, EOK);
fibril_rwlock_read_unlock(&device_tree.rwlock);
fun_del_ref(fun);
free(buffer);
}
static void devman_fun_get_driver_name(ipc_call_t *icall)
{
devman_handle_t handle = ipc_get_arg1(icall);
fun_node_t *fun = find_fun_node(&device_tree, handle);
if (fun == NULL) {
async_answer_0(icall, ENOMEM);
return;
}
ipc_call_t data;
size_t data_len;
if (!async_data_read_receive(&data, &data_len)) {
async_answer_0(icall, EINVAL);
fun_del_ref(fun);
return;
}
void *buffer = malloc(data_len);
if (buffer == NULL) {
async_answer_0(&data, ENOMEM);
async_answer_0(icall, ENOMEM);
fun_del_ref(fun);
return;
}
fibril_rwlock_read_lock(&device_tree.rwlock);
if (fun->state == FUN_REMOVED) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
free(buffer);
async_answer_0(&data, ENOENT);
async_answer_0(icall, ENOENT);
fun_del_ref(fun);
return;
}
if (fun->child == NULL || fun->child->drv == NULL) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
free(buffer);
async_answer_0(&data, EINVAL);
async_answer_0(icall, EINVAL);
fun_del_ref(fun);
return;
}
size_t sent_length = str_size(fun->child->drv->name);
if (sent_length > data_len) {
sent_length = data_len;
}
async_data_read_finalize(&data, fun->child->drv->name,
sent_length);
async_answer_0(icall, EOK);
fibril_rwlock_read_unlock(&device_tree.rwlock);
fun_del_ref(fun);
free(buffer);
}
static void devman_fun_get_path(ipc_call_t *icall)
{
devman_handle_t handle = ipc_get_arg1(icall);
fun_node_t *fun = find_fun_node(&device_tree, handle);
if (fun == NULL) {
async_answer_0(icall, ENOMEM);
return;
}
ipc_call_t data;
size_t data_len;
if (!async_data_read_receive(&data, &data_len)) {
async_answer_0(icall, EINVAL);
fun_del_ref(fun);
return;
}
void *buffer = malloc(data_len);
if (buffer == NULL) {
async_answer_0(&data, ENOMEM);
async_answer_0(icall, ENOMEM);
fun_del_ref(fun);
return;
}
fibril_rwlock_read_lock(&device_tree.rwlock);
if (fun->state == FUN_REMOVED) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
free(buffer);
async_answer_0(&data, ENOENT);
async_answer_0(icall, ENOENT);
fun_del_ref(fun);
return;
}
size_t sent_length = str_size(fun->pathname);
if (sent_length > data_len) {
sent_length = data_len;
}
async_data_read_finalize(&data, fun->pathname, sent_length);
async_answer_0(icall, EOK);
fibril_rwlock_read_unlock(&device_tree.rwlock);
fun_del_ref(fun);
free(buffer);
}
static void devman_dev_get_parent(ipc_call_t *icall)
{
dev_node_t *dev;
fibril_rwlock_read_lock(&device_tree.rwlock);
dev = find_dev_node_no_lock(&device_tree, ipc_get_arg1(icall));
if (dev == NULL || dev->state == DEVICE_REMOVED) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
async_answer_0(icall, ENOENT);
return;
}
if (dev->pfun == NULL) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
async_answer_0(icall, ENOENT);
return;
}
async_answer_1(icall, EOK, dev->pfun->handle);
fibril_rwlock_read_unlock(&device_tree.rwlock);
}
static void devman_dev_get_functions(ipc_call_t *icall)
{
ipc_call_t call;
size_t size;
size_t act_size;
errno_t rc;
if (!async_data_read_receive(&call, &size)) {
async_answer_0(&call, EREFUSED);
async_answer_0(icall, EREFUSED);
return;
}
fibril_rwlock_read_lock(&device_tree.rwlock);
dev_node_t *dev = find_dev_node_no_lock(&device_tree,
ipc_get_arg1(icall));
if (dev == NULL || dev->state == DEVICE_REMOVED) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
async_answer_0(&call, ENOENT);
async_answer_0(icall, ENOENT);
return;
}
devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
if (hdl_buf == NULL) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
async_answer_0(&call, ENOMEM);
async_answer_0(icall, ENOMEM);
return;
}
rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size);
if (rc != EOK) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
async_answer_0(&call, rc);
async_answer_0(icall, rc);
return;
}
fibril_rwlock_read_unlock(&device_tree.rwlock);
errno_t retval = async_data_read_finalize(&call, hdl_buf, size);
free(hdl_buf);
async_answer_1(icall, retval, act_size);
}
static void devman_fun_get_child(ipc_call_t *icall)
{
fun_node_t *fun;
fibril_rwlock_read_lock(&device_tree.rwlock);
fun = find_fun_node_no_lock(&device_tree, ipc_get_arg1(icall));
if (fun == NULL || fun->state == FUN_REMOVED) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
async_answer_0(icall, ENOENT);
return;
}
if (fun->child == NULL) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
async_answer_0(icall, ENOENT);
return;
}
async_answer_1(icall, EOK, fun->child->handle);
fibril_rwlock_read_unlock(&device_tree.rwlock);
}
static void devman_fun_online(ipc_call_t *icall)
{
fun_node_t *fun;
errno_t rc;
fun = find_fun_node(&device_tree, ipc_get_arg1(icall));
if (fun == NULL) {
async_answer_0(icall, ENOENT);
return;
}
rc = driver_fun_online(&device_tree, fun);
fun_del_ref(fun);
async_answer_0(icall, rc);
}
static void devman_fun_offline(ipc_call_t *icall)
{
fun_node_t *fun;
errno_t rc;
fun = find_fun_node(&device_tree, ipc_get_arg1(icall));
if (fun == NULL) {
async_answer_0(icall, ENOENT);
return;
}
rc = driver_fun_offline(&device_tree, fun);
fun_del_ref(fun);
async_answer_0(icall, rc);
}
static void devman_fun_sid_to_handle(ipc_call_t *icall)
{
fun_node_t *fun;
fun = find_loc_tree_function(&device_tree, ipc_get_arg1(icall));
if (fun == NULL) {
async_answer_0(icall, ENOENT);
return;
}
fibril_rwlock_read_lock(&device_tree.rwlock);
if (fun->state == FUN_REMOVED) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
async_answer_0(icall, ENOENT);
return;
}
async_answer_1(icall, EOK, fun->handle);
fibril_rwlock_read_unlock(&device_tree.rwlock);
fun_del_ref(fun);
}
static void devman_get_drivers(ipc_call_t *icall)
{
ipc_call_t call;
size_t size;
size_t act_size;
errno_t rc;
if (!async_data_read_receive(&call, &size)) {
async_answer_0(icall, EREFUSED);
return;
}
devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
if (hdl_buf == NULL) {
async_answer_0(&call, ENOMEM);
async_answer_0(icall, ENOMEM);
return;
}
rc = driver_get_list(&drivers_list, hdl_buf, size, &act_size);
if (rc != EOK) {
async_answer_0(&call, rc);
async_answer_0(icall, rc);
return;
}
errno_t retval = async_data_read_finalize(&call, hdl_buf, size);
free(hdl_buf);
async_answer_1(icall, retval, act_size);
}
static void devman_driver_get_devices(ipc_call_t *icall)
{
ipc_call_t call;
size_t size;
size_t act_size;
errno_t rc;
if (!async_data_read_receive(&call, &size)) {
async_answer_0(icall, EREFUSED);
return;
}
driver_t *drv = driver_find(&drivers_list, ipc_get_arg1(icall));
if (drv == NULL) {
async_answer_0(&call, ENOENT);
async_answer_0(icall, ENOENT);
return;
}
devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
if (hdl_buf == NULL) {
async_answer_0(&call, ENOMEM);
async_answer_0(icall, ENOMEM);
return;
}
rc = driver_get_devices(drv, hdl_buf, size, &act_size);
if (rc != EOK) {
fibril_rwlock_read_unlock(&device_tree.rwlock);
async_answer_0(&call, rc);
async_answer_0(icall, rc);
return;
}
errno_t retval = async_data_read_finalize(&call, hdl_buf, size);
free(hdl_buf);
async_answer_1(icall, retval, act_size);
}
static void devman_driver_get_handle(ipc_call_t *icall)
{
char *drvname;
errno_t rc = async_data_write_accept((void **) &drvname, true, 0, 0, 0, 0);
if (rc != EOK) {
async_answer_0(icall, rc);
return;
}
driver_t *driver = driver_find_by_name(&drivers_list, drvname);
free(drvname);
if (driver == NULL) {
async_answer_0(icall, ENOENT);
return;
}
async_answer_1(icall, EOK, driver->handle);
}
static void devman_driver_get_match_id(ipc_call_t *icall)
{
devman_handle_t handle = ipc_get_arg1(icall);
size_t index = ipc_get_arg2(icall);
driver_t *drv = driver_find(&drivers_list, handle);
if (drv == NULL) {
async_answer_0(icall, ENOMEM);
return;
}
ipc_call_t data;
size_t data_len;
if (!async_data_read_receive(&data, &data_len)) {
async_answer_0(icall, EINVAL);
return;
}
void *buffer = malloc(data_len);
if (buffer == NULL) {
async_answer_0(&data, ENOMEM);
async_answer_0(icall, ENOMEM);
return;
}
fibril_mutex_lock(&drv->driver_mutex);
link_t *link = list_nth(&drv->match_ids.ids, index);
if (link == NULL) {
fibril_mutex_unlock(&drv->driver_mutex);
free(buffer);
async_answer_0(&data, ENOMEM);
async_answer_0(icall, ENOMEM);
return;
}
match_id_t *mid = list_get_instance(link, match_id_t, link);
size_t sent_length = str_size(mid->id);
if (sent_length > data_len) {
sent_length = data_len;
}
async_data_read_finalize(&data, mid->id, sent_length);
async_answer_1(icall, EOK, mid->score);
fibril_mutex_unlock(&drv->driver_mutex);
free(buffer);
}
static void devman_driver_get_name(ipc_call_t *icall)
{
devman_handle_t handle = ipc_get_arg1(icall);
driver_t *drv = driver_find(&drivers_list, handle);
if (drv == NULL) {
async_answer_0(icall, ENOMEM);
return;
}
ipc_call_t data;
size_t data_len;
if (!async_data_read_receive(&data, &data_len)) {
async_answer_0(icall, EINVAL);
return;
}
void *buffer = malloc(data_len);
if (buffer == NULL) {
async_answer_0(&data, ENOMEM);
async_answer_0(icall, ENOMEM);
return;
}
fibril_mutex_lock(&drv->driver_mutex);
size_t sent_length = str_size(drv->name);
if (sent_length > data_len) {
sent_length = data_len;
}
async_data_read_finalize(&data, drv->name, sent_length);
async_answer_0(icall, EOK);
fibril_mutex_unlock(&drv->driver_mutex);
free(buffer);
}
static void devman_driver_get_state(ipc_call_t *icall)
{
driver_t *drv;
drv = driver_find(&drivers_list, ipc_get_arg1(icall));
if (drv == NULL) {
async_answer_0(icall, ENOENT);
return;
}
async_answer_1(icall, EOK, (sysarg_t) drv->state);
}
static void devman_driver_load(ipc_call_t *icall)
{
driver_t *drv;
errno_t rc;
drv = driver_find(&drivers_list, ipc_get_arg1(icall));
if (drv == NULL) {
async_answer_0(icall, ENOENT);
return;
}
fibril_mutex_lock(&drv->driver_mutex);
rc = start_driver(drv) ? EOK : EIO;
fibril_mutex_unlock(&drv->driver_mutex);
async_answer_0(icall, rc);
}
static void devman_driver_unload(ipc_call_t *icall)
{
driver_t *drv;
errno_t rc;
drv = driver_find(&drivers_list, ipc_get_arg1(icall));
if (drv == NULL) {
async_answer_0(icall, ENOENT);
return;
}
fibril_mutex_lock(&drv->driver_mutex);
rc = stop_driver(drv);
fibril_mutex_unlock(&drv->driver_mutex);
async_answer_0(icall, rc);
}
void devman_connection_client(ipc_call_t *icall, void *arg)
{
async_accept_0(icall);
while (true) {
ipc_call_t call;
async_get_call(&call);
if (!ipc_get_imethod(&call)) {
async_answer_0(&call, EOK);
break;
}
switch (ipc_get_imethod(&call)) {
case DEVMAN_DEVICE_GET_HANDLE:
devman_function_get_handle(&call);
break;
case DEVMAN_DEV_GET_PARENT:
devman_dev_get_parent(&call);
break;
case DEVMAN_DEV_GET_FUNCTIONS:
devman_dev_get_functions(&call);
break;
case DEVMAN_FUN_GET_CHILD:
devman_fun_get_child(&call);
break;
case DEVMAN_FUN_GET_MATCH_ID:
devman_fun_get_match_id(&call);
break;
case DEVMAN_FUN_GET_NAME:
devman_fun_get_name(&call);
break;
case DEVMAN_FUN_GET_DRIVER_NAME:
devman_fun_get_driver_name(&call);
break;
case DEVMAN_FUN_GET_PATH:
devman_fun_get_path(&call);
break;
case DEVMAN_FUN_ONLINE:
devman_fun_online(&call);
break;
case DEVMAN_FUN_OFFLINE:
devman_fun_offline(&call);
break;
case DEVMAN_FUN_SID_TO_HANDLE:
devman_fun_sid_to_handle(&call);
break;
case DEVMAN_GET_DRIVERS:
devman_get_drivers(&call);
break;
case DEVMAN_DRIVER_GET_DEVICES:
devman_driver_get_devices(&call);
break;
case DEVMAN_DRIVER_GET_HANDLE:
devman_driver_get_handle(&call);
break;
case DEVMAN_DRIVER_GET_MATCH_ID:
devman_driver_get_match_id(&call);
break;
case DEVMAN_DRIVER_GET_NAME:
devman_driver_get_name(&call);
break;
case DEVMAN_DRIVER_GET_STATE:
devman_driver_get_state(&call);
break;
case DEVMAN_DRIVER_LOAD:
devman_driver_load(&call);
break;
case DEVMAN_DRIVER_UNLOAD:
devman_driver_unload(&call);
break;
default:
async_answer_0(&call, ENOENT);
}
}
}
HelenOS homepage, sources at GitHub