source: mainline/uspace/srv/devmap/devmap.c@ 1d1bb0f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1d1bb0f was 9934f7d, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Add extra argument to async connection handlers that can be used for passing
information from async_connect_to_me() to the handler.

  • Property mode set to 100644
File size: 27.0 KB
RevLine 
[13125d3]1/*
2 * Copyright (c) 2007 Josef Cejka
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @defgroup devmap Device mapper.
[6519d6f]31 * @brief HelenOS device mapper.
[13125d3]32 * @{
[6519d6f]33 */
[13125d3]34
35/** @file
36 */
37
38#include <ipc/services.h>
[79ae36dd]39#include <ns.h>
[13125d3]40#include <async.h>
41#include <stdio.h>
42#include <errno.h>
[07e4a3c]43#include <bool.h>
[1e4cada]44#include <fibril_synch.h>
[798f364]45#include <stdlib.h>
[19f857a]46#include <str.h>
[21c5d41]47#include <ipc/devmap.h>
[01b87dc5]48#include <assert.h>
[13125d3]49
[7fcb74c]50#define NAME "devmap"
51#define NULL_DEVICES 256
[13125d3]52
[cb41a5e]53/** Representation of device driver.
54 *
55 * Each driver is responsible for a set of devices.
56 *
57 */
58typedef struct {
59 /** Pointers to previous and next drivers in linked list */
60 link_t drivers;
[79ae36dd]61
[cb41a5e]62 /** Pointer to the linked list of devices controlled by this driver */
63 link_t devices;
[79ae36dd]64
65 /** Session asociated with this driver */
66 async_sess_t *sess;
67
[cb41a5e]68 /** Device driver name */
69 char *name;
[79ae36dd]70
[fc02cc41]71 /** Fibril mutex for list of devices owned by this driver */
72 fibril_mutex_t devices_mutex;
[cb41a5e]73} devmap_driver_t;
74
[1313ee9]75/** Info about registered namespaces
76 *
77 */
78typedef struct {
79 /** Pointer to the previous and next device in the list of all namespaces */
80 link_t namespaces;
[79ae36dd]81
[1313ee9]82 /** Unique namespace identifier */
[991f645]83 devmap_handle_t handle;
[79ae36dd]84
[1313ee9]85 /** Namespace name */
86 char *name;
[79ae36dd]87
[1313ee9]88 /** Reference count */
89 size_t refcnt;
90} devmap_namespace_t;
91
[cb41a5e]92/** Info about registered device
93 *
94 */
95typedef struct {
96 /** Pointer to the previous and next device in the list of all devices */
97 link_t devices;
98 /** Pointer to the previous and next device in the list of devices
99 owned by one driver */
100 link_t driver_devices;
[1313ee9]101 /** Unique device identifier */
[991f645]102 devmap_handle_t handle;
[1313ee9]103 /** Device namespace */
104 devmap_namespace_t *namespace;
[cb41a5e]105 /** Device name */
106 char *name;
107 /** Device driver handling this device */
108 devmap_driver_t *driver;
[47a7174f]109 /** Use this interface when forwarding to driver. */
110 sysarg_t forward_interface;
[cb41a5e]111} devmap_device_t;
112
[798f364]113LIST_INITIALIZE(devices_list);
[1313ee9]114LIST_INITIALIZE(namespaces_list);
[798f364]115LIST_INITIALIZE(drivers_list);
[c07af37]116
[fc02cc41]117/* Locking order:
118 * drivers_list_mutex
119 * devices_list_mutex
120 * (devmap_driver_t *)->devices_mutex
121 * create_handle_mutex
122 **/
123
124static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex);
[1cab2f41]125static FIBRIL_CONDVAR_INITIALIZE(devices_list_cv);
[fc02cc41]126static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex);
127static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex);
[7fcb74c]128static FIBRIL_MUTEX_INITIALIZE(null_devices_mutex);
[fc02cc41]129
[991f645]130static devmap_handle_t last_handle = 0;
[7fcb74c]131static devmap_device_t *null_devices[NULL_DEVICES];
[cb41a5e]132
[63e0bdd]133/*
134 * Dummy list for null devices. This is necessary so that null devices can
135 * be used just as any other devices, e.g. in devmap_device_unregister_core().
136 */
137static LIST_INITIALIZE(dummy_null_driver_devices);
138
[991f645]139static devmap_handle_t devmap_create_handle(void)
[798f364]140{
141 /* TODO: allow reusing old handles after their unregistration
[5d0e461]142 * and implement some version of LRU algorithm, avoid overflow
[6519d6f]143 */
144
[fc02cc41]145 fibril_mutex_lock(&create_handle_mutex);
[cb41a5e]146 last_handle++;
[fc02cc41]147 fibril_mutex_unlock(&create_handle_mutex);
[6519d6f]148
[cb41a5e]149 return last_handle;
[13125d3]150}
151
[1313ee9]152/** Convert fully qualified device name to namespace and device name.
153 *
154 * A fully qualified device name can be either a plain device name
155 * (then the namespace is considered to be an empty string) or consist
156 * of two components separated by a slash. No more than one slash
157 * is allowed.
158 *
159 */
160static bool devmap_fqdn_split(const char *fqdn, char **ns_name, char **name)
161{
162 size_t cnt = 0;
163 size_t slash_offset = 0;
164 size_t slash_after = 0;
165
166 size_t offset = 0;
167 size_t offset_prev = 0;
168 wchar_t c;
169
170 while ((c = str_decode(fqdn, &offset, STR_NO_LIMIT)) != 0) {
171 if (c == '/') {
172 cnt++;
173 slash_offset = offset_prev;
174 slash_after = offset;
175 }
176 offset_prev = offset;
177 }
178
179 /* More than one slash */
180 if (cnt > 1)
181 return false;
182
183 /* No slash -> namespace is empty */
184 if (cnt == 0) {
185 *ns_name = str_dup("");
186 if (*ns_name == NULL)
187 return false;
188
189 *name = str_dup(fqdn);
[ab108be4]190 if (*name == NULL) {
191 free(*ns_name);
192 return false;
193 }
194
195 if (str_cmp(*name, "") == 0) {
196 free(*name);
[1313ee9]197 free(*ns_name);
198 return false;
199 }
200
201 return true;
202 }
203
204 /* Exactly one slash */
205 *ns_name = str_ndup(fqdn, slash_offset);
206 if (*ns_name == NULL)
207 return false;
208
209 *name = str_dup(fqdn + slash_after);
[ab108be4]210 if (*name == NULL) {
211 free(*ns_name);
212 return false;
213 }
214
215 if (str_cmp(*name, "") == 0) {
216 free(*name);
[1313ee9]217 free(*ns_name);
218 return false;
219 }
220
221 return true;
222}
223
[01b87dc5]224/** Find namespace with given name. */
[1313ee9]225static devmap_namespace_t *devmap_namespace_find_name(const char *name)
226{
[ab108be4]227 link_t *item;
[01b87dc5]228
229 assert(fibril_mutex_is_locked(&devices_list_mutex));
230
[ab108be4]231 for (item = namespaces_list.next; item != &namespaces_list; item = item->next) {
232 devmap_namespace_t *namespace =
233 list_get_instance(item, devmap_namespace_t, namespaces);
[1313ee9]234 if (str_cmp(namespace->name, name) == 0)
235 return namespace;
236 }
237
238 return NULL;
239}
240
241/** Find namespace with given handle.
242 *
243 * @todo: use hash table
244 *
245 */
[991f645]246static devmap_namespace_t *devmap_namespace_find_handle(devmap_handle_t handle)
[1313ee9]247{
[ab108be4]248 link_t *item;
[01b87dc5]249
250 assert(fibril_mutex_is_locked(&devices_list_mutex));
251
[ab108be4]252 for (item = namespaces_list.next; item != &namespaces_list; item = item->next) {
253 devmap_namespace_t *namespace =
254 list_get_instance(item, devmap_namespace_t, namespaces);
[1313ee9]255 if (namespace->handle == handle)
256 return namespace;
257 }
258
259 return NULL;
260}
261
[01b87dc5]262/** Find device with given name. */
[1313ee9]263static devmap_device_t *devmap_device_find_name(const char *ns_name,
264 const char *name)
[07e4a3c]265{
[ab108be4]266 link_t *item;
[01b87dc5]267
268 assert(fibril_mutex_is_locked(&devices_list_mutex));
269
[ab108be4]270 for (item = devices_list.next; item != &devices_list; item = item->next) {
271 devmap_device_t *device =
272 list_get_instance(item, devmap_device_t, devices);
273 if ((str_cmp(device->namespace->name, ns_name) == 0)
274 && (str_cmp(device->name, name) == 0))
[1313ee9]275 return device;
[798f364]276 }
[6519d6f]277
[1313ee9]278 return NULL;
[798f364]279}
280
281/** Find device with given handle.
[6519d6f]282 *
[798f364]283 * @todo: use hash table
[6519d6f]284 *
[798f364]285 */
[991f645]286static devmap_device_t *devmap_device_find_handle(devmap_handle_t handle)
[798f364]287{
[ab108be4]288 link_t *item;
[01b87dc5]289
290 assert(fibril_mutex_is_locked(&devices_list_mutex));
291
[ab108be4]292 for (item = devices_list.next; item != &devices_list; item = item->next) {
293 devmap_device_t *device =
294 list_get_instance(item, devmap_device_t, devices);
[6519d6f]295 if (device->handle == handle)
[1313ee9]296 return device;
[798f364]297 }
[6519d6f]298
[1313ee9]299 return NULL;
300}
301
[01b87dc5]302/** Create a namespace (if not already present). */
[1313ee9]303static devmap_namespace_t *devmap_namespace_create(const char *ns_name)
304{
[01b87dc5]305 devmap_namespace_t *namespace;
306
307 assert(fibril_mutex_is_locked(&devices_list_mutex));
308
309 namespace = devmap_namespace_find_name(ns_name);
[1313ee9]310 if (namespace != NULL)
311 return namespace;
312
313 namespace = (devmap_namespace_t *) malloc(sizeof(devmap_namespace_t));
314 if (namespace == NULL)
315 return NULL;
316
317 namespace->name = str_dup(ns_name);
318 if (namespace->name == NULL) {
319 free(namespace);
[798f364]320 return NULL;
[fc02cc41]321 }
[6519d6f]322
[1313ee9]323 namespace->handle = devmap_create_handle();
324 namespace->refcnt = 0;
[798f364]325
[1313ee9]326 /*
327 * Insert new namespace into list of registered namespaces
328 */
329 list_append(&(namespace->namespaces), &namespaces_list);
[fc02cc41]330
[1313ee9]331 return namespace;
[798f364]332}
333
[01b87dc5]334/** Destroy a namespace (if it is no longer needed). */
[1313ee9]335static void devmap_namespace_destroy(devmap_namespace_t *namespace)
336{
[01b87dc5]337 assert(fibril_mutex_is_locked(&devices_list_mutex));
338
[1313ee9]339 if (namespace->refcnt == 0) {
340 list_remove(&(namespace->namespaces));
341
342 free(namespace->name);
343 free(namespace);
344 }
345}
346
[01b87dc5]347/** Increase namespace reference count by including device. */
[1313ee9]348static void devmap_namespace_addref(devmap_namespace_t *namespace,
349 devmap_device_t *device)
350{
[01b87dc5]351 assert(fibril_mutex_is_locked(&devices_list_mutex));
352
[1313ee9]353 device->namespace = namespace;
354 namespace->refcnt++;
355}
356
[01b87dc5]357/** Decrease namespace reference count. */
[1313ee9]358static void devmap_namespace_delref(devmap_namespace_t *namespace)
359{
[01b87dc5]360 assert(fibril_mutex_is_locked(&devices_list_mutex));
361
[1313ee9]362 namespace->refcnt--;
363 devmap_namespace_destroy(namespace);
364}
365
[01b87dc5]366/** Unregister device and free it. */
[1313ee9]367static void devmap_device_unregister_core(devmap_device_t *device)
[798f364]368{
[01b87dc5]369 assert(fibril_mutex_is_locked(&devices_list_mutex));
370
[1313ee9]371 devmap_namespace_delref(device->namespace);
[798f364]372 list_remove(&(device->devices));
373 list_remove(&(device->driver_devices));
[6519d6f]374
375 free(device->name);
[798f364]376 free(device);
377}
378
[7f3e3e7]379/**
380 * Read info about new driver and add it into linked list of registered
381 * drivers.
[798f364]382 */
[1313ee9]383static devmap_driver_t *devmap_driver_register(void)
[798f364]384{
[6519d6f]385 ipc_call_t icall;
386 ipc_callid_t iid = async_get_call(&icall);
387
[228e490]388 if (IPC_GET_IMETHOD(icall) != DEVMAP_DRIVER_REGISTER) {
[ffa2c8ef]389 async_answer_0(iid, EREFUSED);
[1313ee9]390 return NULL;
[6519d6f]391 }
392
[ab108be4]393 devmap_driver_t *driver =
394 (devmap_driver_t *) malloc(sizeof(devmap_driver_t));
[6519d6f]395 if (driver == NULL) {
[ffa2c8ef]396 async_answer_0(iid, ENOMEM);
[1313ee9]397 return NULL;
[07e4a3c]398 }
[6519d6f]399
400 /*
[798f364]401 * Get driver name
402 */
[4cac2d69]403 int rc = async_data_write_accept((void **) &driver->name, true, 0,
[eda925a]404 DEVMAP_NAME_MAXLEN, 0, NULL);
[1313ee9]405 if (rc != EOK) {
[798f364]406 free(driver);
[ffa2c8ef]407 async_answer_0(iid, rc);
[1313ee9]408 return NULL;
[798f364]409 }
[6519d6f]410
411 /*
[5d0e461]412 * Create connection to the driver
[798f364]413 */
[79ae36dd]414 driver->sess = async_callback_receive(EXCHANGE_SERIALIZE);
415 if (!driver->sess) {
[798f364]416 free(driver->name);
417 free(driver);
[ffa2c8ef]418 async_answer_0(iid, ENOTSUP);
[1313ee9]419 return NULL;
[798f364]420 }
[6519d6f]421
[ab108be4]422 /*
423 * Initialize mutex for list of devices
424 * owned by this driver
425 */
426 fibril_mutex_initialize(&driver->devices_mutex);
427
428 /*
429 * Initialize list of asociated devices
430 */
431 list_initialize(&driver->devices);
[ca2a18e]432
433 link_initialize(&driver->drivers);
[6519d6f]434
[fc02cc41]435 fibril_mutex_lock(&drivers_list_mutex);
436
[7f3e3e7]437 /* TODO:
[ab108be4]438 * Check that no driver with name equal to
439 * driver->name is registered
[7f3e3e7]440 */
[6519d6f]441
442 /*
[798f364]443 * Insert new driver into list of registered drivers
444 */
445 list_append(&(driver->drivers), &drivers_list);
[fc02cc41]446 fibril_mutex_unlock(&drivers_list_mutex);
[798f364]447
[ffa2c8ef]448 async_answer_0(iid, EOK);
[6519d6f]449
[1313ee9]450 return driver;
[07e4a3c]451}
452
[6519d6f]453/**
454 * Unregister device driver, unregister all its devices and free driver
[b74959bd]455 * structure.
[6519d6f]456 *
[798f364]457 */
458static int devmap_driver_unregister(devmap_driver_t *driver)
[07e4a3c]459{
[6519d6f]460 if (driver == NULL)
[798f364]461 return EEXISTS;
[21c5d41]462
[fc02cc41]463 fibril_mutex_lock(&drivers_list_mutex);
464
[79ae36dd]465 if (driver->sess)
466 async_hangup(driver->sess);
[798f364]467
[cb41a5e]468 /* Remove it from list of drivers */
[798f364]469 list_remove(&(driver->drivers));
[6519d6f]470
[fc02cc41]471 /* Unregister all its devices */
472 fibril_mutex_lock(&devices_list_mutex);
473 fibril_mutex_lock(&driver->devices_mutex);
474
[798f364]475 while (!list_empty(&(driver->devices))) {
[6519d6f]476 devmap_device_t *device = list_get_instance(driver->devices.next,
[7f3e3e7]477 devmap_device_t, driver_devices);
[798f364]478 devmap_device_unregister_core(device);
479 }
480
[fc02cc41]481 fibril_mutex_unlock(&driver->devices_mutex);
482 fibril_mutex_unlock(&devices_list_mutex);
483 fibril_mutex_unlock(&drivers_list_mutex);
484
[ab108be4]485 /* Free name and driver */
[cb41a5e]486 if (driver->name != NULL)
[798f364]487 free(driver->name);
[6519d6f]488
[798f364]489 free(driver);
[6519d6f]490
[07e4a3c]491 return EOK;
492}
493
[798f364]494/** Register instance of device
495 *
496 */
497static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
[b74959bd]498 devmap_driver_t *driver)
[07e4a3c]499{
[6519d6f]500 if (driver == NULL) {
[ffa2c8ef]501 async_answer_0(iid, EREFUSED);
[798f364]502 return;
503 }
504
505 /* Create new device entry */
[ab108be4]506 devmap_device_t *device =
507 (devmap_device_t *) malloc(sizeof(devmap_device_t));
[6519d6f]508 if (device == NULL) {
[ffa2c8ef]509 async_answer_0(iid, ENOMEM);
[798f364]510 return;
511 }
512
[47a7174f]513 /* Set the interface, if any. */
514 device->forward_interface = IPC_GET_ARG1(*icall);
515
[1313ee9]516 /* Get fqdn */
517 char *fqdn;
[4cac2d69]518 int rc = async_data_write_accept((void **) &fqdn, true, 0,
[eda925a]519 DEVMAP_NAME_MAXLEN, 0, NULL);
[1313ee9]520 if (rc != EOK) {
[798f364]521 free(device);
[ffa2c8ef]522 async_answer_0(iid, rc);
[798f364]523 return;
524 }
[6519d6f]525
[1313ee9]526 char *ns_name;
527 if (!devmap_fqdn_split(fqdn, &ns_name, &device->name)) {
528 free(fqdn);
[798f364]529 free(device);
[ffa2c8ef]530 async_answer_0(iid, EINVAL);
[798f364]531 return;
532 }
[21c5d41]533
[1313ee9]534 free(fqdn);
535
536 fibril_mutex_lock(&devices_list_mutex);
[6519d6f]537
[1313ee9]538 devmap_namespace_t *namespace = devmap_namespace_create(ns_name);
539 free(ns_name);
[ab108be4]540 if (namespace == NULL) {
[1313ee9]541 fibril_mutex_unlock(&devices_list_mutex);
[ab108be4]542 free(device->name);
[798f364]543 free(device);
[ffa2c8ef]544 async_answer_0(iid, ENOMEM);
[798f364]545 return;
[07e4a3c]546 }
[798f364]547
[ca2a18e]548 link_initialize(&device->devices);
549 link_initialize(&device->driver_devices);
[6519d6f]550
[1313ee9]551 /* Check that device is not already registered */
552 if (devmap_device_find_name(namespace->name, device->name) != NULL) {
[ab108be4]553 printf("%s: Device '%s/%s' already registered\n", NAME,
[4ae90f9]554 namespace->name, device->name);
[1313ee9]555 devmap_namespace_destroy(namespace);
[fc02cc41]556 fibril_mutex_unlock(&devices_list_mutex);
[798f364]557 free(device->name);
558 free(device);
[ffa2c8ef]559 async_answer_0(iid, EEXISTS);
[798f364]560 return;
[07e4a3c]561 }
[6519d6f]562
[798f364]563 /* Get unique device handle */
[6519d6f]564 device->handle = devmap_create_handle();
[47a7174f]565
[1313ee9]566 devmap_namespace_addref(namespace, device);
[798f364]567 device->driver = driver;
[07e4a3c]568
[798f364]569 /* Insert device into list of all devices */
[b74959bd]570 list_append(&device->devices, &devices_list);
[6519d6f]571
[fc02cc41]572 /* Insert device into list of devices that belog to one driver */
573 fibril_mutex_lock(&device->driver->devices_mutex);
574
[b74959bd]575 list_append(&device->driver_devices, &device->driver->devices);
[798f364]576
[fc02cc41]577 fibril_mutex_unlock(&device->driver->devices_mutex);
[1cab2f41]578 fibril_condvar_broadcast(&devices_list_cv);
[fc02cc41]579 fibril_mutex_unlock(&devices_list_mutex);
580
[ffa2c8ef]581 async_answer_1(iid, EOK, device->handle);
[07e4a3c]582}
583
[798f364]584/**
585 *
586 */
587static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
[b74959bd]588 devmap_driver_t *driver)
[07e4a3c]589{
[798f364]590 /* TODO */
[07e4a3c]591 return EOK;
592}
[13125d3]593
[798f364]594/** Connect client to the device.
[6519d6f]595 *
[798f364]596 * Find device driver owning requested device and forward
597 * the message to it.
[6519d6f]598 *
[798f364]599 */
600static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
601{
[1313ee9]602 fibril_mutex_lock(&devices_list_mutex);
603
[798f364]604 /*
605 * Get handle from request
606 */
[991f645]607 devmap_handle_t handle = IPC_GET_ARG2(*call);
[6519d6f]608 devmap_device_t *dev = devmap_device_find_handle(handle);
609
[79ae36dd]610 if ((dev == NULL) || (dev->driver == NULL) || (!dev->driver->sess)) {
[ab108be4]611 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]612 async_answer_0(callid, ENOENT);
[798f364]613 return;
[6519d6f]614 }
615
[79ae36dd]616 async_exch_t *exch = async_exchange_begin(dev->driver->sess);
617
618 if (dev->forward_interface == 0)
619 async_forward_fast(callid, exch, dev->handle, 0, 0, IPC_FF_NONE);
620 else
621 async_forward_fast(callid, exch, dev->forward_interface,
622 dev->handle, 0, IPC_FF_NONE);
623
624 async_exchange_end(exch);
[1313ee9]625
626 fibril_mutex_unlock(&devices_list_mutex);
[798f364]627}
628
629/** Find handle for device instance identified by name.
[6519d6f]630 *
[798f364]631 * In answer will be send EOK and device handle in arg1 or a error
[6519d6f]632 * code from errno.h.
633 *
[798f364]634 */
[1313ee9]635static void devmap_device_get_handle(ipc_callid_t iid, ipc_call_t *icall)
[798f364]636{
[1313ee9]637 char *fqdn;
[6519d6f]638
[1313ee9]639 /* Get fqdn */
[4cac2d69]640 int rc = async_data_write_accept((void **) &fqdn, true, 0,
[eda925a]641 DEVMAP_NAME_MAXLEN, 0, NULL);
[1313ee9]642 if (rc != EOK) {
[ffa2c8ef]643 async_answer_0(iid, rc);
[798f364]644 return;
645 }
[6519d6f]646
[1313ee9]647 char *ns_name;
648 char *name;
649 if (!devmap_fqdn_split(fqdn, &ns_name, &name)) {
650 free(fqdn);
[ffa2c8ef]651 async_answer_0(iid, EINVAL);
[798f364]652 return;
[6519d6f]653 }
654
[1313ee9]655 free(fqdn);
[6519d6f]656
[c07af37]657 fibril_mutex_lock(&devices_list_mutex);
[1cab2f41]658 const devmap_device_t *dev;
[1313ee9]659
[1cab2f41]660recheck:
[1313ee9]661
[798f364]662 /*
[1cab2f41]663 * Find device name in the list of known devices.
[798f364]664 */
[1313ee9]665 dev = devmap_device_find_name(ns_name, name);
[6519d6f]666
[798f364]667 /*
668 * Device was not found.
669 */
[6519d6f]670 if (dev == NULL) {
671 if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
[1cab2f41]672 /* Blocking lookup */
673 fibril_condvar_wait(&devices_list_cv,
674 &devices_list_mutex);
675 goto recheck;
[6519d6f]676 }
677
[ffa2c8ef]678 async_answer_0(iid, ENOENT);
[1313ee9]679 free(ns_name);
[6519d6f]680 free(name);
[c07af37]681 fibril_mutex_unlock(&devices_list_mutex);
[798f364]682 return;
683 }
[6519d6f]684
[ffa2c8ef]685 async_answer_1(iid, EOK, dev->handle);
[ab108be4]686
687 fibril_mutex_unlock(&devices_list_mutex);
[1313ee9]688 free(ns_name);
[6519d6f]689 free(name);
[798f364]690}
691
[1313ee9]692/** Find handle for namespace identified by name.
693 *
694 * In answer will be send EOK and device handle in arg1 or a error
695 * code from errno.h.
[798f364]696 *
697 */
[1313ee9]698static void devmap_namespace_get_handle(ipc_callid_t iid, ipc_call_t *icall)
[798f364]699{
[1313ee9]700 char *name;
701
702 /* Get device name */
[4cac2d69]703 int rc = async_data_write_accept((void **) &name, true, 0,
[eda925a]704 DEVMAP_NAME_MAXLEN, 0, NULL);
[1313ee9]705 if (rc != EOK) {
[ffa2c8ef]706 async_answer_0(iid, rc);
[1313ee9]707 return;
708 }
709
710 fibril_mutex_lock(&devices_list_mutex);
711 const devmap_namespace_t *namespace;
712
713recheck:
[6519d6f]714
[798f364]715 /*
[1313ee9]716 * Find namespace name in the list of known namespaces.
[798f364]717 */
[1313ee9]718 namespace = devmap_namespace_find_name(name);
719
720 /*
721 * Namespace was not found.
722 */
723 if (namespace == NULL) {
724 if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
725 /* Blocking lookup */
726 fibril_condvar_wait(&devices_list_cv,
727 &devices_list_mutex);
728 goto recheck;
729 }
730
[ffa2c8ef]731 async_answer_0(iid, ENOENT);
[1313ee9]732 free(name);
733 fibril_mutex_unlock(&devices_list_mutex);
[798f364]734 return;
735 }
[6519d6f]736
[ffa2c8ef]737 async_answer_1(iid, EOK, namespace->handle);
[ab108be4]738
739 fibril_mutex_unlock(&devices_list_mutex);
[1313ee9]740 free(name);
741}
742
743static void devmap_handle_probe(ipc_callid_t iid, ipc_call_t *icall)
744{
745 fibril_mutex_lock(&devices_list_mutex);
[6519d6f]746
[ab108be4]747 devmap_namespace_t *namespace =
748 devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]749 if (namespace == NULL) {
[ab108be4]750 devmap_device_t *dev =
751 devmap_device_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]752 if (dev == NULL)
[ffa2c8ef]753 async_answer_1(iid, EOK, DEV_HANDLE_NONE);
[1313ee9]754 else
[ffa2c8ef]755 async_answer_1(iid, EOK, DEV_HANDLE_DEVICE);
[1313ee9]756 } else
[ffa2c8ef]757 async_answer_1(iid, EOK, DEV_HANDLE_NAMESPACE);
[6519d6f]758
[1313ee9]759 fibril_mutex_unlock(&devices_list_mutex);
[798f364]760}
761
[1313ee9]762static void devmap_get_namespace_count(ipc_callid_t iid, ipc_call_t *icall)
[cb41a5e]763{
[fc02cc41]764 fibril_mutex_lock(&devices_list_mutex);
[ffa2c8ef]765 async_answer_1(iid, EOK, list_count(&namespaces_list));
[fc02cc41]766 fibril_mutex_unlock(&devices_list_mutex);
[cb41a5e]767}
768
[1313ee9]769static void devmap_get_device_count(ipc_callid_t iid, ipc_call_t *icall)
[cb41a5e]770{
[fc02cc41]771 fibril_mutex_lock(&devices_list_mutex);
772
[ab108be4]773 devmap_namespace_t *namespace =
774 devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]775 if (namespace == NULL)
[ffa2c8ef]776 async_answer_0(iid, EEXISTS);
[1313ee9]777 else
[ffa2c8ef]778 async_answer_1(iid, EOK, namespace->refcnt);
[1313ee9]779
780 fibril_mutex_unlock(&devices_list_mutex);
781}
782
783static void devmap_get_namespaces(ipc_callid_t iid, ipc_call_t *icall)
784{
[cb41a5e]785 ipc_callid_t callid;
786 size_t size;
[0da4e41]787 if (!async_data_read_receive(&callid, &size)) {
[ffa2c8ef]788 async_answer_0(callid, EREFUSED);
789 async_answer_0(iid, EREFUSED);
[cb41a5e]790 return;
791 }
792
793 if ((size % sizeof(dev_desc_t)) != 0) {
[ffa2c8ef]794 async_answer_0(callid, EINVAL);
795 async_answer_0(iid, EINVAL);
[cb41a5e]796 return;
797 }
798
[1313ee9]799 fibril_mutex_lock(&devices_list_mutex);
800
[5d0e461]801 size_t count = size / sizeof(dev_desc_t);
[1313ee9]802 if (count != list_count(&namespaces_list)) {
[ab108be4]803 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]804 async_answer_0(callid, EOVERFLOW);
805 async_answer_0(iid, EOVERFLOW);
[1313ee9]806 return;
807 }
808
[cb41a5e]809 dev_desc_t *desc = (dev_desc_t *) malloc(size);
810 if (desc == NULL) {
[ab108be4]811 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]812 async_answer_0(callid, ENOMEM);
813 async_answer_0(iid, ENOMEM);
[cb41a5e]814 return;
815 }
816
[ab108be4]817 link_t *item;
[5d0e461]818 size_t pos = 0;
[ab108be4]819 for (item = namespaces_list.next; item != &namespaces_list;
820 item = item->next) {
821 devmap_namespace_t *namespace =
822 list_get_instance(item, devmap_namespace_t, namespaces);
[cb41a5e]823
[1313ee9]824 desc[pos].handle = namespace->handle;
825 str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, namespace->name);
[cb41a5e]826 pos++;
827 }
828
[96b02eb9]829 sysarg_t retval = async_data_read_finalize(callid, desc, size);
[1313ee9]830
831 free(desc);
832 fibril_mutex_unlock(&devices_list_mutex);
833
[ffa2c8ef]834 async_answer_0(iid, retval);
[1313ee9]835}
836
837static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
838{
839 /* FIXME: Use faster algorithm which can make better use
840 of namespaces */
841
842 ipc_callid_t callid;
843 size_t size;
844 if (!async_data_read_receive(&callid, &size)) {
[ffa2c8ef]845 async_answer_0(callid, EREFUSED);
846 async_answer_0(iid, EREFUSED);
[cb41a5e]847 return;
848 }
849
[1313ee9]850 if ((size % sizeof(dev_desc_t)) != 0) {
[ffa2c8ef]851 async_answer_0(callid, EINVAL);
852 async_answer_0(iid, EINVAL);
[1313ee9]853 return;
854 }
855
856 fibril_mutex_lock(&devices_list_mutex);
857
[ab108be4]858 devmap_namespace_t *namespace =
859 devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]860 if (namespace == NULL) {
861 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]862 async_answer_0(callid, ENOENT);
863 async_answer_0(iid, ENOENT);
[1313ee9]864 return;
865 }
866
867 size_t count = size / sizeof(dev_desc_t);
868 if (count != namespace->refcnt) {
[ab108be4]869 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]870 async_answer_0(callid, EOVERFLOW);
871 async_answer_0(iid, EOVERFLOW);
[1313ee9]872 return;
873 }
874
875 dev_desc_t *desc = (dev_desc_t *) malloc(size);
876 if (desc == NULL) {
[ab108be4]877 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]878 async_answer_0(callid, ENOMEM);
879 async_answer_0(iid, EREFUSED);
[1313ee9]880 return;
881 }
[cb41a5e]882
[ab108be4]883 link_t *item;
[1313ee9]884 size_t pos = 0;
[ab108be4]885 for (item = devices_list.next; item != &devices_list; item = item->next) {
886 devmap_device_t *device =
887 list_get_instance(item, devmap_device_t, devices);
[1313ee9]888
889 if (device->namespace == namespace) {
890 desc[pos].handle = device->handle;
891 str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
892 pos++;
893 }
894 }
895
[96b02eb9]896 sysarg_t retval = async_data_read_finalize(callid, desc, size);
[1313ee9]897
898 free(desc);
[fc02cc41]899 fibril_mutex_unlock(&devices_list_mutex);
900
[ffa2c8ef]901 async_answer_0(iid, retval);
[cb41a5e]902}
903
[7fcb74c]904static void devmap_null_create(ipc_callid_t iid, ipc_call_t *icall)
[cb41a5e]905{
[7fcb74c]906 fibril_mutex_lock(&null_devices_mutex);
907
908 unsigned int i;
909 bool fnd = false;
910
911 for (i = 0; i < NULL_DEVICES; i++) {
912 if (null_devices[i] == NULL) {
913 fnd = true;
914 break;
915 }
916 }
917
918 if (!fnd) {
919 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]920 async_answer_0(iid, ENOMEM);
[7fcb74c]921 return;
922 }
923
[1313ee9]924 char null[DEVMAP_NAME_MAXLEN];
925 snprintf(null, DEVMAP_NAME_MAXLEN, "%u", i);
926
927 char *dev_name = str_dup(null);
928 if (dev_name == NULL) {
929 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]930 async_answer_0(iid, ENOMEM);
[1313ee9]931 return;
932 }
933
[ab108be4]934 devmap_device_t *device =
935 (devmap_device_t *) malloc(sizeof(devmap_device_t));
[7fcb74c]936 if (device == NULL) {
937 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]938 async_answer_0(iid, ENOMEM);
[7fcb74c]939 return;
940 }
[cb41a5e]941
[1313ee9]942 fibril_mutex_lock(&devices_list_mutex);
[7fcb74c]943
[1313ee9]944 devmap_namespace_t *namespace = devmap_namespace_create("null");
[ab108be4]945 if (namespace == NULL) {
[1313ee9]946 fibril_mutex_lock(&devices_list_mutex);
[7fcb74c]947 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]948 async_answer_0(iid, ENOMEM);
[7fcb74c]949 return;
[cb41a5e]950 }
951
[ca2a18e]952 link_initialize(&device->devices);
953 link_initialize(&device->driver_devices);
[cb41a5e]954
955 /* Get unique device handle */
956 device->handle = devmap_create_handle();
957 device->driver = NULL;
958
[1313ee9]959 devmap_namespace_addref(namespace, device);
960 device->name = dev_name;
961
[63e0bdd]962 /*
963 * Insert device into list of all devices and into null devices array.
964 * Insert device into a dummy list of null driver's devices so that it
965 * can be safely removed later.
966 */
[cb41a5e]967 list_append(&device->devices, &devices_list);
[63e0bdd]968 list_append(&device->driver_devices, &dummy_null_driver_devices);
[7fcb74c]969 null_devices[i] = device;
[cb41a5e]970
[fc02cc41]971 fibril_mutex_unlock(&devices_list_mutex);
[7fcb74c]972 fibril_mutex_unlock(&null_devices_mutex);
973
[ffa2c8ef]974 async_answer_1(iid, EOK, (sysarg_t) i);
[7fcb74c]975}
976
977static void devmap_null_destroy(ipc_callid_t iid, ipc_call_t *icall)
978{
[96b02eb9]979 sysarg_t i = IPC_GET_ARG1(*icall);
[ab108be4]980 if (i >= NULL_DEVICES) {
[ffa2c8ef]981 async_answer_0(iid, ELIMIT);
[ab108be4]982 return;
983 }
984
985 fibril_mutex_lock(&null_devices_mutex);
[7fcb74c]986
987 if (null_devices[i] == NULL) {
[ab108be4]988 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]989 async_answer_0(iid, ENOENT);
[7fcb74c]990 return;
991 }
992
[1313ee9]993 fibril_mutex_lock(&devices_list_mutex);
[7fcb74c]994 devmap_device_unregister_core(null_devices[i]);
[1313ee9]995 fibril_mutex_unlock(&devices_list_mutex);
996
[7fcb74c]997 null_devices[i] = NULL;
998
999 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]1000 async_answer_0(iid, EOK);
[7fcb74c]1001}
1002
1003/** Initialize device mapper.
1004 *
1005 *
1006 */
1007static bool devmap_init(void)
1008{
1009 fibril_mutex_lock(&null_devices_mutex);
1010
1011 unsigned int i;
1012 for (i = 0; i < NULL_DEVICES; i++)
1013 null_devices[i] = NULL;
1014
1015 fibril_mutex_unlock(&null_devices_mutex);
[fc02cc41]1016
[cb41a5e]1017 return true;
1018}
1019
[798f364]1020/** Handle connection with device driver.
[13125d3]1021 *
1022 */
[21c5d41]1023static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
[13125d3]1024{
[6519d6f]1025 /* Accept connection */
[ffa2c8ef]1026 async_answer_0(iid, EOK);
[6519d6f]1027
[1313ee9]1028 devmap_driver_t *driver = devmap_driver_register();
1029 if (driver == NULL)
[798f364]1030 return;
1031
[79ae36dd]1032 while (true) {
[6519d6f]1033 ipc_call_t call;
1034 ipc_callid_t callid = async_get_call(&call);
1035
[79ae36dd]1036 if (!IPC_GET_IMETHOD(call))
1037 break;
1038
[228e490]1039 switch (IPC_GET_IMETHOD(call)) {
[798f364]1040 case DEVMAP_DRIVER_UNREGISTER:
[6519d6f]1041 if (NULL == driver)
[ffa2c8ef]1042 async_answer_0(callid, ENOENT);
[6519d6f]1043 else
[ffa2c8ef]1044 async_answer_0(callid, EOK);
[07e4a3c]1045 break;
[798f364]1046 case DEVMAP_DEVICE_REGISTER:
1047 /* Register one instance of device */
1048 devmap_device_register(callid, &call, driver);
[07e4a3c]1049 break;
[798f364]1050 case DEVMAP_DEVICE_UNREGISTER:
1051 /* Remove instance of device identified by handler */
1052 devmap_device_unregister(callid, &call, driver);
1053 break;
1054 case DEVMAP_DEVICE_GET_HANDLE:
[1313ee9]1055 devmap_device_get_handle(callid, &call);
[798f364]1056 break;
[1313ee9]1057 case DEVMAP_NAMESPACE_GET_HANDLE:
1058 devmap_namespace_get_handle(callid, &call);
[798f364]1059 break;
1060 default:
[ffa2c8ef]1061 async_answer_0(callid, ENOENT);
[798f364]1062 }
1063 }
1064
[7fcb74c]1065 if (driver != NULL) {
[6519d6f]1066 /*
[b74959bd]1067 * Unregister the device driver and all its devices.
1068 */
[798f364]1069 devmap_driver_unregister(driver);
1070 driver = NULL;
1071 }
1072}
1073
1074/** Handle connection with device client.
1075 *
1076 */
[21c5d41]1077static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
[798f364]1078{
[6519d6f]1079 /* Accept connection */
[ffa2c8ef]1080 async_answer_0(iid, EOK);
[6519d6f]1081
[79ae36dd]1082 while (true) {
[6519d6f]1083 ipc_call_t call;
1084 ipc_callid_t callid = async_get_call(&call);
1085
[79ae36dd]1086 if (!IPC_GET_IMETHOD(call))
1087 break;
1088
[228e490]1089 switch (IPC_GET_IMETHOD(call)) {
[798f364]1090 case DEVMAP_DEVICE_GET_HANDLE:
[1313ee9]1091 devmap_device_get_handle(callid, &call);
1092 break;
1093 case DEVMAP_NAMESPACE_GET_HANDLE:
1094 devmap_namespace_get_handle(callid, &call);
[07e4a3c]1095 break;
[1313ee9]1096 case DEVMAP_HANDLE_PROBE:
1097 devmap_handle_probe(callid, &call);
[13125d3]1098 break;
[1313ee9]1099 case DEVMAP_NULL_CREATE:
[7fcb74c]1100 devmap_null_create(callid, &call);
1101 break;
[1313ee9]1102 case DEVMAP_NULL_DESTROY:
[7fcb74c]1103 devmap_null_destroy(callid, &call);
1104 break;
[1313ee9]1105 case DEVMAP_GET_NAMESPACE_COUNT:
1106 devmap_get_namespace_count(callid, &call);
1107 break;
1108 case DEVMAP_GET_DEVICE_COUNT:
1109 devmap_get_device_count(callid, &call);
1110 break;
1111 case DEVMAP_GET_NAMESPACES:
1112 devmap_get_namespaces(callid, &call);
[cb41a5e]1113 break;
[1313ee9]1114 case DEVMAP_GET_DEVICES:
[cb41a5e]1115 devmap_get_devices(callid, &call);
1116 break;
[13125d3]1117 default:
[ffa2c8ef]1118 async_answer_0(callid, ENOENT);
[13125d3]1119 }
1120 }
1121}
1122
[6519d6f]1123/** Function for handling connections to devmap
[798f364]1124 *
1125 */
[9934f7d]1126static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[798f364]1127{
[21c5d41]1128 /* Select interface */
[96b02eb9]1129 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
[7f3e3e7]1130 case DEVMAP_DRIVER:
1131 devmap_connection_driver(iid, icall);
1132 break;
1133 case DEVMAP_CLIENT:
1134 devmap_connection_client(iid, icall);
1135 break;
[b61d47d]1136 case DEVMAP_CONNECT_TO_DEVICE:
[21c5d41]1137 /* Connect client to selected device */
[b61d47d]1138 devmap_forward(iid, icall);
1139 break;
[7f3e3e7]1140 default:
[6519d6f]1141 /* No such interface */
[ffa2c8ef]1142 async_answer_0(iid, ENOENT);
[798f364]1143 }
1144}
[13125d3]1145
[798f364]1146/**
1147 *
1148 */
[13125d3]1149int main(int argc, char *argv[])
1150{
[ab108be4]1151 printf("%s: HelenOS Device Mapper\n", NAME);
[21c5d41]1152
[cb41a5e]1153 if (!devmap_init()) {
[ab108be4]1154 printf("%s: Error while initializing service\n", NAME);
[13125d3]1155 return -1;
1156 }
[21c5d41]1157
[c07af37]1158 /* Set a handler of incomming connections */
[798f364]1159 async_set_client_connection(devmap_connection);
[7fcb74c]1160
[7f3e3e7]1161 /* Register device mapper at naming service */
[007e6efa]1162 if (service_register(SERVICE_DEVMAP) != EOK)
[13125d3]1163 return -1;
1164
[ab108be4]1165 printf("%s: Accepting connections\n", NAME);
[13125d3]1166 async_manager();
[6519d6f]1167
[13125d3]1168 /* Never reached */
1169 return 0;
1170}
1171
[fb623e2]1172/**
[13125d3]1173 * @}
1174 */
Note: See TracBrowser for help on using the repository browser.