2 * Copyright (c) 2010 Lenka Trochtova
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
42 /* hash table operations */
44 static inline size_t handle_key_hash(const void *key
)
46 const devman_handle_t
*handle
= key
;
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(const void *key
, const ht_link_t
*item
)
64 const devman_handle_t
*handle
= 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(const void *key
, const ht_link_t
*item
)
71 const devman_handle_t
*handle
= 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(const void *key
)
78 const service_id_t
*service_id
= key
;
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(const void *key
, const ht_link_t
*item
)
90 const service_id_t
*service_id
= key
;
91 fun_node_t
*fun
= hash_table_get_inst(item
, fun_node_t
, loc_fun
);
92 return fun
->service_id
== *service_id
;
95 static const 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
,
100 .remove_callback
= NULL
103 static const 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
,
108 .remove_callback
= NULL
111 static const 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
,
116 .remove_callback
= NULL
119 /** Create root device and function node in the device tree.
121 * @param tree The device tree.
122 * @return True on success, false otherwise.
124 bool create_root_nodes(dev_tree_t
*tree
)
129 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "create_root_nodes()");
131 fibril_rwlock_write_lock(&tree
->rwlock
);
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.
140 fun
= create_fun_node();
142 fibril_rwlock_write_unlock(&tree
->rwlock
);
146 if (!insert_fun_node(tree
, fun
, str_dup(""), NULL
)) {
147 fun_del_ref(fun
); /* fun is destroyed */
148 fibril_rwlock_write_unlock(&tree
->rwlock
);
152 match_id_t
*id
= create_match_id();
153 id
->id
= str_dup("root");
155 add_match_id(&fun
->match_ids
, id
);
156 tree
->root_node
= fun
;
159 * Create root device node.
161 dev
= create_dev_node();
163 fibril_rwlock_write_unlock(&tree
->rwlock
);
167 insert_dev_node(tree
, dev
, fun
);
169 fibril_rwlock_write_unlock(&tree
->rwlock
);
174 /** Initialize the device tree.
176 * Create root device node of the tree and assign driver to it.
178 * @param tree The device tree.
179 * @param drivers_list the list of available drivers.
180 * @return True on success, false otherwise.
182 bool init_device_tree(dev_tree_t
*tree
, driver_list_t
*drivers_list
)
184 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "init_device_tree()");
186 tree
->current_handle
= 0;
188 hash_table_create(&tree
->devman_devices
, 0, 0, &devman_devices_ops
);
189 hash_table_create(&tree
->devman_functions
, 0, 0, &devman_functions_ops
);
190 hash_table_create(&tree
->loc_functions
, 0, 0, &loc_devices_ops
);
192 fibril_rwlock_initialize(&tree
->rwlock
);
194 /* Create root function and root device and add them to the device tree. */
195 if (!create_root_nodes(tree
))
198 /* Find suitable driver and start it. */
199 dev_node_t
*rdev
= tree
->root_node
->child
;
201 bool rc
= assign_driver(rdev
, drivers_list
, tree
);
207 /** Insert new device into device tree.
209 * @param tree The device tree.
210 * @param dev The newly added device node.
211 * @param pfun The parent function node.
213 * @return True on success, false otherwise (insufficient resources
216 bool insert_dev_node(dev_tree_t
*tree
, dev_node_t
*dev
, fun_node_t
*pfun
)
218 assert(fibril_rwlock_is_write_locked(&tree
->rwlock
));
220 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "insert_dev_node(dev=%p, pfun=%p [\"%s\"])",
221 dev
, pfun
, pfun
->pathname
);
223 /* Add the node to the handle-to-node map. */
224 dev
->handle
= ++tree
->current_handle
;
225 hash_table_insert(&tree
->devman_devices
, &dev
->devman_dev
);
227 /* Add the node to the list of its parent's children. */
234 /** Remove device from device tree.
236 * @param tree Device tree
237 * @param dev Device node
239 void remove_dev_node(dev_tree_t
*tree
, dev_node_t
*dev
)
241 assert(fibril_rwlock_is_write_locked(&tree
->rwlock
));
243 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "remove_dev_node(dev=%p)", dev
);
245 /* Remove node from the handle-to-node map. */
246 hash_table_remove(&tree
->devman_devices
, &dev
->handle
);
248 /* Unlink from parent function. */
249 dev
->pfun
->child
= NULL
;
252 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
265 bool insert_fun_node(dev_tree_t
*tree
, fun_node_t
*fun
, char *fun_name
,
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
)) {
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. */
291 list_append(&fun
->dev_functions
, &dev
->functions
);
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
);
313 fun
->state
= FUN_REMOVED
;