source: mainline/uspace/srv/devmap/devmap.c@ 6e50466

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6e50466 was 47a7174f, checked in by Vojtech Horky <vojtechhorky@…>, 15 years ago

Devmap drivers can customize forwarded connections

It is possible to set an extra parameter for forwarded connections through
devmap. The change shall ensure backward compatibility and allows to connect
to devman-style drivers through their devmap path.

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