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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since dd8d5a7 was 96b02eb9, checked in by Martin Decky <martin@…>, 15 years ago

more unification of basic types

  • use sysarg_t and native_t (unsigned and signed variant) in both kernel and uspace
  • remove ipcarg_t in favour of sysarg_t

(no change in functionality)

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