source: mainline/uspace/srv/devman/client_conn.c@ 889cdb1

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

Always answer the IPC_M_PHONE_HUNGUP message

  • Property mode set to 100644
File size: 18.5 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/**
[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{
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) {
[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{
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) {
[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{
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) {
[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{
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) {
[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
[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);
[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,
376 IPC_GET_ARG1(*icall));
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
[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);
[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
444 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
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
469 fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
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
481/** Find handle for the function instance identified by its service ID. */
[984a9ba]482static void devman_fun_sid_to_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) {
[984a9ba]489 async_answer_0(icall, 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);
[984a9ba]498 async_answer_0(icall, ENOENT);
[d80d7a8]499 return;
500 }
501
[984a9ba]502 async_answer_1(icall, 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. */
[984a9ba]508static void devman_get_drivers(ipc_call_t *icall)
[0511549]509{
[984a9ba]510 ipc_call_t call;
[0511549]511 size_t size;
512 size_t act_size;
[b7fd2a0]513 errno_t rc;
[a35b458]514
[984a9ba]515 if (!async_data_read_receive(&call, &size)) {
516 async_answer_0(icall, EREFUSED);
[0511549]517 return;
518 }
[a35b458]519
[0511549]520 devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
521 if (hdl_buf == NULL) {
[984a9ba]522 async_answer_0(&call, ENOMEM);
523 async_answer_0(icall, ENOMEM);
[0511549]524 return;
525 }
[a35b458]526
[0511549]527 rc = driver_get_list(&drivers_list, hdl_buf, size, &act_size);
528 if (rc != EOK) {
[984a9ba]529 async_answer_0(&call, rc);
530 async_answer_0(icall, rc);
[0511549]531 return;
532 }
[a35b458]533
[984a9ba]534 errno_t retval = async_data_read_finalize(&call, hdl_buf, size);
[0511549]535 free(hdl_buf);
[a35b458]536
[984a9ba]537 async_answer_1(icall, retval, act_size);
[0511549]538}
539
[984a9ba]540static void devman_driver_get_devices(ipc_call_t *icall)
[1db5669]541{
[984a9ba]542 ipc_call_t call;
[1db5669]543 size_t size;
544 size_t act_size;
[b7fd2a0]545 errno_t rc;
[a35b458]546
[984a9ba]547 if (!async_data_read_receive(&call, &size)) {
548 async_answer_0(icall, EREFUSED);
[1db5669]549 return;
550 }
[a35b458]551
[1db5669]552 driver_t *drv = driver_find(&drivers_list, IPC_GET_ARG1(*icall));
553 if (drv == NULL) {
[984a9ba]554 async_answer_0(&call, ENOENT);
555 async_answer_0(icall, ENOENT);
[1db5669]556 return;
557 }
[a35b458]558
[1db5669]559 devman_handle_t *hdl_buf = (devman_handle_t *) malloc(size);
560 if (hdl_buf == NULL) {
[984a9ba]561 async_answer_0(&call, ENOMEM);
562 async_answer_0(icall, 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);
[984a9ba]569 async_answer_0(&call, rc);
570 async_answer_0(icall, rc);
[1db5669]571 return;
572 }
[a35b458]573
[984a9ba]574 errno_t retval = async_data_read_finalize(&call, hdl_buf, size);
[1db5669]575 free(hdl_buf);
[a35b458]576
[984a9ba]577 async_answer_1(icall, retval, act_size);
[1db5669]578}
579
[7969087]580/** Find driver by name. */
[984a9ba]581static void devman_driver_get_handle(ipc_call_t *icall)
[7969087]582{
583 char *drvname;
[a35b458]584
[b7fd2a0]585 errno_t rc = async_data_write_accept((void **) &drvname, true, 0, 0, 0, 0);
[7969087]586 if (rc != EOK) {
[984a9ba]587 async_answer_0(icall, rc);
[7969087]588 return;
589 }
[a35b458]590
[7969087]591 driver_t *driver = driver_find_by_name(&drivers_list, drvname);
[a35b458]592
[7969087]593 free(drvname);
[a35b458]594
[7969087]595 if (driver == NULL) {
[984a9ba]596 async_answer_0(icall, ENOENT);
[7969087]597 return;
598 }
[a35b458]599
[984a9ba]600 async_answer_1(icall, EOK, driver->handle);
[7969087]601}
602
[4c9b28a]603/** Get driver match ID. */
[984a9ba]604static void devman_driver_get_match_id(ipc_call_t *icall)
[4c9b28a]605{
606 devman_handle_t handle = IPC_GET_ARG1(*icall);
607 size_t index = IPC_GET_ARG2(*icall);
608
609 driver_t *drv = driver_find(&drivers_list, handle);
610 if (drv == NULL) {
[984a9ba]611 async_answer_0(icall, ENOMEM);
[4c9b28a]612 return;
613 }
614
[984a9ba]615 ipc_call_t data;
[4c9b28a]616 size_t data_len;
[984a9ba]617 if (!async_data_read_receive(&data, &data_len)) {
618 async_answer_0(icall, EINVAL);
[4c9b28a]619 return;
620 }
621
622 void *buffer = malloc(data_len);
623 if (buffer == NULL) {
[984a9ba]624 async_answer_0(&data, ENOMEM);
625 async_answer_0(icall, ENOMEM);
[4c9b28a]626 return;
627 }
628
629 fibril_mutex_lock(&drv->driver_mutex);
630 link_t *link = list_nth(&drv->match_ids.ids, index);
631 if (link == NULL) {
632 fibril_mutex_unlock(&drv->driver_mutex);
[5b18137]633 free(buffer);
[984a9ba]634 async_answer_0(&data, ENOMEM);
635 async_answer_0(icall, ENOMEM);
[4c9b28a]636 return;
637 }
638
639 match_id_t *mid = list_get_instance(link, match_id_t, link);
640
641 size_t sent_length = str_size(mid->id);
642 if (sent_length > data_len) {
643 sent_length = data_len;
644 }
645
[984a9ba]646 async_data_read_finalize(&data, mid->id, sent_length);
647 async_answer_1(icall, EOK, mid->score);
[4c9b28a]648
649 fibril_mutex_unlock(&drv->driver_mutex);
650
651 free(buffer);
652}
653
[0511549]654/** Get driver name. */
[984a9ba]655static void devman_driver_get_name(ipc_call_t *icall)
[0511549]656{
657 devman_handle_t handle = IPC_GET_ARG1(*icall);
658
659 driver_t *drv = driver_find(&drivers_list, handle);
660 if (drv == NULL) {
[984a9ba]661 async_answer_0(icall, ENOMEM);
[0511549]662 return;
663 }
664
[984a9ba]665 ipc_call_t data;
[0511549]666 size_t data_len;
[984a9ba]667 if (!async_data_read_receive(&data, &data_len)) {
668 async_answer_0(icall, EINVAL);
[0511549]669 return;
670 }
671
672 void *buffer = malloc(data_len);
673 if (buffer == NULL) {
[984a9ba]674 async_answer_0(&data, ENOMEM);
675 async_answer_0(icall, ENOMEM);
[0511549]676 return;
677 }
678
679 fibril_mutex_lock(&drv->driver_mutex);
680
681 size_t sent_length = str_size(drv->name);
682 if (sent_length > data_len) {
683 sent_length = data_len;
684 }
685
[984a9ba]686 async_data_read_finalize(&data, drv->name, sent_length);
687 async_answer_0(icall, EOK);
[0511549]688
689 fibril_mutex_unlock(&drv->driver_mutex);
690
691 free(buffer);
692}
693
[e5556e4a]694/** Get driver state. */
[984a9ba]695static void devman_driver_get_state(ipc_call_t *icall)
[e5556e4a]696{
697 driver_t *drv;
[a35b458]698
[e5556e4a]699 drv = driver_find(&drivers_list, IPC_GET_ARG1(*icall));
700 if (drv == NULL) {
[984a9ba]701 async_answer_0(icall, ENOENT);
[e5556e4a]702 return;
703 }
[a35b458]704
[984a9ba]705 async_answer_1(icall, EOK, (sysarg_t) drv->state);
[e5556e4a]706}
707
[7969087]708/** Forcibly load a driver. */
[984a9ba]709static void devman_driver_load(ipc_call_t *icall)
[7969087]710{
711 driver_t *drv;
[b7fd2a0]712 errno_t rc;
[a35b458]713
[7969087]714 drv = driver_find(&drivers_list, IPC_GET_ARG1(*icall));
715 if (drv == NULL) {
[984a9ba]716 async_answer_0(icall, ENOENT);
[7969087]717 return;
718 }
[a35b458]719
[7969087]720 fibril_mutex_lock(&drv->driver_mutex);
721 rc = start_driver(drv) ? EOK : EIO;
722 fibril_mutex_unlock(&drv->driver_mutex);
723
[984a9ba]724 async_answer_0(icall, rc);
[7969087]725}
726
[81685dd9]727/** Unload a driver by user request. */
[984a9ba]728static void devman_driver_unload(ipc_call_t *icall)
[81685dd9]729{
730 driver_t *drv;
[b7fd2a0]731 errno_t rc;
[a35b458]732
[81685dd9]733 drv = driver_find(&drivers_list, IPC_GET_ARG1(*icall));
734 if (drv == NULL) {
[984a9ba]735 async_answer_0(icall, ENOENT);
[81685dd9]736 return;
737 }
[a35b458]738
[81685dd9]739 fibril_mutex_lock(&drv->driver_mutex);
740 rc = stop_driver(drv);
741 fibril_mutex_unlock(&drv->driver_mutex);
742
[984a9ba]743 async_answer_0(icall, rc);
[81685dd9]744}
745
[d80d7a8]746/** Function for handling connections from a client to the device manager. */
[984a9ba]747void devman_connection_client(ipc_call_t *icall, void *arg)
[d80d7a8]748{
749 /* Accept connection. */
[984a9ba]750 async_answer_0(icall, EOK);
[a35b458]751
[d80d7a8]752 while (true) {
753 ipc_call_t call;
[984a9ba]754 async_get_call(&call);
[a35b458]755
[889cdb1]756 if (!IPC_GET_IMETHOD(call)) {
757 async_answer_0(&call, EOK);
[d80d7a8]758 break;
[889cdb1]759 }
[a35b458]760
[d80d7a8]761 switch (IPC_GET_IMETHOD(call)) {
762 case DEVMAN_DEVICE_GET_HANDLE:
[984a9ba]763 devman_function_get_handle(&call);
[d80d7a8]764 break;
[1db5669]765 case DEVMAN_DEV_GET_PARENT:
[984a9ba]766 devman_dev_get_parent(&call);
[1db5669]767 break;
[d80d7a8]768 case DEVMAN_DEV_GET_FUNCTIONS:
[984a9ba]769 devman_dev_get_functions(&call);
[d80d7a8]770 break;
771 case DEVMAN_FUN_GET_CHILD:
[984a9ba]772 devman_fun_get_child(&call);
[d80d7a8]773 break;
[4c9b28a]774 case DEVMAN_FUN_GET_MATCH_ID:
[984a9ba]775 devman_fun_get_match_id(&call);
[4c9b28a]776 break;
[d80d7a8]777 case DEVMAN_FUN_GET_NAME:
[984a9ba]778 devman_fun_get_name(&call);
[d80d7a8]779 break;
780 case DEVMAN_FUN_GET_DRIVER_NAME:
[984a9ba]781 devman_fun_get_driver_name(&call);
[d80d7a8]782 break;
783 case DEVMAN_FUN_GET_PATH:
[984a9ba]784 devman_fun_get_path(&call);
[d80d7a8]785 break;
786 case DEVMAN_FUN_ONLINE:
[984a9ba]787 devman_fun_online(&call);
[d80d7a8]788 break;
789 case DEVMAN_FUN_OFFLINE:
[984a9ba]790 devman_fun_offline(&call);
[d80d7a8]791 break;
792 case DEVMAN_FUN_SID_TO_HANDLE:
[984a9ba]793 devman_fun_sid_to_handle(&call);
[d80d7a8]794 break;
[0511549]795 case DEVMAN_GET_DRIVERS:
[984a9ba]796 devman_get_drivers(&call);
[0511549]797 break;
[1db5669]798 case DEVMAN_DRIVER_GET_DEVICES:
[984a9ba]799 devman_driver_get_devices(&call);
[1db5669]800 break;
[7969087]801 case DEVMAN_DRIVER_GET_HANDLE:
[984a9ba]802 devman_driver_get_handle(&call);
[7969087]803 break;
[4c9b28a]804 case DEVMAN_DRIVER_GET_MATCH_ID:
[984a9ba]805 devman_driver_get_match_id(&call);
[4c9b28a]806 break;
[0511549]807 case DEVMAN_DRIVER_GET_NAME:
[984a9ba]808 devman_driver_get_name(&call);
[0511549]809 break;
[e5556e4a]810 case DEVMAN_DRIVER_GET_STATE:
[984a9ba]811 devman_driver_get_state(&call);
[e5556e4a]812 break;
[7969087]813 case DEVMAN_DRIVER_LOAD:
[984a9ba]814 devman_driver_load(&call);
[7969087]815 break;
[81685dd9]816 case DEVMAN_DRIVER_UNLOAD:
[984a9ba]817 devman_driver_unload(&call);
[81685dd9]818 break;
[d80d7a8]819 default:
[984a9ba]820 async_answer_0(&call, ENOENT);
[d80d7a8]821 }
822 }
823}
824
825/** @}
826 */
Note: See TracBrowser for help on using the repository browser.