source: mainline/uspace/srv/devman/client_conn.c@ a46e56b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a46e56b was a46e56b, checked in by Jakub Jermar <jakub@…>, 7 years ago

Prefer handle over ID in naming handle variables

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