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

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

Separate list_t typedef from link_t (user-space part).

  • list_t represents lists
  • Use list_first(), list_last(), list_empty() where appropriate
  • Use list_foreach() where possible
  • assert_link_not_used()
  • usb_hid_report_path_free() shall not unlink the path, caller must do it
  • Property mode set to 100644
File size: 26.5 KB
RevLine 
[13125d3]1/*
2 * Copyright (c) 2007 Josef Cejka
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @defgroup devmap Device mapper.
[6519d6f]31 * @brief HelenOS device mapper.
[13125d3]32 * @{
[6519d6f]33 */
[13125d3]34
35/** @file
36 */
37
38#include <ipc/services.h>
[79ae36dd]39#include <ns.h>
[13125d3]40#include <async.h>
41#include <stdio.h>
42#include <errno.h>
[07e4a3c]43#include <bool.h>
[1e4cada]44#include <fibril_synch.h>
[798f364]45#include <stdlib.h>
[19f857a]46#include <str.h>
[21c5d41]47#include <ipc/devmap.h>
[01b87dc5]48#include <assert.h>
[13125d3]49
[7fcb74c]50#define NAME "devmap"
51#define NULL_DEVICES 256
[13125d3]52
[cb41a5e]53/** Representation of device driver.
54 *
55 * Each driver is responsible for a set of devices.
56 *
57 */
58typedef struct {
[b72efe8]59 /** Link to drivers_list */
[cb41a5e]60 link_t drivers;
[79ae36dd]61
[b72efe8]62 /** List of devices controlled by this driver */
63 list_t devices;
[79ae36dd]64
65 /** Session asociated with this driver */
66 async_sess_t *sess;
67
[cb41a5e]68 /** Device driver name */
69 char *name;
[79ae36dd]70
[fc02cc41]71 /** Fibril mutex for list of devices owned by this driver */
72 fibril_mutex_t devices_mutex;
[cb41a5e]73} devmap_driver_t;
74
[1313ee9]75/** Info about registered namespaces
76 *
77 */
78typedef struct {
[b72efe8]79 /** Link to namespaces_list */
[1313ee9]80 link_t namespaces;
[79ae36dd]81
[1313ee9]82 /** Unique namespace identifier */
[991f645]83 devmap_handle_t handle;
[79ae36dd]84
[1313ee9]85 /** Namespace name */
86 char *name;
[79ae36dd]87
[1313ee9]88 /** Reference count */
89 size_t refcnt;
90} devmap_namespace_t;
91
[cb41a5e]92/** Info about registered device
93 *
94 */
95typedef struct {
[b72efe8]96 /** Link to global list of devices (devices_list) */
[cb41a5e]97 link_t devices;
[b72efe8]98 /** Link to driver list of devices (devmap_driver_t.devices) */
[cb41a5e]99 link_t driver_devices;
[1313ee9]100 /** Unique device identifier */
[991f645]101 devmap_handle_t handle;
[1313ee9]102 /** Device namespace */
103 devmap_namespace_t *namespace;
[cb41a5e]104 /** Device name */
105 char *name;
106 /** Device driver handling this device */
107 devmap_driver_t *driver;
[47a7174f]108 /** Use this interface when forwarding to driver. */
109 sysarg_t forward_interface;
[cb41a5e]110} devmap_device_t;
111
[798f364]112LIST_INITIALIZE(devices_list);
[1313ee9]113LIST_INITIALIZE(namespaces_list);
[798f364]114LIST_INITIALIZE(drivers_list);
[c07af37]115
[fc02cc41]116/* Locking order:
117 * drivers_list_mutex
118 * devices_list_mutex
119 * (devmap_driver_t *)->devices_mutex
120 * create_handle_mutex
121 **/
122
123static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex);
[1cab2f41]124static FIBRIL_CONDVAR_INITIALIZE(devices_list_cv);
[fc02cc41]125static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex);
126static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex);
[7fcb74c]127static FIBRIL_MUTEX_INITIALIZE(null_devices_mutex);
[fc02cc41]128
[991f645]129static devmap_handle_t last_handle = 0;
[7fcb74c]130static devmap_device_t *null_devices[NULL_DEVICES];
[cb41a5e]131
[63e0bdd]132/*
133 * Dummy list for null devices. This is necessary so that null devices can
134 * be used just as any other devices, e.g. in devmap_device_unregister_core().
135 */
136static LIST_INITIALIZE(dummy_null_driver_devices);
137
[991f645]138static devmap_handle_t devmap_create_handle(void)
[798f364]139{
140 /* TODO: allow reusing old handles after their unregistration
[5d0e461]141 * and implement some version of LRU algorithm, avoid overflow
[6519d6f]142 */
143
[fc02cc41]144 fibril_mutex_lock(&create_handle_mutex);
[cb41a5e]145 last_handle++;
[fc02cc41]146 fibril_mutex_unlock(&create_handle_mutex);
[6519d6f]147
[cb41a5e]148 return last_handle;
[13125d3]149}
150
[1313ee9]151/** Convert fully qualified device name to namespace and device name.
152 *
153 * A fully qualified device name can be either a plain device name
154 * (then the namespace is considered to be an empty string) or consist
155 * of two components separated by a slash. No more than one slash
156 * is allowed.
157 *
158 */
159static bool devmap_fqdn_split(const char *fqdn, char **ns_name, char **name)
160{
161 size_t cnt = 0;
162 size_t slash_offset = 0;
163 size_t slash_after = 0;
164
165 size_t offset = 0;
166 size_t offset_prev = 0;
167 wchar_t c;
168
169 while ((c = str_decode(fqdn, &offset, STR_NO_LIMIT)) != 0) {
170 if (c == '/') {
171 cnt++;
172 slash_offset = offset_prev;
173 slash_after = offset;
174 }
175 offset_prev = offset;
176 }
177
178 /* More than one slash */
179 if (cnt > 1)
180 return false;
181
182 /* No slash -> namespace is empty */
183 if (cnt == 0) {
184 *ns_name = str_dup("");
185 if (*ns_name == NULL)
186 return false;
187
188 *name = str_dup(fqdn);
[ab108be4]189 if (*name == NULL) {
190 free(*ns_name);
191 return false;
192 }
193
194 if (str_cmp(*name, "") == 0) {
195 free(*name);
[1313ee9]196 free(*ns_name);
197 return false;
198 }
199
200 return true;
201 }
202
203 /* Exactly one slash */
204 *ns_name = str_ndup(fqdn, slash_offset);
205 if (*ns_name == NULL)
206 return false;
207
208 *name = str_dup(fqdn + slash_after);
[ab108be4]209 if (*name == NULL) {
210 free(*ns_name);
211 return false;
212 }
213
214 if (str_cmp(*name, "") == 0) {
215 free(*name);
[1313ee9]216 free(*ns_name);
217 return false;
218 }
219
220 return true;
221}
222
[01b87dc5]223/** Find namespace with given name. */
[1313ee9]224static devmap_namespace_t *devmap_namespace_find_name(const char *name)
225{
[01b87dc5]226 assert(fibril_mutex_is_locked(&devices_list_mutex));
227
[b72efe8]228 list_foreach(namespaces_list, item) {
[ab108be4]229 devmap_namespace_t *namespace =
230 list_get_instance(item, devmap_namespace_t, namespaces);
[1313ee9]231 if (str_cmp(namespace->name, name) == 0)
232 return namespace;
233 }
234
235 return NULL;
236}
237
238/** Find namespace with given handle.
239 *
240 * @todo: use hash table
241 *
242 */
[991f645]243static devmap_namespace_t *devmap_namespace_find_handle(devmap_handle_t handle)
[1313ee9]244{
[01b87dc5]245 assert(fibril_mutex_is_locked(&devices_list_mutex));
246
[b72efe8]247 list_foreach(namespaces_list, item) {
[ab108be4]248 devmap_namespace_t *namespace =
249 list_get_instance(item, devmap_namespace_t, namespaces);
[1313ee9]250 if (namespace->handle == handle)
251 return namespace;
252 }
253
254 return NULL;
255}
256
[01b87dc5]257/** Find device with given name. */
[1313ee9]258static devmap_device_t *devmap_device_find_name(const char *ns_name,
259 const char *name)
[07e4a3c]260{
[01b87dc5]261 assert(fibril_mutex_is_locked(&devices_list_mutex));
262
[b72efe8]263 list_foreach(devices_list, item) {
[ab108be4]264 devmap_device_t *device =
265 list_get_instance(item, devmap_device_t, devices);
266 if ((str_cmp(device->namespace->name, ns_name) == 0)
267 && (str_cmp(device->name, name) == 0))
[1313ee9]268 return device;
[798f364]269 }
[6519d6f]270
[1313ee9]271 return NULL;
[798f364]272}
273
274/** Find device with given handle.
[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{
[01b87dc5]281 assert(fibril_mutex_is_locked(&devices_list_mutex));
282
[b72efe8]283 list_foreach(devices_list, item) {
[ab108be4]284 devmap_device_t *device =
285 list_get_instance(item, devmap_device_t, devices);
[6519d6f]286 if (device->handle == handle)
[1313ee9]287 return device;
[798f364]288 }
[6519d6f]289
[1313ee9]290 return NULL;
291}
292
[01b87dc5]293/** Create a namespace (if not already present). */
[1313ee9]294static devmap_namespace_t *devmap_namespace_create(const char *ns_name)
295{
[01b87dc5]296 devmap_namespace_t *namespace;
297
298 assert(fibril_mutex_is_locked(&devices_list_mutex));
299
300 namespace = devmap_namespace_find_name(ns_name);
[1313ee9]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
[01b87dc5]325/** Destroy a namespace (if it is no longer needed). */
[1313ee9]326static void devmap_namespace_destroy(devmap_namespace_t *namespace)
327{
[01b87dc5]328 assert(fibril_mutex_is_locked(&devices_list_mutex));
329
[1313ee9]330 if (namespace->refcnt == 0) {
331 list_remove(&(namespace->namespaces));
332
333 free(namespace->name);
334 free(namespace);
335 }
336}
337
[01b87dc5]338/** Increase namespace reference count by including device. */
[1313ee9]339static void devmap_namespace_addref(devmap_namespace_t *namespace,
340 devmap_device_t *device)
341{
[01b87dc5]342 assert(fibril_mutex_is_locked(&devices_list_mutex));
343
[1313ee9]344 device->namespace = namespace;
345 namespace->refcnt++;
346}
347
[01b87dc5]348/** Decrease namespace reference count. */
[1313ee9]349static void devmap_namespace_delref(devmap_namespace_t *namespace)
350{
[01b87dc5]351 assert(fibril_mutex_is_locked(&devices_list_mutex));
352
[1313ee9]353 namespace->refcnt--;
354 devmap_namespace_destroy(namespace);
355}
356
[01b87dc5]357/** Unregister device and free it. */
[1313ee9]358static void devmap_device_unregister_core(devmap_device_t *device)
[798f364]359{
[01b87dc5]360 assert(fibril_mutex_is_locked(&devices_list_mutex));
361
[1313ee9]362 devmap_namespace_delref(device->namespace);
[798f364]363 list_remove(&(device->devices));
364 list_remove(&(device->driver_devices));
[6519d6f]365
366 free(device->name);
[798f364]367 free(device);
368}
369
[7f3e3e7]370/**
371 * Read info about new driver and add it into linked list of registered
372 * drivers.
[798f364]373 */
[1313ee9]374static devmap_driver_t *devmap_driver_register(void)
[798f364]375{
[6519d6f]376 ipc_call_t icall;
377 ipc_callid_t iid = async_get_call(&icall);
378
[228e490]379 if (IPC_GET_IMETHOD(icall) != DEVMAP_DRIVER_REGISTER) {
[ffa2c8ef]380 async_answer_0(iid, EREFUSED);
[1313ee9]381 return NULL;
[6519d6f]382 }
383
[ab108be4]384 devmap_driver_t *driver =
385 (devmap_driver_t *) malloc(sizeof(devmap_driver_t));
[6519d6f]386 if (driver == NULL) {
[ffa2c8ef]387 async_answer_0(iid, ENOMEM);
[1313ee9]388 return NULL;
[07e4a3c]389 }
[6519d6f]390
391 /*
[798f364]392 * Get driver name
393 */
[4cac2d69]394 int rc = async_data_write_accept((void **) &driver->name, true, 0,
[eda925a]395 DEVMAP_NAME_MAXLEN, 0, NULL);
[1313ee9]396 if (rc != EOK) {
[798f364]397 free(driver);
[ffa2c8ef]398 async_answer_0(iid, rc);
[1313ee9]399 return NULL;
[798f364]400 }
[6519d6f]401
402 /*
[5d0e461]403 * Create connection to the driver
[798f364]404 */
[79ae36dd]405 driver->sess = async_callback_receive(EXCHANGE_SERIALIZE);
406 if (!driver->sess) {
[798f364]407 free(driver->name);
408 free(driver);
[ffa2c8ef]409 async_answer_0(iid, ENOTSUP);
[1313ee9]410 return NULL;
[798f364]411 }
[6519d6f]412
[ab108be4]413 /*
414 * Initialize mutex for list of devices
415 * owned by this driver
416 */
417 fibril_mutex_initialize(&driver->devices_mutex);
418
419 /*
420 * Initialize list of asociated devices
421 */
422 list_initialize(&driver->devices);
[ca2a18e]423
424 link_initialize(&driver->drivers);
[6519d6f]425
[fc02cc41]426 fibril_mutex_lock(&drivers_list_mutex);
427
[7f3e3e7]428 /* TODO:
[ab108be4]429 * Check that no driver with name equal to
430 * driver->name is registered
[7f3e3e7]431 */
[6519d6f]432
433 /*
[798f364]434 * Insert new driver into list of registered drivers
435 */
436 list_append(&(driver->drivers), &drivers_list);
[fc02cc41]437 fibril_mutex_unlock(&drivers_list_mutex);
[798f364]438
[ffa2c8ef]439 async_answer_0(iid, EOK);
[6519d6f]440
[1313ee9]441 return driver;
[07e4a3c]442}
443
[6519d6f]444/**
445 * Unregister device driver, unregister all its devices and free driver
[b74959bd]446 * structure.
[6519d6f]447 *
[798f364]448 */
449static int devmap_driver_unregister(devmap_driver_t *driver)
[07e4a3c]450{
[6519d6f]451 if (driver == NULL)
[798f364]452 return EEXISTS;
[21c5d41]453
[fc02cc41]454 fibril_mutex_lock(&drivers_list_mutex);
455
[79ae36dd]456 if (driver->sess)
457 async_hangup(driver->sess);
[798f364]458
[cb41a5e]459 /* Remove it from list of drivers */
[798f364]460 list_remove(&(driver->drivers));
[6519d6f]461
[fc02cc41]462 /* Unregister all its devices */
463 fibril_mutex_lock(&devices_list_mutex);
464 fibril_mutex_lock(&driver->devices_mutex);
465
[b72efe8]466 while (!list_empty(&driver->devices)) {
467 devmap_device_t *device = list_get_instance(
468 list_first(&driver->devices), devmap_device_t,
469 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) {
[ffa2c8ef]493 async_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) {
[ffa2c8ef]501 async_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);
[ffa2c8ef]514 async_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);
[ffa2c8ef]522 async_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);
[ffa2c8ef]536 async_answer_0(iid, ENOMEM);
[798f364]537 return;
[07e4a3c]538 }
[798f364]539
[ca2a18e]540 link_initialize(&device->devices);
541 link_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,
[4ae90f9]546 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);
[ffa2c8ef]551 async_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
[ffa2c8ef]573 async_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
[79ae36dd]602 if ((dev == NULL) || (dev->driver == NULL) || (!dev->driver->sess)) {
[ab108be4]603 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]604 async_answer_0(callid, ENOENT);
[798f364]605 return;
[6519d6f]606 }
607
[79ae36dd]608 async_exch_t *exch = async_exchange_begin(dev->driver->sess);
609
610 if (dev->forward_interface == 0)
611 async_forward_fast(callid, exch, dev->handle, 0, 0, IPC_FF_NONE);
612 else
613 async_forward_fast(callid, exch, dev->forward_interface,
614 dev->handle, 0, IPC_FF_NONE);
615
616 async_exchange_end(exch);
[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) {
[ffa2c8ef]635 async_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);
[ffa2c8ef]643 async_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
[ffa2c8ef]670 async_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
[ffa2c8ef]677 async_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) {
[ffa2c8ef]698 async_answer_0(iid, rc);
[1313ee9]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
[ffa2c8ef]723 async_answer_0(iid, ENOENT);
[1313ee9]724 free(name);
725 fibril_mutex_unlock(&devices_list_mutex);
[798f364]726 return;
727 }
[6519d6f]728
[ffa2c8ef]729 async_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)
[ffa2c8ef]745 async_answer_1(iid, EOK, DEV_HANDLE_NONE);
[1313ee9]746 else
[ffa2c8ef]747 async_answer_1(iid, EOK, DEV_HANDLE_DEVICE);
[1313ee9]748 } else
[ffa2c8ef]749 async_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);
[ffa2c8ef]757 async_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)
[ffa2c8ef]768 async_answer_0(iid, EEXISTS);
[1313ee9]769 else
[ffa2c8ef]770 async_answer_1(iid, EOK, namespace->refcnt);
[1313ee9]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)) {
[ffa2c8ef]780 async_answer_0(callid, EREFUSED);
781 async_answer_0(iid, EREFUSED);
[cb41a5e]782 return;
783 }
784
785 if ((size % sizeof(dev_desc_t)) != 0) {
[ffa2c8ef]786 async_answer_0(callid, EINVAL);
787 async_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);
[ffa2c8ef]796 async_answer_0(callid, EOVERFLOW);
797 async_answer_0(iid, EOVERFLOW);
[1313ee9]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);
[ffa2c8ef]804 async_answer_0(callid, ENOMEM);
805 async_answer_0(iid, ENOMEM);
[cb41a5e]806 return;
807 }
808
[5d0e461]809 size_t pos = 0;
[b72efe8]810 list_foreach(namespaces_list, item) {
[ab108be4]811 devmap_namespace_t *namespace =
812 list_get_instance(item, devmap_namespace_t, namespaces);
[cb41a5e]813
[1313ee9]814 desc[pos].handle = namespace->handle;
815 str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, namespace->name);
[cb41a5e]816 pos++;
817 }
818
[96b02eb9]819 sysarg_t retval = async_data_read_finalize(callid, desc, size);
[1313ee9]820
821 free(desc);
822 fibril_mutex_unlock(&devices_list_mutex);
823
[ffa2c8ef]824 async_answer_0(iid, retval);
[1313ee9]825}
826
827static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
828{
829 /* FIXME: Use faster algorithm which can make better use
830 of namespaces */
831
832 ipc_callid_t callid;
833 size_t size;
834 if (!async_data_read_receive(&callid, &size)) {
[ffa2c8ef]835 async_answer_0(callid, EREFUSED);
836 async_answer_0(iid, EREFUSED);
[cb41a5e]837 return;
838 }
839
[1313ee9]840 if ((size % sizeof(dev_desc_t)) != 0) {
[ffa2c8ef]841 async_answer_0(callid, EINVAL);
842 async_answer_0(iid, EINVAL);
[1313ee9]843 return;
844 }
845
846 fibril_mutex_lock(&devices_list_mutex);
847
[ab108be4]848 devmap_namespace_t *namespace =
849 devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
[1313ee9]850 if (namespace == NULL) {
851 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]852 async_answer_0(callid, ENOENT);
853 async_answer_0(iid, ENOENT);
[1313ee9]854 return;
855 }
856
857 size_t count = size / sizeof(dev_desc_t);
858 if (count != namespace->refcnt) {
[ab108be4]859 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]860 async_answer_0(callid, EOVERFLOW);
861 async_answer_0(iid, EOVERFLOW);
[1313ee9]862 return;
863 }
864
865 dev_desc_t *desc = (dev_desc_t *) malloc(size);
866 if (desc == NULL) {
[ab108be4]867 fibril_mutex_unlock(&devices_list_mutex);
[ffa2c8ef]868 async_answer_0(callid, ENOMEM);
869 async_answer_0(iid, EREFUSED);
[1313ee9]870 return;
871 }
[cb41a5e]872
[1313ee9]873 size_t pos = 0;
[b72efe8]874 list_foreach(devices_list, item) {
[ab108be4]875 devmap_device_t *device =
876 list_get_instance(item, devmap_device_t, devices);
[1313ee9]877
878 if (device->namespace == namespace) {
879 desc[pos].handle = device->handle;
880 str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
881 pos++;
882 }
883 }
884
[96b02eb9]885 sysarg_t retval = async_data_read_finalize(callid, desc, size);
[1313ee9]886
887 free(desc);
[fc02cc41]888 fibril_mutex_unlock(&devices_list_mutex);
889
[ffa2c8ef]890 async_answer_0(iid, retval);
[cb41a5e]891}
892
[7fcb74c]893static void devmap_null_create(ipc_callid_t iid, ipc_call_t *icall)
[cb41a5e]894{
[7fcb74c]895 fibril_mutex_lock(&null_devices_mutex);
896
897 unsigned int i;
898 bool fnd = false;
899
900 for (i = 0; i < NULL_DEVICES; i++) {
901 if (null_devices[i] == NULL) {
902 fnd = true;
903 break;
904 }
905 }
906
907 if (!fnd) {
908 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]909 async_answer_0(iid, ENOMEM);
[7fcb74c]910 return;
911 }
912
[1313ee9]913 char null[DEVMAP_NAME_MAXLEN];
914 snprintf(null, DEVMAP_NAME_MAXLEN, "%u", i);
915
916 char *dev_name = str_dup(null);
917 if (dev_name == NULL) {
918 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]919 async_answer_0(iid, ENOMEM);
[1313ee9]920 return;
921 }
922
[ab108be4]923 devmap_device_t *device =
924 (devmap_device_t *) malloc(sizeof(devmap_device_t));
[7fcb74c]925 if (device == NULL) {
926 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]927 async_answer_0(iid, ENOMEM);
[7fcb74c]928 return;
929 }
[cb41a5e]930
[1313ee9]931 fibril_mutex_lock(&devices_list_mutex);
[7fcb74c]932
[1313ee9]933 devmap_namespace_t *namespace = devmap_namespace_create("null");
[ab108be4]934 if (namespace == NULL) {
[1313ee9]935 fibril_mutex_lock(&devices_list_mutex);
[7fcb74c]936 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]937 async_answer_0(iid, ENOMEM);
[7fcb74c]938 return;
[cb41a5e]939 }
940
[ca2a18e]941 link_initialize(&device->devices);
942 link_initialize(&device->driver_devices);
[cb41a5e]943
944 /* Get unique device handle */
945 device->handle = devmap_create_handle();
946 device->driver = NULL;
947
[1313ee9]948 devmap_namespace_addref(namespace, device);
949 device->name = dev_name;
950
[63e0bdd]951 /*
952 * Insert device into list of all devices and into null devices array.
953 * Insert device into a dummy list of null driver's devices so that it
954 * can be safely removed later.
955 */
[cb41a5e]956 list_append(&device->devices, &devices_list);
[63e0bdd]957 list_append(&device->driver_devices, &dummy_null_driver_devices);
[7fcb74c]958 null_devices[i] = device;
[cb41a5e]959
[fc02cc41]960 fibril_mutex_unlock(&devices_list_mutex);
[7fcb74c]961 fibril_mutex_unlock(&null_devices_mutex);
962
[ffa2c8ef]963 async_answer_1(iid, EOK, (sysarg_t) i);
[7fcb74c]964}
965
966static void devmap_null_destroy(ipc_callid_t iid, ipc_call_t *icall)
967{
[96b02eb9]968 sysarg_t i = IPC_GET_ARG1(*icall);
[ab108be4]969 if (i >= NULL_DEVICES) {
[ffa2c8ef]970 async_answer_0(iid, ELIMIT);
[ab108be4]971 return;
972 }
973
974 fibril_mutex_lock(&null_devices_mutex);
[7fcb74c]975
976 if (null_devices[i] == NULL) {
[ab108be4]977 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]978 async_answer_0(iid, ENOENT);
[7fcb74c]979 return;
980 }
981
[1313ee9]982 fibril_mutex_lock(&devices_list_mutex);
[7fcb74c]983 devmap_device_unregister_core(null_devices[i]);
[1313ee9]984 fibril_mutex_unlock(&devices_list_mutex);
985
[7fcb74c]986 null_devices[i] = NULL;
987
988 fibril_mutex_unlock(&null_devices_mutex);
[ffa2c8ef]989 async_answer_0(iid, EOK);
[7fcb74c]990}
991
992/** Initialize device mapper.
993 *
994 *
995 */
996static bool devmap_init(void)
997{
998 fibril_mutex_lock(&null_devices_mutex);
999
1000 unsigned int i;
1001 for (i = 0; i < NULL_DEVICES; i++)
1002 null_devices[i] = NULL;
1003
1004 fibril_mutex_unlock(&null_devices_mutex);
[fc02cc41]1005
[cb41a5e]1006 return true;
1007}
1008
[798f364]1009/** Handle connection with device driver.
[13125d3]1010 *
1011 */
[21c5d41]1012static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
[13125d3]1013{
[6519d6f]1014 /* Accept connection */
[ffa2c8ef]1015 async_answer_0(iid, EOK);
[6519d6f]1016
[1313ee9]1017 devmap_driver_t *driver = devmap_driver_register();
1018 if (driver == NULL)
[798f364]1019 return;
1020
[79ae36dd]1021 while (true) {
[6519d6f]1022 ipc_call_t call;
1023 ipc_callid_t callid = async_get_call(&call);
1024
[79ae36dd]1025 if (!IPC_GET_IMETHOD(call))
1026 break;
1027
[228e490]1028 switch (IPC_GET_IMETHOD(call)) {
[798f364]1029 case DEVMAP_DRIVER_UNREGISTER:
[6519d6f]1030 if (NULL == driver)
[ffa2c8ef]1031 async_answer_0(callid, ENOENT);
[6519d6f]1032 else
[ffa2c8ef]1033 async_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:
[ffa2c8ef]1050 async_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 */
[ffa2c8ef]1069 async_answer_0(iid, EOK);
[6519d6f]1070
[79ae36dd]1071 while (true) {
[6519d6f]1072 ipc_call_t call;
1073 ipc_callid_t callid = async_get_call(&call);
1074
[79ae36dd]1075 if (!IPC_GET_IMETHOD(call))
1076 break;
1077
[228e490]1078 switch (IPC_GET_IMETHOD(call)) {
[798f364]1079 case DEVMAP_DEVICE_GET_HANDLE:
[1313ee9]1080 devmap_device_get_handle(callid, &call);
1081 break;
1082 case DEVMAP_NAMESPACE_GET_HANDLE:
1083 devmap_namespace_get_handle(callid, &call);
[07e4a3c]1084 break;
[1313ee9]1085 case DEVMAP_HANDLE_PROBE:
1086 devmap_handle_probe(callid, &call);
[13125d3]1087 break;
[1313ee9]1088 case DEVMAP_NULL_CREATE:
[7fcb74c]1089 devmap_null_create(callid, &call);
1090 break;
[1313ee9]1091 case DEVMAP_NULL_DESTROY:
[7fcb74c]1092 devmap_null_destroy(callid, &call);
1093 break;
[1313ee9]1094 case DEVMAP_GET_NAMESPACE_COUNT:
1095 devmap_get_namespace_count(callid, &call);
1096 break;
1097 case DEVMAP_GET_DEVICE_COUNT:
1098 devmap_get_device_count(callid, &call);
1099 break;
1100 case DEVMAP_GET_NAMESPACES:
1101 devmap_get_namespaces(callid, &call);
[cb41a5e]1102 break;
[1313ee9]1103 case DEVMAP_GET_DEVICES:
[cb41a5e]1104 devmap_get_devices(callid, &call);
1105 break;
[13125d3]1106 default:
[ffa2c8ef]1107 async_answer_0(callid, ENOENT);
[13125d3]1108 }
1109 }
1110}
1111
[6519d6f]1112/** Function for handling connections to devmap
[798f364]1113 *
1114 */
[9934f7d]1115static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[798f364]1116{
[21c5d41]1117 /* Select interface */
[96b02eb9]1118 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
[7f3e3e7]1119 case DEVMAP_DRIVER:
1120 devmap_connection_driver(iid, icall);
1121 break;
1122 case DEVMAP_CLIENT:
1123 devmap_connection_client(iid, icall);
1124 break;
[b61d47d]1125 case DEVMAP_CONNECT_TO_DEVICE:
[21c5d41]1126 /* Connect client to selected device */
[b61d47d]1127 devmap_forward(iid, icall);
1128 break;
[7f3e3e7]1129 default:
[6519d6f]1130 /* No such interface */
[ffa2c8ef]1131 async_answer_0(iid, ENOENT);
[798f364]1132 }
1133}
[13125d3]1134
[798f364]1135/**
1136 *
1137 */
[13125d3]1138int main(int argc, char *argv[])
1139{
[ab108be4]1140 printf("%s: HelenOS Device Mapper\n", NAME);
[21c5d41]1141
[cb41a5e]1142 if (!devmap_init()) {
[ab108be4]1143 printf("%s: Error while initializing service\n", NAME);
[13125d3]1144 return -1;
1145 }
[21c5d41]1146
[c07af37]1147 /* Set a handler of incomming connections */
[798f364]1148 async_set_client_connection(devmap_connection);
[7fcb74c]1149
[7f3e3e7]1150 /* Register device mapper at naming service */
[007e6efa]1151 if (service_register(SERVICE_DEVMAP) != EOK)
[13125d3]1152 return -1;
1153
[ab108be4]1154 printf("%s: Accepting connections\n", NAME);
[13125d3]1155 async_manager();
[6519d6f]1156
[13125d3]1157 /* Never reached */
1158 return 0;
1159}
1160
[fb623e2]1161/**
[13125d3]1162 * @}
1163 */
Note: See TracBrowser for help on using the repository browser.