source: mainline/uspace/srv/devman/main.c@ 59dc181

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

Move devtree-related functionality to separate devman module.

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