source: mainline/uspace/srv/devman/main.c@ 984a9ba

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

do not expose the call capability handler from the async framework

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

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

  • Property mode set to 100644
File size: 10.2 KB
RevLine 
[e2b9a993]1/*
2 * Copyright (c) 2010 Lenka Trochtova
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @defgroup devman Device manager.
31 * @brief HelenOS device manager.
32 * @{
33 */
34
35/** @file
36 */
37
38#include <assert.h>
39#include <ipc/services.h>
[79ae36dd]40#include <ns.h>
[e2b9a993]41#include <async.h>
42#include <stdio.h>
43#include <errno.h>
[c1694b6b]44#include <str_error.h>
[3e6a98c5]45#include <stdbool.h>
[e2b9a993]46#include <fibril_synch.h>
47#include <stdlib.h>
[c47e1a8]48#include <str.h>
[e2b9a993]49#include <ctype.h>
[9b415c9]50#include <io/log.h>
[e2b9a993]51#include <ipc/devman.h>
[15f3c3f]52#include <loc.h>
[e2b9a993]53
[d80d7a8]54#include "client_conn.h"
[d1bafbf]55#include "dev.h"
[e2b9a993]56#include "devman.h"
[59dc181]57#include "devtree.h"
[181c32f]58#include "drv_conn.h"
[041b026]59#include "driver.h"
[38e52c92]60#include "fun.h"
[a60e90b]61#include "loc.h"
[e2b9a993]62
[a79d88d]63#define DRIVER_DEFAULT_STORE "/drv"
[e2b9a993]64
[181c32f]65driver_list_t drivers_list;
[d80d7a8]66dev_tree_t device_tree;
[e2b9a993]67
[984a9ba]68static void devman_connection_device(ipc_call_t *icall, void *arg)
[38b3baf]69{
[0b5a4131]70 devman_handle_t handle = IPC_GET_ARG2(*icall);
[8b1e15ac]71 dev_node_t *dev = NULL;
[a35b458]72
[f9b2cb4c]73 fun_node_t *fun = find_fun_node(&device_tree, handle);
74 if (fun == NULL) {
[8b1e15ac]75 dev = find_dev_node(&device_tree, handle);
[f9b2cb4c]76 } else {
[58cbb0c8]77 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]78
[8b1e15ac]79 dev = fun->dev;
[58cbb0c8]80 if (dev != NULL)
81 dev_add_ref(dev);
[a35b458]82
[58cbb0c8]83 fibril_rwlock_read_unlock(&device_tree.rwlock);
84 }
[a35b458]85
[0418050]86 /*
87 * For a valid function to connect to we need a device. The root
88 * function, for example, has no device and cannot be connected to.
89 * This means @c dev needs to be valid regardless whether we are
90 * connecting to a device or to a function.
91 */
92 if (dev == NULL) {
[a1a101d]93 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding failed - no device or "
[ebcb05a]94 "function with handle %" PRIun " was found.", handle);
[984a9ba]95 async_answer_0(icall, ENOENT);
[58cbb0c8]96 goto cleanup;
[5cd136ab]97 }
[a35b458]98
[f9b2cb4c]99 if (fun == NULL) {
[a1a101d]100 log_msg(LOG_DEFAULT, LVL_ERROR, NAME ": devman_forward error - cannot "
[ebcb05a]101 "connect to handle %" PRIun ", refers to a device.",
[9b415c9]102 handle);
[984a9ba]103 async_answer_0(icall, ENOENT);
[58cbb0c8]104 goto cleanup;
[5cd136ab]105 }
[a35b458]106
[e2b9b341]107 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]108
[f9b2cb4c]109 /* Connect to the specified function */
110 driver_t *driver = dev->drv;
[a35b458]111
[f9b2cb4c]112 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a35b458]113
[f9b2cb4c]114 if (driver == NULL) {
[5ef16903]115 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding refused - "
[f9b2cb4c]116 "the device %" PRIun " is not in usable state.", handle);
[984a9ba]117 async_answer_0(icall, ENOENT);
[f9b2cb4c]118 goto cleanup;
119 }
[a35b458]120
[f9b2cb4c]121 if (!driver->sess) {
122 log_msg(LOG_DEFAULT, LVL_ERROR,
123 "Could not forward to driver `%s'.", driver->name);
[984a9ba]124 async_answer_0(icall, EINVAL);
[f9b2cb4c]125 goto cleanup;
126 }
[a35b458]127
[f9b2cb4c]128 if (fun != NULL) {
129 log_msg(LOG_DEFAULT, LVL_DEBUG,
130 "Forwarding request for `%s' function to driver `%s'.",
131 fun->pathname, driver->name);
132 } else {
133 log_msg(LOG_DEFAULT, LVL_DEBUG,
134 "Forwarding request for `%s' device to driver `%s'.",
135 dev->pfun->pathname, driver->name);
136 }
[a35b458]137
[f9b2cb4c]138 async_exch_t *exch = async_exchange_begin(driver->sess);
[984a9ba]139 async_forward_fast(icall, exch, INTERFACE_DDF_CLIENT, handle, 0, IPC_FF_NONE);
[f9b2cb4c]140 async_exchange_end(exch);
[a35b458]141
[f9b2cb4c]142cleanup:
143 if (dev != NULL)
144 dev_del_ref(dev);
[a35b458]145
[f9b2cb4c]146 if (fun != NULL)
147 fun_del_ref(fun);
148}
149
[984a9ba]150static void devman_connection_parent(ipc_call_t *icall, void *arg)
[f9b2cb4c]151{
152 devman_handle_t handle = IPC_GET_ARG2(*icall);
153 dev_node_t *dev = NULL;
[a35b458]154
[f9b2cb4c]155 fun_node_t *fun = find_fun_node(&device_tree, handle);
156 if (fun == NULL) {
157 dev = find_dev_node(&device_tree, handle);
[005ac3c]158 } else {
[f9b2cb4c]159 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]160
[f9b2cb4c]161 dev = fun->dev;
162 if (dev != NULL)
163 dev_add_ref(dev);
[a35b458]164
[f9b2cb4c]165 fibril_rwlock_read_unlock(&device_tree.rwlock);
[5cd136ab]166 }
[a35b458]167
[f9b2cb4c]168 /*
169 * For a valid function to connect to we need a device. The root
170 * function, for example, has no device and cannot be connected to.
171 * This means @c dev needs to be valid regardless whether we are
172 * connecting to a device or to a function.
173 */
174 if (dev == NULL) {
175 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding failed - no device or "
176 "function with handle %" PRIun " was found.", handle);
[984a9ba]177 async_answer_0(icall, ENOENT);
[f9b2cb4c]178 goto cleanup;
179 }
[a35b458]180
[f9b2cb4c]181 driver_t *driver = NULL;
[a35b458]182
[f9b2cb4c]183 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]184
[f9b2cb4c]185 /* Connect to parent function of a device (or device function). */
186 if (dev->pfun->dev != NULL)
187 driver = dev->pfun->dev->drv;
[a35b458]188
[f9b2cb4c]189 devman_handle_t fun_handle = dev->pfun->handle;
[a35b458]190
[e2b9b341]191 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a35b458]192
[c6c389ed]193 if (driver == NULL) {
[5ef16903]194 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding refused - "
[79ae36dd]195 "the device %" PRIun " is not in usable state.", handle);
[984a9ba]196 async_answer_0(icall, ENOENT);
[58cbb0c8]197 goto cleanup;
[5cd136ab]198 }
[a35b458]199
[79ae36dd]200 if (!driver->sess) {
[a1a101d]201 log_msg(LOG_DEFAULT, LVL_ERROR,
[79ae36dd]202 "Could not forward to driver `%s'.", driver->name);
[984a9ba]203 async_answer_0(icall, EINVAL);
[58cbb0c8]204 goto cleanup;
[9a66bc2e]205 }
[a35b458]206
[8b1e15ac]207 if (fun != NULL) {
[a1a101d]208 log_msg(LOG_DEFAULT, LVL_DEBUG,
[ebcb05a]209 "Forwarding request for `%s' function to driver `%s'.",
[9b415c9]210 fun->pathname, driver->name);
[8b1e15ac]211 } else {
[a1a101d]212 log_msg(LOG_DEFAULT, LVL_DEBUG,
[ebcb05a]213 "Forwarding request for `%s' device to driver `%s'.",
[9b415c9]214 dev->pfun->pathname, driver->name);
[8b1e15ac]215 }
[a35b458]216
[79ae36dd]217 async_exch_t *exch = async_exchange_begin(driver->sess);
[984a9ba]218 async_forward_fast(icall, exch, INTERFACE_DDF_DRIVER, fun_handle, 0, IPC_FF_NONE);
[79ae36dd]219 async_exchange_end(exch);
[a35b458]220
[58cbb0c8]221cleanup:
222 if (dev != NULL)
223 dev_del_ref(dev);
[a35b458]224
[58cbb0c8]225 if (fun != NULL)
226 fun_del_ref(fun);
[5cd136ab]227}
228
[984a9ba]229static void devman_forward(ipc_call_t *icall, void *arg)
[ce89036b]230{
[f9b2cb4c]231 iface_t iface = IPC_GET_ARG1(*icall);
[15f3c3f]232 service_id_t service_id = IPC_GET_ARG2(*icall);
[a35b458]233
[f9b2cb4c]234 fun_node_t *fun = find_loc_tree_function(&device_tree, service_id);
[a35b458]235
[e2b9b341]236 fibril_rwlock_read_lock(&device_tree.rwlock);
[a35b458]237
[f9b2cb4c]238 if ((fun == NULL) || (fun->dev == NULL) || (fun->dev->drv == NULL)) {
239 log_msg(LOG_DEFAULT, LVL_WARN, "devman_forward(): function "
[12f9f0d0]240 "not found.\n");
[e2b9b341]241 fibril_rwlock_read_unlock(&device_tree.rwlock);
[984a9ba]242 async_answer_0(icall, ENOENT);
[ce89036b]243 return;
244 }
[a35b458]245
[f9b2cb4c]246 dev_node_t *dev = fun->dev;
247 driver_t *driver = dev->drv;
248 devman_handle_t handle = fun->handle;
[a35b458]249
[e2b9b341]250 fibril_rwlock_read_unlock(&device_tree.rwlock);
[a35b458]251
[e2b9b341]252 async_exch_t *exch = async_exchange_begin(driver->sess);
[984a9ba]253 async_forward_fast(icall, exch, iface, handle, 0, IPC_FF_NONE);
[79ae36dd]254 async_exchange_end(exch);
[a35b458]255
[a1a101d]256 log_msg(LOG_DEFAULT, LVL_DEBUG,
[f9b2cb4c]257 "Forwarding service request for `%s' function to driver `%s'.",
[e2b9b341]258 fun->pathname, driver->name);
[a35b458]259
[e2b9b341]260 fun_del_ref(fun);
[ce89036b]261}
262
[422722e]263static void *devman_client_data_create(void)
264{
265 client_t *client;
[a35b458]266
[422722e]267 client = calloc(1, sizeof(client_t));
268 if (client == NULL)
269 return NULL;
[a35b458]270
[422722e]271 fibril_mutex_initialize(&client->mutex);
272 return client;
273}
274
275static void devman_client_data_destroy(void *data)
276{
277 free(data);
278}
279
[38b3baf]280/** Initialize device manager internal structures. */
281static bool devman_init(void)
[e2b9a993]282{
[a1a101d]283 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - looking for available drivers.");
[a35b458]284
[38b3baf]285 /* Initialize list of available drivers. */
[0c3666d]286 init_driver_list(&drivers_list);
[c6c389ed]287 if (lookup_available_drivers(&drivers_list,
288 DRIVER_DEFAULT_STORE) == 0) {
[a1a101d]289 log_msg(LOG_DEFAULT, LVL_FATAL, "No drivers found.");
[e2b9a993]290 return false;
291 }
[a35b458]292
[a1a101d]293 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - list of drivers has been initialized.");
[a35b458]294
[38b3baf]295 /* Create root device node. */
[e2b9a993]296 if (!init_device_tree(&device_tree, &drivers_list)) {
[a1a101d]297 log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to initialize device tree.");
[38b3baf]298 return false;
[e2b9a993]299 }
[a35b458]300
[38b3baf]301 /*
[f302586]302 * Caution: As the device manager is not a real loc
303 * driver (it uses a completely different IPC protocol
304 * than an ordinary loc driver), forwarding a connection
305 * from client to the devman by location service will
306 * not work.
[38b3baf]307 */
[f302586]308 loc_server_register(NAME);
[a35b458]309
[e2b9a993]310 return true;
311}
312
313int main(int argc, char *argv[])
314{
[50ad3f3]315 printf("%s: HelenOS Device Manager\n", NAME);
[a35b458]316
[b7fd2a0]317 errno_t rc = log_init(NAME);
[50ad3f3]318 if (rc != EOK) {
[c1694b6b]319 printf("%s: Error initializing logging subsystem: %s\n", NAME, str_error(rc));
[50ad3f3]320 return rc;
[9b415c9]321 }
[a35b458]322
[422722e]323 /* Set handlers for incoming connections. */
324 async_set_client_data_constructor(devman_client_data_create);
325 async_set_client_data_destructor(devman_client_data_destroy);
[a35b458]326
[f9b2cb4c]327 port_id_t port;
328 rc = async_create_port(INTERFACE_DDF_DRIVER,
329 devman_connection_driver, NULL, &port);
[c1694b6b]330 if (rc != EOK) {
331 printf("%s: Error creating DDF driver port: %s\n", NAME, str_error(rc));
[f9b2cb4c]332 return rc;
[c1694b6b]333 }
[a35b458]334
[f9b2cb4c]335 rc = async_create_port(INTERFACE_DDF_CLIENT,
336 devman_connection_client, NULL, &port);
[c1694b6b]337 if (rc != EOK) {
338 printf("%s: Error creating DDF client port: %s\n", NAME, str_error(rc));
[f9b2cb4c]339 return rc;
[c1694b6b]340 }
[a35b458]341
[f9b2cb4c]342 rc = async_create_port(INTERFACE_DEVMAN_DEVICE,
343 devman_connection_device, NULL, &port);
[c1694b6b]344 if (rc != EOK) {
345 printf("%s: Error creating devman device port: %s\n", NAME, str_error(rc));
[f9b2cb4c]346 return rc;
[c1694b6b]347 }
[a35b458]348
[f9b2cb4c]349 rc = async_create_port(INTERFACE_DEVMAN_PARENT,
350 devman_connection_parent, NULL, &port);
[c1694b6b]351 if (rc != EOK) {
352 printf("%s: Error creating devman parent port: %s\n", NAME, str_error(rc));
[f9b2cb4c]353 return rc;
[c1694b6b]354 }
[a35b458]355
[f9b2cb4c]356 async_set_fallback_port_handler(devman_forward, NULL);
[a35b458]357
[f302586]358 if (!devman_init()) {
[a1a101d]359 log_msg(LOG_DEFAULT, LVL_ERROR, "Error while initializing service.");
[f302586]360 return -1;
361 }
[a35b458]362
[38b3baf]363 /* Register device manager at naming service. */
[50ad3f3]364 rc = service_register(SERVICE_DEVMAN);
365 if (rc != EOK) {
[c1694b6b]366 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering as a service: %s", str_error(rc));
[50ad3f3]367 return rc;
[9b415c9]368 }
[a35b458]369
[50ad3f3]370 printf("%s: Accepting connections.\n", NAME);
[79ae36dd]371 task_retval(0);
[e2b9a993]372 async_manager();
[a35b458]373
[38b3baf]374 /* Never reached. */
[e2b9a993]375 return 0;
376}
[c16cf62]377
378/** @}
[38b3baf]379 */
Note: See TracBrowser for help on using the repository browser.