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

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

improve naming conventions:
merge async_data_receive() and async_string_receive() into async_data_write_accept()
rename async_data_void() to async_data_write_void()
rename async_data_forward_fast() to async_data_write_forward_fast()
rename async_data_forward_n_m to async_data_write_forward_n_m

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