source: mainline/uspace/srv/devman/main.c@ 181c32f

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

Separate module for devman-driver communication.

  • Property mode set to 100644
File size: 8.6 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>
[3e6a98c5]44#include <stdbool.h>
[e2b9a993]45#include <fibril_synch.h>
46#include <stdlib.h>
[c47e1a8]47#include <str.h>
[e2b9a993]48#include <ctype.h>
[9b415c9]49#include <io/log.h>
[e2b9a993]50#include <ipc/devman.h>
[5cd136ab]51#include <ipc/driver.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
[c6c389ed]68static void devman_forward(ipc_callid_t iid, ipc_call_t *icall,
69 bool drv_to_parent)
[38b3baf]70{
[0b5a4131]71 devman_handle_t handle = IPC_GET_ARG2(*icall);
[8b1e15ac]72 devman_handle_t fwd_h;
73 fun_node_t *fun = NULL;
74 dev_node_t *dev = NULL;
[9a66bc2e]75
[8b1e15ac]76 fun = find_fun_node(&device_tree, handle);
77 if (fun == NULL)
78 dev = find_dev_node(&device_tree, handle);
[58cbb0c8]79 else {
80 fibril_rwlock_read_lock(&device_tree.rwlock);
[8b1e15ac]81 dev = fun->dev;
[58cbb0c8]82 if (dev != NULL)
83 dev_add_ref(dev);
84 fibril_rwlock_read_unlock(&device_tree.rwlock);
85 }
[8b1e15ac]86
[0418050]87 /*
88 * For a valid function to connect to we need a device. The root
89 * function, for example, has no device and cannot be connected to.
90 * This means @c dev needs to be valid regardless whether we are
91 * connecting to a device or to a function.
92 */
93 if (dev == NULL) {
[a1a101d]94 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding failed - no device or "
[ebcb05a]95 "function with handle %" PRIun " was found.", handle);
[ffa2c8ef]96 async_answer_0(iid, ENOENT);
[58cbb0c8]97 goto cleanup;
[5cd136ab]98 }
[8b1e15ac]99
100 if (fun == NULL && !drv_to_parent) {
[a1a101d]101 log_msg(LOG_DEFAULT, LVL_ERROR, NAME ": devman_forward error - cannot "
[ebcb05a]102 "connect to handle %" PRIun ", refers to a device.",
[9b415c9]103 handle);
[ffa2c8ef]104 async_answer_0(iid, ENOENT);
[58cbb0c8]105 goto cleanup;
[5cd136ab]106 }
107
108 driver_t *driver = NULL;
109
[e2b9b341]110 fibril_rwlock_read_lock(&device_tree.rwlock);
111
[5cd136ab]112 if (drv_to_parent) {
[8b1e15ac]113 /* Connect to parent function of a device (or device function). */
114 if (dev->pfun->dev != NULL)
115 driver = dev->pfun->dev->drv;
[50ad3f3]116
[8b1e15ac]117 fwd_h = dev->pfun->handle;
[c6c389ed]118 } else if (dev->state == DEVICE_USABLE) {
[8b1e15ac]119 /* Connect to the specified function */
[38b3baf]120 driver = dev->drv;
[c6c389ed]121 assert(driver != NULL);
[50ad3f3]122
[8b1e15ac]123 fwd_h = handle;
[5cd136ab]124 }
125
[e2b9b341]126 fibril_rwlock_read_unlock(&device_tree.rwlock);
127
[c6c389ed]128 if (driver == NULL) {
[a1a101d]129 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding refused - " \
[79ae36dd]130 "the device %" PRIun " is not in usable state.", handle);
[ffa2c8ef]131 async_answer_0(iid, ENOENT);
[58cbb0c8]132 goto cleanup;
[5cd136ab]133 }
134
[38b3baf]135 int method;
136 if (drv_to_parent)
[5cd136ab]137 method = DRIVER_DRIVER;
[38b3baf]138 else
[5cd136ab]139 method = DRIVER_CLIENT;
140
[79ae36dd]141 if (!driver->sess) {
[a1a101d]142 log_msg(LOG_DEFAULT, LVL_ERROR,
[79ae36dd]143 "Could not forward to driver `%s'.", driver->name);
[ffa2c8ef]144 async_answer_0(iid, EINVAL);
[58cbb0c8]145 goto cleanup;
[9a66bc2e]146 }
[c6c389ed]147
[8b1e15ac]148 if (fun != NULL) {
[a1a101d]149 log_msg(LOG_DEFAULT, LVL_DEBUG,
[ebcb05a]150 "Forwarding request for `%s' function to driver `%s'.",
[9b415c9]151 fun->pathname, driver->name);
[8b1e15ac]152 } else {
[a1a101d]153 log_msg(LOG_DEFAULT, LVL_DEBUG,
[ebcb05a]154 "Forwarding request for `%s' device to driver `%s'.",
[9b415c9]155 dev->pfun->pathname, driver->name);
[8b1e15ac]156 }
[79ae36dd]157
158 async_exch_t *exch = async_exchange_begin(driver->sess);
159 async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
160 async_exchange_end(exch);
[50ad3f3]161
[58cbb0c8]162cleanup:
163 if (dev != NULL)
164 dev_del_ref(dev);
[50ad3f3]165
[58cbb0c8]166 if (fun != NULL)
167 fun_del_ref(fun);
[5cd136ab]168}
169
[15f3c3f]170/** Function for handling connections from a client forwarded by the location
171 * service to the device manager. */
172static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall)
[ce89036b]173{
[15f3c3f]174 service_id_t service_id = IPC_GET_ARG2(*icall);
[ba38f72c]175 fun_node_t *fun;
176 dev_node_t *dev;
[e2b9b341]177 devman_handle_t handle;
178 driver_t *driver;
[c6c389ed]179
[15f3c3f]180 fun = find_loc_tree_function(&device_tree, service_id);
[ce89036b]181
[e2b9b341]182 fibril_rwlock_read_lock(&device_tree.rwlock);
183
184 if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
[a1a101d]185 log_msg(LOG_DEFAULT, LVL_WARN, "devman_connection_loc(): function "
[12f9f0d0]186 "not found.\n");
[e2b9b341]187 fibril_rwlock_read_unlock(&device_tree.rwlock);
[ffa2c8ef]188 async_answer_0(iid, ENOENT);
[ce89036b]189 return;
190 }
191
[ba38f72c]192 dev = fun->dev;
[e2b9b341]193 driver = dev->drv;
194 handle = fun->handle;
195
196 fibril_rwlock_read_unlock(&device_tree.rwlock);
[ba38f72c]197
[e2b9b341]198 async_exch_t *exch = async_exchange_begin(driver->sess);
199 async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0,
[38b3baf]200 IPC_FF_NONE);
[79ae36dd]201 async_exchange_end(exch);
202
[a1a101d]203 log_msg(LOG_DEFAULT, LVL_DEBUG,
[15f3c3f]204 "Forwarding loc service request for `%s' function to driver `%s'.",
[e2b9b341]205 fun->pathname, driver->name);
206
207 fun_del_ref(fun);
[ce89036b]208}
209
[38b3baf]210/** Function for handling connections to device manager. */
[9934f7d]211static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[38b3baf]212{
[422722e]213 /* Select port. */
[96b02eb9]214 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
[924c75e1]215 case DEVMAN_DRIVER:
216 devman_connection_driver(iid, icall);
217 break;
[f658458]218 case DEVMAN_CLIENT:
219 devman_connection_client(iid, icall);
220 break;
[924c75e1]221 case DEVMAN_CONNECT_TO_DEVICE:
[38b3baf]222 /* Connect client to selected device. */
[5cd136ab]223 devman_forward(iid, icall, false);
224 break;
[15f3c3f]225 case DEVMAN_CONNECT_FROM_LOC:
226 /* Someone connected through loc node. */
227 devman_connection_loc(iid, icall);
[47a7174f]228 break;
[5cd136ab]229 case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
[38b3baf]230 /* Connect client to selected device. */
[5cd136ab]231 devman_forward(iid, icall, true);
[38b3baf]232 break;
[924c75e1]233 default:
234 /* No such interface */
[ffa2c8ef]235 async_answer_0(iid, ENOENT);
[924c75e1]236 }
237}
238
[422722e]239static void *devman_client_data_create(void)
240{
241 client_t *client;
242
243 client = calloc(1, sizeof(client_t));
244 if (client == NULL)
245 return NULL;
246
247 fibril_mutex_initialize(&client->mutex);
248 return client;
249}
250
251static void devman_client_data_destroy(void *data)
252{
253 free(data);
254}
255
[38b3baf]256/** Initialize device manager internal structures. */
257static bool devman_init(void)
[e2b9a993]258{
[a1a101d]259 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - looking for available drivers.");
[08d9c4e6]260
[38b3baf]261 /* Initialize list of available drivers. */
[0c3666d]262 init_driver_list(&drivers_list);
[c6c389ed]263 if (lookup_available_drivers(&drivers_list,
264 DRIVER_DEFAULT_STORE) == 0) {
[a1a101d]265 log_msg(LOG_DEFAULT, LVL_FATAL, "No drivers found.");
[e2b9a993]266 return false;
267 }
[50ad3f3]268
[a1a101d]269 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - list of drivers has been initialized.");
[50ad3f3]270
[38b3baf]271 /* Create root device node. */
[e2b9a993]272 if (!init_device_tree(&device_tree, &drivers_list)) {
[a1a101d]273 log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to initialize device tree.");
[38b3baf]274 return false;
[e2b9a993]275 }
[50ad3f3]276
[38b3baf]277 /*
[f302586]278 * Caution: As the device manager is not a real loc
279 * driver (it uses a completely different IPC protocol
280 * than an ordinary loc driver), forwarding a connection
281 * from client to the devman by location service will
282 * not work.
[38b3baf]283 */
[f302586]284 loc_server_register(NAME);
[ce89036b]285
[e2b9a993]286 return true;
287}
288
289int main(int argc, char *argv[])
290{
[50ad3f3]291 printf("%s: HelenOS Device Manager\n", NAME);
292
[267f235]293 int rc = log_init(NAME);
[50ad3f3]294 if (rc != EOK) {
295 printf("%s: Error initializing logging subsystem.\n", NAME);
296 return rc;
[9b415c9]297 }
[e2b9a993]298
[422722e]299 /* Set handlers for incoming connections. */
300 async_set_client_data_constructor(devman_client_data_create);
301 async_set_client_data_destructor(devman_client_data_destroy);
[e2b9a993]302 async_set_client_connection(devman_connection);
[50ad3f3]303
[f302586]304 if (!devman_init()) {
[a1a101d]305 log_msg(LOG_DEFAULT, LVL_ERROR, "Error while initializing service.");
[f302586]306 return -1;
307 }
[50ad3f3]308
[38b3baf]309 /* Register device manager at naming service. */
[50ad3f3]310 rc = service_register(SERVICE_DEVMAN);
311 if (rc != EOK) {
[a1a101d]312 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering as a service.");
[50ad3f3]313 return rc;
[9b415c9]314 }
[50ad3f3]315
316 printf("%s: Accepting connections.\n", NAME);
[79ae36dd]317 task_retval(0);
[e2b9a993]318 async_manager();
[50ad3f3]319
[38b3baf]320 /* Never reached. */
[e2b9a993]321 return 0;
322}
[c16cf62]323
324/** @}
[38b3baf]325 */
Note: See TracBrowser for help on using the repository browser.