source: mainline/uspace/srv/devman/client_conn.c@ 5f36841

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

Fix block comment formatting (ccheck).

  • Property mode set to 100644
File size: 20.1 KB
RevLine 
[d80d7a8]1/*
2 * Copyright (c) 2010 Lenka Trochtova
[1db5669]3 * Copyright (c) 2013 Jiri Svoboda
[d80d7a8]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/**
31 * @defgroup devman Device manager.
32 * @brief HelenOS device manager.
33 * @{
34 */
35
36/** @file
37 */
38
39#include <inttypes.h>
40#include <assert.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 <ctype.h>
51#include <ipc/devman.h>
52
53#include "client_conn.h"
54#include "dev.h"
55#include "devman.h"
56#include "driver.h"
57#include "fun.h"
58#include "loc.h"
59#include "main.h"
60
61/** Find handle for the device instance identified by the device's path in the
[7c3fb9b]62 * device tree.
63 */
[a46e56b]64static void devman_function_get_handle(cap_call_handle_t icall_handle, ipc_call_t *icall)
[d80d7a8]65{
66 char *pathname;
67 devman_handle_t handle;
[a35b458]68
[b7fd2a0]69 errno_t rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
[d80d7a8]70 if (rc != EOK) {
[a46e56b]71 async_answer_0(icall_handle, rc);
[d80d7a8]72 return;
73 }
[a35b458]74
[d80d7a8]75 fun_node_t *fun = find_fun_node_by_path(&device_tree, pathname);
[a35b458]76
[d80d7a8]77 free(pathname);
78
79 if (fun == NULL) {
[a46e56b]80 async_answer_0(icall_handle, ENOENT);
[d80d7a8]81 return;
82 }
83
84 fibril_rwlock_read_lock(&device_tree.rwlock);
85
86 /* Check function state */
87 if (fun->state == FUN_REMOVED) {
88 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a46e56b]89 async_answer_0(icall_handle, ENOENT);
[d80d7a8]90 return;
91 }
92 handle = fun->handle;
93
94 fibril_rwlock_read_unlock(&device_tree.rwlock);
95
96 /* Delete reference created above by find_fun_node_by_path() */
97 fun_del_ref(fun);
98
[a46e56b]99 async_answer_1(icall_handle, EOK, handle);
[d80d7a8]100}
101
[4c9b28a]102/** Get device match ID. */
[a46e56b]103static void devman_fun_get_match_id(cap_call_handle_t icall_handle, ipc_call_t *icall)
[4c9b28a]104{
105 devman_handle_t handle = IPC_GET_ARG1(*icall);
106 size_t index = IPC_GET_ARG2(*icall);
107 void *buffer = NULL;
108
109 fun_node_t *fun = find_fun_node(&device_tree, handle);
110 if (fun == NULL) {
[a46e56b]111 async_answer_0(icall_handle, ENOMEM);
[4c9b28a]112 return;
113 }
114
[a46e56b]115 cap_call_handle_t data_chandle;
[4c9b28a]116 size_t data_len;
[a46e56b]117 if (!async_data_read_receive(&data_chandle, &data_len)) {
118 async_answer_0(icall_handle, EINVAL);
[4c9b28a]119 fun_del_ref(fun);
120 return;
121 }
122
123 buffer = malloc(data_len);
124 if (buffer == NULL) {
[a46e56b]125 async_answer_0(data_chandle, ENOMEM);
126 async_answer_0(icall_handle, ENOMEM);
[4c9b28a]127 fun_del_ref(fun);
128 return;
129 }
130
131 fibril_rwlock_read_lock(&device_tree.rwlock);
132
133 /* Check function state */
134 if (fun->state == FUN_REMOVED)
135 goto error;
136
137 link_t *link = list_nth(&fun->match_ids.ids, index);
138 if (link == NULL)
139 goto error;
140
141 match_id_t *mid = list_get_instance(link, match_id_t, link);
142
143 size_t sent_length = str_size(mid->id);
144 if (sent_length > data_len) {
145 sent_length = data_len;
146 }
147
[a46e56b]148 async_data_read_finalize(data_chandle, mid->id, sent_length);
149 async_answer_1(icall_handle, EOK, mid->score);
[4c9b28a]150
151 fibril_rwlock_read_unlock(&device_tree.rwlock);
152 fun_del_ref(fun);
153 free(buffer);
154
155 return;
156error:
157 fibril_rwlock_read_unlock(&device_tree.rwlock);
158 free(buffer);
159
[a46e56b]160 async_answer_0(data_chandle, ENOENT);
161 async_answer_0(icall_handle, ENOENT);
[4c9b28a]162 fun_del_ref(fun);
163}
164
[d80d7a8]165/** Get device name. */
[a46e56b]166static void devman_fun_get_name(cap_call_handle_t icall_handle, ipc_call_t *icall)
[d80d7a8]167{
168 devman_handle_t handle = IPC_GET_ARG1(*icall);
169
170 fun_node_t *fun = find_fun_node(&device_tree, handle);
171 if (fun == NULL) {
[a46e56b]172 async_answer_0(icall_handle, ENOMEM);
[d80d7a8]173 return;
174 }
175
[a46e56b]176 cap_call_handle_t data_chandle;
[d80d7a8]177 size_t data_len;
[a46e56b]178 if (!async_data_read_receive(&data_chandle, &data_len)) {
179 async_answer_0(icall_handle, EINVAL);
[d80d7a8]180 fun_del_ref(fun);
181 return;
182 }
183
184 void *buffer = malloc(data_len);
185 if (buffer == NULL) {
[a46e56b]186 async_answer_0(data_chandle, ENOMEM);
187 async_answer_0(icall_handle, ENOMEM);
[d80d7a8]188 fun_del_ref(fun);
189 return;
190 }
191
192 fibril_rwlock_read_lock(&device_tree.rwlock);
193
194 /* Check function state */
195 if (fun->state == FUN_REMOVED) {
196 fibril_rwlock_read_unlock(&device_tree.rwlock);
197 free(buffer);
198
[a46e56b]199 async_answer_0(data_chandle, ENOENT);
200 async_answer_0(icall_handle, ENOENT);
[d80d7a8]201 fun_del_ref(fun);
202 return;
203 }
204
205 size_t sent_length = str_size(fun->name);
206 if (sent_length > data_len) {
207 sent_length = data_len;
208 }
209
[a46e56b]210 async_data_read_finalize(data_chandle, fun->name, sent_length);
211 async_answer_0(icall_handle, EOK);
[d80d7a8]212
213 fibril_rwlock_read_unlock(&device_tree.rwlock);
214 fun_del_ref(fun);
215 free(buffer);
216}
217
218/** Get function driver name. */
[a46e56b]219static void devman_fun_get_driver_name(cap_call_handle_t icall_handle, ipc_call_t *icall)
[d80d7a8]220{
221 devman_handle_t handle = IPC_GET_ARG1(*icall);
222
223 fun_node_t *fun = find_fun_node(&device_tree, handle);
224 if (fun == NULL) {
[a46e56b]225 async_answer_0(icall_handle, ENOMEM);
[d80d7a8]226 return;
227 }
228
[a46e56b]229 cap_call_handle_t data_chandle;
[d80d7a8]230 size_t data_len;
[a46e56b]231 if (!async_data_read_receive(&data_chandle, &data_len)) {
232 async_answer_0(icall_handle, EINVAL);
[d80d7a8]233 fun_del_ref(fun);
234 return;
235 }
236
237 void *buffer = malloc(data_len);
238 if (buffer == NULL) {
[a46e56b]239 async_answer_0(data_chandle, ENOMEM);
240 async_answer_0(icall_handle, ENOMEM);
[d80d7a8]241 fun_del_ref(fun);
242 return;
243 }
244
245 fibril_rwlock_read_lock(&device_tree.rwlock);
246
247 /* Check function state */
248 if (fun->state == FUN_REMOVED) {
249 fibril_rwlock_read_unlock(&device_tree.rwlock);
250 free(buffer);
251
[a46e56b]252 async_answer_0(data_chandle, ENOENT);
253 async_answer_0(icall_handle, ENOENT);
[d80d7a8]254 fun_del_ref(fun);
255 return;
256 }
257
258 /* Check whether function has a driver */
259 if (fun->child == NULL || fun->child->drv == NULL) {
260 fibril_rwlock_read_unlock(&device_tree.rwlock);
261 free(buffer);
262
[a46e56b]263 async_answer_0(data_chandle, EINVAL);
264 async_answer_0(icall_handle, EINVAL);
[d80d7a8]265 fun_del_ref(fun);
266 return;
267 }
268
269 size_t sent_length = str_size(fun->child->drv->name);
270 if (sent_length > data_len) {
271 sent_length = data_len;
272 }
273
[a46e56b]274 async_data_read_finalize(data_chandle, fun->child->drv->name,
[d80d7a8]275 sent_length);
[a46e56b]276 async_answer_0(icall_handle, EOK);
[d80d7a8]277
278 fibril_rwlock_read_unlock(&device_tree.rwlock);
279 fun_del_ref(fun);
280 free(buffer);
281}
282
283/** Get device path. */
[a46e56b]284static void devman_fun_get_path(cap_call_handle_t icall_handle, ipc_call_t *icall)
[d80d7a8]285{
286 devman_handle_t handle = IPC_GET_ARG1(*icall);
287
288 fun_node_t *fun = find_fun_node(&device_tree, handle);
289 if (fun == NULL) {
[a46e56b]290 async_answer_0(icall_handle, ENOMEM);
[d80d7a8]291 return;
292 }
293
[a46e56b]294 cap_call_handle_t data_chandle;
[d80d7a8]295 size_t data_len;
[a46e56b]296 if (!async_data_read_receive(&data_chandle, &data_len)) {
297 async_answer_0(icall_handle, EINVAL);
[d80d7a8]298 fun_del_ref(fun);
299 return;
300 }
301
302 void *buffer = malloc(data_len);
303 if (buffer == NULL) {
[a46e56b]304 async_answer_0(data_chandle, ENOMEM);
305 async_answer_0(icall_handle, ENOMEM);
[d80d7a8]306 fun_del_ref(fun);
307 return;
308 }
[a35b458]309
[d80d7a8]310 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]311
[d80d7a8]312 /* Check function state */
313 if (fun->state == FUN_REMOVED) {
314 fibril_rwlock_read_unlock(&device_tree.rwlock);
315 free(buffer);
316
[a46e56b]317 async_answer_0(data_chandle, ENOENT);
318 async_answer_0(icall_handle, ENOENT);
[d80d7a8]319 fun_del_ref(fun);
320 return;
321 }
[a35b458]322
[d80d7a8]323 size_t sent_length = str_size(fun->pathname);
324 if (sent_length > data_len) {
325 sent_length = data_len;
326 }
327
[a46e56b]328 async_data_read_finalize(data_chandle, fun->pathname, sent_length);
329 async_answer_0(icall_handle, EOK);
[d80d7a8]330
331 fibril_rwlock_read_unlock(&device_tree.rwlock);
332 fun_del_ref(fun);
333 free(buffer);
334}
335
[1db5669]336/** Get handle for parent function of a device. */
[a46e56b]337static void devman_dev_get_parent(cap_call_handle_t icall_handle, ipc_call_t *icall)
[1db5669]338{
339 dev_node_t *dev;
[a35b458]340
[1db5669]341 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]342
[1db5669]343 dev = find_dev_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
344 if (dev == NULL || dev->state == DEVICE_REMOVED) {
345 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a46e56b]346 async_answer_0(icall_handle, ENOENT);
[1db5669]347 return;
348 }
[a35b458]349
[1db5669]350 if (dev->pfun == NULL) {
351 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a46e56b]352 async_answer_0(icall_handle, ENOENT);
[1db5669]353 return;
354 }
[a35b458]355
[a46e56b]356 async_answer_1(icall_handle, EOK, dev->pfun->handle);
[a35b458]357
[1db5669]358 fibril_rwlock_read_unlock(&device_tree.rwlock);
359}
360
[a46e56b]361static void devman_dev_get_functions(cap_call_handle_t icall_handle, ipc_call_t *icall)
[d80d7a8]362{
[a46e56b]363 cap_call_handle_t chandle;
[d80d7a8]364 size_t size;
365 size_t act_size;
[b7fd2a0]366 errno_t rc;
[a35b458]367
[a46e56b]368 if (!async_data_read_receive(&chandle, &size)) {
369 async_answer_0(chandle, EREFUSED);
370 async_answer_0(icall_handle, EREFUSED);
[d80d7a8]371 return;
372 }
[a35b458]373
[d80d7a8]374 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]375
[d80d7a8]376 dev_node_t *dev = find_dev_node_no_lock(&device_tree,
377 IPC_GET_ARG1(*icall));
378 if (dev == NULL || dev->state == DEVICE_REMOVED) {
379 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a46e56b]380 async_answer_0(chandle, ENOENT);
381 async_answer_0(icall_handle, ENOENT);
[d80d7a8]382 return;
383 }
[a35b458]384
[d80d7a8]385 devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
386 if (hdl_buf == NULL) {
387 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a46e56b]388 async_answer_0(chandle, ENOMEM);
389 async_answer_0(icall_handle, ENOMEM);
[d80d7a8]390 return;
391 }
[a35b458]392
[d80d7a8]393 rc = dev_get_functions(&device_tree, dev, hdl_buf, size, &act_size);
394 if (rc != EOK) {
395 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a46e56b]396 async_answer_0(chandle, rc);
397 async_answer_0(icall_handle, rc);
[d80d7a8]398 return;
399 }
[a35b458]400
[d80d7a8]401 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a35b458]402
[a46e56b]403 errno_t retval = async_data_read_finalize(chandle, hdl_buf, size);
[d80d7a8]404 free(hdl_buf);
[a35b458]405
[a46e56b]406 async_answer_1(icall_handle, retval, act_size);
[d80d7a8]407}
408
409/** Get handle for child device of a function. */
[a46e56b]410static void devman_fun_get_child(cap_call_handle_t icall_handle, ipc_call_t *icall)
[d80d7a8]411{
412 fun_node_t *fun;
[a35b458]413
[d80d7a8]414 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]415
[d80d7a8]416 fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
417 if (fun == NULL || fun->state == FUN_REMOVED) {
418 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a46e56b]419 async_answer_0(icall_handle, ENOENT);
[d80d7a8]420 return;
421 }
[a35b458]422
[d80d7a8]423 if (fun->child == NULL) {
424 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a46e56b]425 async_answer_0(icall_handle, ENOENT);
[d80d7a8]426 return;
427 }
[a35b458]428
[a46e56b]429 async_answer_1(icall_handle, EOK, fun->child->handle);
[a35b458]430
[d80d7a8]431 fibril_rwlock_read_unlock(&device_tree.rwlock);
432}
433
434/** Online function.
435 *
436 * Send a request to online a function to the responsible driver.
437 * The driver may offline other functions if necessary (i.e. if the state
438 * of this function is linked to state of another function somehow).
439 */
[a46e56b]440static void devman_fun_online(cap_call_handle_t icall_handle, ipc_call_t *icall)
[d80d7a8]441{
442 fun_node_t *fun;
[b7fd2a0]443 errno_t rc;
[d80d7a8]444
445 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
446 if (fun == NULL) {
[a46e56b]447 async_answer_0(icall_handle, ENOENT);
[d80d7a8]448 return;
449 }
[a35b458]450
[d80d7a8]451 rc = driver_fun_online(&device_tree, fun);
452 fun_del_ref(fun);
[a35b458]453
[a46e56b]454 async_answer_0(icall_handle, rc);
[d80d7a8]455}
456
457/** Offline function.
458 *
459 * Send a request to offline a function to the responsible driver. As
460 * a result the subtree rooted at that function should be cleanly
461 * detatched. The driver may offline other functions if necessary
462 * (i.e. if the state of this function is linked to state of another
463 * function somehow).
464 */
[a46e56b]465static void devman_fun_offline(cap_call_handle_t icall_handle, ipc_call_t *icall)
[d80d7a8]466{
467 fun_node_t *fun;
[b7fd2a0]468 errno_t rc;
[d80d7a8]469
470 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
471 if (fun == NULL) {
[a46e56b]472 async_answer_0(icall_handle, ENOENT);
[d80d7a8]473 return;
474 }
[a35b458]475
[d80d7a8]476 rc = driver_fun_offline(&device_tree, fun);
477 fun_del_ref(fun);
[a35b458]478
[a46e56b]479 async_answer_0(icall_handle, rc);
[d80d7a8]480}
481
482/** Find handle for the function instance identified by its service ID. */
[a46e56b]483static void devman_fun_sid_to_handle(cap_call_handle_t icall_handle, ipc_call_t *icall)
[d80d7a8]484{
485 fun_node_t *fun;
486
487 fun = find_loc_tree_function(&device_tree, IPC_GET_ARG1(*icall));
[a35b458]488
[d80d7a8]489 if (fun == NULL) {
[a46e56b]490 async_answer_0(icall_handle, ENOENT);
[d80d7a8]491 return;
492 }
493
494 fibril_rwlock_read_lock(&device_tree.rwlock);
495
496 /* Check function state */
497 if (fun->state == FUN_REMOVED) {
498 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a46e56b]499 async_answer_0(icall_handle, ENOENT);
[d80d7a8]500 return;
501 }
502
[a46e56b]503 async_answer_1(icall_handle, EOK, fun->handle);
[d80d7a8]504 fibril_rwlock_read_unlock(&device_tree.rwlock);
505 fun_del_ref(fun);
506}
507
[0511549]508/** Get list of all registered drivers. */
[a46e56b]509static void devman_get_drivers(cap_call_handle_t icall_handle, ipc_call_t *icall)
[0511549]510{
[a46e56b]511 cap_call_handle_t chandle;
[0511549]512 size_t size;
513 size_t act_size;
[b7fd2a0]514 errno_t rc;
[a35b458]515
[a46e56b]516 if (!async_data_read_receive(&chandle, &size)) {
517 async_answer_0(icall_handle, EREFUSED);
[0511549]518 return;
519 }
[a35b458]520
[0511549]521 devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
522 if (hdl_buf == NULL) {
[a46e56b]523 async_answer_0(chandle, ENOMEM);
524 async_answer_0(icall_handle, ENOMEM);
[0511549]525 return;
526 }
[a35b458]527
[0511549]528 rc = driver_get_list(&drivers_list, hdl_buf, size, &act_size);
529 if (rc != EOK) {
[a46e56b]530 async_answer_0(chandle, rc);
531 async_answer_0(icall_handle, rc);
[0511549]532 return;
533 }
[a35b458]534
[a46e56b]535 errno_t retval = async_data_read_finalize(chandle, hdl_buf, size);
[0511549]536 free(hdl_buf);
[a35b458]537
[a46e56b]538 async_answer_1(icall_handle, retval, act_size);
[0511549]539}
540
[a46e56b]541static void devman_driver_get_devices(cap_call_handle_t icall_handle, ipc_call_t *icall)
[1db5669]542{
[a46e56b]543 cap_call_handle_t chandle;
[1db5669]544 size_t size;
545 size_t act_size;
[b7fd2a0]546 errno_t rc;
[a35b458]547
[a46e56b]548 if (!async_data_read_receive(&chandle, &size)) {
549 async_answer_0(icall_handle, EREFUSED);
[1db5669]550 return;
551 }
[a35b458]552
[1db5669]553 driver_t *drv = driver_find(&drivers_list, IPC_GET_ARG1(*icall));
554 if (drv == NULL) {
[a46e56b]555 async_answer_0(chandle, ENOENT);
556 async_answer_0(icall_handle, ENOENT);
[1db5669]557 return;
558 }
[a35b458]559
[1db5669]560 devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
561 if (hdl_buf == NULL) {
[a46e56b]562 async_answer_0(chandle, ENOMEM);
563 async_answer_0(icall_handle, ENOMEM);
[1db5669]564 return;
565 }
[a35b458]566
[1db5669]567 rc = driver_get_devices(drv, hdl_buf, size, &act_size);
568 if (rc != EOK) {
569 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a46e56b]570 async_answer_0(chandle, rc);
571 async_answer_0(icall_handle, rc);
[1db5669]572 return;
573 }
[a35b458]574
[a46e56b]575 errno_t retval = async_data_read_finalize(chandle, hdl_buf, size);
[1db5669]576 free(hdl_buf);
[a35b458]577
[a46e56b]578 async_answer_1(icall_handle, retval, act_size);
[1db5669]579}
580
581
[7969087]582/** Find driver by name. */
[a46e56b]583static void devman_driver_get_handle(cap_call_handle_t icall_handle, ipc_call_t *icall)
[7969087]584{
585 char *drvname;
[a35b458]586
[b7fd2a0]587 errno_t rc = async_data_write_accept((void **) &drvname, true, 0, 0, 0, 0);
[7969087]588 if (rc != EOK) {
[a46e56b]589 async_answer_0(icall_handle, rc);
[7969087]590 return;
591 }
[a35b458]592
[7969087]593 driver_t *driver = driver_find_by_name(&drivers_list, drvname);
[a35b458]594
[7969087]595 free(drvname);
[a35b458]596
[7969087]597 if (driver == NULL) {
[a46e56b]598 async_answer_0(icall_handle, ENOENT);
[7969087]599 return;
600 }
[a35b458]601
[a46e56b]602 async_answer_1(icall_handle, EOK, driver->handle);
[7969087]603}
604
[4c9b28a]605/** Get driver match ID. */
[a46e56b]606static void devman_driver_get_match_id(cap_call_handle_t icall_handle, ipc_call_t *icall)
[4c9b28a]607{
608 devman_handle_t handle = IPC_GET_ARG1(*icall);
609 size_t index = IPC_GET_ARG2(*icall);
610
611 driver_t *drv = driver_find(&drivers_list, handle);
612 if (drv == NULL) {
[a46e56b]613 async_answer_0(icall_handle, ENOMEM);
[4c9b28a]614 return;
615 }
616
[a46e56b]617 cap_call_handle_t data_chandle;
[4c9b28a]618 size_t data_len;
[a46e56b]619 if (!async_data_read_receive(&data_chandle, &data_len)) {
620 async_answer_0(icall_handle, EINVAL);
[4c9b28a]621 return;
622 }
623
624 void *buffer = malloc(data_len);
625 if (buffer == NULL) {
[a46e56b]626 async_answer_0(data_chandle, ENOMEM);
627 async_answer_0(icall_handle, ENOMEM);
[4c9b28a]628 return;
629 }
630
631 fibril_mutex_lock(&drv->driver_mutex);
632 link_t *link = list_nth(&drv->match_ids.ids, index);
633 if (link == NULL) {
634 fibril_mutex_unlock(&drv->driver_mutex);
[5b18137]635 free(buffer);
[a46e56b]636 async_answer_0(data_chandle, ENOMEM);
637 async_answer_0(icall_handle, ENOMEM);
[4c9b28a]638 return;
639 }
640
641 match_id_t *mid = list_get_instance(link, match_id_t, link);
642
643 size_t sent_length = str_size(mid->id);
644 if (sent_length > data_len) {
645 sent_length = data_len;
646 }
647
[a46e56b]648 async_data_read_finalize(data_chandle, mid->id, sent_length);
649 async_answer_1(icall_handle, EOK, mid->score);
[4c9b28a]650
651 fibril_mutex_unlock(&drv->driver_mutex);
652
653 free(buffer);
654}
655
[0511549]656/** Get driver name. */
[a46e56b]657static void devman_driver_get_name(cap_call_handle_t icall_handle, ipc_call_t *icall)
[0511549]658{
659 devman_handle_t handle = IPC_GET_ARG1(*icall);
660
661 driver_t *drv = driver_find(&drivers_list, handle);
662 if (drv == NULL) {
[a46e56b]663 async_answer_0(icall_handle, ENOMEM);
[0511549]664 return;
665 }
666
[a46e56b]667 cap_call_handle_t data_chandle;
[0511549]668 size_t data_len;
[a46e56b]669 if (!async_data_read_receive(&data_chandle, &data_len)) {
670 async_answer_0(icall_handle, EINVAL);
[0511549]671 return;
672 }
673
674 void *buffer = malloc(data_len);
675 if (buffer == NULL) {
[a46e56b]676 async_answer_0(data_chandle, ENOMEM);
677 async_answer_0(icall_handle, ENOMEM);
[0511549]678 return;
679 }
680
681 fibril_mutex_lock(&drv->driver_mutex);
682
683 size_t sent_length = str_size(drv->name);
684 if (sent_length > data_len) {
685 sent_length = data_len;
686 }
687
[a46e56b]688 async_data_read_finalize(data_chandle, drv->name, sent_length);
689 async_answer_0(icall_handle, EOK);
[0511549]690
691 fibril_mutex_unlock(&drv->driver_mutex);
692
693 free(buffer);
694}
695
[e5556e4a]696/** Get driver state. */
[a46e56b]697static void devman_driver_get_state(cap_call_handle_t icall_handle, ipc_call_t *icall)
[e5556e4a]698{
699 driver_t *drv;
[a35b458]700
[e5556e4a]701 drv = driver_find(&drivers_list, IPC_GET_ARG1(*icall));
702 if (drv == NULL) {
[a46e56b]703 async_answer_0(icall_handle, ENOENT);
[e5556e4a]704 return;
705 }
[a35b458]706
[a46e56b]707 async_answer_1(icall_handle, EOK, (sysarg_t) drv->state);
[e5556e4a]708}
709
[7969087]710/** Forcibly load a driver. */
[a46e56b]711static void devman_driver_load(cap_call_handle_t icall_handle, ipc_call_t *icall)
[7969087]712{
713 driver_t *drv;
[b7fd2a0]714 errno_t rc;
[a35b458]715
[7969087]716 drv = driver_find(&drivers_list, IPC_GET_ARG1(*icall));
717 if (drv == NULL) {
[a46e56b]718 async_answer_0(icall_handle, ENOENT);
[7969087]719 return;
720 }
[a35b458]721
[7969087]722 fibril_mutex_lock(&drv->driver_mutex);
723 rc = start_driver(drv) ? EOK : EIO;
724 fibril_mutex_unlock(&drv->driver_mutex);
725
[a46e56b]726 async_answer_0(icall_handle, rc);
[7969087]727}
728
[81685dd9]729/** Unload a driver by user request. */
[a46e56b]730static void devman_driver_unload(cap_call_handle_t icall_handle, ipc_call_t *icall)
[81685dd9]731{
732 driver_t *drv;
[b7fd2a0]733 errno_t rc;
[a35b458]734
[81685dd9]735 drv = driver_find(&drivers_list, IPC_GET_ARG1(*icall));
736 if (drv == NULL) {
[a46e56b]737 async_answer_0(icall_handle, ENOENT);
[81685dd9]738 return;
739 }
[a35b458]740
[81685dd9]741 fibril_mutex_lock(&drv->driver_mutex);
742 rc = stop_driver(drv);
743 fibril_mutex_unlock(&drv->driver_mutex);
744
[a46e56b]745 async_answer_0(icall_handle, rc);
[81685dd9]746}
747
[d80d7a8]748/** Function for handling connections from a client to the device manager. */
[a46e56b]749void devman_connection_client(cap_call_handle_t icall_handle, ipc_call_t *icall, void *arg)
[d80d7a8]750{
751 /* Accept connection. */
[a46e56b]752 async_answer_0(icall_handle, EOK);
[a35b458]753
[d80d7a8]754 while (true) {
755 ipc_call_t call;
[a46e56b]756 cap_call_handle_t chandle = async_get_call(&call);
[a35b458]757
[d80d7a8]758 if (!IPC_GET_IMETHOD(call))
759 break;
[a35b458]760
[d80d7a8]761 switch (IPC_GET_IMETHOD(call)) {
762 case DEVMAN_DEVICE_GET_HANDLE:
[a46e56b]763 devman_function_get_handle(chandle, &call);
[d80d7a8]764 break;
[1db5669]765 case DEVMAN_DEV_GET_PARENT:
[a46e56b]766 devman_dev_get_parent(chandle, &call);
[1db5669]767 break;
[d80d7a8]768 case DEVMAN_DEV_GET_FUNCTIONS:
[a46e56b]769 devman_dev_get_functions(chandle, &call);
[d80d7a8]770 break;
771 case DEVMAN_FUN_GET_CHILD:
[a46e56b]772 devman_fun_get_child(chandle, &call);
[d80d7a8]773 break;
[4c9b28a]774 case DEVMAN_FUN_GET_MATCH_ID:
[a46e56b]775 devman_fun_get_match_id(chandle, &call);
[4c9b28a]776 break;
[d80d7a8]777 case DEVMAN_FUN_GET_NAME:
[a46e56b]778 devman_fun_get_name(chandle, &call);
[d80d7a8]779 break;
780 case DEVMAN_FUN_GET_DRIVER_NAME:
[a46e56b]781 devman_fun_get_driver_name(chandle, &call);
[d80d7a8]782 break;
783 case DEVMAN_FUN_GET_PATH:
[a46e56b]784 devman_fun_get_path(chandle, &call);
[d80d7a8]785 break;
786 case DEVMAN_FUN_ONLINE:
[a46e56b]787 devman_fun_online(chandle, &call);
[d80d7a8]788 break;
789 case DEVMAN_FUN_OFFLINE:
[a46e56b]790 devman_fun_offline(chandle, &call);
[d80d7a8]791 break;
792 case DEVMAN_FUN_SID_TO_HANDLE:
[a46e56b]793 devman_fun_sid_to_handle(chandle, &call);
[d80d7a8]794 break;
[0511549]795 case DEVMAN_GET_DRIVERS:
[a46e56b]796 devman_get_drivers(chandle, &call);
[0511549]797 break;
[1db5669]798 case DEVMAN_DRIVER_GET_DEVICES:
[a46e56b]799 devman_driver_get_devices(chandle, &call);
[1db5669]800 break;
[7969087]801 case DEVMAN_DRIVER_GET_HANDLE:
[a46e56b]802 devman_driver_get_handle(chandle, &call);
[7969087]803 break;
[4c9b28a]804 case DEVMAN_DRIVER_GET_MATCH_ID:
[a46e56b]805 devman_driver_get_match_id(chandle, &call);
[4c9b28a]806 break;
[0511549]807 case DEVMAN_DRIVER_GET_NAME:
[a46e56b]808 devman_driver_get_name(chandle, &call);
[0511549]809 break;
[e5556e4a]810 case DEVMAN_DRIVER_GET_STATE:
[a46e56b]811 devman_driver_get_state(chandle, &call);
[e5556e4a]812 break;
[7969087]813 case DEVMAN_DRIVER_LOAD:
[a46e56b]814 devman_driver_load(chandle, &call);
[7969087]815 break;
[81685dd9]816 case DEVMAN_DRIVER_UNLOAD:
[a46e56b]817 devman_driver_unload(chandle, &call);
[81685dd9]818 break;
[d80d7a8]819 default:
[a46e56b]820 async_answer_0(chandle, ENOENT);
[d80d7a8]821 }
822 }
823}
824
825
826/** @}
827 */
Note: See TracBrowser for help on using the repository browser.