source: mainline/uspace/srv/devman/drv_conn.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 16.7 KB
RevLine 
[181c32f]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 <assert.h>
39#include <ipc/services.h>
40#include <ns.h>
41#include <async.h>
42#include <stdio.h>
43#include <errno.h>
44#include <str_error.h>
45#include <stdbool.h>
46#include <fibril_synch.h>
47#include <stdlib.h>
48#include <str.h>
49#include <io/log.h>
50#include <ipc/devman.h>
51#include <loc.h>
52
53#include "client_conn.h"
54#include "dev.h"
55#include "devman.h"
56#include "devtree.h"
57#include "driver.h"
58#include "drv_conn.h"
59#include "fun.h"
60#include "loc.h"
61#include "main.h"
62
[b7fd2a0]63static errno_t init_running_drv(void *drv);
[181c32f]64
65/** Register running driver. */
66static driver_t *devman_driver_register(ipc_callid_t callid, ipc_call_t *call)
67{
68 driver_t *driver = NULL;
69 char *drv_name = NULL;
70
71 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_driver_register");
[a35b458]72
[181c32f]73 /* Get driver name. */
[b7fd2a0]74 errno_t rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
[181c32f]75 if (rc != EOK) {
76 async_answer_0(callid, rc);
77 return NULL;
78 }
79
80 log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s' driver is trying to register.",
81 drv_name);
[a35b458]82
[181c32f]83 /* Find driver structure. */
[0511549]84 driver = driver_find_by_name(&drivers_list, drv_name);
[181c32f]85 if (driver == NULL) {
86 log_msg(LOG_DEFAULT, LVL_ERROR, "No driver named `%s' was found.", drv_name);
87 free(drv_name);
88 drv_name = NULL;
89 async_answer_0(callid, ENOENT);
90 return NULL;
91 }
[a35b458]92
[181c32f]93 free(drv_name);
94 drv_name = NULL;
[a35b458]95
[181c32f]96 fibril_mutex_lock(&driver->driver_mutex);
[a35b458]97
[181c32f]98 if (driver->sess) {
99 /* We already have a connection to the driver. */
100 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver '%s' already started.\n",
101 driver->name);
102 fibril_mutex_unlock(&driver->driver_mutex);
[8a637a4]103 async_answer_0(callid, EEXIST);
[181c32f]104 return NULL;
105 }
[a35b458]106
[181c32f]107 switch (driver->state) {
108 case DRIVER_NOT_STARTED:
109 /* Somebody started the driver manually. */
110 log_msg(LOG_DEFAULT, LVL_NOTE, "Driver '%s' started manually.\n",
111 driver->name);
112 driver->state = DRIVER_STARTING;
113 break;
114 case DRIVER_STARTING:
115 /* The expected case */
116 break;
117 case DRIVER_RUNNING:
118 /* Should not happen since we do not have a connected session */
119 assert(false);
120 }
[a35b458]121
[181c32f]122 /* Create connection to the driver. */
123 log_msg(LOG_DEFAULT, LVL_DEBUG, "Creating connection to the `%s' driver.",
124 driver->name);
125 driver->sess = async_callback_receive(EXCHANGE_PARALLEL);
126 if (!driver->sess) {
127 fibril_mutex_unlock(&driver->driver_mutex);
128 async_answer_0(callid, ENOTSUP);
129 return NULL;
130 }
131 /* FIXME: Work around problem with callback sessions */
[f9b2cb4c]132 async_sess_args_set(driver->sess, INTERFACE_DDF_DEVMAN, 0, 0);
[a35b458]133
[181c32f]134 log_msg(LOG_DEFAULT, LVL_NOTE,
135 "The `%s' driver was successfully registered as running.",
136 driver->name);
[a35b458]137
[181c32f]138 /*
139 * Initialize the driver as running (e.g. pass assigned devices to it)
140 * in a separate fibril; the separate fibril is used to enable the
141 * driver to use devman service during the driver's initialization.
142 */
143 fid_t fid = fibril_create(init_running_drv, driver);
144 if (fid == 0) {
145 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to create initialization fibril " \
146 "for driver `%s'.", driver->name);
147 fibril_mutex_unlock(&driver->driver_mutex);
148 async_answer_0(callid, ENOMEM);
149 return NULL;
150 }
[a35b458]151
[181c32f]152 fibril_add_ready(fid);
153 fibril_mutex_unlock(&driver->driver_mutex);
[a35b458]154
[181c32f]155 async_answer_0(callid, EOK);
156 return driver;
157}
158
159/** Receive device match ID from the device's parent driver and add it to the
160 * list of devices match ids.
161 *
162 * @param match_ids The list of the device's match ids.
[cde999a]163 * @return Zero on success, error code otherwise.
[181c32f]164 */
[b7fd2a0]165static errno_t devman_receive_match_id(match_id_list_t *match_ids)
[181c32f]166{
167 match_id_t *match_id = create_match_id();
168 ipc_callid_t callid;
169 ipc_call_t call;
[b7fd2a0]170 errno_t rc = 0;
[a35b458]171
[181c32f]172 callid = async_get_call(&call);
173 if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
[acb8766e]174 log_msg(LOG_DEFAULT, LVL_ERROR,
[181c32f]175 "Invalid protocol when trying to receive match id.");
[acb8766e]176 async_answer_0(callid, EINVAL);
[181c32f]177 delete_match_id(match_id);
178 return EINVAL;
179 }
[a35b458]180
[181c32f]181 if (match_id == NULL) {
182 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate match id.");
183 async_answer_0(callid, ENOMEM);
184 return ENOMEM;
185 }
[a35b458]186
[181c32f]187 async_answer_0(callid, EOK);
[a35b458]188
[181c32f]189 match_id->score = IPC_GET_ARG1(call);
[a35b458]190
[181c32f]191 char *match_id_str;
192 rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0);
193 match_id->id = match_id_str;
194 if (rc != EOK) {
195 delete_match_id(match_id);
196 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to receive match id string: %s.",
197 str_error(rc));
198 return rc;
199 }
[a35b458]200
[181c32f]201 list_append(&match_id->link, &match_ids->ids);
[a35b458]202
[181c32f]203 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received match id `%s', score %d.",
204 match_id->id, match_id->score);
205 return rc;
206}
207
208/** Receive device match IDs from the device's parent driver and add them to the
209 * list of devices match ids.
210 *
211 * @param match_count The number of device's match ids to be received.
212 * @param match_ids The list of the device's match ids.
[cde999a]213 * @return Zero on success, error code otherwise.
[181c32f]214 */
[b7fd2a0]215static errno_t devman_receive_match_ids(sysarg_t match_count,
[181c32f]216 match_id_list_t *match_ids)
217{
[b7fd2a0]218 errno_t ret = EOK;
[181c32f]219 size_t i;
[a35b458]220
[181c32f]221 for (i = 0; i < match_count; i++) {
222 if (EOK != (ret = devman_receive_match_id(match_ids)))
223 return ret;
224 }
225 return ret;
226}
227
228/** Handle function registration.
229 *
230 * Child devices are registered by their parent's device driver.
231 */
232static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
233{
234 fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
235 devman_handle_t dev_handle = IPC_GET_ARG2(*call);
236 sysarg_t match_count = IPC_GET_ARG3(*call);
237 dev_tree_t *tree = &device_tree;
[a35b458]238
[181c32f]239 dev_node_t *pdev = find_dev_node(&device_tree, dev_handle);
240 if (pdev == NULL) {
241 async_answer_0(callid, ENOENT);
242 return;
243 }
[a35b458]244
[181c32f]245 if (ftype != fun_inner && ftype != fun_exposed) {
246 /* Unknown function type */
[acb8766e]247 log_msg(LOG_DEFAULT, LVL_ERROR,
[181c32f]248 "Unknown function type %d provided by driver.",
249 (int) ftype);
250
251 dev_del_ref(pdev);
252 async_answer_0(callid, EINVAL);
253 return;
254 }
[a35b458]255
[181c32f]256 char *fun_name = NULL;
[b7fd2a0]257 errno_t rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
[181c32f]258 if (rc != EOK) {
259 dev_del_ref(pdev);
260 async_answer_0(callid, rc);
261 return;
262 }
[a35b458]263
[181c32f]264 fibril_rwlock_write_lock(&tree->rwlock);
[a35b458]265
[181c32f]266 /* Check device state */
267 if (pdev->state == DEVICE_REMOVED) {
268 fibril_rwlock_write_unlock(&tree->rwlock);
269 dev_del_ref(pdev);
270 async_answer_0(callid, ENOENT);
271 return;
272 }
[a35b458]273
[181c32f]274 /* Check that function with same name is not there already. */
275 fun_node_t *tfun = find_fun_node_in_device(tree, pdev, fun_name);
276 if (tfun) {
277 fun_del_ref(tfun); /* drop the new unwanted reference */
278 fibril_rwlock_write_unlock(&tree->rwlock);
279 dev_del_ref(pdev);
[8a637a4]280 async_answer_0(callid, EEXIST);
[181c32f]281 printf(NAME ": Warning, driver tried to register `%s' twice.\n",
282 fun_name);
283 free(fun_name);
284 return;
285 }
[a35b458]286
[181c32f]287 fun_node_t *fun = create_fun_node();
288 /* One reference for creation, one for us */
289 fun_add_ref(fun);
290 fun_add_ref(fun);
291 fun->ftype = ftype;
[a35b458]292
[181c32f]293 /*
294 * We can lock the function here even when holding the tree because
295 * we know it cannot be held by anyone else yet.
296 */
297 fun_busy_lock(fun);
[a35b458]298
[181c32f]299 if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
300 fibril_rwlock_write_unlock(&tree->rwlock);
301 dev_del_ref(pdev);
302 fun_busy_unlock(fun);
303 fun_del_ref(fun);
304 delete_fun_node(fun);
305 async_answer_0(callid, ENOMEM);
306 return;
307 }
[a35b458]308
[181c32f]309 fibril_rwlock_write_unlock(&tree->rwlock);
310 dev_del_ref(pdev);
[a35b458]311
[181c32f]312 devman_receive_match_ids(match_count, &fun->match_ids);
[a35b458]313
[02e5e34]314 rc = fun_online(fun);
[181c32f]315 if (rc != EOK) {
316 /* XXX Set some failed state? */
317 fun_busy_unlock(fun);
318 fun_del_ref(fun);
319 async_answer_0(callid, rc);
320 return;
321 }
[a35b458]322
[181c32f]323 fun_busy_unlock(fun);
324 fun_del_ref(fun);
[a35b458]325
[181c32f]326 /* Return device handle to parent's driver. */
327 async_answer_1(callid, EOK, fun->handle);
328}
329
330static void devman_add_function_to_cat(ipc_callid_t callid, ipc_call_t *call)
331{
332 devman_handle_t handle = IPC_GET_ARG1(*call);
333 category_id_t cat_id;
[b7fd2a0]334 errno_t rc;
[a35b458]335
[181c32f]336 /* Get category name. */
337 char *cat_name;
338 rc = async_data_write_accept((void **) &cat_name, true,
339 0, 0, 0, 0);
340 if (rc != EOK) {
341 async_answer_0(callid, rc);
342 return;
343 }
[a35b458]344
[181c32f]345 fun_node_t *fun = find_fun_node(&device_tree, handle);
346 if (fun == NULL) {
347 async_answer_0(callid, ENOENT);
348 return;
349 }
[a35b458]350
[181c32f]351 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]352
[181c32f]353 /* Check function state */
354 if (fun->state == FUN_REMOVED) {
355 fibril_rwlock_read_unlock(&device_tree.rwlock);
356 async_answer_0(callid, ENOENT);
357 return;
358 }
[a35b458]359
[181c32f]360 rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
361 if (rc == EOK) {
362 loc_service_add_to_cat(fun->service_id, cat_id);
363 log_msg(LOG_DEFAULT, LVL_NOTE, "Function `%s' added to category `%s'.",
364 fun->pathname, cat_name);
365 } else {
366 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding function `%s' to category "
367 "`%s'.", fun->pathname, cat_name);
368 }
[a35b458]369
[181c32f]370 fibril_rwlock_read_unlock(&device_tree.rwlock);
371 fun_del_ref(fun);
[a35b458]372
[181c32f]373 async_answer_0(callid, rc);
374}
375
376/** Online function by driver request.
377 *
378 */
379static void devman_drv_fun_online(ipc_callid_t iid, ipc_call_t *icall,
380 driver_t *drv)
381{
382 fun_node_t *fun;
[b7fd2a0]383 errno_t rc;
[a35b458]384
[181c32f]385 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_drv_fun_online()");
[a35b458]386
[181c32f]387 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
388 if (fun == NULL) {
389 async_answer_0(iid, ENOENT);
390 return;
391 }
[a35b458]392
[181c32f]393 fun_busy_lock(fun);
[a35b458]394
[181c32f]395 fibril_rwlock_read_lock(&device_tree.rwlock);
396 if (fun->dev == NULL || fun->dev->drv != drv) {
397 fibril_rwlock_read_unlock(&device_tree.rwlock);
398 fun_busy_unlock(fun);
399 fun_del_ref(fun);
400 async_answer_0(iid, ENOENT);
401 return;
402 }
403 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a35b458]404
[acb8766e]405 rc = fun_online(fun);
[181c32f]406 if (rc != EOK) {
407 fun_busy_unlock(fun);
408 fun_del_ref(fun);
[25a179e]409 async_answer_0(iid, rc);
[181c32f]410 return;
411 }
[a35b458]412
[181c32f]413 fun_busy_unlock(fun);
414 fun_del_ref(fun);
[a35b458]415
[25a179e]416 async_answer_0(iid, EOK);
[181c32f]417}
418
419
420/** Offline function by driver request.
421 *
422 */
423static void devman_drv_fun_offline(ipc_callid_t iid, ipc_call_t *icall,
424 driver_t *drv)
425{
426 fun_node_t *fun;
[b7fd2a0]427 errno_t rc;
[181c32f]428
429 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
430 if (fun == NULL) {
431 async_answer_0(iid, ENOENT);
432 return;
433 }
[a35b458]434
[181c32f]435 fun_busy_lock(fun);
[a35b458]436
[181c32f]437 fibril_rwlock_write_lock(&device_tree.rwlock);
438 if (fun->dev == NULL || fun->dev->drv != drv) {
439 fun_busy_unlock(fun);
440 fun_del_ref(fun);
441 async_answer_0(iid, ENOENT);
442 return;
443 }
444 fibril_rwlock_write_unlock(&device_tree.rwlock);
[a35b458]445
[02e5e34]446 rc = fun_offline(fun);
[181c32f]447 if (rc != EOK) {
448 fun_busy_unlock(fun);
449 fun_del_ref(fun);
[25a179e]450 async_answer_0(iid, rc);
[181c32f]451 return;
452 }
[a35b458]453
[181c32f]454 fun_busy_unlock(fun);
455 fun_del_ref(fun);
[25a179e]456 async_answer_0(iid, EOK);
[181c32f]457}
458
459/** Remove function. */
460static void devman_remove_function(ipc_callid_t callid, ipc_call_t *call)
461{
462 devman_handle_t fun_handle = IPC_GET_ARG1(*call);
463 dev_tree_t *tree = &device_tree;
[b7fd2a0]464 errno_t rc;
[a35b458]465
[181c32f]466 fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
467 if (fun == NULL) {
468 async_answer_0(callid, ENOENT);
469 return;
470 }
[a35b458]471
[181c32f]472 fun_busy_lock(fun);
[a35b458]473
[181c32f]474 fibril_rwlock_write_lock(&tree->rwlock);
[a35b458]475
[181c32f]476 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
[a35b458]477
[181c32f]478 /* Check function state */
479 if (fun->state == FUN_REMOVED) {
480 fibril_rwlock_write_unlock(&tree->rwlock);
481 fun_busy_unlock(fun);
482 fun_del_ref(fun);
483 async_answer_0(callid, ENOENT);
484 return;
485 }
[a35b458]486
[181c32f]487 if (fun->ftype == fun_inner) {
488 /* This is a surprise removal. Handle possible descendants */
489 if (fun->child != NULL) {
490 dev_node_t *dev = fun->child;
491 device_state_t dev_state;
[b7fd2a0]492 errno_t gone_rc;
[a35b458]493
[181c32f]494 dev_add_ref(dev);
495 dev_state = dev->state;
[a35b458]496
[181c32f]497 fibril_rwlock_write_unlock(&device_tree.rwlock);
[a35b458]498
[181c32f]499 /* If device is owned by driver, inform driver it is gone. */
500 if (dev_state == DEVICE_USABLE)
501 gone_rc = driver_dev_gone(&device_tree, dev);
502 else
503 gone_rc = EOK;
[a35b458]504
[181c32f]505 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]506
[181c32f]507 /* Verify that driver succeeded and removed all functions */
508 if (gone_rc != EOK || !list_empty(&dev->functions)) {
509 log_msg(LOG_DEFAULT, LVL_ERROR, "Driver did not remove "
510 "functions for device that is gone. "
511 "Device node is now defunct.");
[a35b458]512
[181c32f]513 /*
514 * Not much we can do but mark the device
515 * node as having invalid state. This
516 * is a driver bug.
517 */
518 dev->state = DEVICE_INVALID;
519 fibril_rwlock_read_unlock(&device_tree.rwlock);
520 dev_del_ref(dev);
521 if (gone_rc == EOK)
522 gone_rc = ENOTSUP;
523 fun_busy_unlock(fun);
524 fun_del_ref(fun);
525 async_answer_0(callid, gone_rc);
526 return;
527 }
[a35b458]528
[181c32f]529 driver_t *driver = dev->drv;
530 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a35b458]531
[181c32f]532 if (driver)
533 detach_driver(&device_tree, dev);
[a35b458]534
[181c32f]535 fibril_rwlock_write_lock(&device_tree.rwlock);
536 remove_dev_node(&device_tree, dev);
[a35b458]537
[181c32f]538 /* Delete ref created when node was inserted */
539 dev_del_ref(dev);
540 /* Delete ref created by dev_add_ref(dev) above */
541 dev_del_ref(dev);
542 }
543 } else {
544 if (fun->service_id != 0) {
545 /* Unregister from location service */
[96ef672]546 rc = loc_unregister_tree_function(fun, &device_tree);
[181c32f]547 if (rc != EOK) {
548 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed unregistering tree "
549 "service.");
550 fibril_rwlock_write_unlock(&tree->rwlock);
551 fun_busy_unlock(fun);
552 fun_del_ref(fun);
553 async_answer_0(callid, EIO);
554 return;
555 }
556 }
557 }
[a35b458]558
[181c32f]559 remove_fun_node(&device_tree, fun);
560 fibril_rwlock_write_unlock(&tree->rwlock);
561 fun_busy_unlock(fun);
[a35b458]562
[181c32f]563 /* Delete ref added when inserting function into tree */
564 fun_del_ref(fun);
565 /* Delete ref added above when looking up function */
566 fun_del_ref(fun);
[a35b458]567
[181c32f]568 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_remove_function() succeeded.");
569 async_answer_0(callid, EOK);
570}
571
572/** Initialize driver which has registered itself as running and ready.
573 *
574 * The initialization is done in a separate fibril to avoid deadlocks (if the
575 * driver needed to be served by devman during the driver's initialization).
576 */
[b7fd2a0]577static errno_t init_running_drv(void *drv)
[181c32f]578{
579 driver_t *driver = (driver_t *) drv;
[a35b458]580
[181c32f]581 initialize_running_driver(driver, &device_tree);
582 log_msg(LOG_DEFAULT, LVL_DEBUG, "The `%s` driver was successfully initialized.",
583 driver->name);
584 return 0;
585}
586
587/** Function for handling connections from a driver to the device manager. */
[f9b2cb4c]588void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[181c32f]589{
590 client_t *client;
591 driver_t *driver = NULL;
[a35b458]592
[181c32f]593 /* Accept the connection. */
594 async_answer_0(iid, EOK);
[a35b458]595
[181c32f]596 client = async_get_client_data();
597 if (client == NULL) {
598 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate client data.");
599 return;
600 }
[a35b458]601
[181c32f]602 while (true) {
603 ipc_call_t call;
604 ipc_callid_t callid = async_get_call(&call);
[a35b458]605
[181c32f]606 if (!IPC_GET_IMETHOD(call))
607 break;
[a35b458]608
[181c32f]609 if (IPC_GET_IMETHOD(call) != DEVMAN_DRIVER_REGISTER) {
610 fibril_mutex_lock(&client->mutex);
611 driver = client->driver;
612 fibril_mutex_unlock(&client->mutex);
613 if (driver == NULL) {
614 /* First call must be to DEVMAN_DRIVER_REGISTER */
615 async_answer_0(callid, ENOTSUP);
616 continue;
617 }
618 }
[a35b458]619
[181c32f]620 switch (IPC_GET_IMETHOD(call)) {
621 case DEVMAN_DRIVER_REGISTER:
622 fibril_mutex_lock(&client->mutex);
623 if (client->driver != NULL) {
624 fibril_mutex_unlock(&client->mutex);
625 async_answer_0(callid, EINVAL);
626 continue;
627 }
628 client->driver = devman_driver_register(callid, &call);
629 fibril_mutex_unlock(&client->mutex);
630 break;
631 case DEVMAN_ADD_FUNCTION:
632 devman_add_function(callid, &call);
633 break;
634 case DEVMAN_ADD_DEVICE_TO_CATEGORY:
635 devman_add_function_to_cat(callid, &call);
636 break;
637 case DEVMAN_DRV_FUN_ONLINE:
638 devman_drv_fun_online(callid, &call, driver);
639 break;
640 case DEVMAN_DRV_FUN_OFFLINE:
641 devman_drv_fun_offline(callid, &call, driver);
642 break;
643 case DEVMAN_REMOVE_FUNCTION:
644 devman_remove_function(callid, &call);
645 break;
646 default:
647 async_answer_0(callid, EINVAL);
648 break;
649 }
650 }
651}
652
653/** @}
654 */
Note: See TracBrowser for help on using the repository browser.