source: mainline/uspace/srv/devman/devman.c@ 59dc181

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

Move devtree-related functionality to separate devman module.

  • Property mode set to 100644
File size: 7.9 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/** @addtogroup devman
30 * @{
31 */
32/** @file Device Manager
33 *
34 * Locking order:
35 * (1) driver_t.driver_mutex
36 * (2) dev_tree_t.rwlock
37 *
38 * Synchronization:
39 * - device_tree.rwlock protects:
40 * - tree root, complete tree topology
41 * - complete contents of device and function nodes
42 * - dev_node_t.refcnt, fun_node_t.refcnt prevent nodes from
43 * being deallocated
44 * - find_xxx() functions increase reference count of returned object
45 * - find_xxx_no_lock() do not increase reference count
46 *
47 * TODO
48 * - Track all steady and transient device/function states
49 * - Check states, wait for steady state on certain operations
50 */
51
52#include <errno.h>
53#include <fcntl.h>
54#include <sys/stat.h>
55#include <io/log.h>
56#include <ipc/driver.h>
57#include <ipc/devman.h>
58#include <loc.h>
59#include <str_error.h>
60#include <stdio.h>
61
62#include "dev.h"
63#include "devman.h"
64#include "driver.h"
65#include "fun.h"
66
67/** Read match id at the specified position of a string and set the position in
68 * the string to the first character following the id.
69 *
70 * @param buf The position in the input string.
71 * @return The match id.
72 */
73char *read_match_id(char **buf)
74{
75 char *res = NULL;
76 size_t len = get_nonspace_len(*buf);
77
78 if (len > 0) {
79 res = malloc(len + 1);
80 if (res != NULL) {
81 str_ncpy(res, len + 1, *buf, len);
82 *buf += len;
83 }
84 }
85
86 return res;
87}
88
89/**
90 * Read match ids and associated match scores from a string.
91 *
92 * Each match score in the string is followed by its match id.
93 * The match ids and match scores are separated by whitespaces.
94 * Neither match ids nor match scores can contain whitespaces.
95 *
96 * @param buf The string from which the match ids are read.
97 * @param ids The list of match ids into which the match ids and
98 * scores are added.
99 * @return True if at least one match id and associated match score
100 * was successfully read, false otherwise.
101 */
102bool parse_match_ids(char *buf, match_id_list_t *ids)
103{
104 int score = 0;
105 char *id = NULL;
106 int ids_read = 0;
107
108 while (true) {
109 /* skip spaces */
110 if (!skip_spaces(&buf))
111 break;
112
113 /* read score */
114 score = strtoul(buf, &buf, 10);
115
116 /* skip spaces */
117 if (!skip_spaces(&buf))
118 break;
119
120 /* read id */
121 id = read_match_id(&buf);
122 if (NULL == id)
123 break;
124
125 /* create new match_id structure */
126 match_id_t *mid = create_match_id();
127 mid->id = id;
128 mid->score = score;
129
130 /* add it to the list */
131 add_match_id(ids, mid);
132
133 ids_read++;
134 }
135
136 return ids_read > 0;
137}
138
139/**
140 * Read match ids and associated match scores from a file.
141 *
142 * Each match score in the file is followed by its match id.
143 * The match ids and match scores are separated by whitespaces.
144 * Neither match ids nor match scores can contain whitespaces.
145 *
146 * @param buf The path to the file from which the match ids are read.
147 * @param ids The list of match ids into which the match ids and
148 * scores are added.
149 * @return True if at least one match id and associated match score
150 * was successfully read, false otherwise.
151 */
152bool read_match_ids(const char *conf_path, match_id_list_t *ids)
153{
154 log_msg(LOG_DEFAULT, LVL_DEBUG, "read_match_ids(conf_path=\"%s\")", conf_path);
155
156 bool suc = false;
157 char *buf = NULL;
158 bool opened = false;
159 int fd;
160 size_t len = 0;
161
162 fd = open(conf_path, O_RDONLY);
163 if (fd < 0) {
164 log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to open `%s' for reading: %s.",
165 conf_path, str_error(fd));
166 goto cleanup;
167 }
168 opened = true;
169
170 len = lseek(fd, 0, SEEK_END);
171 lseek(fd, 0, SEEK_SET);
172 if (len == 0) {
173 log_msg(LOG_DEFAULT, LVL_ERROR, "Configuration file '%s' is empty.",
174 conf_path);
175 goto cleanup;
176 }
177
178 buf = malloc(len + 1);
179 if (buf == NULL) {
180 log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failed when parsing file "
181 "'%s'.", conf_path);
182 goto cleanup;
183 }
184
185 ssize_t read_bytes = read_all(fd, buf, len);
186 if (read_bytes <= 0) {
187 log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to read file '%s' (%zd).", conf_path,
188 read_bytes);
189 goto cleanup;
190 }
191 buf[read_bytes] = 0;
192
193 suc = parse_match_ids(buf, ids);
194
195cleanup:
196 free(buf);
197
198 if (opened)
199 close(fd);
200
201 return suc;
202}
203
204/** Create loc path and name for the function. */
205void loc_register_tree_function(fun_node_t *fun, dev_tree_t *tree)
206{
207 char *loc_pathname = NULL;
208 char *loc_name = NULL;
209
210 assert(fibril_rwlock_is_locked(&tree->rwlock));
211
212 asprintf(&loc_name, "%s", fun->pathname);
213 if (loc_name == NULL)
214 return;
215
216 replace_char(loc_name, '/', LOC_SEPARATOR);
217
218 asprintf(&loc_pathname, "%s/%s", LOC_DEVICE_NAMESPACE,
219 loc_name);
220 if (loc_pathname == NULL) {
221 free(loc_name);
222 return;
223 }
224
225 loc_service_register_with_iface(loc_pathname,
226 &fun->service_id, DEVMAN_CONNECT_FROM_LOC);
227
228 tree_add_loc_function(tree, fun);
229
230 free(loc_name);
231 free(loc_pathname);
232}
233
234/** Pass a device to running driver.
235 *
236 * @param drv The driver's structure.
237 * @param node The device's node in the device tree.
238 */
239void add_device(driver_t *drv, dev_node_t *dev, dev_tree_t *tree)
240{
241 /*
242 * We do not expect to have driver's mutex locked as we do not
243 * access any structures that would affect driver_t.
244 */
245 log_msg(LOG_DEFAULT, LVL_DEBUG, "add_device(drv=\"%s\", dev=\"%s\")",
246 drv->name, dev->pfun->name);
247
248 /* Send the device to the driver. */
249 devman_handle_t parent_handle;
250 if (dev->pfun) {
251 parent_handle = dev->pfun->handle;
252 } else {
253 parent_handle = 0;
254 }
255
256 async_exch_t *exch = async_exchange_begin(drv->sess);
257
258 ipc_call_t answer;
259 aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle,
260 parent_handle, &answer);
261
262 /* Send the device name to the driver. */
263 sysarg_t rc = async_data_write_start(exch, dev->pfun->name,
264 str_size(dev->pfun->name) + 1);
265
266 async_exchange_end(exch);
267
268 if (rc != EOK) {
269 /* TODO handle error */
270 }
271
272 /* Wait for answer from the driver. */
273 async_wait_for(req, &rc);
274
275 switch(rc) {
276 case EOK:
277 dev->state = DEVICE_USABLE;
278 break;
279 case ENOENT:
280 dev->state = DEVICE_NOT_PRESENT;
281 break;
282 default:
283 dev->state = DEVICE_INVALID;
284 break;
285 }
286
287 dev->passed_to_driver = true;
288
289 return;
290}
291
292/* loc devices */
293
294fun_node_t *find_loc_tree_function(dev_tree_t *tree, service_id_t service_id)
295{
296 fun_node_t *fun = NULL;
297
298 fibril_rwlock_read_lock(&tree->rwlock);
299 ht_link_t *link = hash_table_find(&tree->loc_functions, &service_id);
300 if (link != NULL) {
301 fun = hash_table_get_inst(link, fun_node_t, loc_fun);
302 fun_add_ref(fun);
303 }
304 fibril_rwlock_read_unlock(&tree->rwlock);
305
306 return fun;
307}
308
309void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
310{
311 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
312
313 hash_table_insert(&tree->loc_functions, &fun->loc_fun);
314}
315
316/** @}
317 */
Note: See TracBrowser for help on using the repository browser.