source: mainline/uspace/srv/devmap/devmap.c@ 83fd0d7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 83fd0d7 was ca2a18e, checked in by Jakub Jermar <jakub@…>, 15 years ago

Fix some list_initialize() vs. link_initialize().

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