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

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

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

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