2 * Copyright (c) 2010 Vojtech Horky
3 * Copyright (c) 2011 Jiri Svoboda
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include <str_error.h>
37 #include <ddf/driver.h>
42 static errno_t
test1_dev_add(ddf_dev_t
*dev
);
43 static errno_t
test1_dev_remove(ddf_dev_t
*dev
);
44 static errno_t
test1_dev_gone(ddf_dev_t
*dev
);
45 static errno_t
test1_fun_online(ddf_fun_t
*fun
);
46 static errno_t
test1_fun_offline(ddf_fun_t
*fun
);
48 static driver_ops_t driver_ops
= {
49 .dev_add
= &test1_dev_add
,
50 .dev_remove
= &test1_dev_remove
,
51 .dev_gone
= &test1_dev_gone
,
52 .fun_online
= &test1_fun_online
,
53 .fun_offline
= &test1_fun_offline
56 static driver_t test1_driver
= {
58 .driver_ops
= &driver_ops
67 /** Register child and inform user about it.
69 * @param parent Parent device.
70 * @param message Message for the user.
71 * @param name Device name.
72 * @param match_id Device match id.
73 * @param score Device match score.
75 static errno_t
register_fun_verbose(ddf_dev_t
*parent
, const char *message
,
76 const char *name
, const char *match_id
, int match_score
,
77 errno_t expected_rc
, ddf_fun_t
**pfun
)
79 ddf_fun_t
*fun
= NULL
;
82 ddf_msg(LVL_DEBUG
, "Registering function `%s': %s.", name
, message
);
84 fun
= ddf_fun_create(parent
, fun_inner
, name
);
86 ddf_msg(LVL_ERROR
, "Failed creating function %s", name
);
91 rc
= ddf_fun_add_match_id(fun
, match_id
, match_score
);
93 ddf_msg(LVL_ERROR
, "Failed adding match IDs to function %s",
98 rc
= ddf_fun_bind(fun
);
100 ddf_msg(LVL_ERROR
, "Failed binding function %s: %s", name
,
105 ddf_msg(LVL_NOTE
, "Registered child device `%s'", name
);
109 if (rc
!= expected_rc
) {
111 NAME
": Unexpected error registering function `%s'.\n"
112 NAME
": Expected \"%s\" but got \"%s\".\n",
113 name
, str_error(expected_rc
), str_error(rc
));
116 if ((rc
!= EOK
) && (fun
!= NULL
)) {
117 ddf_fun_destroy(fun
);
126 /** Callback when new device is passed to this driver.
127 * This function is the body of the test: it shall register new child
128 * (named `clone') that shall be driven by the same task. When the clone
129 * is added, it registers another child (named `child') that is also driven
130 * by this task. The conditions ensure that we do not recurse indefinitely.
131 * When successful, the device tree shall contain following fragment:
134 * /virtual/test1/clone
135 * /virtual/test1/clone/child
137 * and the DDF shall not deadlock.
140 * @param dev New device.
141 * @return Error code reporting success of the operation.
143 static errno_t
test1_dev_add(ddf_dev_t
*dev
)
147 const char *dev_name
;
150 dev_name
= ddf_dev_get_name(dev
);
151 ddf_msg(LVL_DEBUG
, "dev_add(name=\"%s\", handle=%d)",
152 dev_name
, (int) ddf_dev_get_handle(dev
));
154 test1
= ddf_dev_data_alloc(dev
, sizeof(test1_t
));
156 ddf_msg(LVL_ERROR
, "Failed allocating soft state.\n");
161 fun_a
= ddf_fun_create(dev
, fun_exposed
, "a");
163 ddf_msg(LVL_ERROR
, "Failed creating function 'a'.");
168 test1
->fun_a
= fun_a
;
170 rc
= ddf_fun_bind(fun_a
);
172 ddf_msg(LVL_ERROR
, "Failed binding function 'a'.");
173 ddf_fun_destroy(fun_a
);
177 ddf_fun_add_to_category(fun_a
, "virtual");
179 if (str_cmp(dev_name
, "test1") == 0) {
180 (void) register_fun_verbose(dev
,
181 "cloning myself ;-)", "clone",
182 "virtual&test1", 10, EOK
, &test1
->clone
);
183 (void) register_fun_verbose(dev
,
184 "cloning myself twice ;-)", "clone",
185 "virtual&test1", 10, EEXIST
, NULL
);
186 } else if (str_cmp(dev_name
, "clone") == 0) {
187 (void) register_fun_verbose(dev
,
188 "run by the same task", "child",
189 "virtual&test1&child", 10, EOK
, &test1
->child
);
192 ddf_msg(LVL_DEBUG
, "Device `%s' accepted.", dev_name
);
198 static errno_t
fun_remove(ddf_fun_t
*fun
, const char *name
)
202 ddf_msg(LVL_DEBUG
, "fun_remove(%p, '%s')", fun
, name
);
203 rc
= ddf_fun_offline(fun
);
205 ddf_msg(LVL_ERROR
, "Error offlining function '%s'.", name
);
209 rc
= ddf_fun_unbind(fun
);
211 ddf_msg(LVL_ERROR
, "Failed unbinding function '%s'.", name
);
215 ddf_fun_destroy(fun
);
219 static errno_t
fun_unbind(ddf_fun_t
*fun
, const char *name
)
223 ddf_msg(LVL_DEBUG
, "fun_unbind(%p, '%s')", fun
, name
);
224 rc
= ddf_fun_unbind(fun
);
226 ddf_msg(LVL_ERROR
, "Failed unbinding function '%s'.", name
);
230 ddf_fun_destroy(fun
);
234 static errno_t
test1_dev_remove(ddf_dev_t
*dev
)
236 test1_t
*test1
= (test1_t
*)ddf_dev_data_get(dev
);
239 ddf_msg(LVL_DEBUG
, "test1_dev_remove(%p)", dev
);
241 if (test1
->fun_a
!= NULL
) {
242 rc
= fun_remove(test1
->fun_a
, "a");
247 if (test1
->clone
!= NULL
) {
248 rc
= fun_remove(test1
->clone
, "clone");
253 if (test1
->child
!= NULL
) {
254 rc
= fun_remove(test1
->child
, "child");
262 static errno_t
test1_dev_gone(ddf_dev_t
*dev
)
264 test1_t
*test1
= (test1_t
*)ddf_dev_data_get(dev
);
267 ddf_msg(LVL_DEBUG
, "test1_dev_remove(%p)", dev
);
269 if (test1
->fun_a
!= NULL
) {
270 rc
= fun_unbind(test1
->fun_a
, "a");
275 if (test1
->clone
!= NULL
) {
276 rc
= fun_unbind(test1
->clone
, "clone");
281 if (test1
->child
!= NULL
) {
282 rc
= fun_unbind(test1
->child
, "child");
290 static errno_t
test1_fun_online(ddf_fun_t
*fun
)
292 ddf_msg(LVL_DEBUG
, "test1_fun_online()");
293 return ddf_fun_online(fun
);
296 static errno_t
test1_fun_offline(ddf_fun_t
*fun
)
298 ddf_msg(LVL_DEBUG
, "test1_fun_offline()");
299 return ddf_fun_offline(fun
);
302 int main(int argc
, char *argv
[])
304 printf(NAME
": HelenOS test1 virtual device driver\n");
306 return ddf_driver_main(&test1_driver
);