source: mainline/uspace/srv/devman/main.c@ b688fd8

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

gradually introduce async ports, initial phase

The initial phase is to reimplement the traditional async client connections as an untyped fallback port. This creates the possibility to introduce ports typed by interface type gradually in later changesets.

  • 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 {
119 /* Connect to the specified function */
120 driver = dev->drv;
121 fwd_h = handle;
122 }
123
124 fibril_rwlock_read_unlock(&device_tree.rwlock);
125
126 if (driver == NULL) {
127 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding refused - " \
128 "the device %" PRIun " is not in usable state.", handle);
129 async_answer_0(iid, ENOENT);
130 goto cleanup;
131 }
132
133 int method;
134 if (drv_to_parent)
135 method = DRIVER_DRIVER;
136 else
137 method = DRIVER_CLIENT;
138
139 if (!driver->sess) {
140 log_msg(LOG_DEFAULT, LVL_ERROR,
141 "Could not forward to driver `%s'.", driver->name);
142 async_answer_0(iid, EINVAL);
143 goto cleanup;
144 }
145
146 if (fun != NULL) {
147 log_msg(LOG_DEFAULT, LVL_DEBUG,
148 "Forwarding request for `%s' function to driver `%s'.",
149 fun->pathname, driver->name);
150 } else {
151 log_msg(LOG_DEFAULT, LVL_DEBUG,
152 "Forwarding request for `%s' device to driver `%s'.",
153 dev->pfun->pathname, driver->name);
154 }
155
156 async_exch_t *exch = async_exchange_begin(driver->sess);
157 async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
158 async_exchange_end(exch);
159
160cleanup:
161 if (dev != NULL)
162 dev_del_ref(dev);
163
164 if (fun != NULL)
165 fun_del_ref(fun);
166}
167
168/** Function for handling connections from a client forwarded by the location
169 * service to the device manager. */
170static void devman_connection_loc(ipc_callid_t iid, ipc_call_t *icall)
171{
172 service_id_t service_id = IPC_GET_ARG2(*icall);
173 fun_node_t *fun;
174 dev_node_t *dev;
175 devman_handle_t handle;
176 driver_t *driver;
177
178 fun = find_loc_tree_function(&device_tree, service_id);
179
180 fibril_rwlock_read_lock(&device_tree.rwlock);
181
182 if (fun == NULL || fun->dev == NULL || fun->dev->drv == NULL) {
183 log_msg(LOG_DEFAULT, LVL_WARN, "devman_connection_loc(): function "
184 "not found.\n");
185 fibril_rwlock_read_unlock(&device_tree.rwlock);
186 async_answer_0(iid, ENOENT);
187 return;
188 }
189
190 dev = fun->dev;
191 driver = dev->drv;
192 handle = fun->handle;
193
194 fibril_rwlock_read_unlock(&device_tree.rwlock);
195
196 async_exch_t *exch = async_exchange_begin(driver->sess);
197 async_forward_fast(iid, exch, DRIVER_CLIENT, handle, 0,
198 IPC_FF_NONE);
199 async_exchange_end(exch);
200
201 log_msg(LOG_DEFAULT, LVL_DEBUG,
202 "Forwarding loc service request for `%s' function to driver `%s'.",
203 fun->pathname, driver->name);
204
205 fun_del_ref(fun);
206}
207
208/** Function for handling connections to device manager. */
209static void devman_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
210{
211 /* Select port. */
212 switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
213 case DEVMAN_DRIVER:
214 devman_connection_driver(iid, icall);
215 break;
216 case DEVMAN_CLIENT:
217 devman_connection_client(iid, icall);
218 break;
219 case DEVMAN_CONNECT_TO_DEVICE:
220 /* Connect client to selected device. */
221 devman_forward(iid, icall, false);
222 break;
223 case DEVMAN_CONNECT_FROM_LOC:
224 /* Someone connected through loc node. */
225 devman_connection_loc(iid, icall);
226 break;
227 case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
228 /* Connect client to selected device. */
229 devman_forward(iid, icall, true);
230 break;
231 default:
232 /* No such interface */
233 async_answer_0(iid, ENOENT);
234 }
235}
236
237static void *devman_client_data_create(void)
238{
239 client_t *client;
240
241 client = calloc(1, sizeof(client_t));
242 if (client == NULL)
243 return NULL;
244
245 fibril_mutex_initialize(&client->mutex);
246 return client;
247}
248
249static void devman_client_data_destroy(void *data)
250{
251 free(data);
252}
253
254/** Initialize device manager internal structures. */
255static bool devman_init(void)
256{
257 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - looking for available drivers.");
258
259 /* Initialize list of available drivers. */
260 init_driver_list(&drivers_list);
261 if (lookup_available_drivers(&drivers_list,
262 DRIVER_DEFAULT_STORE) == 0) {
263 log_msg(LOG_DEFAULT, LVL_FATAL, "No drivers found.");
264 return false;
265 }
266
267 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - list of drivers has been initialized.");
268
269 /* Create root device node. */
270 if (!init_device_tree(&device_tree, &drivers_list)) {
271 log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to initialize device tree.");
272 return false;
273 }
274
275 /*
276 * Caution: As the device manager is not a real loc
277 * driver (it uses a completely different IPC protocol
278 * than an ordinary loc driver), forwarding a connection
279 * from client to the devman by location service will
280 * not work.
281 */
282 loc_server_register(NAME);
283
284 return true;
285}
286
287int main(int argc, char *argv[])
288{
289 printf("%s: HelenOS Device Manager\n", NAME);
290
291 int rc = log_init(NAME);
292 if (rc != EOK) {
293 printf("%s: Error initializing logging subsystem.\n", NAME);
294 return rc;
295 }
296
297 /* Set handlers for incoming connections. */
298 async_set_client_data_constructor(devman_client_data_create);
299 async_set_client_data_destructor(devman_client_data_destroy);
300 async_set_fallback_port_handler(devman_connection, NULL);
301
302 if (!devman_init()) {
303 log_msg(LOG_DEFAULT, LVL_ERROR, "Error while initializing service.");
304 return -1;
305 }
306
307 /* Register device manager at naming service. */
308 rc = service_register(SERVICE_DEVMAN);
309 if (rc != EOK) {
310 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering as a service.");
311 return rc;
312 }
313
314 printf("%s: Accepting connections.\n", NAME);
315 task_retval(0);
316 async_manager();
317
318 /* Never reached. */
319 return 0;
320}
321
322/** @}
323 */
Note: See TracBrowser for help on using the repository browser.