Remove stricmp()
[helenos.git] / uspace / srv / devman / devtree.c
blobbdf48d3aaca9ea468d8cc608f6774091e70f8c2e
1 /*
2 * Copyright (c) 2010 Lenka Trochtova
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
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.
29 /** @addtogroup devman
30 * @{
33 #include <errno.h>
34 #include <io/log.h>
36 #include "dev.h"
37 #include "devtree.h"
38 #include "devman.h"
39 #include "driver.h"
40 #include "fun.h"
42 /* hash table operations */
44 static inline size_t handle_key_hash(void *key)
46 devman_handle_t handle = *(devman_handle_t*)key;
47 return handle;
50 static size_t devman_devices_hash(const ht_link_t *item)
52 dev_node_t *dev = hash_table_get_inst(item, dev_node_t, devman_dev);
53 return handle_key_hash(&dev->handle);
56 static size_t devman_functions_hash(const ht_link_t *item)
58 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, devman_fun);
59 return handle_key_hash(&fun->handle);
62 static bool devman_devices_key_equal(void *key, const ht_link_t *item)
64 devman_handle_t handle = *(devman_handle_t*)key;
65 dev_node_t *dev = hash_table_get_inst(item, dev_node_t, devman_dev);
66 return dev->handle == handle;
69 static bool devman_functions_key_equal(void *key, const ht_link_t *item)
71 devman_handle_t handle = *(devman_handle_t*)key;
72 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, devman_fun);
73 return fun->handle == handle;
76 static inline size_t service_id_key_hash(void *key)
78 service_id_t service_id = *(service_id_t*)key;
79 return service_id;
82 static size_t loc_functions_hash(const ht_link_t *item)
84 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, loc_fun);
85 return service_id_key_hash(&fun->service_id);
88 static bool loc_functions_key_equal(void *key, const ht_link_t *item)
90 service_id_t service_id = *(service_id_t*)key;
91 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, loc_fun);
92 return fun->service_id == service_id;
96 static hash_table_ops_t devman_devices_ops = {
97 .hash = devman_devices_hash,
98 .key_hash = handle_key_hash,
99 .key_equal = devman_devices_key_equal,
100 .equal = NULL,
101 .remove_callback = NULL
104 static hash_table_ops_t devman_functions_ops = {
105 .hash = devman_functions_hash,
106 .key_hash = handle_key_hash,
107 .key_equal = devman_functions_key_equal,
108 .equal = NULL,
109 .remove_callback = NULL
112 static hash_table_ops_t loc_devices_ops = {
113 .hash = loc_functions_hash,
114 .key_hash = service_id_key_hash,
115 .key_equal = loc_functions_key_equal,
116 .equal = NULL,
117 .remove_callback = NULL
120 /** Create root device and function node in the device tree.
122 * @param tree The device tree.
123 * @return True on success, false otherwise.
125 bool create_root_nodes(dev_tree_t *tree)
127 fun_node_t *fun;
128 dev_node_t *dev;
130 log_msg(LOG_DEFAULT, LVL_DEBUG, "create_root_nodes()");
132 fibril_rwlock_write_lock(&tree->rwlock);
135 * Create root function. This is a pseudo function to which
136 * the root device node is attached. It allows us to match
137 * the root device driver in a standard manner, i.e. against
138 * the parent function.
141 fun = create_fun_node();
142 if (fun == NULL) {
143 fibril_rwlock_write_unlock(&tree->rwlock);
144 return false;
147 fun_add_ref(fun);
148 insert_fun_node(tree, fun, str_dup(""), NULL);
150 match_id_t *id = create_match_id();
151 id->id = str_dup("root");
152 id->score = 100;
153 add_match_id(&fun->match_ids, id);
154 tree->root_node = fun;
157 * Create root device node.
159 dev = create_dev_node();
160 if (dev == NULL) {
161 fibril_rwlock_write_unlock(&tree->rwlock);
162 return false;
165 dev_add_ref(dev);
166 insert_dev_node(tree, dev, fun);
168 fibril_rwlock_write_unlock(&tree->rwlock);
170 return dev != NULL;
173 /** Initialize the device tree.
175 * Create root device node of the tree and assign driver to it.
177 * @param tree The device tree.
178 * @param drivers_list the list of available drivers.
179 * @return True on success, false otherwise.
181 bool init_device_tree(dev_tree_t *tree, driver_list_t *drivers_list)
183 log_msg(LOG_DEFAULT, LVL_DEBUG, "init_device_tree()");
185 tree->current_handle = 0;
187 hash_table_create(&tree->devman_devices, 0, 0, &devman_devices_ops);
188 hash_table_create(&tree->devman_functions, 0, 0, &devman_functions_ops);
189 hash_table_create(&tree->loc_functions, 0, 0, &loc_devices_ops);
191 fibril_rwlock_initialize(&tree->rwlock);
193 /* Create root function and root device and add them to the device tree. */
194 if (!create_root_nodes(tree))
195 return false;
197 /* Find suitable driver and start it. */
198 dev_node_t *rdev = tree->root_node->child;
199 dev_add_ref(rdev);
200 int rc = assign_driver(rdev, drivers_list, tree);
201 dev_del_ref(rdev);
203 return rc;
206 /** Insert new device into device tree.
208 * @param tree The device tree.
209 * @param dev The newly added device node.
210 * @param pfun The parent function node.
212 * @return True on success, false otherwise (insufficient resources
213 * etc.).
215 bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
217 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
219 log_msg(LOG_DEFAULT, LVL_DEBUG, "insert_dev_node(dev=%p, pfun=%p [\"%s\"])",
220 dev, pfun, pfun->pathname);
222 /* Add the node to the handle-to-node map. */
223 dev->handle = ++tree->current_handle;
224 hash_table_insert(&tree->devman_devices, &dev->devman_dev);
226 /* Add the node to the list of its parent's children. */
227 dev->pfun = pfun;
228 pfun->child = dev;
230 return true;
233 /** Remove device from device tree.
235 * @param tree Device tree
236 * @param dev Device node
238 void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
240 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
242 log_msg(LOG_DEFAULT, LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
244 /* Remove node from the handle-to-node map. */
245 hash_table_remove(&tree->devman_devices, &dev->handle);
247 /* Unlink from parent function. */
248 dev->pfun->child = NULL;
249 dev->pfun = NULL;
251 dev->state = DEVICE_REMOVED;
255 /** Insert new function into device tree.
257 * @param tree The device tree.
258 * @param fun The newly added function node.
259 * @param fun_name The name of the newly added function.
260 * @param dev Owning device node.
262 * @return True on success, false otherwise (insufficient resources
263 * etc.).
265 bool insert_fun_node(dev_tree_t *tree, fun_node_t *fun, char *fun_name,
266 dev_node_t *dev)
268 fun_node_t *pfun;
270 assert(fun_name != NULL);
271 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
274 * The root function is a special case, it does not belong to any
275 * device so for the root function dev == NULL.
277 pfun = (dev != NULL) ? dev->pfun : NULL;
279 fun->name = fun_name;
280 if (!set_fun_path(tree, fun, pfun)) {
281 return false;
284 /* Add the node to the handle-to-node map. */
285 fun->handle = ++tree->current_handle;
286 hash_table_insert(&tree->devman_functions, &fun->devman_fun);
288 /* Add the node to the list of its parent's children. */
289 fun->dev = dev;
290 if (dev != NULL)
291 list_append(&fun->dev_functions, &dev->functions);
293 return true;
296 /** Remove function from device tree.
298 * @param tree Device tree
299 * @param node Function node to remove
301 void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
303 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
305 /* Remove the node from the handle-to-node map. */
306 hash_table_remove(&tree->devman_functions, &fun->handle);
308 /* Remove the node from the list of its parent's children. */
309 if (fun->dev != NULL)
310 list_remove(&fun->dev_functions);
312 fun->dev = NULL;
313 fun->state = FUN_REMOVED;
316 /** @}