Subversion Repositories HelenOS

Compare Revisions

Regard whitespace Rev 4054 → Rev 4055

/branches/dd/uspace/srv/devmap/devmap.c
44,14 → 44,22
#include <futex.h>
#include <stdlib.h>
#include <string.h>
#include <ipc/devmap.h>
 
#include "devmap.h"
#define NAME "devmap"
 
/** Pending lookup structure. */
typedef struct {
link_t link;
char *name; /**< Device name */
ipc_callid_t callid; /**< Call ID waiting for the lookup */
} pending_req_t;
 
LIST_INITIALIZE(devices_list);
LIST_INITIALIZE(drivers_list);
LIST_INITIALIZE(pending_req);
 
/* order of locking:
/* Locking order:
* drivers_list_futex
* devices_list_futex
* (devmap_driver_t *)->devices_futex
62,7 → 70,6
static atomic_t drivers_list_futex = FUTEX_INITIALIZER;
static atomic_t create_handle_futex = FUTEX_INITIALIZER;
 
 
static int devmap_create_handle(void)
{
static int last_handle = 0;
69,7 → 76,9
int handle;
 
/* TODO: allow reusing old handles after their unregistration
and implement some version of LRU algorithm */
* and implement some version of LRU algorithm
*/
/* FIXME: overflow */
futex_down(&create_handle_futex);
 
98,24 → 107,18
*/
static devmap_device_t *devmap_device_find_name(const char *name)
{
link_t *item;
link_t *item = devices_list.next;
devmap_device_t *device = NULL;
 
item = devices_list.next;
 
while (item != &devices_list) {
 
device = list_get_instance(item, devmap_device_t, devices);
if (0 == strcmp(device->name, name)) {
if (0 == strcmp(device->name, name))
break;
}
item = item->next;
}
 
if (item == &devices_list) {
printf("DEVMAP: no device named %s.\n", name);
if (item == &devices_list)
return NULL;
}
 
device = list_get_instance(item, devmap_device_t, devices);
return device;
122,23 → 125,21
}
 
/** Find device with given handle.
*
* @todo: use hash table
*
*/
static devmap_device_t *devmap_device_find_handle(int handle)
{
link_t *item;
devmap_device_t *device = NULL;
futex_down(&devices_list_futex);
 
item = (&devices_list)->next;
link_t *item = (&devices_list)->next;
devmap_device_t *device = NULL;
 
while (item != &devices_list) {
 
device = list_get_instance(item, devmap_device_t, devices);
if (device->handle == handle) {
if (device->handle == handle)
break;
}
item = item->next;
}
 
155,12 → 156,13
}
 
/**
*
* Unregister device and free it. It's assumed that driver's device list is
* already locked.
*
*/
static int devmap_device_unregister_core(devmap_device_t *device)
{
 
list_remove(&(device->devices));
list_remove(&(device->driver_devices));
 
167,26 → 169,21
free(device->name);
free(device);
 
 
return EOK;
}
 
/**
*
* Read info about new driver and add it into linked list of registered
* drivers.
*
*/
static void devmap_driver_register(devmap_driver_t **odriver)
{
size_t name_size;
ipc_callid_t callid;
ipc_call_t call;
devmap_driver_t *driver;
ipc_callid_t iid;
ipc_call_t icall;
 
*odriver = NULL;
iid = async_get_call(&icall);
ipc_call_t icall;
ipc_callid_t iid = async_get_call(&icall);
 
if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
ipc_answer_0(iid, EREFUSED);
193,8 → 190,9
return;
}
 
