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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c21d4d6 was fafb8e5, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Mechanically lowercase IPC_SET_*/IPC_GET_*

  • Property mode set to 100644
File size: 10.0 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 * @addtogroup devman
31 * @{
32 */
33
34/** @file
35 */
36
37#include <assert.h>
38#include <ipc/services.h>
39#include <ns.h>
40#include <async.h>
41#include <stdio.h>
42#include <errno.h>
43#include <str_error.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 <loc.h>
52
53#include "client_conn.h"
54#include "dev.h"
55#include "devman.h"
56#include "devtree.h"
57#include "drv_conn.h"
58#include "driver.h"
59#include "fun.h"
60#include "loc.h"
61
62#define DRIVER_DEFAULT_STORE "/drv"
63
64driver_list_t drivers_list;
65dev_tree_t device_tree;
66
67static void devman_connection_device(ipc_call_t *icall, void *arg)
68{
69 devman_handle_t handle = ipc_get_arg2(icall);
70 dev_node_t *dev = NULL;
71
72 fun_node_t *fun = find_fun_node(&device_tree, handle);
73 if (fun == NULL) {
74 dev = find_dev_node(&device_tree, handle);
75 } else {
76 fibril_rwlock_read_lock(&device_tree.rwlock);
77
78 dev = fun->dev;
79 if (dev != NULL)
80 dev_add_ref(dev);
81
82 fibril_rwlock_read_unlock(&device_tree.rwlock);
83 }
84
85 /*
86 * For a valid function to connect to we need a device. The root
87 * function, for example, has no device and cannot be connected to.
88 * This means @c dev needs to be valid regardless whether we are
89 * connecting to a device or to a function.
90 */
91 if (dev == NULL) {
92 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding failed - no device or "
93 "function with handle %" PRIun " was found.", handle);
94 async_answer_0(icall, ENOENT);
95 goto cleanup;
96 }
97
98 if (fun == NULL) {
99 log_msg(LOG_DEFAULT, LVL_ERROR, NAME ": devman_forward error - cannot "
100 "connect to handle %" PRIun ", refers to a device.",
101 handle);
102 async_answer_0(icall, ENOENT);
103 goto cleanup;
104 }
105
106 fibril_rwlock_read_lock(&device_tree.rwlock);
107
108 /* Connect to the specified function */
109 driver_t *driver = dev->drv;
110
111 fibril_rwlock_read_unlock(&device_tree.rwlock);
112
113 if (driver == NULL) {
114 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding refused - "
115 "the device %" PRIun " is not in usable state.", handle);
116 async_answer_0(icall, ENOENT);
117 goto cleanup;
118 }
119
120 if (!driver->sess) {
121 log_msg(LOG_DEFAULT, LVL_ERROR,
122 "Could not forward to driver `%s'.", driver->name);
123 async_answer_0(icall, EINVAL);
124 goto cleanup;
125 }
126
127 if (fun != NULL) {
128 log_msg(LOG_DEFAULT, LVL_DEBUG,
129 "Forwarding request for `%s' function to driver `%s'.",
130 fun->pathname, driver->name);
131 } else {
132 log_msg(LOG_DEFAULT, LVL_DEBUG,
133 "Forwarding request for `%s' device to driver `%s'.",
134 dev->pfun->pathname, driver->name);
135 }
136
137 async_exch_t *exch = async_exchange_begin(driver->sess);
138 async_forward_1(icall, exch, INTERFACE_DDF_CLIENT, handle, IPC_FF_NONE);
139 async_exchange_end(exch);
140
141cleanup:
142 if (dev != NULL)
143 dev_del_ref(dev);
144
145 if (fun != NULL)
146 fun_del_ref(fun);
147}
148
149static void devman_connection_parent(ipc_call_t *icall, void *arg)
150{
151 devman_handle_t handle = ipc_get_arg2(icall);
152 dev_node_t *dev = NULL;
153
154 fun_node_t *fun = find_fun_node(&device_tree, handle);
155 if (fun == NULL) {
156 dev = find_dev_node(&device_tree, handle);
157 } else {
158 fibril_rwlock_read_lock(&device_tree.rwlock);
159
160 dev = fun->dev;
161 if (dev != NULL)
162 dev_add_ref(dev);
163
164 fibril_rwlock_read_unlock(&device_tree.rwlock);
165 }
166
167 /*
168 * For a valid function to connect to we need a device. The root
169 * function, for example, has no device and cannot be connected to.
170 * This means @c dev needs to be valid regardless whether we are
171 * connecting to a device or to a function.
172 */
173 if (dev == NULL) {
174 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding failed - no device or "
175 "function with handle %" PRIun " was found.", handle);
176 async_answer_0(icall, ENOENT);
177 goto cleanup;
178 }
179
180 driver_t *driver = NULL;
181
182 fibril_rwlock_read_lock(&device_tree.rwlock);
183
184 /* Connect to parent function of a device (or device function). */
185 if (dev->pfun->dev != NULL)
186 driver = dev->pfun->dev->drv;
187
188 devman_handle_t fun_handle = dev->pfun->handle;
189
190 fibril_rwlock_read_unlock(&device_tree.rwlock);
191
192 if (driver == NULL) {
193 log_msg(LOG_DEFAULT, LVL_ERROR, "IPC forwarding refused - "
194 "the device %" PRIun " is not in usable state.", handle);
195 async_answer_0(icall, ENOENT);
196 goto cleanup;
197 }
198
199 if (!driver->sess) {
200 log_msg(LOG_DEFAULT, LVL_ERROR,
201 "Could not forward to driver `%s'.", driver->name);
202 async_answer_0(icall, EINVAL);
203 goto cleanup;
204 }
205
206 if (fun != NULL) {
207 log_msg(LOG_DEFAULT, LVL_DEBUG,
208 "Forwarding request for `%s' function to driver `%s'.",
209 fun->pathname, driver->name);
210 } else {
211 log_msg(LOG_DEFAULT, LVL_DEBUG,
212 "Forwarding request for `%s' device to driver `%s'.",
213 dev->pfun->pathname, driver->name);
214 }
215
216 async_exch_t *exch = async_exchange_begin(driver->sess);
217 async_forward_1(icall, exch, INTERFACE_DDF_DRIVER, fun_handle, IPC_FF_NONE);
218 async_exchange_end(exch);
219
220cleanup:
221 if (dev != NULL)
222 dev_del_ref(dev);
223
224 if (fun != NULL)
225 fun_del_ref(fun);
226}
227
228static void devman_forward(ipc_call_t *icall, void *arg)
229{
230 iface_t iface = ipc_get_arg1(icall);
231 service_id_t service_id = ipc_get_arg2(icall);
232
233 fun_node_t *fun = find_loc_tree_function(&device_tree, service_id);
234
235 fibril_rwlock_read_lock(&device_tree.rwlock);
236
237 if ((fun == NULL) || (fun->dev == NULL) || (fun->dev->drv == NULL)) {
238 log_msg(LOG_DEFAULT, LVL_WARN, "devman_forward(): function "
239 "not found.\n");
240 fibril_rwlock_read_unlock(&device_tree.rwlock);
241 async_answer_0(icall, ENOENT);
242 return;
243 }
244
245 dev_node_t *dev = fun->dev;
246 driver_t *driver = dev->drv;
247 devman_handle_t handle = fun->handle;
248
249 fibril_rwlock_read_unlock(&device_tree.rwlock);
250
251 async_exch_t *exch = async_exchange_begin(driver->sess);
252 async_forward_1(icall, exch, iface, handle, IPC_FF_NONE);
253 async_exchange_end(exch);
254
255 log_msg(LOG_DEFAULT, LVL_DEBUG,
256 "Forwarding service request for `%s' function to driver `%s'.",
257 fun->pathname, driver->name);
258
259 fun_del_ref(fun);
260}
261
262static void *devman_client_data_create(void)
263{
264 client_t *client;
265
266 client = calloc(1, sizeof(client_t));
267 if (client == NULL)
268 return NULL;
269
270 fibril_mutex_initialize(&client->mutex);
271 return client;
272}
273
274static void devman_client_data_destroy(void *data)
275{
276 free(data);
277}
278
279/** Initialize device manager internal structures. */
280static bool devman_init(void)
281{
282 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - looking for available drivers.");
283
284 /* Initialize list of available drivers. */
285 init_driver_list(&drivers_list);
286 if (lookup_available_drivers(&drivers_list,
287 DRIVER_DEFAULT_STORE) == 0) {
288 log_msg(LOG_DEFAULT, LVL_FATAL, "No drivers found.");
289 return false;
290 }
291
292 log_msg(LOG_DEFAULT, LVL_DEBUG, "devman_init - list of drivers has been initialized.");
293
294 /* Create root device node. */
295 if (!init_device_tree(&device_tree, &drivers_list)) {
296 log_msg(LOG_DEFAULT, LVL_FATAL, "Failed to initialize device tree.");
297 return false;
298 }
299
300 /*
301 * Caution: As the device manager is not a real loc
302 * driver (it uses a completely different IPC protocol
303 * than an ordinary loc driver), forwarding a connection
304 * from client to the devman by location service will
305 * not work.
306 */
307 loc_server_register(NAME);
308
309 return true;
310}
311
312int main(int argc, char *argv[])
313{
314 printf("%s: HelenOS Device Manager\n", NAME);
315
316 errno_t rc = log_init(NAME);
317 if (rc != EOK) {
318 printf("%s: Error initializing logging subsystem: %s\n", NAME, str_error(rc));
319 return rc;
320 }
321
322 /* Set handlers for incoming connections. */
323 async_set_client_data_constructor(devman_client_data_create);
324 async_set_client_data_destructor(devman_client_data_destroy);
325
326 async_set_fallback_port_handler(devman_forward, NULL);
327
328 if (!devman_init()) {
329 log_msg(LOG_DEFAULT, LVL_ERROR, "Error while initializing service.");
330 return -1;
331 }
332
333 /* Register device manager at naming service. */
334 rc = service_register(SERVICE_DEVMAN, INTERFACE_DDF_DRIVER,
335 devman_connection_driver, NULL);
336 if (rc != EOK) {
337 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering driver port: %s", str_error(rc));
338 return rc;
339 }
340
341 rc = service_register(SERVICE_DEVMAN, INTERFACE_DDF_CLIENT,
342 devman_connection_client, NULL);
343 if (rc != EOK) {
344 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering client port: %s", str_error(rc));
345 return rc;
346 }
347
348 rc = service_register(SERVICE_DEVMAN, INTERFACE_DEVMAN_DEVICE,
349 devman_connection_device, NULL);
350 if (rc != EOK) {
351 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering device port: %s", str_error(rc));
352 return rc;
353 }
354
355 rc = service_register(SERVICE_DEVMAN, INTERFACE_DEVMAN_PARENT,
356 devman_connection_parent, NULL);
357 if (rc != EOK) {
358 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering parent port: %s", str_error(rc));
359 return rc;
360 }
361
362 printf("%s: Accepting connections.\n", NAME);
363 task_retval(0);
364 async_manager();
365
366 /* Never reached. */
367 return 0;
368}
369
370/** @}
371 */
Note: See TracBrowser for help on using the repository browser.