source: mainline/uspace/lib/drv/generic/driver.c@ 8a637a4

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8a637a4 was 8a637a4, checked in by Martin Decky <martin@…>, 10 years ago

remove EEXISTS in favor of EEXIST

  • Property mode set to 100644
File size: 21.9 KB
Line 
1/*
2 * Copyright (c) 2010 Lenka Trochtova
3 * Copyright (c) 2011 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
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.
17 *
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.
28 */
29
30/**
31 * @defgroup libdrv generic device driver support.
32 * @brief HelenOS generic device driver support.
33 * @{
34 */
35
36/** @file
37 */
38
39#include <assert.h>
40#include <ipc/services.h>
41#include <ipc/ns.h>
42#include <async.h>
43#include <stdio.h>
44#include <errno.h>
45#include <stdbool.h>
46#include <fibril_synch.h>
47#include <stdlib.h>
48#include <str.h>
49#include <str_error.h>
50#include <ctype.h>
51#include <errno.h>
52#include <inttypes.h>
53#include <devman.h>
54
55#include "dev_iface.h"
56#include "ddf/driver.h"
57#include "ddf/interrupt.h"
58#include "private/driver.h"
59
60/** Driver structure */
61static const driver_t *driver;
62
63/** Devices */
64LIST_INITIALIZE(devices);
65FIBRIL_MUTEX_INITIALIZE(devices_mutex);
66
67/** Functions */
68LIST_INITIALIZE(functions);
69FIBRIL_MUTEX_INITIALIZE(functions_mutex);
70
71static ddf_dev_t *create_device(void);
72static void delete_device(ddf_dev_t *);
73static void dev_add_ref(ddf_dev_t *);
74static void dev_del_ref(ddf_dev_t *);
75static void fun_add_ref(ddf_fun_t *);
76static void fun_del_ref(ddf_fun_t *);
77static remote_handler_t *function_get_default_handler(ddf_fun_t *);
78static void *function_get_ops(ddf_fun_t *, dev_inferface_idx_t);
79
80static void add_to_functions_list(ddf_fun_t *fun)
81{
82 fibril_mutex_lock(&functions_mutex);
83 list_append(&fun->link, &functions);
84 fibril_mutex_unlock(&functions_mutex);
85}
86
87static void remove_from_functions_list(ddf_fun_t *fun)
88{
89 fibril_mutex_lock(&functions_mutex);
90 list_remove(&fun->link);
91 fibril_mutex_unlock(&functions_mutex);
92}
93
94static ddf_dev_t *driver_get_device(devman_handle_t handle)
95{
96 assert(fibril_mutex_is_locked(&devices_mutex));
97
98 list_foreach(devices, link, ddf_dev_t, dev) {
99 if (dev->handle == handle)
100 return dev;
101 }
102
103 return NULL;
104}
105
106static ddf_fun_t *driver_get_function(devman_handle_t handle)
107{
108 assert(fibril_mutex_is_locked(&functions_mutex));
109
110 list_foreach(functions, link, ddf_fun_t, fun) {
111 if (fun->handle == handle)
112 return fun;
113 }
114
115 return NULL;
116}
117
118static void driver_dev_add(ipc_callid_t iid, ipc_call_t *icall)
119{
120 devman_handle_t dev_handle = IPC_GET_ARG1(*icall);
121 devman_handle_t parent_fun_handle = IPC_GET_ARG2(*icall);
122
123 ddf_dev_t *dev = create_device();
124
125 /* Add one reference that will be dropped by driver_dev_remove() */
126 dev_add_ref(dev);
127 dev->handle = dev_handle;
128
129 char *dev_name = NULL;
130 int rc = async_data_write_accept((void **) &dev_name, true, 0, 0, 0, 0);
131 if (rc != EOK) {
132 async_answer_0(iid, rc);
133 return;
134 }
135
136 dev->name = dev_name;
137
138 /*
139 * Currently not used, parent fun handle is stored in context
140 * of the connection to the parent device driver.
141 */
142 (void) parent_fun_handle;
143
144 int res = driver->driver_ops->dev_add(dev);
145
146 if (res != EOK) {
147 dev_del_ref(dev);
148 async_answer_0(iid, res);
149 return;
150 }
151
152 fibril_mutex_lock(&devices_mutex);
153 list_append(&dev->link, &devices);
154 fibril_mutex_unlock(&devices_mutex);
155
156 async_answer_0(iid, res);
157}
158
159static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall)
160{
161 devman_handle_t devh = IPC_GET_ARG1(*icall);
162
163 fibril_mutex_lock(&devices_mutex);
164 ddf_dev_t *dev = driver_get_device(devh);
165 if (dev != NULL)
166 dev_add_ref(dev);
167 fibril_mutex_unlock(&devices_mutex);
168
169 if (dev == NULL) {
170 async_answer_0(iid, ENOENT);
171 return;
172 }
173
174 int rc;
175
176 if (driver->driver_ops->dev_remove != NULL)
177 rc = driver->driver_ops->dev_remove(dev);
178 else
179 rc = ENOTSUP;
180
181 if (rc == EOK)
182 dev_del_ref(dev);
183
184 async_answer_0(iid, (sysarg_t) rc);
185}
186
187static void driver_dev_gone(ipc_callid_t iid, ipc_call_t *icall)
188{
189 devman_handle_t devh = IPC_GET_ARG1(*icall);
190
191 fibril_mutex_lock(&devices_mutex);
192 ddf_dev_t *dev = driver_get_device(devh);
193 if (dev != NULL)
194 dev_add_ref(dev);
195 fibril_mutex_unlock(&devices_mutex);
196
197 if (dev == NULL) {
198 async_answer_0(iid, ENOENT);
199 return;
200 }
201
202 int rc;
203
204 if (driver->driver_ops->dev_gone != NULL)
205 rc = driver->driver_ops->dev_gone(dev);
206 else
207 rc = ENOTSUP;
208
209 if (rc == EOK)
210 dev_del_ref(dev);
211
212 async_answer_0(iid, (sysarg_t) rc);
213}
214
215static void driver_fun_online(ipc_callid_t iid, ipc_call_t *icall)
216{
217 devman_handle_t funh = IPC_GET_ARG1(*icall);
218
219 /*
220 * Look the function up. Bump reference count so that
221 * the function continues to exist until we return
222 * from the driver.
223 */
224 fibril_mutex_lock(&functions_mutex);
225
226 ddf_fun_t *fun = driver_get_function(funh);
227 if (fun != NULL)
228 fun_add_ref(fun);
229
230 fibril_mutex_unlock(&functions_mutex);
231
232 if (fun == NULL) {
233 async_answer_0(iid, ENOENT);
234 return;
235 }
236
237 /* Call driver entry point */
238 int rc;
239
240 if (driver->driver_ops->fun_online != NULL)
241 rc = driver->driver_ops->fun_online(fun);
242 else
243 rc = ENOTSUP;
244
245 fun_del_ref(fun);
246
247 async_answer_0(iid, (sysarg_t) rc);
248}
249
250static void driver_fun_offline(ipc_callid_t iid, ipc_call_t *icall)
251{
252 devman_handle_t funh = IPC_GET_ARG1(*icall);
253
254 /*
255 * Look the function up. Bump reference count so that
256 * the function continues to exist until we return
257 * from the driver.
258 */
259 fibril_mutex_lock(&functions_mutex);
260
261 ddf_fun_t *fun = driver_get_function(funh);
262 if (fun != NULL)
263 fun_add_ref(fun);
264
265 fibril_mutex_unlock(&functions_mutex);
266
267 if (fun == NULL) {
268 async_answer_0(iid, ENOENT);
269 return;
270 }
271
272 /* Call driver entry point */
273 int rc;
274
275 if (driver->driver_ops->fun_offline != NULL)
276 rc = driver->driver_ops->fun_offline(fun);
277 else
278 rc = ENOTSUP;
279
280 async_answer_0(iid, (sysarg_t) rc);
281}
282
283static void driver_connection_devman(ipc_callid_t iid, ipc_call_t *icall,
284 void *arg)
285{
286 /* Accept connection */
287 async_answer_0(iid, EOK);
288
289 while (true) {
290 ipc_call_t call;
291 ipc_callid_t callid = async_get_call(&call);
292
293 if (!IPC_GET_IMETHOD(call))
294 break;
295
296 switch (IPC_GET_IMETHOD(call)) {
297 case DRIVER_DEV_ADD:
298 driver_dev_add(callid, &call);
299 break;
300 case DRIVER_DEV_REMOVE:
301 driver_dev_remove(callid, &call);
302 break;
303 case DRIVER_DEV_GONE:
304 driver_dev_gone(callid, &call);
305 break;
306 case DRIVER_FUN_ONLINE:
307 driver_fun_online(callid, &call);
308 break;
309 case DRIVER_FUN_OFFLINE:
310 driver_fun_offline(callid, &call);
311 break;
312 default:
313 async_answer_0(callid, ENOTSUP);
314 }
315 }
316}
317
318/** Generic client connection handler both for applications and drivers.
319 *
320 * @param drv True for driver client, false for other clients
321 * (applications, services, etc.).
322 *
323 */
324static void driver_connection_gen(ipc_callid_t iid, ipc_call_t *icall, bool drv)
325{
326 /*
327 * Answer the first IPC_M_CONNECT_ME_TO call and remember the handle of
328 * the device to which the client connected.
329 */
330 devman_handle_t handle = IPC_GET_ARG2(*icall);
331
332 fibril_mutex_lock(&functions_mutex);
333 ddf_fun_t *fun = driver_get_function(handle);
334 fibril_mutex_unlock(&functions_mutex);
335 /* XXX Need a lock on fun */
336
337 if (fun == NULL) {
338 printf("%s: driver_connection_gen error - no function with handle"
339 " %" PRIun " was found.\n", driver->name, handle);
340 async_answer_0(iid, ENOENT);
341 return;
342 }
343
344 if (fun->conn_handler != NULL) {
345 /* Driver has a custom connection handler. */
346 (*fun->conn_handler)(iid, icall, (void *)fun);
347 return;
348 }
349
350 /*
351 * TODO - if the client is not a driver, check whether it is allowed to
352 * use the device.
353 */
354
355 int ret = EOK;
356 /* Open device function */
357 if (fun->ops != NULL && fun->ops->open != NULL)
358 ret = (*fun->ops->open)(fun);
359
360 async_answer_0(iid, ret);
361 if (ret != EOK)
362 return;
363
364 while (true) {
365 ipc_callid_t callid;
366 ipc_call_t call;
367 callid = async_get_call(&call);
368 sysarg_t method = IPC_GET_IMETHOD(call);
369
370 if (!method) {
371 /* Close device function */
372 if (fun->ops != NULL && fun->ops->close != NULL)
373 (*fun->ops->close)(fun);
374 async_answer_0(callid, EOK);
375 return;
376 }
377
378 /* Convert ipc interface id to interface index */
379
380 int iface_idx = DEV_IFACE_IDX(method);
381
382 if (!is_valid_iface_idx(iface_idx)) {
383 remote_handler_t *default_handler =
384 function_get_default_handler(fun);
385 if (default_handler != NULL) {
386 (*default_handler)(fun, callid, &call);
387 continue;
388 }
389
390 /*
391 * Function has no such interface and
392 * default handler is not provided.
393 */
394 printf("%s: driver_connection_gen error - "
395 "invalid interface id %d.",
396 driver->name, iface_idx);
397 async_answer_0(callid, ENOTSUP);
398 continue;
399 }
400
401 /* Calling one of the function's interfaces */
402
403 /* Get the interface ops structure. */
404 void *ops = function_get_ops(fun, iface_idx);
405 if (ops == NULL) {
406 printf("%s: driver_connection_gen error - ", driver->name);
407 printf("Function with handle %" PRIun " has no interface "
408 "with id %d.\n", handle, iface_idx);
409 async_answer_0(callid, ENOTSUP);
410 continue;
411 }
412
413 /*
414 * Get the corresponding interface for remote request
415 * handling ("remote interface").
416 */
417 const remote_iface_t *rem_iface = get_remote_iface(iface_idx);
418 assert(rem_iface != NULL);
419
420 /* get the method of the remote interface */
421 sysarg_t iface_method_idx = IPC_GET_ARG1(call);
422 remote_iface_func_ptr_t iface_method_ptr =
423 get_remote_method(rem_iface, iface_method_idx);
424 if (iface_method_ptr == NULL) {
425 /* The interface has not such method */
426 printf("%s: driver_connection_gen error - "
427 "invalid interface method.", driver->name);
428 async_answer_0(callid, ENOTSUP);
429 continue;
430 }
431
432 /*
433 * Call the remote interface's method, which will
434 * receive parameters from the remote client and it will
435 * pass it to the corresponding local interface method
436 * associated with the function by its driver.
437 */
438 (*iface_method_ptr)(fun, ops, callid, &call);
439 }
440}
441
442static void driver_connection_driver(ipc_callid_t iid, ipc_call_t *icall,
443 void *arg)
444{
445 driver_connection_gen(iid, icall, true);
446}
447
448static void driver_connection_client(ipc_callid_t iid, ipc_call_t *icall,
449 void *arg)
450{
451 driver_connection_gen(iid, icall, false);
452}
453
454/** Create new device structure.
455 *
456 * @return The device structure.
457 */
458static ddf_dev_t *create_device(void)
459{
460 ddf_dev_t *dev;
461
462 dev = calloc(1, sizeof(ddf_dev_t));
463 if (dev == NULL)
464 return NULL;
465
466 return dev;
467}
468
469/** Create new function structure.
470 *
471 * @return The device structure.
472 */
473static ddf_fun_t *create_function(void)
474{
475 ddf_fun_t *fun;
476
477 fun = calloc(1, sizeof(ddf_fun_t));
478 if (fun == NULL)
479 return NULL;
480
481 init_match_ids(&fun->match_ids);
482 link_initialize(&fun->link);
483
484 return fun;
485}
486
487/** Delete device structure.
488 *
489 * @param dev The device structure.
490 */
491static void delete_device(ddf_dev_t *dev)
492{
493 if (dev->parent_sess)
494 async_hangup(dev->parent_sess);
495 if (dev->driver_data != NULL)
496 free(dev->driver_data);
497 free(dev);
498}
499
500/** Delete function structure.
501 *
502 * @param dev The device structure.
503 */
504static void delete_function(ddf_fun_t *fun)
505{
506 clean_match_ids(&fun->match_ids);
507 if (fun->driver_data != NULL)
508 free(fun->driver_data);
509 if (fun->name != NULL)
510 free(fun->name);
511 free(fun);
512}
513
514/** Increase device reference count. */
515static void dev_add_ref(ddf_dev_t *dev)
516{
517 atomic_inc(&dev->refcnt);
518}
519
520/** Decrease device reference count.
521 *
522 * Free the device structure if the reference count drops to zero.
523 */
524static void dev_del_ref(ddf_dev_t *dev)
525{
526 if (atomic_predec(&dev->refcnt) == 0)
527 delete_device(dev);
528}
529
530/** Increase function reference count.
531 *
532 * This also increases reference count on the device. The device structure
533 * will thus not be deallocated while there are some associated function
534 * structures.
535 */
536static void fun_add_ref(ddf_fun_t *fun)
537{
538 dev_add_ref(fun->dev);
539 atomic_inc(&fun->refcnt);
540}
541
542/** Decrease function reference count.
543 *
544 * Free the function structure if the reference count drops to zero.
545 */
546static void fun_del_ref(ddf_fun_t *fun)
547{
548 ddf_dev_t *dev = fun->dev;
549
550 if (atomic_predec(&fun->refcnt) == 0)
551 delete_function(fun);
552
553 dev_del_ref(dev);
554}
555
556/** Allocate driver-specific device data. */
557void *ddf_dev_data_alloc(ddf_dev_t *dev, size_t size)
558{
559 assert(dev->driver_data == NULL);
560
561 void *data = calloc(1, size);
562 if (data == NULL)
563 return NULL;
564
565 dev->driver_data = data;
566 return data;
567}
568
569/** Return driver-specific device data. */
570void *ddf_dev_data_get(ddf_dev_t *dev)
571{
572 return dev->driver_data;
573}
574
575/** Get device handle. */
576devman_handle_t ddf_dev_get_handle(ddf_dev_t *dev)
577{
578 return dev->handle;
579}
580
581/** Return device name.
582 *
583 * @param dev Device
584 * @return Device name. Valid as long as @a dev is valid.
585 */
586const char *ddf_dev_get_name(ddf_dev_t *dev)
587{
588 return dev->name;
589}
590
591/** Create session with the parent function.
592 *
593 * The session will be automatically closed when @a dev is destroyed.
594 *
595 * @param dev Device
596 *
597 * @return New session or NULL if session could not be created
598 *
599 */
600async_sess_t *ddf_dev_parent_sess_create(ddf_dev_t *dev)
601{
602 assert(dev->parent_sess == NULL);
603 dev->parent_sess = devman_parent_device_connect(dev->handle,
604 IPC_FLAG_BLOCKING);
605
606 return dev->parent_sess;
607}
608
609/** Return existing session with the parent function.
610 *
611 * @param dev Device
612 * @return Existing session or NULL if there is no session
613 */
614async_sess_t *ddf_dev_parent_sess_get(ddf_dev_t *dev)
615{
616 return dev->parent_sess;
617}
618
619/** Set function name (if it was not specified when node was created.)
620 *
621 * @param dev Device whose name has not been set yet
622 * @param name Name, will be copied
623 * @return EOK on success, ENOMEM if out of memory
624 */
625int ddf_fun_set_name(ddf_fun_t *dev, const char *name)
626{
627 assert(dev->name == NULL);
628
629 dev->name = str_dup(name);
630 if (dev->name == NULL)
631 return ENOENT;
632
633 return EOK;
634}
635
636/** Get device to which function belongs. */
637ddf_dev_t *ddf_fun_get_dev(ddf_fun_t *fun)
638{
639 return fun->dev;
640}
641
642/** Get function handle.
643 *
644 * XXX USB uses this, but its use should be eliminated.
645 */
646devman_handle_t ddf_fun_get_handle(ddf_fun_t *fun)
647{
648 return fun->handle;
649}
650
651/** Create a DDF function node.
652 *
653 * Create a DDF function (in memory). Both child devices and external clients
654 * communicate with a device via its functions.
655 *
656 * The created function node is fully formed, but only exists in the memory
657 * of the client task. In order to be visible to the system, the function
658 * must be bound using ddf_fun_bind().
659 *
660 * This function should only fail if there is not enough free memory.
661 * Specifically, this function succeeds even if @a dev already has
662 * a (bound) function with the same name. @a name can be NULL in which
663 * case the caller will set the name later using ddf_fun_set_name().
664 * He must do this before binding the function.
665 *
666 * Type: A function of type fun_inner indicates that DDF should attempt
667 * to attach child devices to the function. fun_exposed means that
668 * the function should be exported to external clients (applications).
669 *
670 * @param dev Device to which we are adding function
671 * @param ftype Type of function (fun_inner or fun_exposed)
672 * @param name Name of function or NULL
673 *
674 * @return New function or @c NULL if memory is not available
675 */
676ddf_fun_t *ddf_fun_create(ddf_dev_t *dev, fun_type_t ftype, const char *name)
677{
678 ddf_fun_t *fun = create_function();
679 if (fun == NULL)
680 return NULL;
681
682 /* Add one reference that will be dropped by ddf_fun_destroy() */
683 fun->dev = dev;
684 fun_add_ref(fun);
685
686 fun->bound = false;
687 fun->ftype = ftype;
688
689 if (name != NULL) {
690 fun->name = str_dup(name);
691 if (fun->name == NULL) {
692 delete_function(fun);
693 return NULL;
694 }
695 }
696
697 return fun;
698}
699
700/** Allocate driver-specific function data. */
701void *ddf_fun_data_alloc(ddf_fun_t *fun, size_t size)
702{
703 assert(fun->bound == false);
704 assert(fun->driver_data == NULL);
705
706 void *data = calloc(1, size);
707 if (data == NULL)
708 return NULL;
709
710 fun->driver_data = data;
711 return data;
712}
713
714/** Return driver-specific function data. */
715void *ddf_fun_data_get(ddf_fun_t *fun)
716{
717 return fun->driver_data;
718}
719
720/** Return function name.
721 *
722 * @param fun Function
723 * @return Function name. Valid as long as @a fun is valid.
724 */
725const char *ddf_fun_get_name(ddf_fun_t *fun)
726{
727 return fun->name;
728}
729
730/** Destroy DDF function node.
731 *
732 * Destroy a function previously created with ddf_fun_create(). The function
733 * must not be bound.
734 *
735 * @param fun Function to destroy
736 *
737 */
738void ddf_fun_destroy(ddf_fun_t *fun)
739{
740 assert(fun->bound == false);
741
742 /*
743 * Drop the reference added by ddf_fun_create(). This will deallocate
744 * the function as soon as all other references are dropped (i.e.
745 * as soon control leaves all driver entry points called in context
746 * of this function.
747 */
748 fun_del_ref(fun);
749}
750
751static void *function_get_ops(ddf_fun_t *fun, dev_inferface_idx_t idx)
752{
753 assert(is_valid_iface_idx(idx));
754 if (fun->ops == NULL)
755 return NULL;
756
757 return fun->ops->interfaces[idx];
758}
759
760/** Bind a function node.
761 *
762 * Bind the specified function to the system. This effectively makes
763 * the function visible to the system (uploads it to the server).
764 *
765 * This function can fail for several reasons. Specifically,
766 * it will fail if the device already has a bound function of
767 * the same name.
768 *
769 * @param fun Function to bind
770 *
771 * @return EOK on success or negative error code
772 *
773 */
774int ddf_fun_bind(ddf_fun_t *fun)
775{
776 assert(fun->bound == false);
777 assert(fun->name != NULL);
778
779 add_to_functions_list(fun);
780 int res = devman_add_function(fun->name, fun->ftype, &fun->match_ids,
781 fun->dev->handle, &fun->handle);
782 if (res != EOK) {
783 remove_from_functions_list(fun);
784 return res;
785 }
786
787 fun->bound = true;
788 return res;
789}
790
791/** Unbind a function node.
792 *
793 * Unbind the specified function from the system. This effectively makes
794 * the function invisible to the system.
795 *
796 * @param fun Function to unbind
797 *
798 * @return EOK on success or negative error code
799 *
800 */
801int ddf_fun_unbind(ddf_fun_t *fun)
802{
803 assert(fun->bound == true);
804
805 int res = devman_remove_function(fun->handle);
806 if (res != EOK)
807 return res;
808
809 remove_from_functions_list(fun);
810
811 fun->bound = false;
812 return EOK;
813}
814
815/** Online function.
816 *
817 * @param fun Function to online
818 *
819 * @return EOK on success or negative error code
820 *
821 */
822int ddf_fun_online(ddf_fun_t *fun)
823{
824 assert(fun->bound == true);
825
826 int res = devman_drv_fun_online(fun->handle);
827 if (res != EOK)
828 return res;
829
830 return EOK;
831}
832
833/** Offline function.
834 *
835 * @param fun Function to offline
836 *
837 * @return EOK on success or negative error code
838 *
839 */
840int ddf_fun_offline(ddf_fun_t *fun)
841{
842 assert(fun->bound == true);
843
844 int res = devman_drv_fun_offline(fun->handle);
845 if (res != EOK)
846 return res;
847
848 return EOK;
849}
850
851/** Add single match ID to inner function.
852 *
853 * Construct and add a single match ID to the specified function.
854 * Cannot be called when the function node is bound.
855 *
856 * @param fun Function
857 * @param match_id_str Match string
858 * @param match_score Match score
859 *
860 * @return EOK on success.
861 * @return ENOMEM if out of memory.
862 *
863 */
864int ddf_fun_add_match_id(ddf_fun_t *fun, const char *match_id_str,
865 int match_score)
866{
867 assert(fun->bound == false);
868 assert(fun->ftype == fun_inner);
869
870 match_id_t *match_id = create_match_id();
871 if (match_id == NULL)
872 return ENOMEM;
873
874 match_id->id = str_dup(match_id_str);
875 match_id->score = match_score;
876
877 add_match_id(&fun->match_ids, match_id);
878 return EOK;
879}
880
881/** Set function ops. */
882void ddf_fun_set_ops(ddf_fun_t *fun, ddf_dev_ops_t *dev_ops)
883{
884 assert(fun->conn_handler == NULL);
885 fun->ops = dev_ops;
886}
887
888/** Set user-defined connection handler.
889 *
890 * This allows handling connections the non-devman way.
891 */
892void ddf_fun_set_conn_handler(ddf_fun_t *fun, async_port_handler_t conn)
893{
894 assert(fun->ops == NULL);
895 fun->conn_handler = conn;
896}
897
898/** Get default handler for client requests */
899static remote_handler_t *function_get_default_handler(ddf_fun_t *fun)
900{
901 if (fun->ops == NULL)
902 return NULL;
903 return fun->ops->default_handler;
904}
905
906/** Add exposed function to category.
907 *
908 * Must only be called when the function is bound.
909 *
910 */
911int ddf_fun_add_to_category(ddf_fun_t *fun, const char *cat_name)
912{
913 assert(fun->bound == true);
914 assert(fun->ftype == fun_exposed);
915
916 return devman_add_device_to_category(fun->handle, cat_name);
917}
918
919int ddf_driver_main(const driver_t *drv)
920{
921 /*
922 * Remember the driver structure - driver_ops will be called by generic
923 * handler for incoming connections.
924 */
925 driver = drv;
926
927 /*
928 * Register driver with device manager using generic handler for
929 * incoming connections.
930 */
931 port_id_t port;
932 int rc = async_create_port(INTERFACE_DDF_DRIVER, driver_connection_driver,
933 NULL, &port);
934 if (rc != EOK)
935 return rc;
936
937 rc = async_create_port(INTERFACE_DDF_DEVMAN, driver_connection_devman,
938 NULL, &port);
939 if (rc != EOK)
940 return rc;
941
942 async_set_fallback_port_handler(driver_connection_client, NULL);
943
944 rc = devman_driver_register(driver->name);
945 if (rc != EOK) {
946 printf("Error: Failed to register driver with device manager "
947 "(%s).\n", (rc == EEXIST) ? "driver already started" :
948 str_error(rc));
949
950 return rc;
951 }
952
953 /* Return success from the task since server has started. */
954 rc = task_retval(0);
955 if (rc != EOK)
956 return rc;
957
958 async_manager();
959
960 /* Never reached. */
961 return EOK;
962}
963
964/**
965 * @}
966 */
Note: See TracBrowser for help on using the repository browser.