source: mainline/uspace/srv/devmap/devmap.c@ a676574

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

Deploy the fibril_{mutex,rwlock}_[*_]is_locked() functions in a few locations.

  • Property mode set to 100644
File size: 26.7 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) {
[b74959bd]376 ipc_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) {
[b74959bd]383 ipc_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);
[1313ee9]394 ipc_answer_0(iid, rc);
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);
[ab108be4]407 ipc_answer_0(callid, ENOTSUP);
[b74959bd]408 ipc_answer_0(iid, ENOTSUP);
[1313ee9]409 return NULL;
[798f364]410 }
[6519d6f]411
[38c706cc]412 driver->phone = IPC_GET_ARG5(call);
[b74959bd]413 ipc_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);
[798f364]425 list_initialize(&(driver->drivers));
[6519d6f]426
[fc02cc41]427 fibril_mutex_lock(&drivers_list_mutex);
428
[7f3e3e7]429 /* TODO:
[ab108be4]430 * Check that no driver with name equal to
431 * driver->name is registered
[7f3e3e7]432 */
[6519d6f]433
434 /*
[798f364]435 * Insert new driver into list of registered drivers
436 */
437 list_append(&(driver->drivers), &drivers_list);
[fc02cc41]438 fibril_mutex_unlock(&drivers_list_mutex);
[798f364]439
[b74959bd]440 ipc_answer_0(iid, EOK);
[6519d6f]441
[1313ee9]442 return driver;
[07e4a3c]443}
444
[6519d6f]445/**
446 * Unregister device driver, unregister all its devices and free driver
[b74959bd]447 * structure.
[6519d6f]448 *
[798f364]449 */
450static int devmap_driver_unregister(devmap_driver_t *driver)
[07e4a3c]451{
[6519d6f]452 if (driver == NULL)
[798f364]453 return EEXISTS;
[21c5d41]454
[fc02cc41]455 fibril_mutex_lock(&drivers_list_mutex);
456
[cb41a5e]457 if (driver->phone != 0)
458 ipc_hangup(driver->phone);
[798f364]459
[cb41a5e]460 /* Remove it from list of drivers */
[798f364]461 list_remove(&(driver->drivers));
[6519d6f]462
[fc02cc41]463 /* Unregister all its devices */
464 fibril_mutex_lock(&devices_list_mutex);
465 fibril_mutex_lock(&driver->devices_mutex);
466
[798f364]467 while (!list_empty(&(driver->devices))) {
[6519d6f]468 devmap_device_t *device = list_get_instance(driver->devices.next,
[7f3e3e7]469 devmap_device_t, driver_devices);
[798f364]470 devmap_device_unregister_core(device);
471 }
472
[fc02cc41]473 fibril_mutex_unlock(&driver->devices_mutex);
474 fibril_mutex_unlock(&devices_list_mutex);
475 fibril_mutex_unlock(&drivers_list_mutex);
476
[ab108be4]477 /* Free name and driver */
[cb41a5e]478 if (driver->name != NULL)
[798f364]479 free(driver->name);
[6519d6f]480
[798f364]481 free(driver);
[6519d6f]482
[07e4a3c]483 return EOK;
484}
485
[798f364]486/** Register instance of device
487 *
488 */
489static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
[b74959bd]490 devmap_driver_t *driver)
[07e4a3c]491{
[6519d6f]492 if (driver == NULL) {
[b74959bd]493 ipc_answer_0(iid, EREFUSED);
[798f364]494 return;
495 }
496
497 /* Create new device entry */
[ab108be4]498 devmap_device_t *device =
499 (devmap_device_t *) malloc(sizeof(devmap_device_t));
[6519d6f]500 if (device == NULL) {
[b74959bd]501 ipc_answer_0(iid, ENOMEM);
[798f364]502 return;
503 }
504
[47a7174f]505 /* Set the interface, if any. */
506 device->forward_interface = IPC_GET_ARG1(*icall);
507
[1313ee9]508 /* Get fqdn */
509 char *fqdn;
[4cac2d69]510 int rc = async_data_write_accept((void **) &fqdn, true, 0,
[eda925a]511 DEVMAP_NAME_MAXLEN, 0, NULL);
[1313ee9]512 if (rc != EOK) {
[798f364]513 free(device);
[1313ee9]514 ipc_answer_0(iid, rc);
[798f364]515 return;
516 }
[6519d6f]517
[1313ee9]518 char *ns_name;
519 if (!devmap_fqdn_split(fqdn, &ns_name, &device->name)) {
520 free(fqdn);
[798f364]521 free(device);
[1313ee9]522 ipc_answer_0(iid, EINVAL);
[798f364]523 return;
524 }
[21c5d41]525
[1313ee9]526 free(fqdn);
527
528 fibril_mutex_lock(&devices_list_mutex);
[6519d6f]529
[1313ee9]530 devmap_namespace_t *namespace = devmap_namespace_create(ns_name);
531 free(ns_name);
[ab108be4]532 if (namespace == NULL) {
[1313ee9]533 fibril_mutex_unlock(&devices_list_mutex);
[ab108be4]534 free(device->name);
[798f364]535 free(device);
[1313ee9]536 ipc_answer_0(iid, ENOMEM);
[798f364]537 return;
[07e4a3c]538 }
[798f364]539
540 list_initialize(&(device->devices));
541 list_initialize(&(device->driver_devices));
[6519d6f]542
[1313ee9]543 /* Check that device is not already registered */
544 if (devmap_device_find_name(namespace->name, device->name) != NULL) {
[ab108be4]545 printf("%s: Device '%s/%s' already registered\n", NAME,
[7e752b2]546 device->namespace->name, device->name);
[1313ee9]547 devmap_namespace_destroy(namespace);
[fc02cc41]548 fibril_mutex_unlock(&devices_list_mutex);
[798f364]549 free(device->name);
550 free(device);
[b74959bd]551 ipc_answer_0(iid, EEXISTS);
[798f364]552 return;
[07e4a3c]553 }
[6519d6f]554
[798f364]555 /* Get unique device handle */
[6519d6f]556 device->handle = devmap_create_handle();
[47a7174f]557
[1313ee9]558 devmap_namespace_addref(namespace, device);
[798f364]559 device->driver = driver;
[07e4a3c]560
[798f364]561 /* Insert device into list of all devices */
[b74959bd]562 list_append(&device->devices, &devices_list);
[6519d6f]563
[fc02cc41]564 /* Insert device into list of devices that belog to one driver */
565 fibril_mutex_lock(&device->driver->devices_mutex);
566
[b74959bd]567 list_append(&device->driver_devices, &device->driver->devices);
[798f364]568
[fc02cc41]569 fibril_mutex_unlock(&device->driver->devices_mutex);
[1cab2f41]570 fibril_condvar_broadcast(&devices_list_cv);
[fc02cc41]571 fibril_mutex_unlock(&devices_list_mutex);
572
[b74959bd]573 ipc_answer_1(iid, EOK, device->handle);
[07e4a3c]574}
575
[798f364]576/**
577 *
578 */
579static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
[b74959bd]580 devmap_driver_t *driver)
[07e4a3c]581{
[798f364]582 /* TODO */
[07e4a3c]583 return EOK;
584}
[13125d3]585
[798f364]586/** Connect client to the device.
[6519d6f]587 *
[798f364]588 * Find device driver owning requested device and forward
589 * the message to it.
[6519d6f]590 *
[798f364]591 */
592static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
593{
[1313ee9]594 fibril_mutex_lock(&devices_list_mutex);
595
[798f364]596 /*
597 * Get handle from request
598 */
[991f645]599 devmap_handle_t handle = IPC_GET_ARG2(*call);
[6519d6f]600 devmap_device_t *dev = devmap_device_find_handle(handle);
601
[cb41a5e]602 if ((dev == NULL) || (dev->driver == NULL) || (dev->driver->phone == 0)) {
[ab108be4]603 fibril_mutex_unlock(&devices_list_mutex);
[b74959bd]604 ipc_answer_0(callid, ENOENT);
[798f364]605 return;
[6519d6f]606 }
607
[47a7174f]608 if (dev->forward_interface == 0) {
609 ipc_forward_fast(callid, dev->driver->phone,
610 dev->handle, 0, 0,
611 IPC_FF_NONE);
612 } else {
613 ipc_forward_fast(callid, dev->driver->phone,
614 dev->forward_interface, dev->handle, 0,
615 IPC_FF_NONE);
616 }
[1313ee9]617
618 fibril_mutex_unlock(&devices_list_mutex);
[798f364]619}
620
621/** Find handle for device instance identified by name.
[6519d6f]622 *
[798f364]623 * In answer will be send EOK and device handle in arg1 or a error
[6519d6f]624 * code from errno.h.
625 *
[798f364]626 */
[1313ee9]627static void devmap_device_get_handle(ipc_callid_t iid, ipc_call_t *icall)
[798f364]628{
[1313ee9]629 char *fqdn;
[6519d6f]630
[1313ee9]631 /* Get fqdn */
[4cac2d69]632 int rc = async_data_write_accept((void **) &fqdn, true, 0,
[eda925a]633 DEVMAP_NAME_MAXLEN, 0, NULL);
[1313ee9]634 if (rc != EOK) {
635 ipc_answer_0(iid, rc);
[798f364]636 return;
637 }
[6519d6f]638
[1313ee9]639 char *ns_name;
640 char *name;
641 if (!devmap_fqdn_split(fqdn, &ns_name, &name)) {
642 free(fqdn);
643 ipc_answer_0(iid, EINVAL);
[798f364]644 return;
[6519d6f]645 }
646
[1313ee9]647 free(fqdn);
[6519d6f]648
[c07af37]649 fibril_mutex_lock(&devices_list_mutex);
[1cab2f41]650 const devmap_device_t *dev;
[1313ee9]651
[1cab2f41]652recheck:
[1313ee9]653
[798f364]654 /*
[1cab2f41]655 * Find device name in the list of known devices.
[798f364]656 */
[1313ee9]657 dev = devmap_device_find_name(ns_name, name);
[6519d6f]658
[798f364]659 /*
660 * Device was not found.
661 */
[6519d6f]662 if (dev == NULL) {
663 if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
[1cab2f41]664 /* Blocking lookup */
665 fibril_condvar_wait(&devices_list_cv,
666 &devices_list_mutex);
667 goto recheck;
[6519d6f]668 }
669
[b74959bd]670 ipc_answer_0(iid, ENOENT);
[1313ee9]671 free(ns_name);
[6519d6f]672 free(name);
[c07af37]673 fibril_mutex_unlock(&devices_list_mutex);
[798f364]674 return;
675 }
[6519d6f]676
[b74959bd]677 ipc_answer_1(iid, EOK, dev->handle);
[ab108be4]678
679 fibril_mutex_unlock(&devices_list_mutex);
[1313ee9]680 free(ns_name);
[6519d6f]681 free(name);
[798f364]682}
683
[1313ee9]684/** Find handle for namespace identified by name.
685 *
686 * In answer will be send EOK and device handle in arg1 or a error
687 * code from errno.h.
[798f364]688 *
689 */
[1313ee9]690static void devmap_namespace_get_handle(ipc_callid_t iid, ipc_call_t *icall)
[798f364]691{
[1313ee9]692 char *name;
693
694 /* Get device name */
[4cac2d69]695 int rc = async_data_write_accept((void **) &name, true, 0,
[eda925a]696 DEVMAP_NAME_MAXLEN, 0, NULL);
[1313ee9]697 if (rc != EOK) {
698 ipc_answer_0(iid, rc);
699 return;
700 }
701
702 fibril_mutex_lock(&devices_list_mutex);
703 const devmap_namespace_t *namespace;
704
705recheck:
[6519d6f]706
[798f364]707 /*
[1313ee9]708 * Find namespace name in the list of known namespaces.
[798f364]709 */
[1313ee9]710 namespace = devmap_namespace_find_name(name);
711
712 /*
713 * Namespace was not found.
714 */
715 if (namespace == NULL) {
716 if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
717 /* Blocking lookup */
718 fibril_condvar_wait(&devices_list_cv,
719 &devices_list_mutex);
720 goto recheck;
721 }
722
[b74959bd]723 ipc_answer_0(iid, ENOENT);
[1313ee9]724 free(name);
725 fibril_mutex_unlock(&devices_list_mutex);
[798f364]726 return;
727 }
[6519d6f]728
[1313ee9]729 ipc_answer_1(iid, EOK, namespace->handle);
[ab108be4]730
731 fibril_mutex_unlock(&devices_list_mutex);
[1313ee9]732 free(name);
733}
734
735static void devmap_handle_probe(ipc_callid_t iid, ipc_call_t *icall)
736{
737 fibril_mutex_lock(&devices_list_mutex);
[6519d6f]738
[ab108be4]739 devmap_namespace_t *namespace =
740 devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]741 if (namespace == NULL) {
[ab108be4]742 devmap_device_t *dev =
743 devmap_device_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]744 if (dev == NULL)
745 ipc_answer_1(iid, EOK, DEV_HANDLE_NONE);
746 else
747 ipc_answer_1(iid, EOK, DEV_HANDLE_DEVICE);
748 } else
749 ipc_answer_1(iid, EOK, DEV_HANDLE_NAMESPACE);
[6519d6f]750
[1313ee9]751 fibril_mutex_unlock(&devices_list_mutex);
[798f364]752}
753
[1313ee9]754static void devmap_get_namespace_count(ipc_callid_t iid, ipc_call_t *icall)
[cb41a5e]755{
[fc02cc41]756 fibril_mutex_lock(&devices_list_mutex);
[1313ee9]757 ipc_answer_1(iid, EOK, list_count(&namespaces_list));
[fc02cc41]758 fibril_mutex_unlock(&devices_list_mutex);
[cb41a5e]759}
760
[1313ee9]761static void devmap_get_device_count(ipc_callid_t iid, ipc_call_t *icall)
[cb41a5e]762{
[fc02cc41]763 fibril_mutex_lock(&devices_list_mutex);
764
[ab108be4]765 devmap_namespace_t *namespace =
766 devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]767 if (namespace == NULL)
768 ipc_answer_0(iid, EEXISTS);
769 else
770 ipc_answer_1(iid, EOK, namespace->refcnt);
771
772 fibril_mutex_unlock(&devices_list_mutex);
773}
774
775static void devmap_get_namespaces(ipc_callid_t iid, ipc_call_t *icall)
776{
[cb41a5e]777 ipc_callid_t callid;
778 size_t size;
[0da4e41]779 if (!async_data_read_receive(&callid, &size)) {
[cb41a5e]780 ipc_answer_0(callid, EREFUSED);
781 ipc_answer_0(iid, EREFUSED);
782 return;
783 }
784
785 if ((size % sizeof(dev_desc_t)) != 0) {
786 ipc_answer_0(callid, EINVAL);
[1313ee9]787 ipc_answer_0(iid, EINVAL);
[cb41a5e]788 return;
789 }
790
[1313ee9]791 fibril_mutex_lock(&devices_list_mutex);
792
[5d0e461]793 size_t count = size / sizeof(dev_desc_t);
[1313ee9]794 if (count != list_count(&namespaces_list)) {
[ab108be4]795 fibril_mutex_unlock(&devices_list_mutex);
[1313ee9]796 ipc_answer_0(callid, EOVERFLOW);
797 ipc_answer_0(iid, EOVERFLOW);
798 return;
799 }
800
[cb41a5e]801 dev_desc_t *desc = (dev_desc_t *) malloc(size);
802 if (desc == NULL) {
[ab108be4]803 fibril_mutex_unlock(&devices_list_mutex);
[cb41a5e]804 ipc_answer_0(callid, ENOMEM);
[1313ee9]805 ipc_answer_0(iid, ENOMEM);
[cb41a5e]806 return;
807 }
808
[ab108be4]809 link_t *item;
[5d0e461]810 size_t pos = 0;
[ab108be4]811 for (item = namespaces_list.next; item != &namespaces_list;
812 item = item->next) {
813 devmap_namespace_t *namespace =
814 list_get_instance(item, devmap_namespace_t, namespaces);
[cb41a5e]815
[1313ee9]816 desc[pos].handle = namespace->handle;
817 str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, namespace->name);
[cb41a5e]818 pos++;
819 }
820
[96b02eb9]821 sysarg_t retval = async_data_read_finalize(callid, desc, size);
[1313ee9]822
823 free(desc);
824 fibril_mutex_unlock(&devices_list_mutex);
825
826 ipc_answer_0(iid, retval);
827}
828
829static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
830{
831 /* FIXME: Use faster algorithm which can make better use
832 of namespaces */
833
834 ipc_callid_t callid;
835 size_t size;
836 if (!async_data_read_receive(&callid, &size)) {
837 ipc_answer_0(callid, EREFUSED);
[cb41a5e]838 ipc_answer_0(iid, EREFUSED);
839 return;
840 }
841
[1313ee9]842 if ((size % sizeof(dev_desc_t)) != 0) {
843 ipc_answer_0(callid, EINVAL);
844 ipc_answer_0(iid, EINVAL);
845 return;
846 }
847
848 fibril_mutex_lock(&devices_list_mutex);
849
[ab108be4]850 devmap_namespace_t *namespace =
851 devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]852 if (namespace == NULL) {
853 fibril_mutex_unlock(&devices_list_mutex);
854 ipc_answer_0(callid, ENOENT);
855 ipc_answer_0(iid, ENOENT);
856 return;
857 }
858
859 size_t count = size / sizeof(dev_desc_t);
860 if (count != namespace->refcnt) {
[ab108be4]861 fibril_mutex_unlock(&devices_list_mutex);
[1313ee9]862 ipc_answer_0(callid, EOVERFLOW);
863 ipc_answer_0(iid, EOVERFLOW);
864 return;
865 }
866
867 dev_desc_t *desc = (dev_desc_t *) malloc(size);
868 if (desc == NULL) {
[ab108be4]869 fibril_mutex_unlock(&devices_list_mutex);
[1313ee9]870 ipc_answer_0(callid, ENOMEM);
871 ipc_answer_0(iid, EREFUSED);
872 return;
873 }
[cb41a5e]874
[ab108be4]875 link_t *item;
[1313ee9]876 size_t pos = 0;
[ab108be4]877 for (item = devices_list.next; item != &devices_list; item = item->next) {
878 devmap_device_t *device =
879 list_get_instance(item, devmap_device_t, devices);
[1313ee9]880
881 if (device->namespace == namespace) {
882 desc[pos].handle = device->handle;
883 str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
884 pos++;
885 }
886 }
887
[96b02eb9]888 sysarg_t retval = async_data_read_finalize(callid, desc, size);
[1313ee9]889
890 free(desc);
[fc02cc41]891 fibril_mutex_unlock(&devices_list_mutex);
892
[1313ee9]893 ipc_answer_0(iid, retval);
[cb41a5e]894}
895
[7fcb74c]896static void devmap_null_create(ipc_callid_t iid, ipc_call_t *icall)
[cb41a5e]897{
[7fcb74c]898 fibril_mutex_lock(&null_devices_mutex);
899
900 unsigned int i;
901 bool fnd = false;
902
903 for (i = 0; i < NULL_DEVICES; i++) {
904 if (null_devices[i] == NULL) {
905 fnd = true;
906 break;
907 }
908 }
909
910 if (!fnd) {
911 fibril_mutex_unlock(&null_devices_mutex);
912 ipc_answer_0(iid, ENOMEM);
913 return;
914 }
915
[1313ee9]916 char null[DEVMAP_NAME_MAXLEN];
917 snprintf(null, DEVMAP_NAME_MAXLEN, "%u", i);
918
919 char *dev_name = str_dup(null);
920 if (dev_name == NULL) {
921 fibril_mutex_unlock(&null_devices_mutex);
922 ipc_answer_0(iid, ENOMEM);
923 return;
924 }
925
[ab108be4]926 devmap_device_t *device =
927 (devmap_device_t *) malloc(sizeof(devmap_device_t));
[7fcb74c]928 if (device == NULL) {
929 fibril_mutex_unlock(&null_devices_mutex);
930 ipc_answer_0(iid, ENOMEM);
931 return;
932 }
[cb41a5e]933
[1313ee9]934 fibril_mutex_lock(&devices_list_mutex);
[7fcb74c]935
[1313ee9]936 devmap_namespace_t *namespace = devmap_namespace_create("null");
[ab108be4]937 if (namespace == NULL) {
[1313ee9]938 fibril_mutex_lock(&devices_list_mutex);
[7fcb74c]939 fibril_mutex_unlock(&null_devices_mutex);
940 ipc_answer_0(iid, ENOMEM);
941 return;
[cb41a5e]942 }
943
944 list_initialize(&(device->devices));
945 list_initialize(&(device->driver_devices));
946
947 /* Get unique device handle */
948 device->handle = devmap_create_handle();
949 device->driver = NULL;
950
[1313ee9]951 devmap_namespace_addref(namespace, device);
952 device->name = dev_name;
953
[7fcb74c]954 /* Insert device into list of all devices
955 and into null devices array */
[cb41a5e]956 list_append(&device->devices, &devices_list);
[7fcb74c]957 null_devices[i] = device;
[cb41a5e]958
[fc02cc41]959 fibril_mutex_unlock(&devices_list_mutex);
[7fcb74c]960 fibril_mutex_unlock(&null_devices_mutex);
961
[96b02eb9]962 ipc_answer_1(iid, EOK, (sysarg_t) i);
[7fcb74c]963}
964
965static void devmap_null_destroy(ipc_callid_t iid, ipc_call_t *icall)
966{
[96b02eb9]967 sysarg_t i = IPC_GET_ARG1(*icall);
[ab108be4]968 if (i >= NULL_DEVICES) {
969 ipc_answer_0(iid, ELIMIT);
970 return;
971 }
972
973 fibril_mutex_lock(&null_devices_mutex);
[7fcb74c]974
975 if (null_devices[i] == NULL) {
[ab108be4]976 fibril_mutex_unlock(&null_devices_mutex);
[7fcb74c]977 ipc_answer_0(iid, ENOENT);
978 return;
979 }
980
[1313ee9]981 fibril_mutex_lock(&devices_list_mutex);
[7fcb74c]982 devmap_device_unregister_core(null_devices[i]);
[1313ee9]983 fibril_mutex_unlock(&devices_list_mutex);
984
[7fcb74c]985 null_devices[i] = NULL;
986
987 fibril_mutex_unlock(&null_devices_mutex);
988 ipc_answer_0(iid, EOK);
989}
990
991/** Initialize device mapper.
992 *
993 *
994 */
995static bool devmap_init(void)
996{
997 fibril_mutex_lock(&null_devices_mutex);
998
999 unsigned int i;
1000 for (i = 0; i < NULL_DEVICES; i++)
1001 null_devices[i] = NULL;
1002
1003 fibril_mutex_unlock(&null_devices_mutex);
[fc02cc41]1004
[cb41a5e]1005 return true;
1006}
1007
[798f364]1008/** Handle connection with device driver.
[13125d3]1009 *
1010 */
[21c5d41]1011static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
[13125d3]1012{
[6519d6f]1013 /* Accept connection */
1014 ipc_answer_0(iid, EOK);
1015
[1313ee9]1016 devmap_driver_t *driver = devmap_driver_register();
1017 if (driver == NULL)
[798f364]1018 return;
1019
[6519d6f]1020 bool cont = true;
[07e4a3c]1021 while (cont) {
[6519d6f]1022 ipc_call_t call;
1023 ipc_callid_t callid = async_get_call(&call);
1024
[228e490]1025 switch (IPC_GET_IMETHOD(call)) {
[13125d3]1026 case IPC_M_PHONE_HUNGUP:
[07e4a3c]1027 cont = false;
[6519d6f]1028 continue;
[798f364]1029 case DEVMAP_DRIVER_UNREGISTER:
[6519d6f]1030 if (NULL == driver)
[b74959bd]1031 ipc_answer_0(callid, ENOENT);
[6519d6f]1032 else
[b74959bd]1033 ipc_answer_0(callid, EOK);
[07e4a3c]1034 break;
[798f364]1035 case DEVMAP_DEVICE_REGISTER:
1036 /* Register one instance of device */
1037 devmap_device_register(callid, &call, driver);
[07e4a3c]1038 break;
[798f364]1039 case DEVMAP_DEVICE_UNREGISTER:
1040 /* Remove instance of device identified by handler */
1041 devmap_device_unregister(callid, &call, driver);
1042 break;
1043 case DEVMAP_DEVICE_GET_HANDLE:
[1313ee9]1044 devmap_device_get_handle(callid, &call);
[798f364]1045 break;
[1313ee9]1046 case DEVMAP_NAMESPACE_GET_HANDLE:
1047 devmap_namespace_get_handle(callid, &call);
[798f364]1048 break;
1049 default:
[cb819f9]1050 ipc_answer_0(callid, ENOENT);
[798f364]1051 }
1052 }
1053
[7fcb74c]1054 if (driver != NULL) {
[6519d6f]1055 /*
[b74959bd]1056 * Unregister the device driver and all its devices.
1057 */
[798f364]1058 devmap_driver_unregister(driver);
1059 driver = NULL;
1060 }
1061}
1062
1063/** Handle connection with device client.
1064 *
1065 */
[21c5d41]1066static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
[798f364]1067{
[6519d6f]1068 /* Accept connection */
1069 ipc_answer_0(iid, EOK);
1070
[798f364]1071 bool cont = true;
1072 while (cont) {
[6519d6f]1073 ipc_call_t call;
1074 ipc_callid_t callid = async_get_call(&call);
1075
[228e490]1076 switch (IPC_GET_IMETHOD(call)) {
[798f364]1077 case IPC_M_PHONE_HUNGUP:
[07e4a3c]1078 cont = false;
[6519d6f]1079 continue;
[798f364]1080 case DEVMAP_DEVICE_GET_HANDLE:
[1313ee9]1081 devmap_device_get_handle(callid, &call);
1082 break;
1083 case DEVMAP_NAMESPACE_GET_HANDLE:
1084 devmap_namespace_get_handle(callid, &call);
[07e4a3c]1085 break;
[1313ee9]1086 case DEVMAP_HANDLE_PROBE:
1087 devmap_handle_probe(callid, &call);
[13125d3]1088 break;
[1313ee9]1089 case DEVMAP_NULL_CREATE:
[7fcb74c]1090 devmap_null_create(callid, &call);
1091 break;
[1313ee9]1092 case DEVMAP_NULL_DESTROY:
[7fcb74c]1093 devmap_null_destroy(callid, &call);
1094 break;
[1313ee9]1095 case DEVMAP_GET_NAMESPACE_COUNT:
1096 devmap_get_namespace_count(callid, &call);
1097 break;
1098 case DEVMAP_GET_DEVICE_COUNT:
1099 devmap_get_device_count(callid, &call);
1100 break;
1101 case DEVMAP_GET_NAMESPACES:
1102 devmap_get_namespaces(callid, &call);
[cb41a5e]1103 break;
[1313ee9]1104 case DEVMAP_GET_DEVICES:
[cb41a5e]1105 devmap_get_devices(callid, &call);
1106 break;
[13125d3]1107 default:
[cb819f9]1108 ipc_answer_0(callid, ENOENT);
[13125d3]1109 }
1110 }
1111}
1112
[6519d6f]1113/** Function for handling connections to devmap
[798f364]1114 *
1115 */
[21c5d41]1116static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
[798f364]1117{
[21c5d41]1118 /* Select interface */
[96b02eb9]1119 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
[7f3e3e7]1120 case DEVMAP_DRIVER:
1121 devmap_connection_driver(iid, icall);
1122 break;
1123 case DEVMAP_CLIENT:
1124 devmap_connection_client(iid, icall);
1125 break;
[b61d47d]1126 case DEVMAP_CONNECT_TO_DEVICE:
[21c5d41]1127 /* Connect client to selected device */
[b61d47d]1128 devmap_forward(iid, icall);
1129 break;
[7f3e3e7]1130 default:
[6519d6f]1131 /* No such interface */
[5d0e461]1132 ipc_answer_0(iid, ENOENT);
[798f364]1133 }
1134}
[13125d3]1135
[798f364]1136/**
1137 *
1138 */
[13125d3]1139int main(int argc, char *argv[])
1140{
[ab108be4]1141 printf("%s: HelenOS Device Mapper\n", NAME);
[21c5d41]1142
[cb41a5e]1143 if (!devmap_init()) {
[ab108be4]1144 printf("%s: Error while initializing service\n", NAME);
[13125d3]1145 return -1;
1146 }
[21c5d41]1147
[c07af37]1148 /* Set a handler of incomming connections */
[798f364]1149 async_set_client_connection(devmap_connection);
[7fcb74c]1150
[7f3e3e7]1151 /* Register device mapper at naming service */
[96b02eb9]1152 sysarg_t phonead;
[38c706cc]1153 if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0)
[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.