source: mainline/uspace/srv/devman/main.c@ 041b026

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

Move driver-related devman functionality to a separate module.

  • Property mode set to 100644
File size: 36.3 KB
Line 
1/*
2 * Copyright (c) 2010 Lenka Trochtova
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 devman Device manager.
31 * @brief HelenOS device manager.
32 * @{
33 */
34
35/** @file
36 */
37
38#include <inttypes.h>
39#include <assert.h>
40#include <ipc/services.h>
41#include <ns.h>
42#include <async.h>
43#include <stdio.h>
44#include <errno.h>
45#include <str_error.h>
46#include <stdbool.h>
47#include <fibril_synch.h>
48#include <stdlib.h>
49#include <str.h>
50#include <dirent.h>
51#include <fcntl.h>
52#include <sys/stat.h>
53#include <ctype.h>
54#include <io/log.h>
55#include <ipc/devman.h>
56#include <ipc/driver.h>
57#include <thread.h>
58#include <loc.h>
59
60#include "devman.h"
61#include "driver.h"
62
63#define DRIVER_DEFAULT_STORE "/drv"
64
65static driver_list_t drivers_list;
66static dev_tree_t device_tree;
67
68static int init_running_drv(void *drv);
69
70/** Register running driver. */
71static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call)
72{
73 driver_t *driver = NULL;
74 char *drv_name = NULL;
75
76 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_driver_register");
77
78 /* Get driver name. */
79 int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
80 if (rc != EOK) {
81 async_answer_0(callid, rc);
82 return NULL;
83 }
84
85 log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s' driver is trying to register.",
86 drv_name);
87
88 /* Find driver structure. */
89 driver = find_driver(&drivers_list, drv_name);
90 if (driver == NULL) {
91 log_msg(LOG_DEFAULT, LVL_ERROR, "No driver named `%s' was found.", drv_name);
92 free(drv_name);
93 drv_name = NULL;
94 async_answer_0(callid, ENOENT);
95 return NULL;
96 }
97
98 free(drv_name);
99 drv_name = NULL;
100
101 fibril_mutex_lock(&driver->driver_mutex);
102
103 if (driver->sess) {
104 /* We already have a connection to the driver. */
105 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver '%s' already started.\n",
106 driver->name);
107 fibril_mutex_unlock(&driver->driver_mutex);
108 async_answer_0(callid, EEXISTS);
109 return NULL;
110 }
111
112 switch (driver->state) {
113 case DRIVER_NOT_STARTED:
114 /* Somebody started the driver manually. */
115 log_msg(LOG_DEFAULT, LVL_NOTE, "Driver '%s' started manually.\n",
116 driver->name);
117 driver->state = DRIVER_STARTING;
118 break;
119 case DRIVER_STARTING:
120 /* The expected case */
121 break;
122 case DRIVER_RUNNING:
123 /* Should not happen since we do not have a connected session */
124 assert(false);
125 }
126
127 /* Create connection to the driver. */
128 log_msg(LOG_DEFAULT, LVL_DEBUG, "Creating connection to the `%s' driver.",
129 driver->name);
130 driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
131 if (!driver->sess) {
132 fibril_mutex_unlock(&driver->driver_mutex);
133 async_answer_0(callid, ENOTSUP);
134 return NULL;
135 }
136 /* FIXME: Work around problem with callback sessions */
137 async_sess_args_set(driver->sess, DRIVER_DEVMAN, 0, 0);
138
139 log_msg(LOG_DEFAULT, LVL_NOTE,
140 "The `%s' driver was successfully registered as running.",
141 driver->name);
142
143 /*
144 * Initialize the driver as running (e.g. pass assigned devices to it)
145 * in a separate fibril; the separate fibril is used to enable the
146 * driver to use devman service during the driver's initialization.
147 */
148 fid_t fid = fibril_create(init_running_drv, driver);
149 if (fid == 0) {
150 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create initialization fibril " \
151 "for driver `%s'.", driver->name);
152 fibril_mutex_unlock(&driver->driver_mutex);
153 async_answer_0(callid, ENOMEM);
154 return NULL;
155 }
156
157 fibril_add_ready(fid);
158 fibril_mutex_unlock(&driver->driver_mutex);
159
160 async_answer_0(callid, EOK);
161 return driver;
162}
163
164/** Receive device match ID from the device's parent driver and add it to the
165 * list of devices match ids.
166 *
167 * @param match_ids The list of the device's match ids.
168 * @return Zero on success, negative error code otherwise.
169 */
170static int devman_receive_match_id(match_id_list_t *match_ids)
171{
172 match_id_t *match_id = create_match_id();
173 ipc_callid_t callid;
174 ipc_call_t call;
175 int rc = 0;
176
177 callid = async_get_call(&call);
178 if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
179 log_msg(LOG_DEFAULT, LVL_ERROR,
180 "Invalid protocol when trying to receive match id.");
181 async_answer_0(callid, EINVAL);
182 delete_match_id(match_id);
183 return EINVAL;
184 }
185
186 if (match_id == NULL) {
187 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate match id.");
188 async_answer_0(callid, ENOMEM);
189 return ENOMEM;
190 }
191
192 async_answer_0(callid, EOK);
193
194 match_id->score = IPC_GET_ARG1(call);
195
196 char *match_id_str;
197 rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0);
198 match_id->id = match_id_str;
199 if (rc != EOK) {
200 delete_match_id(match_id);
201 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to receive match id string: %s.",
202 str_error(rc));
203 return rc;
204 }
205
206 list_append(&match_id->link, &match_ids->ids);
207
208 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received match id `%s', score %d.",
209 match_id->id, match_id->score);
210 return rc;
211}
212
213/** Receive device match IDs from the device's parent driver and add them to the
214 * list of devices match ids.
215 *
216 * @param match_count The number of device's match ids to be received.
217 * @param match_ids The list of the device's match ids.
218 * @return Zero on success, negative error code otherwise.
219 */
220static int devman_receive_match_ids(sysarg_t match_count,
221 match_id_list_t *match_ids)
222{
223 int ret = EOK;
224 size_t i;
225
226 for (i = 0; i < match_count; i++) {
227 if (EOK != (ret = devman_receive_match_id(match_ids)))
228 return ret;
229 }
230 return ret;
231}
232
233static int assign_driver_fibril(void *arg)
234{
235 dev_node_t *dev_node = (dev_node_t *) arg;
236 assign_driver(dev_node, &drivers_list, &device_tree);
237
238 /* Delete one reference we got from the caller. */
239 dev_del_ref(dev_node);
240 return EOK;
241}
242
243static int online_function(fun_node_t *fun)
244{
245 dev_node_t *dev;
246
247 fibril_rwlock_write_lock(&device_tree.rwlock);
248
249 if (fun->state == FUN_ON_LINE) {
250 fibril_rwlock_write_unlock(&device_tree.rwlock);
251 log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already on line.",
252 fun->pathname);
253 return EOK;
254 }
255
256 if (fun->ftype == fun_inner) {
257 dev = create_dev_node();
258 if (dev == NULL) {
259 fibril_rwlock_write_unlock(&device_tree.rwlock);
260 return ENOMEM;
261 }
262
263 insert_dev_node(&device_tree, dev, fun);
264 dev_add_ref(dev);
265 }
266
267 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
268
269 if (fun->ftype == fun_inner) {
270 dev = fun->child;
271 assert(dev != NULL);
272
273 /* Give one reference over to assign_driver_fibril(). */
274 dev_add_ref(dev);
275
276 /*
277 * Try to find a suitable driver and assign it to the device. We do
278 * not want to block the current fibril that is used for processing
279 * incoming calls: we will launch a separate fibril to handle the
280 * driver assigning. That is because assign_driver can actually include
281 * task spawning which could take some time.
282 */
283 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
284 if (assign_fibril == 0) {
285 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create fibril for "
286 "assigning driver.");
287 /* XXX Cleanup */
288 fibril_rwlock_write_unlock(&device_tree.rwlock);
289 return ENOMEM;
290 }
291 fibril_add_ready(assign_fibril);
292 } else
293 loc_register_tree_function(fun, &device_tree);
294
295 fibril_rwlock_write_unlock(&device_tree.rwlock);
296
297 return EOK;
298}
299
300static int offline_function(fun_node_t *fun)
301{
302 int rc;
303
304 fibril_rwlock_write_lock(&device_tree.rwlock);
305
306 if (fun->state == FUN_OFF_LINE) {
307 fibril_rwlock_write_unlock(&device_tree.rwlock);
308 log_msg(LOG_DEFAULT, LVL_WARN, "Function %s is already off line.",
309 fun->pathname);
310 return EOK;
311 }
312
313 if (fun->ftype == fun_inner) {
314 log_msg(LOG_DEFAULT, LVL_DEBUG, "Offlining inner function %s.",
315 fun->pathname);
316
317 if (fun->child != NULL) {
318 dev_node_t *dev = fun->child;
319 device_state_t dev_state;
320
321 dev_add_ref(dev);
322 dev_state = dev->state;
323
324 fibril_rwlock_write_unlock(&device_tree.rwlock);
325
326 /* If device is owned by driver, ask driver to give it up. */
327 if (dev_state == DEVICE_USABLE) {
328 rc = driver_dev_remove(&device_tree, dev);
329 if (rc != EOK) {
330 dev_del_ref(dev);
331 return ENOTSUP;
332 }
333 }
334
335 /* Verify that driver removed all functions */
336 fibril_rwlock_read_lock(&device_tree.rwlock);
337 if (!list_empty(&dev->functions)) {
338 fibril_rwlock_read_unlock(&device_tree.rwlock);
339 dev_del_ref(dev);
340 return EIO;
341 }
342
343 driver_t *driver = dev->drv;
344 fibril_rwlock_read_unlock(&device_tree.rwlock);
345
346 if (driver)
347 detach_driver(&device_tree, dev);
348
349 fibril_rwlock_write_lock(&device_tree.rwlock);
350 remove_dev_node(&device_tree, dev);
351
352 /* Delete ref created when node was inserted */
353 dev_del_ref(dev);
354 /* Delete ref created by dev_add_ref(dev) above */
355 dev_del_ref(dev);
356 }
357 } else {
358 /* Unregister from location service */
359 rc = loc_service_unregister(fun->service_id);
360 if (rc != EOK) {
361 fibril_rwlock_write_unlock(&device_tree.rwlock);
362 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree service.");
363 return EIO;
364 }
365
366 fun->service_id = 0;
367 }
368
369 fun->state = FUN_OFF_LINE;
370 fibril_rwlock_write_unlock(&device_tree.rwlock);
371
372 return EOK;
373}
374
375/** Handle function registration.
376 *
377 * Child devices are registered by their parent's device driver.
378 */
379static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
380{
381 fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
382 devman_handle_t dev_handle = IPC_GET_ARG2(*call);
383 sysarg_t match_count = IPC_GET_ARG3(*call);
384 dev_tree_t *tree = &device_tree;
385
386 dev_node_t *pdev = find_dev_node(&device_tree, dev_handle);
387 if (pdev == NULL) {
388 async_answer_0(callid, ENOENT);
389 return;
390 }
391
392 if (ftype != fun_inner && ftype != fun_exposed) {
393 /* Unknown function type */
394 log_msg(LOG_DEFAULT, LVL_ERROR,
395 "Unknown function type %d provided by driver.",
396 (int) ftype);
397
398 dev_del_ref(pdev);
399 async_answer_0(callid, EINVAL);
400 return;
401 }
402
403 char *fun_name = NULL;
404 int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
405 if (rc != EOK) {
406 dev_del_ref(pdev);
407 async_answer_0(callid, rc);
408 return;
409 }
410
411 fibril_rwlock_write_lock(&tree->rwlock);
412
413 /* Check device state */
414 if (pdev->state == DEVICE_REMOVED) {
415 fibril_rwlock_write_unlock(&tree->rwlock);
416 dev_del_ref(pdev);
417 async_answer_0(callid, ENOENT);
418 return;
419 }
420
421 /* Check that function with same name is not there already. */
422 fun_node_t *tfun = find_fun_node_in_device(tree, pdev, fun_name);
423 if (tfun) {
424 fun_del_ref(tfun); /* drop the new unwanted reference */
425 fibril_rwlock_write_unlock(&tree->rwlock);
426 dev_del_ref(pdev);
427 async_answer_0(callid, EEXISTS);
428 printf(NAME ": Warning, driver tried to register `%s' twice.\n",
429 fun_name);
430 free(fun_name);
431 return;
432 }
433
434 fun_node_t *fun = create_fun_node();
435 /* One reference for creation, one for us */
436 fun_add_ref(fun);
437 fun_add_ref(fun);
438 fun->ftype = ftype;
439
440 /*
441 * We can lock the function here even when holding the tree because
442 * we know it cannot be held by anyone else yet.
443 */
444 fun_busy_lock(fun);
445
446 if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
447 fibril_rwlock_write_unlock(&tree->rwlock);
448 dev_del_ref(pdev);
449 fun_busy_unlock(fun);
450 fun_del_ref(fun);
451 delete_fun_node(fun);
452 async_answer_0(callid, ENOMEM);
453 return;
454 }
455
456 fibril_rwlock_write_unlock(&tree->rwlock);
457 dev_del_ref(pdev);
458
459 devman_receive_match_ids(match_count, &fun->match_ids);
460
461 rc = online_function(fun);
462 if (rc != EOK) {
463 /* XXX Set some failed state? */
464 fun_busy_unlock(fun);
465 fun_del_ref(fun);
466 async_answer_0(callid, rc);
467 return;
468 }
469
470 fun_busy_unlock(fun);
471 fun_del_ref(fun);
472
473 /* Return device handle to parent's driver. */
474 async_answer_1(callid, EOK, fun->handle);
475}
476
477static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)
478{
479 devman_handle_t handle = IPC_GET_ARG1(*call);
480 category_id_t cat_id;
481 int rc;
482
483 /* Get category name. */
484 char *cat_name;
485 rc = async_data_write_accept((void **) &cat_name, true,
486 0, 0, 0, 0);
487 if (rc != EOK) {
488 async_answer_0(callid, rc);
489 return;
490 }
491
492 fun_node_t *fun = find_fun_node(&device_tree, handle);
493 if (fun == NULL) {
494 async_answer_0(callid, ENOENT);
495 return;
496 }
497
498 fibril_rwlock_read_lock(&device_tree.rwlock);
499
500 /* Check function state */
501 if (fun->state == FUN_REMOVED) {
502 fibril_rwlock_read_unlock(&device_tree.rwlock);
503 async_answer_0(callid, ENOENT);
504 return;
505 }
506
507 rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
508 if (rc == EOK) {
509 loc_service_add_to_cat(fun->service_id, cat_id);
510 log_msg(LOG_DEFAULT, LVL_NOTE, "Function `%s' added to category `%s'.",
511 fun->pathname, cat_name);
512 } else {
513 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding function `%s' to category "
514 "`%s'.", fun->pathname, cat_name);
515 }
516
517 fibril_rwlock_read_unlock(&device_tree.rwlock);
518 fun_del_ref(fun);
519
520 async_answer_0(callid, rc);
521}
522
523/** Online function by driver request.
524 *
525 */
526static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
527 driver_t *drv)
528{
529 fun_node_t *fun;
530 int rc;
531
532 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_drv_fun_online()");
533
534 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
535 if (fun == NULL) {
536 async_answer_0(iid, ENOENT);
537 return;
538 }
539
540 fun_busy_lock(fun);
541
542 fibril_rwlock_read_lock(&device_tree.rwlock);
543 if (fun->dev == NULL || fun->dev->drv != drv) {
544 fibril_rwlock_read_unlock(&device_tree.rwlock);
545 fun_busy_unlock(fun);
546 fun_del_ref(fun);
547 async_answer_0(iid, ENOENT);
548 return;
549 }
550 fibril_rwlock_read_unlock(&device_tree.rwlock);
551
552 rc = online_function(fun);
553 if (rc != EOK) {
554 fun_busy_unlock(fun);
555 fun_del_ref(fun);
556 async_answer_0(iid, (sysarg_t) rc);
557 return;
558 }
559
560 fun_busy_unlock(fun);
561 fun_del_ref(fun);
562
563 async_answer_0(iid, (sysarg_t) EOK);
564}
565
566
567/** Offline function by driver request.
568 *
569 */
570static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
571 driver_t *drv)
572{
573 fun_node_t *fun;
574 int rc;
575
576 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
577 if (fun == NULL) {
578 async_answer_0(iid, ENOENT);
579 return;
580 }
581
582 fun_busy_lock(fun);
583
584 fibril_rwlock_write_lock(&device_tree.rwlock);
585 if (fun->dev == NULL || fun->dev->drv != drv) {
586 fun_busy_unlock(fun);
587 fun_del_ref(fun);
588 async_answer_0(iid, ENOENT);
589 return;
590 }
591 fibril_rwlock_write_unlock(&device_tree.rwlock);
592
593 rc = offline_function(fun);
594 if (rc != EOK) {
595 fun_busy_unlock(fun);
596 fun_del_ref(fun);
597 async_answer_0(iid, (sysarg_t) rc);
598 return;
599 }
600
601 fun_busy_unlock(fun);
602 fun_del_ref(fun);
603 async_answer_0(iid, (sysarg_t) EOK);
604}
605
606/** Remove function. */
607static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
608{
609 devman_handle_t fun_handle = IPC_GET_ARG1(*call);
610 dev_tree_t *tree = &device_tree;
611 int rc;
612
613 fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
614 if (fun == NULL) {
615 async_answer_0(callid, ENOENT);
616 return;
617 }
618
619 fun_busy_lock(fun);
620
621 fibril_rwlock_write_lock(&tree->rwlock);
622
623 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
624
625 /* Check function state */
626 if (fun->state == FUN_REMOVED) {
627 fibril_rwlock_write_unlock(&tree->rwlock);
628 fun_busy_unlock(fun);
629 fun_del_ref(fun);
630 async_answer_0(callid, ENOENT);
631 return;
632 }
633
634 if (fun->ftype == fun_inner) {
635 /* This is a surprise removal. Handle possible descendants */
636 if (fun->child != NULL) {
637 dev_node_t *dev = fun->child;
638 device_state_t dev_state;
639 int gone_rc;
640
641 dev_add_ref(dev);
642 dev_state = dev->state;
643
644 fibril_rwlock_write_unlock(&device_tree.rwlock);
645
646 /* If device is owned by driver, inform driver it is gone. */
647 if (dev_state == DEVICE_USABLE)
648 gone_rc = driver_dev_gone(&device_tree, dev);
649 else
650 gone_rc = EOK;
651
652 fibril_rwlock_read_lock(&device_tree.rwlock);
653
654 /* Verify that driver succeeded and removed all functions */
655 if (gone_rc != EOK || !list_empty(&dev->functions)) {
656 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver did not remove "
657 "functions for device that is gone. "
658 "Device node is now defunct.");
659
660 /*
661 * Not much we can do but mark the device
662 * node as having invalid state. This
663 * is a driver bug.
664 */
665 dev->state = DEVICE_INVALID;
666 fibril_rwlock_read_unlock(&device_tree.rwlock);
667 dev_del_ref(dev);
668 if (gone_rc == EOK)
669 gone_rc = ENOTSUP;
670 fun_busy_unlock(fun);
671 fun_del_ref(fun);
672 async_answer_0(callid, gone_rc);
673 return;
674 }
675
676 driver_t *driver = dev->drv;
677 fibril_rwlock_read_unlock(&device_tree.rwlock);
678
679 if (driver)
680 detach_driver(&device_tree, dev);
681
682 fibril_rwlock_write_lock(&device_tree.rwlock);
683 remove_dev_node(&device_tree, dev);
684
685 /* Delete ref created when node was inserted */
686 dev_del_ref(dev);
687 /* Delete ref created by dev_add_ref(dev) above */
688 dev_del_ref(dev);
689 }
690 } else {
691 if (fun->service_id != 0) {
692 /* Unregister from location service */
693 rc = loc_service_unregister(fun->service_id);
694 if (rc != EOK) {
695 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree "
696 "service.");
697 fibril_rwlock_write_unlock(&tree->rwlock);
698 fun_busy_unlock(fun);
699 fun_del_ref(fun);
700 async_answer_0(callid, EIO);
701 return;
702 }
703 }
704 }
705
706 remove_fun_node(&device_tree, fun);
707 fibril_rwlock_write_unlock(&tree->rwlock);
708 fun_busy_unlock(fun);
709
710 /* Delete ref added when inserting function into tree */
711 fun_del_ref(fun);
712 /* Delete ref added above when looking up function */
713 fun_del_ref(fun);
714
715 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function() succeeded.");
716 async_answer_0(callid, EOK);
717}
718
719/** Initialize driver which has registered itself as running and ready.
720 *
721 * The initialization is done in a separate fibril to avoid deadlocks (if the
722 * driver needed to be served by devman during the driver's initialization).
723 */
724static int init_running_drv(void *drv)
725{
726 driver_t *driver = (driver_t *) drv;
727
728 initialize_running_driver(driver, &device_tree);
729 log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s` driver was successfully initialized.",
730 driver->name);
731 return 0;
732}
733
734/** Function for handling connections from a driver to the device manager. */
735static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
736{
737 client_t *client;
738 driver_t *driver = NULL;
739
740 /* Accept the connection. */
741 async_answer_0(iid, EOK);
742
743 client = async_get_client_data();
744 if (client == NULL) {
745 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate client data.");
746 return;
747 }
748
749 while (true) {
750 ipc_call_t call;
751 ipc_callid_t callid = async_get_call(&call);
752
753 if (!IPC_GET_IMETHOD(call))
754 break;
755
756 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {
757 fibril_mutex_lock(&client->mutex);
758 driver = client->driver;
759 fibril_mutex_unlock(&client->mutex);
760 if (driver == NULL) {
761 /* First call must be to DEVMAN_DRIVER_REGISTER */
762 async_answer_0(callid, ENOTSUP);
763 continue;
764 }
765 }
766
767 switch (IPC_GET_IMETHOD(call)) {
768 case DEVMAN_DRIVER_REGISTER:
769 fibril_mutex_lock(&client->mutex);
770 if (client->driver != NULL) {
771 fibril_mutex_unlock(&client->mutex);
772 async_answer_0(callid, EINVAL);
773 continue;
774 }
775 client->driver = devman_driver_register(callid, &call);
776 fibril_mutex_unlock(&client->mutex);
777 break;
778 case DEVMAN_ADD_FUNCTION:
779 devman_add_function(callid, &call);
780 break;
781 case DEVMAN_ADD_DEVICE_TO_CATEGORY:
782 devman_add_function_to_cat(callid, &call);
783 break;
784 case DEVMAN_DRV_FUN_ONLINE:
785 devman_drv_fun_online(callid, &call, driver);
786 break;
787 case DEVMAN_DRV_FUN_OFFLINE:
788 devman_drv_fun_offline(callid, &call, driver);
789 break;
790 case DEVMAN_REMOVE_FUNCTION:
791 devman_remove_function(callid, &call);
792 break;
793 default:
794 async_answer_0(callid, EINVAL);
795 break;
796 }
797 }
798}
799
800/** Find handle for the device instance identified by the device's path in the
801 * device tree. */
802static void devman_function_get_handle(ipc_callid_t iid, ipc_call_t *icall)
803{
804 char *pathname;
805 devman_handle_t handle;
806
807 int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
808 if (rc != EOK) {
809 async_answer_0(iid, rc);
810 return;
811 }
812
813 fun_node_t *fun = find_fun_node_by_path(&device_tree, pathname);
814
815 free(pathname);
816
817 if (fun == NULL) {
818 async_answer_0(iid, ENOENT);
819 return;
820 }
821
822 fibril_rwlock_read_lock(&device_tree.rwlock);
823
824 /* Check function state */
825 if (fun->state == FUN_REMOVED) {
826 fibril_rwlock_read_unlock(&device_tree.rwlock);
827 async_answer_0(iid, ENOENT);
828 return;
829 }
830 handle = fun->handle;
831
832 fibril_rwlock_read_unlock(&device_tree.rwlock);
833
834 /* Delete reference created above by find_fun_node_by_path() */
835 fun_del_ref(fun);
836
837 async_answer_1(iid, EOK, handle);
838}
839
840/** Get device name. */
841static void devman_fun_get_name(ipc_callid_t iid, ipc_call_t *icall)
842{
843 devman_handle_t handle = IPC_GET_ARG1(*icall);
844
845 fun_node_t *fun = find_fun_node(&device_tree, handle);
846 if (fun == NULL) {
847 async_answer_0(iid, ENOMEM);
848 return;
849 }
850
851 ipc_callid_t data_callid;
852 size_t data_len;
853 if (!async_data_read_receive(&data_callid, &data_len)) {
854 async_answer_0(iid, EINVAL);
855 fun_del_ref(fun);
856 return;
857 }
858
859 void *buffer = malloc(data_len);
860 if (buffer == NULL) {
861 async_answer_0(data_callid, ENOMEM);
862 async_answer_0(iid, ENOMEM);
863 fun_del_ref(fun);
864 return;
865 }
866
867 fibril_rwlock_read_lock(&device_tree.rwlock);
868
869 /* Check function state */
870 if (fun->state == FUN_REMOVED) {
871 fibril_rwlock_read_unlock(&device_tree.rwlock);
872 free(buffer);
873
874 async_answer_0(data_callid, ENOENT);
875 async_answer_0(iid, ENOENT);
876 fun_del_ref(fun);
877 return;
878 }
879
880 size_t sent_length = str_size(fun->name);
881 if (sent_length > data_len) {
882 sent_length = data_len;
883 }
884
885 async_data_read_finalize(data_callid, fun->name, sent_length);
886 async_answer_0(iid, EOK);
887
888 fibril_rwlock_read_unlock(&device_tree.rwlock);
889 fun_del_ref(fun);
890 free(buffer);
891}
892
893/** Get function driver name. */
894static void devman_fun_get_driver_name(ipc_callid_t iid, ipc_call_t *icall)
895{
896 devman_handle_t handle = IPC_GET_ARG1(*icall);
897
898 fun_node_t *fun = find_fun_node(&device_tree, handle);
899 if (fun == NULL) {
900 async_answer_0(iid, ENOMEM);
901 return;
902 }
903
904 ipc_callid_t data_callid;
905 size_t data_len;
906 if (!async_data_read_receive(&data_callid, &data_len)) {
907 async_answer_0(iid, EINVAL);
908 fun_del_ref(fun);
909 return;
910 }
911
912 void *buffer = malloc(data_len);
913 if (buffer == NULL) {
914 async_answer_0(data_callid, ENOMEM);
915 async_answer_0(iid, ENOMEM);
916 fun_del_ref(fun);
917 return;
918 }
919
920 fibril_rwlock_read_lock(&device_tree.rwlock);
921
922 /* Check function state */
923 if (fun->state == FUN_REMOVED) {
924 fibril_rwlock_read_unlock(&device_tree.rwlock);
925 free(buffer);
926
927 async_answer_0(data_callid, ENOENT);
928 async_answer_0(iid, ENOENT);
929 fun_del_ref(fun);
930 return;
931 }
932
933 /* Check whether function has a driver */
934 if (fun->child == NULL || fun->child->drv == NULL) {
935 fibril_rwlock_read_unlock(&device_tree.rwlock);
936 free(buffer);
937
938 async_answer_0(data_callid, EINVAL);
939 async_answer_0(iid, EINVAL);
940 fun_del_ref(fun);
941 return;
942 }
943
944 size_t sent_length = str_size(fun->child->drv->name);
945 if (sent_length > data_len) {
946 sent_length = data_len;
947 }
948
949 async_data_read_finalize(data_callid, fun->child->drv->name,
950 sent_length);
951 async_answer_0(iid, EOK);
952
953 fibril_rwlock_read_unlock(&device_tree.rwlock);
954 fun_del_ref(fun);
955 free(buffer);
956}
957
958/** Get device path. */
959static void devman_fun_get_path(ipc_callid_t iid, ipc_call_t *icall)
960{
961 devman_handle_t handle = IPC_GET_ARG1(*icall);
962
963 fun_node_t *fun = find_fun_node(&device_tree, handle);
964 if (fun == NULL) {
965 async_answer_0(iid, ENOMEM);
966 return;
967 }
968
969 ipc_callid_t data_callid;
970 size_t data_len;
971 if (!async_data_read_receive(&data_callid, &data_len)) {
972 async_answer_0(iid, EINVAL);
973 fun_del_ref(fun);
974 return;
975 }
976
977 void *buffer = malloc(data_len);
978 if (buffer == NULL) {
979 async_answer_0(data_callid, ENOMEM);
980 async_answer_0(iid, ENOMEM);
981 fun_del_ref(fun);
982 return;
983 }
984
985 fibril_rwlock_read_lock(&device_tree.rwlock);
986
987 /* Check function state */
988 if (fun->state == FUN_REMOVED) {
989 fibril_rwlock_read_unlock(&device_tree.rwlock);
990 free(buffer);
991
992 async_answer_0(data_callid, ENOENT);
993 async_answer_0(iid, ENOENT);
994 fun_del_ref(fun);
995 return;
996 }
997
998 size_t sent_length = str_size(fun->pathname);
999 if (sent_length > data_len) {
1000 sent_length = data_len;
1001 }
1002
1003 async_data_read_finalize(data_callid, fun->pathname, sent_length);
1004 async_answer_0(iid, EOK);
1005
1006 fibril_rwlock_read_unlock(&device_tree.rwlock);
1007 fun_del_ref(fun);
1008 free(buffer);
1009}
1010
1011static void devman_dev_get_functions(ipc_callid_t iid, ipc_call_t *icall)
1012{
1013 ipc_callid_t callid;
1014 size_t size;
1015 size_t act_size;
1016 int rc;
1017
1018 if (!async_data_read_receive(&callid, &size)) {
1019 async_answer_0(callid, EREFUSED);
1020 async_answer_0(iid, EREFUSED);
1021 return;
1022 }
1023
1024 fibril_rwlock_read_lock(&device_tree.rwlock);
1025
1026 dev_node_t *dev = find_dev_node_no_lock(&device_tree,
1027 IPC_GET_ARG1(*icall));
1028 if (dev == NULL || dev->state == DEVICE_REMOVED) {
1029 fibril_rwlock_read_unlock(&device_tree.rwlock);
1030 async_answer_0(callid, ENOENT);
1031 async_answer_0(iid, ENOENT);
1032 return;
1033 }
1034
1035 devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
1036 if (hdl_buf == NULL) {
1037 fibril_rwlock_read_unlock(&device_tree.rwlock);
1038 async_answer_0(callid, ENOMEM);
1039 async_answer_0(iid, ENOMEM);
1040 return;
1041 }
1042
1043 rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size);
1044 if (rc != EOK) {
1045 fibril_rwlock_read_unlock(&device_tree.rwlock);
1046 async_answer_0(callid, rc);
1047 async_answer_0(iid, rc);
1048 return;
1049 }
1050
1051 fibril_rwlock_read_unlock(&device_tree.rwlock);
1052
1053 sysarg_t retval = async_data_read_finalize(callid, hdl_buf, size);
1054 free(hdl_buf);
1055
1056 async_answer_1(iid, retval, act_size);
1057}
1058
1059
1060/** Get handle for child device of a function. */
1061static void devman_fun_get_child(ipc_callid_t iid, ipc_call_t *icall)
1062{
1063 fun_node_t *fun;
1064
1065 fibril_rwlock_read_lock(&device_tree.rwlock);
1066
1067 fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
1068 if (fun == NULL || fun->state == FUN_REMOVED) {
1069 fibril_rwlock_read_unlock(&device_tree.rwlock);
1070 async_answer_0(iid, ENOENT);
1071 return;
1072 }
1073
1074 if (fun->child == NULL) {
1075 fibril_rwlock_read_unlock(&device_tree.rwlock);
1076 async_answer_0(iid, ENOENT);
1077 return;
1078 }
1079
1080 async_answer_1(iid, EOK, fun->child->handle);
1081
1082 fibril_rwlock_read_unlock(&device_tree.rwlock);
1083}
1084
1085/** Online function.
1086 *
1087 * Send a request to online a function to the responsible driver.
1088 * The driver may offline other functions if necessary (i.e. if the state
1089 * of this function is linked to state of another function somehow).
1090 */
1091static void devman_fun_online(ipc_callid_t iid, ipc_call_t *icall)
1092{
1093 fun_node_t *fun;
1094 int rc;
1095
1096 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
1097 if (fun == NULL) {
1098 async_answer_0(iid, ENOENT);
1099 return;
1100 }
1101
1102 rc = driver_fun_online(&device_tree, fun);
1103 fun_del_ref(fun);
1104
1105 async_answer_0(iid, (sysarg_t) rc);
1106}
1107
1108/** Offline function.
1109 *
1110 * Send a request to offline a function to the responsible driver. As
1111 * a result the subtree rooted at that function should be cleanly
1112 * detatched. The driver may offline other functions if necessary
1113 * (i.e. if the state of this function is linked to state of another
1114 * function somehow).
1115 */
1116static void devman_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
1117{
1118 fun_node_t *fun;
1119 int rc;
1120
1121 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
1122 if (fun == NULL) {
1123 async_answer_0(iid, ENOENT);
1124 return;
1125 }
1126
1127 rc = driver_fun_offline(&device_tree, fun);
1128 fun_del_ref(fun);
1129
1130 async_answer_0(iid, (sysarg_t) rc);
1131}
1132
1133/** Find handle for the function instance identified by its service ID. */
1134static void devman_fun_sid_to_handle(ipc_callid_t iid, ipc_call_t *icall)
1135{
1136 fun_node_t *fun;
1137
1138 fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall));
1139
1140 if (fun == NULL) {
1141 async_answer_0(iid, ENOENT);
1142 return;
1143 }
1144
1145 fibril_rwlock_read_lock(&device_tree.rwlock);
1146
1147 /* Check function state */
1148 if (fun->state == FUN_REMOVED) {
1149 fibril_rwlock_read_unlock(&device_tree.rwlock);
1150 async_answer_0(iid, ENOENT);
1151 return;
1152 }
1153
1154 async_answer_1(iid, EOK, fun->handle);
1155 fibril_rwlock_read_unlock(&device_tree.rwlock);
1156 fun_del_ref(fun);
1157}
1158
1159/** Function for handling connections from a client to the device manager. */
1160static void devman_connection_client(ipc_callid_t iid, ipc_call_t *icall)
1161{
1162 /* Accept connection. */
1163 async_answer_0(iid, EOK);
1164
1165 while (true) {
1166 ipc_call_t call;
1167 ipc_callid_t callid = async_get_call(&call);
1168
1169 if (!IPC_GET_IMETHOD(call))
1170 break;
1171
1172 switch (IPC_GET_IMETHOD(call)) {
1173 case DEVMAN_DEVICE_GET_HANDLE:
1174 devman_function_get_handle(callid, &call);
1175 break;
1176 case DEVMAN_DEV_GET_FUNCTIONS:
1177 devman_dev_get_functions(callid, &call);
1178 break;
1179 case DEVMAN_FUN_GET_CHILD:
1180 devman_fun_get_child(callid, &call);
1181 break;
1182 case DEVMAN_FUN_GET_NAME:
1183 devman_fun_get_name(callid, &call);
1184 break;
1185 case DEVMAN_FUN_GET_DRIVER_NAME:
1186 devman_fun_get_driver_name(callid, &call);
1187 break;
1188 case DEVMAN_FUN_GET_PATH:
1189 devman_fun_get_path(callid, &call);
1190 break;
1191 case DEVMAN_FUN_ONLINE:
1192 devman_fun_online(callid, &call);
1193 break;
1194 case DEVMAN_FUN_OFFLINE:
1195 devman_fun_offline(callid, &call);
1196 break;
1197 case DEVMAN_FUN_SID_TO_HANDLE:
1198 devman_fun_sid_to_handle(callid, &call);
1199 break;
1200 default:
1201 async_answer_0(callid, ENOENT);
1202 }
1203 }
1204}
1205
1206static void devman_forward(ipc_callid_t iid, ipc_call_t *icall,
1207 bool drv_to_parent)
1208{
1209 devman_handle_t handle = IPC_GET_ARG2(*icall);
1210 devman_handle_t fwd_h;
1211 fun_node_t *fun = NULL;
1212 dev_node_t *dev = NULL;
1213
1214 fun = find_fun_node(&device_tree, handle);
1215 if (fun == NULL)
1216 dev = find_dev_node(&device_tree, handle);
1217 else {
1218 fibril_rwlock_read_lock(&device_tree.rwlock);
1219 dev = fun->dev;
1220 if (dev != NULL)
1221 dev_add_ref(dev);
1222 fibril_rwlock_read_unlock(&device_tree.rwlock);
1223 }
1224
1225 /*
1226 * For a valid function to connect to we need a device. The root
1227 * function, for example, has no device and cannot be connected to.
1228 * This means @c dev needs to be valid regardless whether we are
1229 * connecting to a device or to a function.
1230 */
1231 if (dev == NULL) {
1232 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding failed - no device or "
1233 "function with handle %" PRIun " was found.", handle);
1234 async_answer_0(iid, ENOENT);
1235 goto cleanup;
1236 }
1237
1238 if (fun == NULL && !drv_to_parent) {
1239 log_msg(LOG_DEFAULT, LVL_ERROR, NAME ": devman_forward error - cannot "
1240 "connect to handle %" PRIun ", refers to a device.",
1241 handle);
1242 async_answer_0(iid, ENOENT);
1243 goto cleanup;
1244 }
1245
1246 driver_t *driver = NULL;
1247
1248 fibril_rwlock_read_lock(&device_tree.rwlock);
1249
1250 if (drv_to_parent) {
1251 /* Connect to parent function of a device (or device function). */
1252 if (dev->pfun->dev != NULL)
1253 driver = dev->pfun->dev->drv;
1254
1255 fwd_h = dev->pfun->handle;
1256 } else if (dev->state == DEVICE_USABLE) {
1257 /* Connect to the specified function */
1258 driver = dev->drv;
1259 assert(driver != NULL);
1260
1261 fwd_h = handle;
1262 }
1263
1264 fibril_rwlock_read_unlock(&device_tree.rwlock);
1265
1266 if (driver == NULL) {
1267 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding refused - " \
1268 "the device %" PRIun " is not in usable state.", handle);
1269 async_answer_0(iid, ENOENT);
1270 goto cleanup;
1271 }
1272
1273 int method;
1274 if (drv_to_parent)
1275 method = DRIVER_DRIVER;
1276 else
1277 method = DRIVER_CLIENT;
1278
1279 if (!driver->sess) {
1280 log_msg(LOG_DEFAULT, LVL_ERROR,
1281 "Could not forward to driver `%s'.", driver->name);
1282 async_answer_0(iid, EINVAL);
1283 goto cleanup;
1284 }
1285
1286 if (fun != NULL) {
1287 log_msg(LOG_DEFAULT, LVL_DEBUG,
1288 "Forwarding request for `%s' function to driver `%s'.",
1289 fun->pathname, driver->name);
1290 } else {
1291 log_msg(LOG_DEFAULT, LVL_DEBUG,
1292 "Forwarding request for `%s' device to driver `%s'.",
1293 dev->pfun->pathname, driver->name);
1294 }
1295
1296 async_exch_t *exch = async_exchange_begin(driver->sess);
1297 async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
1298 async_exchange_end(exch);
1299
1300cleanup:
1301 if (dev != NULL)
1302 dev_del_ref(dev);
1303
1304 if (fun != NULL)
1305 fun_del_ref(fun);
1306}
1307
1308/** Function for handling connections from a client forwarded by the location
1309 * service to the device manager. */
1310static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall)
1311{
1312 service_id_t service_id = IPC_GET_ARG2(*icall);
1313 fun_node_t *fun;
1314 dev_node_t *dev;
1315 devman_handle_t handle;
1316 driver_t *driver;
1317
1318 fun = find_loc_tree_function(&device_tree, service_id);
1319
1320 fibril_rwlock_read_lock(&device_tree.rwlock);
1321
1322 if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
1323 log_msg(LOG_DEFAULT, LVL_WARN, "devman_connection_loc(): function "
1324 "not found.\n");
1325 fibril_rwlock_read_unlock(&device_tree.rwlock);
1326 async_answer_0(iid, ENOENT);
1327 return;
1328 }
1329
1330 dev = fun->dev;
1331 driver = dev->drv;
1332 handle = fun->handle;
1333
1334 fibril_rwlock_read_unlock(&device_tree.rwlock);
1335
1336 async_exch_t *exch = async_exchange_begin(driver->sess);
1337 async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0,
1338 IPC_FF_NONE);
1339 async_exchange_end(exch);
1340
1341 log_msg(LOG_DEFAULT, LVL_DEBUG,
1342 "Forwarding loc service request for `%s' function to driver `%s'.",
1343 fun->pathname, driver->name);
1344
1345 fun_del_ref(fun);
1346}
1347
1348/** Function for handling connections to device manager. */
1349static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
1350{
1351 /* Select port. */
1352 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
1353 case DEVMAN_DRIVER:
1354 devman_connection_driver(iid, icall);
1355 break;
1356 case DEVMAN_CLIENT:
1357 devman_connection_client(iid, icall);
1358 break;
1359 case DEVMAN_CONNECT_TO_DEVICE:
1360 /* Connect client to selected device. */
1361 devman_forward(iid, icall, false);
1362 break;
1363 case DEVMAN_CONNECT_FROM_LOC:
1364 /* Someone connected through loc node. */
1365 devman_connection_loc(iid, icall);
1366 break;
1367 case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
1368 /* Connect client to selected device. */
1369 devman_forward(iid, icall, true);
1370 break;
1371 default:
1372 /* No such interface */
1373 async_answer_0(iid, ENOENT);
1374 }
1375}
1376
1377static void *devman_client_data_create(void)
1378{
1379 client_t *client;
1380
1381 client = calloc(1, sizeof(client_t));
1382 if (client == NULL)
1383 return NULL;
1384
1385 fibril_mutex_initialize(&client->mutex);
1386 return client;
1387}
1388
1389static void devman_client_data_destroy(void *data)
1390{
1391 free(data);
1392}
1393
1394/** Initialize device manager internal structures. */
1395static bool devman_init(void)
1396{
1397 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - looking for available drivers.");
1398
1399 /* Initialize list of available drivers. */
1400 init_driver_list(&drivers_list);
1401 if (lookup_available_drivers(&drivers_list,
1402 DRIVER_DEFAULT_STORE) == 0) {
1403 log_msg(LOG_DEFAULT, LVL_FATAL, "No drivers found.");
1404 return false;
1405 }
1406
1407 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - list of drivers has been initialized.");
1408
1409 /* Create root device node. */
1410 if (!init_device_tree(&device_tree, &drivers_list)) {
1411 log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to initialize device tree.");
1412 return false;
1413 }
1414
1415 /*
1416 * Caution: As the device manager is not a real loc
1417 * driver (it uses a completely different IPC protocol
1418 * than an ordinary loc driver), forwarding a connection
1419 * from client to the devman by location service will
1420 * not work.
1421 */
1422 loc_server_register(NAME);
1423
1424 return true;
1425}
1426
1427int main(int argc, char *argv[])
1428{
1429 printf("%s: HelenOS Device Manager\n", NAME);
1430
1431 int rc = log_init(NAME);
1432 if (rc != EOK) {
1433 printf("%s: Error initializing logging subsystem.\n", NAME);
1434 return rc;
1435 }
1436
1437 /* Set handlers for incoming connections. */
1438 async_set_client_data_constructor(devman_client_data_create);
1439 async_set_client_data_destructor(devman_client_data_destroy);
1440 async_set_client_connection(devman_connection);
1441
1442 if (!devman_init()) {
1443 log_msg(LOG_DEFAULT, LVL_ERROR, "Error while initializing service.");
1444 return -1;
1445 }
1446
1447 /* Register device manager at naming service. */
1448 rc = service_register(SERVICE_DEVMAN);
1449 if (rc != EOK) {
1450 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering as a service.");
1451 return rc;
1452 }
1453
1454 printf("%s: Accepting connections.\n", NAME);
1455 task_retval(0);
1456 async_manager();
1457
1458 /* Never reached. */
1459 return 0;
1460}
1461
1462/** @}
1463 */
Note: See TracBrowser for help on using the repository browser.