46,7 → 46,8 |
#include <string.h> |
#include <ipc/devmap.h> |
|
#define NAME "devmap" |
#define NAME "devmap" |
#define NULL_DEVICES 256 |
|
/** Representation of device driver. |
* |
83,16 → 84,8 |
devmap_driver_t *driver; |
} devmap_device_t; |
|
/** 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); |
|
/* Locking order: |
* drivers_list_mutex |
102,10 → 95,13 |
**/ |
|
static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex); |
static FIBRIL_CONDVAR_INITIALIZE(devices_list_cv); |
static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex); |
static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex); |
static FIBRIL_MUTEX_INITIALIZE(null_devices_mutex); |
|
static dev_handle_t last_handle = 0; |
static devmap_device_t *null_devices[NULL_DEVICES]; |
|
static dev_handle_t devmap_create_handle(void) |
{ |
174,10 → 170,8 |
} |
|
/** |
* |
* 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) |
{ |
191,10 → 185,8 |
} |
|
/** |
* |
* Read info about new driver and add it into linked list of registered |
* drivers. |
* |
*/ |
static void devmap_driver_register(devmap_driver_t **odriver) |
{ |
344,31 → 336,6 |
return EOK; |
} |
|
|
/** Process pending lookup requests */ |
static void process_pending_lookup(void) |
{ |
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 |
* |
*/ |
445,6 → 412,7 |
list_append(&device->driver_devices, &device->driver->devices); |
|
fibril_mutex_unlock(&device->driver->devices_mutex); |
fibril_condvar_broadcast(&devices_list_cv); |
fibril_mutex_unlock(&devices_list_mutex); |
|
ipc_answer_1(iid, EOK, device->handle); |
530,10 → 498,14 |
} |
name[size] = '\0'; |
|
fibril_mutex_lock(&devices_list_mutex); |
const devmap_device_t *dev; |
recheck: |
|
/* |
* Find device name in linked list of known devices. |
* Find device name in the list of known devices. |
*/ |
const devmap_device_t *dev = devmap_device_find_name(name); |
dev = devmap_device_find_name(name); |
|
/* |
* Device was not found. |
540,24 → 512,18 |
*/ |
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; |
} |
|
pr->name = name; |
pr->callid = iid; |
list_append(&pr->link, &pending_req); |
return; |
/* Blocking lookup */ |
fibril_condvar_wait(&devices_list_cv, |
&devices_list_mutex); |
goto recheck; |
} |
|
ipc_answer_0(iid, ENOENT); |
free(name); |
fibril_mutex_unlock(&devices_list_mutex); |
return; |
} |
fibril_mutex_unlock(&devices_list_mutex); |
|
ipc_answer_1(iid, EOK, dev->handle); |
free(name); |
655,21 → 621,43 |
ipc_answer_1(iid, EOK, pos); |
} |
|
/** Initialize device mapper. |
* |
* |
*/ |
static bool devmap_init() |
static void devmap_null_create(ipc_callid_t iid, ipc_call_t *icall) |
{ |
fibril_mutex_lock(&null_devices_mutex); |
|
unsigned int i; |
bool fnd = false; |
|
for (i = 0; i < NULL_DEVICES; i++) { |
if (null_devices[i] == NULL) { |
fnd = true; |
break; |
} |
} |
|
if (!fnd) { |
fibril_mutex_unlock(&null_devices_mutex); |
ipc_answer_0(iid, ENOMEM); |
return; |
} |
|
/* Create NULL device entry */ |
devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t)); |
if (device == NULL) |
return false; |
if (device == NULL) { |
fibril_mutex_unlock(&null_devices_mutex); |
ipc_answer_0(iid, ENOMEM); |
return; |
} |
|
device->name = str_dup("null"); |
char null[DEVMAP_NAME_MAXLEN]; |
snprintf(null, DEVMAP_NAME_MAXLEN, "null%u", i); |
|
device->name = str_dup(null); |
if (device->name == NULL) { |
fibril_mutex_unlock(&null_devices_mutex); |
free(device); |
return false; |
ipc_answer_0(iid, ENOMEM); |
return; |
} |
|
list_initialize(&(device->devices)); |
681,11 → 669,50 |
device->handle = devmap_create_handle(); |
device->driver = NULL; |
|
/* Insert device into list of all devices */ |
/* Insert device into list of all devices |
and into null devices array */ |
list_append(&device->devices, &devices_list); |
null_devices[i] = device; |
|
fibril_mutex_unlock(&devices_list_mutex); |
fibril_mutex_unlock(&null_devices_mutex); |
|
ipc_answer_1(iid, EOK, (ipcarg_t) i); |
} |
|
static void devmap_null_destroy(ipc_callid_t iid, ipc_call_t *icall) |
{ |
fibril_mutex_lock(&null_devices_mutex); |
|
ipcarg_t i = IPC_GET_ARG1(*icall); |
|
if (null_devices[i] == NULL) { |
ipc_answer_0(iid, ENOENT); |
return; |
} |
|
devmap_device_unregister_core(null_devices[i]); |
null_devices[i] = NULL; |
|
fibril_mutex_unlock(&null_devices_mutex); |
|
ipc_answer_0(iid, EOK); |
} |
|
/** Initialize device mapper. |
* |
* |
*/ |
static bool devmap_init(void) |
{ |
fibril_mutex_lock(&null_devices_mutex); |
|
unsigned int i; |
for (i = 0; i < NULL_DEVICES; i++) |
null_devices[i] = NULL; |
|
fibril_mutex_unlock(&null_devices_mutex); |
|
return true; |
} |
|
738,7 → 765,7 |
} |
} |
|
if (NULL != driver) { |
if (driver != NULL) { |
/* |
* Unregister the device driver and all its devices. |
*/ |
770,6 → 797,12 |
case DEVMAP_DEVICE_GET_NAME: |
devmap_get_name(callid, &call); |
break; |
case DEVMAP_DEVICE_NULL_CREATE: |
devmap_null_create(callid, &call); |
break; |
case DEVMAP_DEVICE_NULL_DESTROY: |
devmap_null_destroy(callid, &call); |
break; |
case DEVMAP_DEVICE_GET_COUNT: |
devmap_get_count(callid, &call); |
break; |
818,9 → 851,7 |
return -1; |
} |
|
/* Set a handler of incomming connections and |
pending operations */ |
async_set_pending(process_pending_lookup); |
/* Set a handler of incomming connections */ |
async_set_client_connection(devmap_connection); |
|
/* Register device mapper at naming service */ |