if (NULL ==
(driver = (devmap_driver_t *)malloc(sizeof(devmap_driver_t)))) {
devmap_driver_t *driver = (devmap_driver_t *) malloc(sizeof(devmap_driver_t));
if (driver == NULL) {
ipc_answer_0(iid, ENOMEM);
return;
}
202,8 → 200,9
/*
* Get driver name
*/
ipc_callid_t callid;
size_t name_size;
if (!ipc_data_write_receive(&callid, &name_size)) {
printf("Unexpected request.\n");
free(driver);
ipc_answer_0(callid, EREFUSED);
ipc_answer_0(iid, EREFUSED);
211,8 → 210,6
}
 
if (name_size > DEVMAP_NAME_MAXLEN) {
printf("Too logn name: %u: maximum is %u.\n", name_size,
DEVMAP_NAME_MAXLEN);
free(driver);
ipc_answer_0(callid, EINVAL);
ipc_answer_0(iid, EREFUSED);
222,8 → 219,8
/*
* Allocate buffer for device name.
*/
if (NULL == (driver->name = (char *)malloc(name_size + 1))) {
printf("Cannot allocate space for driver name.\n");
driver->name = (char *) malloc(name_size + 1);
if (driver->name == NULL) {
free(driver);
ipc_answer_0(callid, ENOMEM);
ipc_answer_0(iid, EREFUSED);
234,7 → 231,6
* Send confirmation to sender and get data into buffer.
*/
if (EOK != ipc_data_write_finalize(callid, driver->name, name_size)) {
printf("Cannot read driver name.\n");
free(driver->name);
free(driver);
ipc_answer_0(iid, EREFUSED);
243,8 → 239,6
 
driver->name[name_size] = 0;
 
printf("Read driver name: '%s'.\n", driver->name);
 
/* Initialize futex for list of devices owned by this driver */
futex_initialize(&(driver->devices_futex), 1);
 
256,11 → 250,10
/*
* Create connection to the driver
*/
ipc_call_t call;
callid = async_get_call(&call);
 
if (IPC_M_CONNECT_TO_ME != IPC_GET_METHOD(call)) {
printf("DEVMAP: Unexpected method: %u.\n",
IPC_GET_METHOD(call));
ipc_answer_0(callid, ENOTSUP);
free(driver->name);
288,25 → 281,20
futex_up(&drivers_list_futex);
ipc_answer_0(iid, EOK);
printf("Driver registered.\n");
 
*odriver = driver;
return;
}
 
/** Unregister device driver, unregister all its devices and free driver
/**
* Unregister device driver, unregister all its devices and free driver
* structure.
*
*/
static int devmap_driver_unregister(devmap_driver_t *driver)
{
devmap_device_t *device;
 
if (NULL == driver) {
printf("Error: driver == NULL.\n");
if (driver == NULL)
return EEXISTS;
}
 
printf("Unregister driver '%s'.\n", driver->name);
futex_down(&drivers_list_futex);
 
ipc_hangup(driver->phone);
320,9 → 308,8
futex_down(&(driver->devices_futex));
 
while (!list_empty(&(driver->devices))) {
device = list_get_instance(driver->devices.next,
devmap_device_t *device = list_get_instance(driver->devices.next,
devmap_device_t, driver_devices);
printf("Unregister device '%s'.\n", device->name);
devmap_device_unregister_core(device);
}
331,18 → 318,38
futex_up(&drivers_list_futex);
 
/* free name and driver */
if (NULL != driver->name) {
if (NULL != driver->name)
free(driver->name);
}
 
free(driver);
 
printf("Driver unregistered.\n");
 
return EOK;
}
 
 
/** Process pending lookup requests */
static void process_pending_lookup()
{
link_t *cur;
loop:
for (cur = pending_req.next; cur != &pending_req; cur = cur->next) {
pending_req_t *pr = list_get_instance(cur, pending_req_t, link);
const devmap_device_t *dev = devmap_device_find_name(pr->name);
if (!dev)
continue;
ipc_answer_1(pr->callid, EOK, dev->handle);
free(pr->name);
list_remove(cur);
free(pr);
goto loop;
}
}
 
 
/** Register instance of device
*
*/
349,34 → 356,28
static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
devmap_driver_t *driver)
{
ipc_callid_t callid;
size_t size;
devmap_device_t *device;
 
if (NULL == driver) {
printf("Invalid driver registration.\n");
if (driver == NULL) {
ipc_answer_0(iid, EREFUSED);
return;
}
/* Create new device entry */
if (NULL ==
(device = (devmap_device_t *)malloc(sizeof(devmap_device_t)))) {
printf("Cannot allocate new device.\n");
devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
if (device == NULL) {
ipc_answer_0(iid, ENOMEM);
return;
}
/* Get device name */
ipc_callid_t callid;
size_t size;
if (!ipc_data_write_receive(&callid, &size)) {
free(device);
printf("Cannot read device name.\n");
ipc_answer_0(iid, EREFUSED);
return;
}
 
if (size > DEVMAP_NAME_MAXLEN) {
printf("Too long device name: %u.\n", size);
free(device);
ipc_answer_0(callid, EINVAL);
ipc_answer_0(iid, EREFUSED);
386,8 → 387,7
/* +1 for terminating \0 */
device->name = (char *)malloc(size + 1);
 
if (NULL == device->name) {
printf("Cannot read device name.\n");
if (device->name == NULL) {
free(device);
ipc_answer_0(callid, ENOMEM);
ipc_answer_0(iid, EREFUSED);
404,7 → 404,7
 
/* Check that device with such name is not already registered */
if (NULL != devmap_device_find_name(device->name)) {
printf("Device '%s' already registered.\n", device->name);
printf(NAME ": Device '%s' already registered\n", device->name);
futex_up(&devices_list_futex);
free(device->name);
free(device);
428,10 → 428,9
futex_up(&device->driver->devices_futex);
futex_up(&devices_list_futex);
 
printf("Device '%s' registered.\n", device->name);
ipc_answer_1(iid, EOK, device->handle);
 
return;
process_pending_lookup();
}
 
/**
441,28 → 440,24
devmap_driver_t *driver)
{
/* TODO */
 
return EOK;
}
 
/** Connect client to the device.
*
* Find device driver owning requested device and forward
* the message to it.
*
*/
static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
{
devmap_device_t *dev;
int handle;
 
/*
* Get handle from request
*/
handle = IPC_GET_ARG2(*call);
dev = devmap_device_find_handle(handle);
int handle = IPC_GET_ARG2(*call);
devmap_device_t *dev = devmap_device_find_handle(handle);
 
if (NULL == dev) {
printf("DEVMAP: No registered device with handle %d.\n",
handle);
ipc_answer_0(callid, ENOENT);
return;
}
469,33 → 464,29
 
ipc_forward_fast(callid, dev->driver->phone, (ipcarg_t)(dev->handle),
IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
return;
}
 
/** Find handle for device instance identified by name.
*
* In answer will be send EOK and device handle in arg1 or a error
* code from errno.h.
*
*/
static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
{
char *name = NULL;
size_t name_size;
const devmap_device_t *dev;
ipc_callid_t callid;
ipcarg_t retval;
/*
* Wait for incoming message with device name (but do not
* read the name itself until the buffer is allocated).
*/
if (!ipc_data_write_receive(&callid, &name_size)) {
ipc_callid_t callid;
size_t size;
if (!ipc_data_write_receive(&callid, &size)) {
ipc_answer_0(callid, EREFUSED);
ipc_answer_0(iid, EREFUSED);
return;
}
 
if (name_size > DEVMAP_NAME_MAXLEN) {
if ((size < 1) || (size > DEVMAP_NAME_MAXLEN)) {
ipc_answer_0(callid, EINVAL);
ipc_answer_0(iid, EREFUSED);
return;
504,7 → 495,8
/*
* Allocate buffer for device name.
*/
if (NULL == (name = (char *)malloc(name_size))) {
char *name = (char *) malloc(size);
if (name == NULL) {
ipc_answer_0(callid, ENOMEM);
ipc_answer_0(iid, EREFUSED);
return;
513,47 → 505,58
/*
* Send confirmation to sender and get data into buffer.
*/
if (EOK != (retval = ipc_data_write_finalize(callid, name,
name_size))) {
ipcarg_t retval = ipc_data_write_finalize(callid, name, size);
if (retval != EOK) {
ipc_answer_0(iid, EREFUSED);
free(name);
return;
}
name[size] = '\0';
 
/*
* Find device name in linked list of known devices.
*/
dev = devmap_device_find_name(name);
const devmap_device_t *dev = devmap_device_find_name(name);
 
/*
* Device was not found.
*/
if (NULL == dev) {
printf("DEVMAP: device %s has not been registered.\n", name);
ipc_answer_0(iid, ENOENT);
if (dev == NULL) {
if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
/* Blocking lookup, add to pending list */
pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t));
if (!pr) {
ipc_answer_0(iid, ENOMEM);
free(name);
return;
}
 
printf("DEVMAP: device %s has handler %d.\n", name, dev->handle);
pr->name = name;
pr->callid = iid;
list_append(&pr->link, &pending_req);
return;
}
ipc_answer_1(iid, EOK, dev->handle);
 
ipc_answer_0(iid, ENOENT);
free(name);
return;
}
 
ipc_answer_1(iid, EOK, dev->handle);
free(name);
}
 
/** Find name of device identified by id and send it to caller.
*
*/
static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
{
const devmap_device_t *device;
size_t name_size;
const devmap_device_t *device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
 
device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
 
/*
* Device not found.
*/
if (NULL == device) {
if (device == NULL) {
ipc_answer_0(iid, ENOENT);
return;
}
560,60 → 563,51
 
ipc_answer_0(iid, EOK);
 
name_size = strlen(device->name);
size_t name_size = strlen(device->name);
 
 
/* FIXME:
we have no channel from DEVMAP to client ->
sending must be initiated by client
* We have no channel from DEVMAP to client, therefore
* sending must be initiated by client.
*
* int rc = ipc_data_write_send(phone, device->name, name_size);
* if (rc != EOK) {
* async_wait_for(req, NULL);
* return rc;
* }
*/
 
int rc = ipc_data_write_send(phone, device->name, name_size);
if (rc != EOK) {
async_wait_for(req, NULL);
return rc;
}
*/
/* TODO: send name in response */
 
return;
}
 
/** Handle connection with device driver.
*
*/
static void
devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
{
ipc_callid_t callid;
ipc_call_t call;
bool cont = true;
devmap_driver_t *driver = NULL;
 
/* Accept connection */
ipc_answer_0(iid, EOK);
 
devmap_driver_t *driver = NULL;
devmap_driver_register(&driver);
 
if (NULL == driver) {
printf("DEVMAP: driver registration failed.\n");
if (NULL == driver)
return;
}
bool cont = true;
while (cont) {
callid = async_get_call(&call);
ipc_call_t call;
ipc_callid_t callid = async_get_call(&call);
 
switch (IPC_GET_METHOD(call)) {
case IPC_M_PHONE_HUNGUP:
printf("DEVMAP: connection hung up.\n");
cont = false;
continue; /* Exit thread */
/* Exit thread */
continue;
case DEVMAP_DRIVER_UNREGISTER:
printf("DEVMAP: unregister driver.\n");
if (NULL == driver) {
printf("DEVMAP: driver was not registered!\n");
if (NULL == driver)
ipc_answer_0(callid, ENOENT);
} else {
else
ipc_answer_0(callid, EOK);
}
break;
case DEVMAP_DEVICE_REGISTER:
/* Register one instance of device */
630,11 → 624,10
devmap_get_handle(callid, &call);
break;
default:
if (!(callid & IPC_CALLID_NOTIFICATION)) {
if (!(callid & IPC_CALLID_NOTIFICATION))
ipc_answer_0(callid, ENOENT);
}
}
}
if (NULL != driver) {
/*
643,33 → 636,28
devmap_driver_unregister(driver);
driver = NULL;
}
}
 
/** Handle connection with device client.
*
*/
static void
devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
{
ipc_callid_t callid;
ipc_call_t call;
/* Accept connection */
ipc_answer_0(iid, EOK);
bool cont = true;
 
ipc_answer_0(iid, EOK); /* Accept connection */
 
while (cont) {
callid = async_get_call(&call);
ipc_call_t call;
ipc_callid_t callid = async_get_call(&call);
 
switch (IPC_GET_METHOD(call)) {
case IPC_M_PHONE_HUNGUP:
printf("DEVMAP: connection hung up.\n");
cont = false;
continue; /* Exit thread */
 
/* Exit thread */
continue;
case DEVMAP_DEVICE_GET_HANDLE:
devmap_get_handle(callid, &call);
 
break;
case DEVMAP_DEVICE_GET_NAME:
/* TODO */
676,22 → 664,17
devmap_get_name(callid, &call);
break;
default:
if (!(callid & IPC_CALLID_NOTIFICATION)) {
if (!(callid & IPC_CALLID_NOTIFICATION))
ipc_answer_0(callid, ENOENT);
}
}
}
}
 
/** Function for handling connections to devmap
*
*/
static void
devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
{
 
printf("DEVMAP: new connection.\n");
 
/* Select interface */
switch ((ipcarg_t)(IPC_GET_ARG1(*icall))) {
case DEVMAP_DRIVER:
702,20 → 685,12
break;
case DEVMAP_CONNECT_TO_DEVICE:
/* Connect client to selected device */
printf("DEVMAP: connect to device %d.\n",
IPC_GET_ARG2(*icall));
devmap_forward(iid, icall);
break;
default:
ipc_answer_0(iid, ENOENT); /* No such interface */
printf("DEVMAP: Unknown interface %u.\n",
(ipcarg_t)(IPC_GET_ARG1(*icall)));
/* No such interface */
ipc_answer_0(iid, ENOENT);
}
 
/* Cleanup */
printf("DEVMAP: connection closed.\n");
return;
}
 
/**
723,12 → 698,10
*/
int main(int argc, char *argv[])
{
ipcarg_t phonead;
printf(NAME ": HelenOS Device Mapper\n");
 
printf("DEVMAP: HelenOS device mapper.\n");
 
if (devmap_init() != 0) {
printf("Error while initializing DEVMAP service.\n");
printf(NAME ": Error while initializing service\n");
return -1;
}
 
736,10 → 709,13
async_set_client_connection(devmap_connection);
 
/* Register device mapper at naming service */
ipcarg_t phonead;
if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0)
return -1;
printf(NAME ": Accepting connections\n");
async_manager();
/* Never reached */
return 0;
}
747,4 → 723,3
/**
* @}
*/