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

Last change on this file since ca48672 was 8300c72, checked in by Jiri Svoboda <jiri@…>, 4 months ago

Quiesce devices before proceeding with shutdown.

Only implemented for e1k, uhci and xhci.

  • Property mode set to 100644
File size: 19.2 KB
RevLine 
[d80d7a8]1/*
[8300c72]2 * Copyright (c) 2025 Jiri Svoboda
[d80d7a8]3 * Copyright (c) 2010 Lenka Trochtova
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/**
[4122410]31 * @addtogroup devman
[d80d7a8]32 * @{
33 */
34
35/** @file
36 */
37
38#include <inttypes.h>
39#include <assert.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 <ctype.h>
50#include <ipc/devman.h>
51
52#include "client_conn.h"
53#include "dev.h"
54#include "devman.h"
55#include "driver.h"
56#include "fun.h"
57#include "loc.h"
58#include "main.h"
59
60/** Find handle for the device instance identified by the device's path in the
[7c3fb9b]61 * device tree.
62 */
[984a9ba]63static void devman_function_get_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) {
[984a9ba]70 async_answer_0(icall, 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) {
[984a9ba]79 async_answer_0(icall, 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);
[984a9ba]88 async_answer_0(icall, 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
[984a9ba]98 async_answer_1(icall, EOK, handle);
[d80d7a8]99}
100
[4c9b28a]101/** Get device match ID. */
[984a9ba]102static void devman_fun_get_match_id(ipc_call_t *icall)
[4c9b28a]103{
[fafb8e5]104 devman_handle_t handle = ipc_get_arg1(icall);
105 size_t index = ipc_get_arg2(icall);
[4c9b28a]106 void *buffer = NULL;
107
108 fun_node_t *fun = find_fun_node(&device_tree, handle);
109 if (fun == NULL) {
[984a9ba]110 async_answer_0(icall, ENOMEM);
[4c9b28a]111 return;
112 }
113
[984a9ba]114 ipc_call_t data;
[4c9b28a]115 size_t data_len;
[984a9ba]116 if (!async_data_read_receive(&data, &data_len)) {
117 async_answer_0(icall, EINVAL);
[4c9b28a]118 fun_del_ref(fun);
119 return;
120 }
121
122 buffer = malloc(data_len);
123 if (buffer == NULL) {
[984a9ba]124 async_answer_0(&data, ENOMEM);
125 async_answer_0(icall, 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
[984a9ba]147 async_data_read_finalize(&data, mid->id, sent_length);
148 async_answer_1(icall, 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
[984a9ba]159 async_answer_0(&data, ENOENT);
160 async_answer_0(icall, ENOENT);
[4c9b28a]161 fun_del_ref(fun);
162}
163
[d80d7a8]164/** Get device name. */
[984a9ba]165static void devman_fun_get_name(ipc_call_t *icall)
[d80d7a8]166{
[fafb8e5]167 devman_handle_t handle = ipc_get_arg1(icall);
[d80d7a8]168
169 fun_node_t *fun = find_fun_node(&device_tree, handle);
170 if (fun == NULL) {
[984a9ba]171 async_answer_0(icall, ENOMEM);
[d80d7a8]172 return;
173 }
174
[984a9ba]175 ipc_call_t data;
[d80d7a8]176 size_t data_len;
[984a9ba]177 if (!async_data_read_receive(&data, &data_len)) {
178 async_answer_0(icall, EINVAL);
[d80d7a8]179 fun_del_ref(fun);
180 return;
181 }
182
183 void *buffer = malloc(data_len);
184 if (buffer == NULL) {
[984a9ba]185 async_answer_0(&data, ENOMEM);
186 async_answer_0(icall, 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
[984a9ba]198 async_answer_0(&data, ENOENT);
199 async_answer_0(icall, 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
[984a9ba]209 async_data_read_finalize(&data, fun->name, sent_length);
210 async_answer_0(icall, 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. */
[984a9ba]218static void devman_fun_get_driver_name(ipc_call_t *icall)
[d80d7a8]219{
[fafb8e5]220 devman_handle_t handle = ipc_get_arg1(icall);
[d80d7a8]221
222 fun_node_t *fun = find_fun_node(&device_tree, handle);
223 if (fun == NULL) {
[984a9ba]224 async_answer_0(icall, ENOMEM);
[d80d7a8]225 return;
226 }
227
[984a9ba]228 ipc_call_t data;
[d80d7a8]229 size_t data_len;
[984a9ba]230 if (!async_data_read_receive(&data, &data_len)) {
231 async_answer_0(icall, EINVAL);
[d80d7a8]232 fun_del_ref(fun);
233 return;
234 }
235
236 void *buffer = malloc(data_len);
237 if (buffer == NULL) {
[984a9ba]238 async_answer_0(&data, ENOMEM);
239 async_answer_0(icall, 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
[984a9ba]251 async_answer_0(&data, ENOENT);
252 async_answer_0(icall, 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
[984a9ba]262 async_answer_0(&data, EINVAL);
263 async_answer_0(icall, 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
[984a9ba]273 async_data_read_finalize(&data, fun->child->drv->name,
[d80d7a8]274 sent_length);
[984a9ba]275 async_answer_0(icall, 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. */
[984a9ba]283static void devman_fun_get_path(ipc_call_t *icall)
[d80d7a8]284{
[fafb8e5]285 devman_handle_t handle = ipc_get_arg1(icall);
[d80d7a8]286
287 fun_node_t *fun = find_fun_node(&device_tree, handle);
288 if (fun == NULL) {
[984a9ba]289 async_answer_0(icall, ENOMEM);
[d80d7a8]290 return;
291 }
292
[984a9ba]293 ipc_call_t data;
[d80d7a8]294 size_t data_len;
[984a9ba]295 if (!async_data_read_receive(&data, &data_len)) {
296 async_answer_0(icall, EINVAL);
[d80d7a8]297 fun_del_ref(fun);
298 return;
299 }
300
301 void *buffer = malloc(data_len);
302 if (buffer == NULL) {
[984a9ba]303 async_answer_0(&data, ENOMEM);
304 async_answer_0(icall, 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
[984a9ba]316 async_answer_0(&data, ENOENT);
317 async_answer_0(icall, 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
[984a9ba]327 async_data_read_finalize(&data, fun->pathname, sent_length);
328 async_answer_0(icall, 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. */
[984a9ba]336static void devman_dev_get_parent(ipc_call_t *icall)
[1db5669]337{
338 dev_node_t *dev;
[a35b458]339
[1db5669]340 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]341
[fafb8e5]342 dev = find_dev_node_no_lock(&device_tree, ipc_get_arg1(icall));
[1db5669]343 if (dev == NULL || dev->state == DEVICE_REMOVED) {
344 fibril_rwlock_read_unlock(&device_tree.rwlock);
[984a9ba]345 async_answer_0(icall, ENOENT);
[1db5669]346 return;
347 }
[a35b458]348
[1db5669]349 if (dev->pfun == NULL) {
350 fibril_rwlock_read_unlock(&device_tree.rwlock);
[984a9ba]351 async_answer_0(icall, ENOENT);
[1db5669]352 return;
353 }
[a35b458]354
[984a9ba]355 async_answer_1(icall, EOK, dev->pfun->handle);
[a35b458]356
[1db5669]357 fibril_rwlock_read_unlock(&device_tree.rwlock);
358}
359
[984a9ba]360static void devman_dev_get_functions(ipc_call_t *icall)
[d80d7a8]361{
[984a9ba]362 ipc_call_t call;
[d80d7a8]363 size_t size;
364 size_t act_size;
[b7fd2a0]365 errno_t rc;
[a35b458]366
[984a9ba]367 if (!async_data_read_receive(&call, &size)) {
368 async_answer_0(&call, EREFUSED);
369 async_answer_0(icall, 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,
[fafb8e5]376 ipc_get_arg1(icall));
[d80d7a8]377 if (dev == NULL || dev->state == DEVICE_REMOVED) {
378 fibril_rwlock_read_unlock(&device_tree.rwlock);
[984a9ba]379 async_answer_0(&call, ENOENT);
380 async_answer_0(icall, 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);
[984a9ba]387 async_answer_0(&call, ENOMEM);
388 async_answer_0(icall, 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);
[984a9ba]395 async_answer_0(&call, rc);
396 async_answer_0(icall, rc);
[d80d7a8]397 return;
398 }
[a35b458]399
[d80d7a8]400 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a35b458]401
[984a9ba]402 errno_t retval = async_data_read_finalize(&call, hdl_buf, size);
[d80d7a8]403 free(hdl_buf);
[a35b458]404
[984a9ba]405 async_answer_1(icall, retval, act_size);
[d80d7a8]406}
407
408/** Get handle for child device of a function. */
[984a9ba]409static void devman_fun_get_child(ipc_call_t *icall)
[d80d7a8]410{
411 fun_node_t *fun;
[a35b458]412
[d80d7a8]413 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]414
[fafb8e5]415 fun = find_fun_node_no_lock(&device_tree, ipc_get_arg1(icall));
[d80d7a8]416 if (fun == NULL || fun->state == FUN_REMOVED) {
417 fibril_rwlock_read_unlock(&device_tree.rwlock);
[984a9ba]418 async_answer_0(icall, ENOENT);
[d80d7a8]419 return;
420 }
[a35b458]421
[d80d7a8]422 if (fun->child == NULL) {
423 fibril_rwlock_read_unlock(&device_tree.rwlock);
[984a9ba]424 async_answer_0(icall, ENOENT);
[d80d7a8]425 return;
426 }
[a35b458]427
[984a9ba]428 async_answer_1(icall, 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 */
[984a9ba]439static void devman_fun_online(ipc_call_t *icall)
[d80d7a8]440{
441 fun_node_t *fun;
[b7fd2a0]442 errno_t rc;
[d80d7a8]443
[fafb8e5]444 fun = find_fun_node(&device_tree, ipc_get_arg1(icall));
[d80d7a8]445 if (fun == NULL) {
[984a9ba]446 async_answer_0(icall, ENOENT);
[d80d7a8]447 return;
448 }
[a35b458]449
[d80d7a8]450 rc = driver_fun_online(&device_tree, fun);
451 fun_del_ref(fun);
[a35b458]452
[984a9ba]453 async_answer_0(icall, 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 */
[984a9ba]464static void devman_fun_offline(ipc_call_t *icall)
[d80d7a8]465{
466 fun_node_t *fun;
[b7fd2a0]467 errno_t rc;
[d80d7a8]468
[fafb8e5]469 fun = find_fun_node(&device_tree, ipc_get_arg1(icall));
[d80d7a8]470 if (fun == NULL) {
[984a9ba]471 async_answer_0(icall, ENOENT);
[d80d7a8]472 return;
473 }
[a35b458]474
[d80d7a8]475 rc = driver_fun_offline(&device_tree, fun);
476 fun_del_ref(fun);
[a35b458]477
[984a9ba]478 async_answer_0(icall, rc);
[d80d7a8]479}
480
[8300c72]481/** Quiesce function.
482 *
483 * Send a request to quiesce a function to the responsible driver.
484 */
485static void devman_fun_quiesce(ipc_call_t *icall)
486{
487 fun_node_t *fun;
488 dev_node_t *child;
489 errno_t rc;
490
491 fun = find_fun_node(&device_tree, ipc_get_arg1(icall));
492 if (fun == NULL) {
493 async_answer_0(icall, ENOENT);
494 return;
495 }
496
497 fibril_rwlock_read_lock(&device_tree.rwlock);
498
499 /* Check function state */
500 if (fun->state == FUN_REMOVED) {
501 fibril_rwlock_read_unlock(&device_tree.rwlock);
502 async_answer_0(icall, ENOENT);
503 return;
504 }
505
506 child = fun->child;
507 dev_add_ref(child);
508 fibril_rwlock_read_unlock(&device_tree.rwlock);
509
510 rc = driver_dev_quiesce(&device_tree, child);
511 fun_del_ref(fun);
512
513 async_answer_0(icall, rc);
514}
515
[d80d7a8]516/** Find handle for the function instance identified by its service ID. */
[984a9ba]517static void devman_fun_sid_to_handle(ipc_call_t *icall)
[d80d7a8]518{
519 fun_node_t *fun;
520
[fafb8e5]521 fun = find_loc_tree_function(&device_tree, ipc_get_arg1(icall));
[a35b458]522
[d80d7a8]523 if (fun == NULL) {
[984a9ba]524 async_answer_0(icall, ENOENT);
[d80d7a8]525 return;
526 }
527
528 fibril_rwlock_read_lock(&device_tree.rwlock);
529
530 /* Check function state */
531 if (fun->state == FUN_REMOVED) {
532 fibril_rwlock_read_unlock(&device_tree.rwlock);
[984a9ba]533 async_answer_0(icall, ENOENT);
[d80d7a8]534 return;
535 }
536
[984a9ba]537 async_answer_1(icall, EOK, fun->handle);
[d80d7a8]538 fibril_rwlock_read_unlock(&device_tree.rwlock);
539 fun_del_ref(fun);
540}
541
[0511549]542/** Get list of all registered drivers. */
[984a9ba]543static void devman_get_drivers(ipc_call_t *icall)
[0511549]544{
[984a9ba]545 ipc_call_t call;
[0511549]546 size_t size;
547 size_t act_size;
[b7fd2a0]548 errno_t rc;
[a35b458]549
[984a9ba]550 if (!async_data_read_receive(&call, &size)) {
551 async_answer_0(icall, EREFUSED);
[0511549]552 return;
553 }
[a35b458]554
[0511549]555 devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
556 if (hdl_buf == NULL) {
[984a9ba]557 async_answer_0(&call, ENOMEM);
558 async_answer_0(icall, ENOMEM);
[0511549]559 return;
560 }
[a35b458]561
[0511549]562 rc = driver_get_list(&drivers_list, hdl_buf, size, &act_size);
563 if (rc != EOK) {
[984a9ba]564 async_answer_0(&call, rc);
565 async_answer_0(icall, rc);
[0511549]566 return;
567 }
[a35b458]568
[984a9ba]569 errno_t retval = async_data_read_finalize(&call, hdl_buf, size);
[0511549]570 free(hdl_buf);
[a35b458]571
[984a9ba]572 async_answer_1(icall, retval, act_size);
[0511549]573}
574
[984a9ba]575static void devman_driver_get_devices(ipc_call_t *icall)
[1db5669]576{
[984a9ba]577 ipc_call_t call;
[1db5669]578 size_t size;
579 size_t act_size;
[b7fd2a0]580 errno_t rc;
[a35b458]581
[984a9ba]582 if (!async_data_read_receive(&call, &size)) {
583 async_answer_0(icall, EREFUSED);
[1db5669]584 return;
585 }
[a35b458]586
[fafb8e5]587 driver_t *drv = driver_find(&drivers_list, ipc_get_arg1(icall));
[1db5669]588 if (drv == NULL) {
[984a9ba]589 async_answer_0(&call, ENOENT);
590 async_answer_0(icall, ENOENT);
[1db5669]591 return;
592 }
[a35b458]593
[1db5669]594 devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
595 if (hdl_buf == NULL) {
[984a9ba]596 async_answer_0(&call, ENOMEM);
597 async_answer_0(icall, ENOMEM);
[1db5669]598 return;
599 }
[a35b458]600
[1db5669]601 rc = driver_get_devices(drv, hdl_buf, size, &act_size);
602 if (rc != EOK) {
603 fibril_rwlock_read_unlock(&device_tree.rwlock);
[984a9ba]604 async_answer_0(&call, rc);
605 async_answer_0(icall, rc);
[1db5669]606 return;
607 }
[a35b458]608
[984a9ba]609 errno_t retval = async_data_read_finalize(&call, hdl_buf, size);
[1db5669]610 free(hdl_buf);
[a35b458]611
[984a9ba]612 async_answer_1(icall, retval, act_size);
[1db5669]613}
614
[7969087]615/** Find driver by name. */
[984a9ba]616static void devman_driver_get_handle(ipc_call_t *icall)
[7969087]617{
618 char *drvname;
[a35b458]619
[b7fd2a0]620 errno_t rc = async_data_write_accept((void **) &drvname, true, 0, 0, 0, 0);
[7969087]621 if (rc != EOK) {
[984a9ba]622 async_answer_0(icall, rc);
[7969087]623 return;
624 }
[a35b458]625
[7969087]626 driver_t *driver = driver_find_by_name(&drivers_list, drvname);
[a35b458]627
[7969087]628 free(drvname);
[a35b458]629
[7969087]630 if (driver == NULL) {
[984a9ba]631 async_answer_0(icall, ENOENT);
[7969087]632 return;
633 }
[a35b458]634
[984a9ba]635 async_answer_1(icall, EOK, driver->handle);
[7969087]636}
637
[4c9b28a]638/** Get driver match ID. */
[984a9ba]639static void devman_driver_get_match_id(ipc_call_t *icall)
[4c9b28a]640{
[fafb8e5]641 devman_handle_t handle = ipc_get_arg1(icall);
642 size_t index = ipc_get_arg2(icall);
[4c9b28a]643
644 driver_t *drv = driver_find(&drivers_list, handle);
645 if (drv == NULL) {
[984a9ba]646 async_answer_0(icall, ENOMEM);
[4c9b28a]647 return;
648 }
649
[984a9ba]650 ipc_call_t data;
[4c9b28a]651 size_t data_len;
[984a9ba]652 if (!async_data_read_receive(&data, &data_len)) {
653 async_answer_0(icall, EINVAL);
[4c9b28a]654 return;
655 }
656
657 void *buffer = malloc(data_len);
658 if (buffer == NULL) {
[984a9ba]659 async_answer_0(&data, ENOMEM);
660 async_answer_0(icall, ENOMEM);
[4c9b28a]661 return;
662 }
663
664 fibril_mutex_lock(&drv->driver_mutex);
665 link_t *link = list_nth(&drv->match_ids.ids, index);
666 if (link == NULL) {
667 fibril_mutex_unlock(&drv->driver_mutex);
[5b18137]668 free(buffer);
[984a9ba]669 async_answer_0(&data, ENOMEM);
670 async_answer_0(icall, ENOMEM);
[4c9b28a]671 return;
672 }
673
674 match_id_t *mid = list_get_instance(link, match_id_t, link);
675
676 size_t sent_length = str_size(mid->id);
677 if (sent_length > data_len) {
678 sent_length = data_len;
679 }
680
[984a9ba]681 async_data_read_finalize(&data, mid->id, sent_length);
682 async_answer_1(icall, EOK, mid->score);
[4c9b28a]683
684 fibril_mutex_unlock(&drv->driver_mutex);
685
686 free(buffer);
687}
688
[0511549]689/** Get driver name. */
[984a9ba]690static void devman_driver_get_name(ipc_call_t *icall)
[0511549]691{
[fafb8e5]692 devman_handle_t handle = ipc_get_arg1(icall);
[0511549]693
694 driver_t *drv = driver_find(&drivers_list, handle);
695 if (drv == NULL) {
[984a9ba]696 async_answer_0(icall, ENOMEM);
[0511549]697 return;
698 }
699
[984a9ba]700 ipc_call_t data;
[0511549]701 size_t data_len;
[984a9ba]702 if (!async_data_read_receive(&data, &data_len)) {
703 async_answer_0(icall, EINVAL);
[0511549]704 return;
705 }
706
707 void *buffer = malloc(data_len);
708 if (buffer == NULL) {
[984a9ba]709 async_answer_0(&data, ENOMEM);
710 async_answer_0(icall, ENOMEM);
[0511549]711 return;
712 }
713
714 fibril_mutex_lock(&drv->driver_mutex);
715
716 size_t sent_length = str_size(drv->name);
717 if (sent_length > data_len) {
718 sent_length = data_len;
719 }
720
[984a9ba]721 async_data_read_finalize(&data, drv->name, sent_length);
722 async_answer_0(icall, EOK);
[0511549]723
724 fibril_mutex_unlock(&drv->driver_mutex);
725
726 free(buffer);
727}
728
[e5556e4a]729/** Get driver state. */
[984a9ba]730static void devman_driver_get_state(ipc_call_t *icall)
[e5556e4a]731{
732 driver_t *drv;
[a35b458]733
[fafb8e5]734 drv = driver_find(&drivers_list, ipc_get_arg1(icall));
[e5556e4a]735 if (drv == NULL) {
[984a9ba]736 async_answer_0(icall, ENOENT);
[e5556e4a]737 return;
738 }
[a35b458]739
[984a9ba]740 async_answer_1(icall, EOK, (sysarg_t) drv->state);
[e5556e4a]741}
742
[7969087]743/** Forcibly load a driver. */
[984a9ba]744static void devman_driver_load(ipc_call_t *icall)
[7969087]745{
746 driver_t *drv;
[b7fd2a0]747 errno_t rc;
[a35b458]748
[fafb8e5]749 drv = driver_find(&drivers_list, ipc_get_arg1(icall));
[7969087]750 if (drv == NULL) {
[984a9ba]751 async_answer_0(icall, ENOENT);
[7969087]752 return;
753 }
[a35b458]754
[7969087]755 fibril_mutex_lock(&drv->driver_mutex);
756 rc = start_driver(drv) ? EOK : EIO;
757 fibril_mutex_unlock(&drv->driver_mutex);
758
[984a9ba]759 async_answer_0(icall, rc);
[7969087]760}
761
[81685dd9]762/** Unload a driver by user request. */
[984a9ba]763static void devman_driver_unload(ipc_call_t *icall)
[81685dd9]764{
765 driver_t *drv;
[b7fd2a0]766 errno_t rc;
[a35b458]767
[fafb8e5]768 drv = driver_find(&drivers_list, ipc_get_arg1(icall));
[81685dd9]769 if (drv == NULL) {
[984a9ba]770 async_answer_0(icall, ENOENT);
[81685dd9]771 return;
772 }
[a35b458]773
[81685dd9]774 fibril_mutex_lock(&drv->driver_mutex);
775 rc = stop_driver(drv);
776 fibril_mutex_unlock(&drv->driver_mutex);
777
[984a9ba]778 async_answer_0(icall, rc);
[81685dd9]779}
780
[d80d7a8]781/** Function for handling connections from a client to the device manager. */
[984a9ba]782void devman_connection_client(ipc_call_t *icall, void *arg)
[d80d7a8]783{
784 /* Accept connection. */
[beb83c1]785 async_accept_0(icall);
[a35b458]786
[d80d7a8]787 while (true) {
788 ipc_call_t call;
[984a9ba]789 async_get_call(&call);
[a35b458]790
[fafb8e5]791 if (!ipc_get_imethod(&call)) {
[889cdb1]792 async_answer_0(&call, EOK);
[d80d7a8]793 break;
[889cdb1]794 }
[a35b458]795
[fafb8e5]796 switch (ipc_get_imethod(&call)) {
[d80d7a8]797 case DEVMAN_DEVICE_GET_HANDLE:
[984a9ba]798 devman_function_get_handle(&call);
[d80d7a8]799 break;
[1db5669]800 case DEVMAN_DEV_GET_PARENT:
[984a9ba]801 devman_dev_get_parent(&call);
[1db5669]802 break;
[d80d7a8]803 case DEVMAN_DEV_GET_FUNCTIONS:
[984a9ba]804 devman_dev_get_functions(&call);
[d80d7a8]805 break;
806 case DEVMAN_FUN_GET_CHILD:
[984a9ba]807 devman_fun_get_child(&call);
[d80d7a8]808 break;
[4c9b28a]809 case DEVMAN_FUN_GET_MATCH_ID:
[984a9ba]810 devman_fun_get_match_id(&call);
[4c9b28a]811 break;
[d80d7a8]812 case DEVMAN_FUN_GET_NAME:
[984a9ba]813 devman_fun_get_name(&call);
[d80d7a8]814 break;
815 case DEVMAN_FUN_GET_DRIVER_NAME:
[984a9ba]816 devman_fun_get_driver_name(&call);
[d80d7a8]817 break;
818 case DEVMAN_FUN_GET_PATH:
[984a9ba]819 devman_fun_get_path(&call);
[d80d7a8]820 break;
821 case DEVMAN_FUN_ONLINE:
[984a9ba]822 devman_fun_online(&call);
[d80d7a8]823 break;
824 case DEVMAN_FUN_OFFLINE:
[984a9ba]825 devman_fun_offline(&call);
[d80d7a8]826 break;
[8300c72]827 case DEVMAN_FUN_QUIESCE:
828 devman_fun_quiesce(&call);
829 break;
[d80d7a8]830 case DEVMAN_FUN_SID_TO_HANDLE:
[984a9ba]831 devman_fun_sid_to_handle(&call);
[d80d7a8]832 break;
[0511549]833 case DEVMAN_GET_DRIVERS:
[984a9ba]834 devman_get_drivers(&call);
[0511549]835 break;
[1db5669]836 case DEVMAN_DRIVER_GET_DEVICES:
[984a9ba]837 devman_driver_get_devices(&call);
[1db5669]838 break;
[7969087]839 case DEVMAN_DRIVER_GET_HANDLE:
[984a9ba]840 devman_driver_get_handle(&call);
[7969087]841 break;
[4c9b28a]842 case DEVMAN_DRIVER_GET_MATCH_ID:
[984a9ba]843 devman_driver_get_match_id(&call);
[4c9b28a]844 break;
[0511549]845 case DEVMAN_DRIVER_GET_NAME:
[984a9ba]846 devman_driver_get_name(&call);
[0511549]847 break;
[e5556e4a]848 case DEVMAN_DRIVER_GET_STATE:
[984a9ba]849 devman_driver_get_state(&call);
[e5556e4a]850 break;
[7969087]851 case DEVMAN_DRIVER_LOAD:
[984a9ba]852 devman_driver_load(&call);
[7969087]853 break;
[81685dd9]854 case DEVMAN_DRIVER_UNLOAD:
[984a9ba]855 devman_driver_unload(&call);
[81685dd9]856 break;
[d80d7a8]857 default:
[984a9ba]858 async_answer_0(&call, ENOENT);
[d80d7a8]859 }
860 }
861}
862
863/** @}
864 */
Note: See TracBrowser for help on using the repository browser.