source: mainline/uspace/srv/devman/main.c@ 84a1a54

Last change on this file since 84a1a54 was 84a1a54, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Wrap returns of errno from main() with EXIT_RC().

Returns of error code from main() prevent type checking when errno_t
and int are considered incompatible. In order to avoid the philosophical
discussion of what should and shouldn't be returned for main(), we simply
wrap the error values and leave the answer to the question for future
generations to decide.

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