source: mainline/uspace/srv/devman/devtree.c@ 889cdb1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 889cdb1 was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

  • Property mode set to 100644
File size: 8.4 KB
RevLine 
[59dc181]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/** @addtogroup devman
30 * @{
31 */
32
33#include <errno.h>
34#include <io/log.h>
35
36#include "dev.h"
37#include "devtree.h"
38#include "devman.h"
39#include "driver.h"
40#include "fun.h"
41
42/* hash table operations */
43
44static inline size_t handle_key_hash(void *key)
45{
[1433ecda]46 devman_handle_t handle = *(devman_handle_t *)key;
[59dc181]47 return handle;
48}
49
50static size_t devman_devices_hash(const ht_link_t *item)
51{
52 dev_node_t *dev = hash_table_get_inst(item, dev_node_t, devman_dev);
53 return handle_key_hash(&dev->handle);
54}
55
56static size_t devman_functions_hash(const ht_link_t *item)
57{
58 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, devman_fun);
59 return handle_key_hash(&fun->handle);
60}
61
62static bool devman_devices_key_equal(void *key, const ht_link_t *item)
63{
[1433ecda]64 devman_handle_t handle = *(devman_handle_t *)key;
[59dc181]65 dev_node_t *dev = hash_table_get_inst(item, dev_node_t, devman_dev);
66 return dev->handle == handle;
67}
68
69static bool devman_functions_key_equal(void *key, const ht_link_t *item)
70{
[1433ecda]71 devman_handle_t handle = *(devman_handle_t *)key;
[59dc181]72 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, devman_fun);
73 return fun->handle == handle;
74}
75
76static inline size_t service_id_key_hash(void *key)
77{
[1433ecda]78 service_id_t service_id = *(service_id_t *)key;
[59dc181]79 return service_id;
80}
81
82static size_t loc_functions_hash(const ht_link_t *item)
83{
84 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, loc_fun);
85 return service_id_key_hash(&fun->service_id);
86}
87
88static bool loc_functions_key_equal(void *key, const ht_link_t *item)
89{
[1433ecda]90 service_id_t service_id = *(service_id_t *)key;
[59dc181]91 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, loc_fun);
92 return fun->service_id == service_id;
93}
94
95static hash_table_ops_t devman_devices_ops = {
96 .hash = devman_devices_hash,
97 .key_hash = handle_key_hash,
98 .key_equal = devman_devices_key_equal,
99 .equal = NULL,
100 .remove_callback = NULL
101};
102
103static hash_table_ops_t devman_functions_ops = {
104 .hash = devman_functions_hash,
105 .key_hash = handle_key_hash,
106 .key_equal = devman_functions_key_equal,
107 .equal = NULL,
108 .remove_callback = NULL
109};
110
111static hash_table_ops_t loc_devices_ops = {
112 .hash = loc_functions_hash,
113 .key_hash = service_id_key_hash,
114 .key_equal = loc_functions_key_equal,
115 .equal = NULL,
116 .remove_callback = NULL
117};
118
119/** Create root device and function node in the device tree.
120 *
121 * @param tree The device tree.
122 * @return True on success, false otherwise.
123 */
124bool create_root_nodes(dev_tree_t *tree)
125{
126 fun_node_t *fun;
127 dev_node_t *dev;
[a35b458]128
[59dc181]129 log_msg(LOG_DEFAULT, LVL_DEBUG, "create_root_nodes()");
[a35b458]130
[59dc181]131 fibril_rwlock_write_lock(&tree->rwlock);
[a35b458]132
[59dc181]133 /*
134 * Create root function. This is a pseudo function to which
135 * the root device node is attached. It allows us to match
136 * the root device driver in a standard manner, i.e. against
137 * the parent function.
138 */
[a35b458]139
[59dc181]140 fun = create_fun_node();
141 if (fun == NULL) {
142 fibril_rwlock_write_unlock(&tree->rwlock);
143 return false;
144 }
[a35b458]145
[59dc181]146 fun_add_ref(fun);
147 insert_fun_node(tree, fun, str_dup(""), NULL);
[a35b458]148
[59dc181]149 match_id_t *id = create_match_id();
150 id->id = str_dup("root");
151 id->score = 100;
152 add_match_id(&fun->match_ids, id);
153 tree->root_node = fun;
[a35b458]154
[59dc181]155 /*
156 * Create root device node.
157 */
158 dev = create_dev_node();
159 if (dev == NULL) {
160 fibril_rwlock_write_unlock(&tree->rwlock);
161 return false;
162 }
[a35b458]163
[59dc181]164 dev_add_ref(dev);
165 insert_dev_node(tree, dev, fun);
[a35b458]166
[59dc181]167 fibril_rwlock_write_unlock(&tree->rwlock);
[a35b458]168
[59dc181]169 return dev != NULL;
170}
171
172/** Initialize the device tree.
173 *
174 * Create root device node of the tree and assign driver to it.
175 *
176 * @param tree The device tree.
177 * @param drivers_list the list of available drivers.
178 * @return True on success, false otherwise.
179 */
180bool init_device_tree(dev_tree_t *tree, driver_list_t *drivers_list)
181{
182 log_msg(LOG_DEFAULT, LVL_DEBUG, "init_device_tree()");
[a35b458]183
[59dc181]184 tree->current_handle = 0;
[a35b458]185
[59dc181]186 hash_table_create(&tree->devman_devices, 0, 0, &devman_devices_ops);
187 hash_table_create(&tree->devman_functions, 0, 0, &devman_functions_ops);
188 hash_table_create(&tree->loc_functions, 0, 0, &loc_devices_ops);
[a35b458]189
[59dc181]190 fibril_rwlock_initialize(&tree->rwlock);
[a35b458]191
[59dc181]192 /* Create root function and root device and add them to the device tree. */
193 if (!create_root_nodes(tree))
194 return false;
[a35b458]195
[59dc181]196 /* Find suitable driver and start it. */
197 dev_node_t *rdev = tree->root_node->child;
198 dev_add_ref(rdev);
[1569a9b]199 bool rc = assign_driver(rdev, drivers_list, tree);
[59dc181]200 dev_del_ref(rdev);
[a35b458]201
[59dc181]202 return rc;
203}
204
205/** Insert new device into device tree.
206 *
207 * @param tree The device tree.
208 * @param dev The newly added device node.
209 * @param pfun The parent function node.
210 *
211 * @return True on success, false otherwise (insufficient resources
212 * etc.).
213 */
214bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
215{
216 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
[a35b458]217
[59dc181]218 log_msg(LOG_DEFAULT, LVL_DEBUG, "insert_dev_node(dev=%p, pfun=%p [\"%s\"])",
219 dev, pfun, pfun->pathname);
220
221 /* Add the node to the handle-to-node map. */
222 dev->handle = ++tree->current_handle;
223 hash_table_insert(&tree->devman_devices, &dev->devman_dev);
224
225 /* Add the node to the list of its parent's children. */
226 dev->pfun = pfun;
227 pfun->child = dev;
[a35b458]228
[59dc181]229 return true;
230}
231
232/** Remove device from device tree.
233 *
234 * @param tree Device tree
235 * @param dev Device node
236 */
237void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
238{
239 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
[a35b458]240
[59dc181]241 log_msg(LOG_DEFAULT, LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
[a35b458]242
[59dc181]243 /* Remove node from the handle-to-node map. */
244 hash_table_remove(&tree->devman_devices, &dev->handle);
[a35b458]245
[59dc181]246 /* Unlink from parent function. */
247 dev->pfun->child = NULL;
248 dev->pfun = NULL;
[a35b458]249
[59dc181]250 dev->state = DEVICE_REMOVED;
251}
252
253/** Insert new function into device tree.
254 *
255 * @param tree The device tree.
[1b20da0]256 * @param fun The newly added function node.
[59dc181]257 * @param fun_name The name of the newly added function.
258 * @param dev Owning device node.
259 *
260 * @return True on success, false otherwise (insufficient resources
261 * etc.).
262 */
263bool insert_fun_node(dev_tree_t *tree, fun_node_t *fun, char *fun_name,
264 dev_node_t *dev)
265{
266 fun_node_t *pfun;
[a35b458]267
[59dc181]268 assert(fun_name != NULL);
269 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
[a35b458]270
[59dc181]271 /*
272 * The root function is a special case, it does not belong to any
273 * device so for the root function dev == NULL.
274 */
275 pfun = (dev != NULL) ? dev->pfun : NULL;
[a35b458]276
[59dc181]277 fun->name = fun_name;
278 if (!set_fun_path(tree, fun, pfun)) {
279 return false;
280 }
[a35b458]281
[59dc181]282 /* Add the node to the handle-to-node map. */
283 fun->handle = ++tree->current_handle;
284 hash_table_insert(&tree->devman_functions, &fun->devman_fun);
285
286 /* Add the node to the list of its parent's children. */
287 fun->dev = dev;
288 if (dev != NULL)
289 list_append(&fun->dev_functions, &dev->functions);
[a35b458]290
[59dc181]291 return true;
292}
293
294/** Remove function from device tree.
295 *
296 * @param tree Device tree
297 * @param node Function node to remove
298 */
299void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
300{
301 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
[a35b458]302
[59dc181]303 /* Remove the node from the handle-to-node map. */
304 hash_table_remove(&tree->devman_functions, &fun->handle);
[a35b458]305
[59dc181]306 /* Remove the node from the list of its parent's children. */
307 if (fun->dev != NULL)
308 list_remove(&fun->dev_functions);
[a35b458]309
[59dc181]310 fun->dev = NULL;
311 fun->state = FUN_REMOVED;
312}
313
314/** @}
315 */
Note: See TracBrowser for help on using the repository browser.