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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a78fa2a was 3843ecb, checked in by Lenka Trochtova <trochtova.lenka@…>, 15 years ago

device classes as interface sets

  • Property mode set to 100644
File size: 10.9 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>
40#include <ipc/ns.h>
41#include <async.h>
42#include <stdio.h>
43#include <errno.h>
44#include <bool.h>
45#include <fibril_synch.h>
46#include <stdlib.h>
47#include <string.h>
48#include <dirent.h>
49#include <fcntl.h>
50#include <sys/stat.h>
51#include <ctype.h>
52#include <ipc/devman.h>
[5cd136ab]53#include <ipc/driver.h>
[d347b53]54#include <thread.h>
[e2b9a993]55
56#include "devman.h"
57
58#define DRIVER_DEFAULT_STORE "/srv/drivers"
59
[0c3666d]60static driver_list_t drivers_list;
[e2b9a993]61static dev_tree_t device_tree;
62
[729fa2d6]63/**
64 * Register running driver.
65 */
66static driver_t * devman_driver_register(void)
67{
68 printf(NAME ": devman_driver_register \n");
69
70 ipc_call_t icall;
71 ipc_callid_t iid = async_get_call(&icall);
72 driver_t *driver = NULL;
73
74 if (IPC_GET_METHOD(icall) != DEVMAN_DRIVER_REGISTER) {
75 ipc_answer_0(iid, EREFUSED);
76 return NULL;
77 }
78
[92413de]79 char *drv_name = NULL;
[729fa2d6]80
81 // Get driver name
[92413de]82 int rc = async_string_receive(&drv_name, DEVMAN_NAME_MAXLEN, NULL);
[729fa2d6]83 if (rc != EOK) {
84 ipc_answer_0(iid, rc);
85 return NULL;
86 }
87 printf(NAME ": the %s driver is trying to register by the service.\n", drv_name);
88
89 // Find driver structure
90 driver = find_driver(&drivers_list, drv_name);
[92413de]91
92 free(drv_name);
93 drv_name = NULL;
94
[729fa2d6]95 if (NULL == driver) {
96 printf(NAME ": no driver named %s was found.\n", drv_name);
97 ipc_answer_0(iid, ENOENT);
98 return NULL;
99 }
100
101 // Create connection to the driver
102 printf(NAME ": creating connection to the %s driver.\n", driver->name);
103 ipc_call_t call;
104 ipc_callid_t callid = async_get_call(&call);
105 if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) {
106 ipc_answer_0(callid, ENOTSUP);
107 ipc_answer_0(iid, ENOTSUP);
108 return NULL;
109 }
110
[c16cf62]111 // remember driver's phone
112 set_driver_phone(driver, IPC_GET_ARG5(call));
[729fa2d6]113
114 printf(NAME ": the %s driver was successfully registered as running.\n", driver->name);
115
116 ipc_answer_0(callid, EOK);
117
118 ipc_answer_0(iid, EOK);
119
120 return driver;
121}
[e2b9a993]122
[3843ecb]123/**
124 * Receive device match ID from the device's parent driver and add it to the list of devices match ids.
125 *
126 * @param match_ids the list of the device's match ids.
127 *
128 * @return 0 on success, negative error code otherwise.
129 */
[66babbd]130static int devman_receive_match_id(match_id_list_t *match_ids) {
131
132 match_id_t *match_id = create_match_id();
133 ipc_callid_t callid;
134 ipc_call_t call;
135 int rc = 0;
136
137 callid = async_get_call(&call);
138 if (DEVMAN_ADD_MATCH_ID != IPC_GET_METHOD(call)) {
139 printf(NAME ": ERROR: devman_receive_match_id - invalid protocol.\n");
140 ipc_answer_0(callid, EINVAL);
141 delete_match_id(match_id);
142 return EINVAL;
143 }
144
145 if (NULL == match_id) {
146 printf(NAME ": ERROR: devman_receive_match_id - failed to allocate match id.\n");
147 ipc_answer_0(callid, ENOMEM);
148 return ENOMEM;
149 }
150
[2480e19]151 ipc_answer_0(callid, EOK);
152
[66babbd]153 match_id->score = IPC_GET_ARG1(call);
154
155 rc = async_string_receive(&match_id->id, DEVMAN_NAME_MAXLEN, NULL);
156 if (EOK != rc) {
157 delete_match_id(match_id);
[2480e19]158 printf(NAME ": devman_receive_match_id - failed to receive match id string.\n");
[66babbd]159 return rc;
160 }
161
162 list_append(&match_id->link, &match_ids->ids);
[a087f2e]163
164 printf(NAME ": received match id '%s', score = %d \n", match_id->id, match_id->score);
[66babbd]165 return rc;
166}
167
[3843ecb]168/**
169 * Receive device match IDs from the device's parent driver
170 * and add them to the list of devices match ids.
171 *
172 * @param match_count the number of device's match ids to be received.
173 * @param match_ids the list of the device's match ids.
174 *
175 * @return 0 on success, negative error code otherwise.
176 */
[66babbd]177static int devman_receive_match_ids(ipcarg_t match_count, match_id_list_t *match_ids)
[2480e19]178{
[66babbd]179 int ret = EOK;
[5cd136ab]180 size_t i;
[66babbd]181 for (i = 0; i < match_count; i++) {
182 if (EOK != (ret = devman_receive_match_id(match_ids))) {
183 return ret;
184 }
185 }
186 return ret;
187}
188
[3843ecb]189/** Handle child device registration.
190 *
191 * Child devices are registered by their parent's device driver.
192 */
193static void devman_add_child(ipc_callid_t callid, ipc_call_t *call)
[bda60d9]194{
[2480e19]195 // printf(NAME ": devman_add_child\n");
[66babbd]196
[d347b53]197 device_handle_t parent_handle = IPC_GET_ARG1(*call);
[66babbd]198 ipcarg_t match_count = IPC_GET_ARG2(*call);
199
[d347b53]200 node_t *parent = find_dev_node(&device_tree, parent_handle);
201
202 if (NULL == parent) {
203 ipc_answer_0(callid, ENOENT);
204 return;
[66babbd]205 }
[d347b53]206
207 char *dev_name = NULL;
208 int rc = async_string_receive(&dev_name, DEVMAN_NAME_MAXLEN, NULL);
[66babbd]209 if (EOK != rc) {
[d347b53]210 ipc_answer_0(callid, rc);
211 return;
212 }
[2480e19]213 // printf(NAME ": newly added child device's name is '%s'.\n", dev_name);
[d347b53]214
215 node_t *node = create_dev_node();
216 if (!insert_dev_node(&device_tree, node, dev_name, parent)) {
217 delete_dev_node(node);
218 ipc_answer_0(callid, ENOMEM);
219 return;
220 }
221
[2480e19]222 printf(NAME ": devman_add_child %s\n", node->pathname);
223
[66babbd]224 devman_receive_match_ids(match_count, &node->match_ids);
[bda60d9]225
[d347b53]226 // return device handle to parent's driver
227 ipc_answer_1(callid, EOK, node->handle);
[bda60d9]228
[d347b53]229 // try to find suitable driver and assign it to the device
230 assign_driver(node, &drivers_list);
231}
232
[3843ecb]233/**
234 * Initialize driver which has registered itself as running and ready.
235 *
236 * The initialization is done in a separate fibril to avoid deadlocks
237 * (if the driver needed to be served by devman during the driver's initialization).
238 */
[d347b53]239static int init_running_drv(void *drv)
240{
241 driver_t *driver = (driver_t *)drv;
242 initialize_running_driver(driver);
243 printf(NAME ": the %s driver was successfully initialized. \n", driver->name);
244 return 0;
[bda60d9]245}
246
[3843ecb]247/** Function for handling connections from a driver to the device manager.
[e2b9a993]248 */
[924c75e1]249static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
[729fa2d6]250{
[e2b9a993]251 /* Accept the connection */
252 ipc_answer_0(iid, EOK);
253
[729fa2d6]254 driver_t *driver = devman_driver_register();
[d347b53]255 if (NULL == driver)
[729fa2d6]256 return;
[d347b53]257
[3843ecb]258 // Initialize the driver as running (e.g. pass assigned devices to it) in a separate fibril;
259 // the separate fibril is used to enable the driver
260 // to use devman service during the driver's initialization.
[d347b53]261 fid_t fid = fibril_create(init_running_drv, driver);
262 if (fid == 0) {
263 printf(NAME ": Error creating fibril for the initialization of the newly registered running driver.\n");
[3843ecb]264 return;
[d347b53]265 }
266 fibril_add_ready(fid);
267
268 /*thread_id_t tid;
269 if (0 != thread_create(init_running_drv, driver, "init_running_drv", &tid)) {
270 printf(NAME ": failed to start the initialization of the newly registered running driver.\n");
271 }*/
[729fa2d6]272
273 ipc_callid_t callid;
274 ipc_call_t call;
275 bool cont = true;
276 while (cont) {
[e2b9a993]277 callid = async_get_call(&call);
278
279 switch (IPC_GET_METHOD(call)) {
[729fa2d6]280 case IPC_M_PHONE_HUNGUP:
281 cont = false;
282 continue;
[e2b9a993]283 case DEVMAN_ADD_CHILD_DEVICE:
[3843ecb]284 devman_add_child(callid, &call);
[e2b9a993]285 break;
286 default:
287 ipc_answer_0(callid, EINVAL);
288 break;
289 }
290 }
291}
292
[9a66bc2e]293static void devman_forward(ipc_callid_t iid, ipc_call_t *icall, bool drv_to_parent) {
294
295 device_handle_t handle = IPC_GET_ARG2(*icall);
[2480e19]296 // printf(NAME ": devman_forward - trying to forward connection to device with handle %x.\n", handle);
[9a66bc2e]297
[5cd136ab]298 node_t *dev = find_dev_node(&device_tree, handle);
299 if (NULL == dev) {
[9a66bc2e]300 printf(NAME ": devman_forward error - no device with handle %x was found.\n", handle);
[5cd136ab]301 ipc_answer_0(iid, ENOENT);
302 return;
303 }
304
305 driver_t *driver = NULL;
306
307 if (drv_to_parent) {
[9a66bc2e]308 if (NULL != dev->parent) {
309 driver = dev->parent->drv;
310 }
[5cd136ab]311 } else {
312 driver = dev->drv;
313 }
314
[9a66bc2e]315 if (NULL == driver) {
316 printf(NAME ": devman_forward error - no driver to connect to.\n", handle);
[5cd136ab]317 ipc_answer_0(iid, ENOENT);
318 return;
319 }
320
321 int method;
322 if (drv_to_parent) {
323 method = DRIVER_DRIVER;
324 } else {
325 method = DRIVER_CLIENT;
326 }
327
[9a66bc2e]328 if (driver->phone <= 0) {
[3843ecb]329 printf(NAME ": devman_forward: cound not forward to driver %s ", driver->name);
330 printf("the driver's phone is %x).\n", driver->phone);
[9a66bc2e]331 return;
332 }
[2480e19]333 printf(NAME ": devman_forward: forward connection to device %s to driver %s with phone %d.\n",
334 dev->pathname, driver->name, driver->phone);
[5cd136ab]335 ipc_forward_fast(iid, driver->phone, method, dev->handle, 0, IPC_FF_NONE);
336}
337
[924c75e1]338/** Function for handling connections to device manager.
339 *
340 */
341static void devman_connection(ipc_callid_t iid, ipc_call_t *icall)
342{
343 // Select interface
344 switch ((ipcarg_t) (IPC_GET_ARG1(*icall))) {
345 case DEVMAN_DRIVER:
346 devman_connection_driver(iid, icall);
347 break;
348 /*case DEVMAN_CLIENT:
349 devmap_connection_client(iid, icall);
[5cd136ab]350 break;*/
[924c75e1]351 case DEVMAN_CONNECT_TO_DEVICE:
352 // Connect client to selected device
[5cd136ab]353 devman_forward(iid, icall, false);
354 break;
355 case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
356 // Connect client to selected device
357 devman_forward(iid, icall, true);
358 break;
[924c75e1]359 default:
360 /* No such interface */
361 ipc_answer_0(iid, ENOENT);
362 }
363}
364
[e2b9a993]365/** Initialize device manager internal structures.
366 */
367static bool devman_init()
368{
[0c3666d]369 printf(NAME ": devman_init - looking for available drivers. \n");
[08d9c4e6]370
[e2b9a993]371 // initialize list of available drivers
[0c3666d]372 init_driver_list(&drivers_list);
[e2b9a993]373 if (0 == lookup_available_drivers(&drivers_list, DRIVER_DEFAULT_STORE)) {
374 printf(NAME " no drivers found.");
375 return false;
376 }
[08d9c4e6]377 printf(NAME ": devman_init - list of drivers has been initialized. \n");
[e2b9a993]378
379 // create root device node
380 if (!init_device_tree(&device_tree, &drivers_list)) {
381 printf(NAME " failed to initialize device tree.");
382 return false;
383 }
384
385 return true;
386}
387
388int main(int argc, char *argv[])
389{
390 printf(NAME ": HelenOS Device Manager\n");
391
392 if (!devman_init()) {
393 printf(NAME ": Error while initializing service\n");
394 return -1;
395 }
396
397 // Set a handler of incomming connections
398 async_set_client_connection(devman_connection);
399
400 // Register device manager at naming service
401 ipcarg_t phonead;
402 if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAN, 0, 0, &phonead) != 0)
403 return -1;
404
405 printf(NAME ": Accepting connections\n");
406 async_manager();
407
408 // Never reached
409 return 0;
410}
[c16cf62]411
412/** @}
413 */
Note: See TracBrowser for help on using the repository browser.