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
Line 
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>
40#include <ns.h>
41#include <async.h>
42#include <stdio.h>
43#include <errno.h>
44#include <stdbool.h>
45#include <fibril_synch.h>
46#include <stdlib.h>
47#include <str.h>
48#include <ctype.h>
49#include <io/log.h>
50#include <ipc/devman.h>
51#include <ipc/driver.h>
52#include <loc.h>
53
54#include "client_conn.h"
55#include "dev.h"
56#include "devman.h"
57#include "devtree.h"
58#include "drv_conn.h"
59#include "driver.h"
60#include "fun.h"
61#include "loc.h"
62
63#define DRIVER_DEFAULT_STORE "/drv"
64
65driver_list_t drivers_list;
66dev_tree_t device_tree;
67
68static void devman_forward(ipc_callid_t iid, ipc_call_t *icall,
69 bool drv_to_parent)
70{
71 devman_handle_t handle = IPC_GET_ARG2(*icall);
72 devman_handle_t fwd_h;
73 fun_node_t *fun = NULL;
74 dev_node_t *dev = NULL;
75
76 fun = find_fun_node(&device_tree, handle);
77 if (fun == NULL)
78 dev = find_dev_node(&device_tree, handle);
79 else {
80 fibril_rwlock_read_lock(&device_tree.rwlock);
81 dev = fun->dev;
82 if (dev != NULL)
83 dev_add_ref(dev);
84 fibril_rwlock_read_unlock(&device_tree.rwlock);
85 }
86
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) {
94 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding failed - no device or "
95 "function with handle %" PRIun " was found.", handle);
96 async_answer_0(iid, ENOENT);
97 goto cleanup;
98 }
99
100 if (fun == NULL && !drv_to_parent) {
101 log_msg(LOG_DEFAULT, LVL_ERROR, NAME ": devman_forward error - cannot "
102 "connect to handle %" PRIun ", refers to a device.",
103 handle);
104 async_answer_0(iid, ENOENT);
105 goto cleanup;
106 }
107
108 driver_t *driver = NULL;
109
110 fibril_rwlock_read_lock(&device_tree.rwlock);
111
112 if (drv_to_parent) {
113 /* Connect to parent function of a device (or device function). */
114 if (dev->pfun->dev != NULL)
115 driver = dev->pfun->dev->drv;
116
117 fwd_h = dev->pfun->handle;
118 } else if (dev->state == DEVICE_USABLE) {
119 /* Connect to the specified function */
120 driver = dev->drv;
121 assert(driver != NULL);
122
123 fwd_h = handle;
124 }
125
126 fibril_rwlock_read_unlock(&device_tree.rwlock);
127
128 if (driver == NULL) {
129 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding refused - " \
130 "the device %" PRIun " is not in usable state.", handle);
131 async_answer_0(iid, ENOENT);
132 goto cleanup;
133 }
134
135 int method;
136 if (drv_to_parent)
137 method = DRIVER_DRIVER;
138 else
139 method = DRIVER_CLIENT;
140
141 if (!driver->sess) {
142 log_msg(LOG_DEFAULT, LVL_ERROR,
143 "Could not forward to driver `%s'.", driver->name);
144 async_answer_0(iid, EINVAL);
145 goto cleanup;
146 }
147
148 if (fun != NULL) {
149 log_msg(LOG_DEFAULT, LVL_DEBUG,
150 "Forwarding request for `%s' function to driver `%s'.",
151 fun->pathname, driver->name);
152 } else {
153 log_msg(LOG_DEFAULT, LVL_DEBUG,
154 "Forwarding request for `%s' device to driver `%s'.",
155 dev->pfun->pathname, driver->name);
156 }
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);
161
162cleanup:
163 if (dev != NULL)
164 dev_del_ref(dev);
165
166 if (fun != NULL)
167 fun_del_ref(fun);
168}
169
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)
173{
174 service_id_t service_id = IPC_GET_ARG2(*icall);
175 fun_node_t *fun;
176 dev_node_t *dev;
177 devman_handle_t handle;
178 driver_t *driver;
179
180 fun = find_loc_tree_function(&device_tree, service_id);
181
182 fibril_rwlock_read_lock(&device_tree.rwlock);
183
184 if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
185 log_msg(LOG_DEFAULT, LVL_WARN, "devman_connection_loc(): function "
186 "not found.\n");
187 fibril_rwlock_read_unlock(&device_tree.rwlock);
188 async_answer_0(iid, ENOENT);
189 return;
190 }
191
192 dev = fun->dev;
193 driver = dev->drv;
194 handle = fun->handle;
195
196 fibril_rwlock_read_unlock(&device_tree.rwlock);
197
198 async_exch_t *exch = async_exchange_begin(driver->sess);
199 async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0,
200 IPC_FF_NONE);
201 async_exchange_end(exch);
202
203 log_msg(LOG_DEFAULT, LVL_DEBUG,
204 "Forwarding loc service request for `%s' function to driver `%s'.",
205 fun->pathname, driver->name);
206
207 fun_del_ref(fun);
208}
209
210/** Function for handling connections to device manager. */
211static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
212{
213 /* Select port. */
214 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
215 case DEVMAN_DRIVER:
216 devman_connection_driver(iid, icall);
217 break;
218 case DEVMAN_CLIENT:
219 devman_connection_client(iid, icall);
220 break;
221 case DEVMAN_CONNECT_TO_DEVICE:
222 /* Connect client to selected device. */
223 devman_forward(iid, icall, false);
224 break;
225 case DEVMAN_CONNECT_FROM_LOC:
226 /* Someone connected through loc node. */
227 devman_connection_loc(iid, icall);
228 break;
229 case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
230 /* Connect client to selected device. */
231 devman_forward(iid, icall, true);
232 break;
233 default:
234 /* No such interface */
235 async_answer_0(iid, ENOENT);
236 }
237}
238
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
256/** Initialize device manager internal structures. */
257static bool devman_init(void)
258{
259 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - looking for available drivers.");
260
261 /* Initialize list of available drivers. */
262 init_driver_list(&drivers_list);
263 if (lookup_available_drivers(&drivers_list,
264 DRIVER_DEFAULT_STORE) == 0) {
265 log_msg(LOG_DEFAULT, LVL_FATAL, "No drivers found.");
266 return false;
267 }
268
269 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - list of drivers has been initialized.");
270
271 /* Create root device node. */
272 if (!init_device_tree(&device_tree, &drivers_list)) {
273 log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to initialize device tree.");
274 return false;
275 }
276
277 /*
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.
283 */
284 loc_server_register(NAME);
285
286 return true;
287}
288
289int main(int argc, char *argv[])
290{
291 printf("%s: HelenOS Device Manager\n", NAME);
292
293 int rc = log_init(NAME);
294 if (rc != EOK) {
295 printf("%s: Error initializing logging subsystem.\n", NAME);
296 return rc;
297 }
298
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);
302 async_set_client_connection(devman_connection);
303
304 if (!devman_init()) {
305 log_msg(LOG_DEFAULT, LVL_ERROR, "Error while initializing service.");
306 return -1;
307 }
308
309 /* Register device manager at naming service. */
310 rc = service_register(SERVICE_DEVMAN);
311 if (rc != EOK) {
312 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering as a service.");
313 return rc;
314 }
315
316 printf("%s: Accepting connections.\n", NAME);
317 task_retval(0);
318 async_manager();
319
320 /* Never reached. */
321 return 0;
322}
323
324/** @}
325 */
Note: See TracBrowser for help on using the repository browser.