2 * Copyright (c) 2010 Lenka Trochtova
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.
39 #include <ipc/services.h>
45 #include <fibril_synch.h>
48 #include <str_error.h>
53 #include "dev_iface.h"
54 #include "ddf/driver.h"
55 #include "ddf/interrupt.h"
56 #include "private/driver.h"
58 /** Driver structure */
59 static const driver_t
*driver
;
62 LIST_INITIALIZE(devices
);
63 FIBRIL_MUTEX_INITIALIZE(devices_mutex
);
66 LIST_INITIALIZE(functions
);
67 FIBRIL_MUTEX_INITIALIZE(functions_mutex
);
69 FIBRIL_RWLOCK_INITIALIZE(stopping_lock
);
70 static bool stopping
= false;
72 static ddf_dev_t
*create_device(void);
73 static void delete_device(ddf_dev_t
*);
74 static void dev_add_ref(ddf_dev_t
*);
75 static void dev_del_ref(ddf_dev_t
*);
76 static void fun_add_ref(ddf_fun_t
*);
77 static void fun_del_ref(ddf_fun_t
*);
78 static remote_handler_t
*function_get_default_handler(ddf_fun_t
*);
79 static void *function_get_ops(ddf_fun_t
*, dev_inferface_idx_t
);
81 static void add_to_functions_list(ddf_fun_t
*fun
)
83 fibril_mutex_lock(&functions_mutex
);
84 list_append(&fun
->link
, &functions
);
85 fibril_mutex_unlock(&functions_mutex
);
88 static void remove_from_functions_list(ddf_fun_t
*fun
)
90 fibril_mutex_lock(&functions_mutex
);
91 list_remove(&fun
->link
);
92 fibril_mutex_unlock(&functions_mutex
);
95 static ddf_dev_t
*driver_get_device(devman_handle_t handle
)
97 assert(fibril_mutex_is_locked(&devices_mutex
));
99 list_foreach(devices
, link
, ddf_dev_t
, dev
) {
100 if (dev
->handle
== handle
)
107 static ddf_fun_t
*driver_get_function(devman_handle_t handle
)
109 assert(fibril_mutex_is_locked(&functions_mutex
));
111 list_foreach(functions
, link
, ddf_fun_t
, fun
) {
112 if (fun
->handle
== handle
)
119 static void driver_dev_add(ipc_call_t
*icall
)
121 devman_handle_t dev_handle
= IPC_GET_ARG1(*icall
);
122 devman_handle_t parent_fun_handle
= IPC_GET_ARG2(*icall
);
124 char *dev_name
= NULL
;
125 errno_t rc
= async_data_write_accept((void **) &dev_name
, true, 0, 0, 0, 0);
127 async_answer_0(icall
, rc
);
131 fibril_rwlock_read_lock(&stopping_lock
);
134 fibril_rwlock_read_unlock(&stopping_lock
);
135 async_answer_0(icall
, EIO
);
139 ddf_dev_t
*dev
= create_device();
141 fibril_rwlock_read_unlock(&stopping_lock
);
143 async_answer_0(icall
, ENOMEM
);
147 dev
->handle
= dev_handle
;
148 dev
->name
= dev_name
;
151 * Currently not used, parent fun handle is stored in context
152 * of the connection to the parent device driver.
154 (void) parent_fun_handle
;
156 errno_t res
= driver
->driver_ops
->dev_add(dev
);
159 fibril_rwlock_read_unlock(&stopping_lock
);
161 async_answer_0(icall
, res
);
165 fibril_mutex_lock(&devices_mutex
);
166 list_append(&dev
->link
, &devices
);
167 fibril_mutex_unlock(&devices_mutex
);
168 fibril_rwlock_read_unlock(&stopping_lock
);
170 async_answer_0(icall
, res
);
173 static void driver_dev_remove(ipc_call_t
*icall
)
175 devman_handle_t devh
= IPC_GET_ARG1(*icall
);
177 fibril_mutex_lock(&devices_mutex
);
178 ddf_dev_t
*dev
= driver_get_device(devh
);
181 fibril_mutex_unlock(&devices_mutex
);
184 async_answer_0(icall
, ENOENT
);
190 if (driver
->driver_ops
->dev_remove
!= NULL
)
191 rc
= driver
->driver_ops
->dev_remove(dev
);
196 fibril_mutex_lock(&devices_mutex
);
197 list_remove(&dev
->link
);
198 fibril_mutex_unlock(&devices_mutex
);
203 async_answer_0(icall
, rc
);
206 static void driver_dev_gone(ipc_call_t
*icall
)
208 devman_handle_t devh
= IPC_GET_ARG1(*icall
);
210 fibril_mutex_lock(&devices_mutex
);
211 ddf_dev_t
*dev
= driver_get_device(devh
);
214 fibril_mutex_unlock(&devices_mutex
);
217 async_answer_0(icall
, ENOENT
);
223 if (driver
->driver_ops
->dev_gone
!= NULL
)
224 rc
= driver
->driver_ops
->dev_gone(dev
);
229 fibril_mutex_lock(&devices_mutex
);
230 list_remove(&dev
->link
);
231 fibril_mutex_unlock(&devices_mutex
);
236 async_answer_0(icall
, rc
);
239 static void driver_fun_online(ipc_call_t
*icall
)
241 devman_handle_t funh
= IPC_GET_ARG1(*icall
);
244 * Look the function up. Bump reference count so that
245 * the function continues to exist until we return
248 fibril_mutex_lock(&functions_mutex
);
250 ddf_fun_t
*fun
= driver_get_function(funh
);
254 fibril_mutex_unlock(&functions_mutex
);
257 async_answer_0(icall
, ENOENT
);
261 /* Call driver entry point */
264 if (driver
->driver_ops
->fun_online
!= NULL
)
265 rc
= driver
->driver_ops
->fun_online(fun
);
271 async_answer_0(icall
, rc
);
274 static void driver_fun_offline(ipc_call_t
*icall
)
276 devman_handle_t funh
= IPC_GET_ARG1(*icall
);
279 * Look the function up. Bump reference count so that
280 * the function continues to exist until we return
283 fibril_mutex_lock(&functions_mutex
);
285 ddf_fun_t
*fun
= driver_get_function(funh
);
289 fibril_mutex_unlock(&functions_mutex
);
292 async_answer_0(icall
, ENOENT
);
296 /* Call driver entry point */
299 if (driver
->driver_ops
->fun_offline
!= NULL
)
300 rc
= driver
->driver_ops
->fun_offline(fun
);
304 async_answer_0(icall
, rc
);
307 static void driver_stop(ipc_call_t
*icall
)
309 /* Prevent new devices from being added */
310 fibril_rwlock_write_lock(&stopping_lock
);
313 /* Check if there are any devices */
314 fibril_mutex_lock(&devices_mutex
);
315 if (list_first(&devices
) != NULL
) {
316 /* Devices exist, roll back */
317 fibril_mutex_unlock(&devices_mutex
);
319 fibril_rwlock_write_unlock(&stopping_lock
);
320 async_answer_0(icall
, EBUSY
);
324 fibril_rwlock_write_unlock(&stopping_lock
);
326 /* There should be no functions at this point */
327 fibril_mutex_lock(&functions_mutex
);
328 assert(list_first(&functions
) == NULL
);
329 fibril_mutex_unlock(&functions_mutex
);
331 /* Reply with success and terminate */
332 async_answer_0(icall
, EOK
);
336 static void driver_connection_devman(ipc_call_t
*icall
, void *arg
)
338 /* Accept connection */
339 async_accept_0(icall
);
343 async_get_call(&call
);
345 if (!IPC_GET_IMETHOD(call
)) {
346 async_answer_0(&call
, EOK
);
350 switch (IPC_GET_IMETHOD(call
)) {
352 driver_dev_add(&call
);
354 case DRIVER_DEV_REMOVE
:
355 driver_dev_remove(&call
);
357 case DRIVER_DEV_GONE
:
358 driver_dev_gone(&call
);
360 case DRIVER_FUN_ONLINE
:
361 driver_fun_online(&call
);
363 case DRIVER_FUN_OFFLINE
:
364 driver_fun_offline(&call
);
370 async_answer_0(&call
, ENOTSUP
);
375 /** Generic client connection handler both for applications and drivers.
377 * @param drv True for driver client, false for other clients
378 * (applications, services, etc.).
381 static void driver_connection_gen(ipc_call_t
*icall
, bool drv
)
384 * Answer the first IPC_M_CONNECT_ME_TO call and remember the handle of
385 * the device to which the client connected.
387 devman_handle_t handle
= IPC_GET_ARG2(*icall
);
389 fibril_mutex_lock(&functions_mutex
);
390 ddf_fun_t
*fun
= driver_get_function(handle
);
393 fibril_mutex_unlock(&functions_mutex
);
396 printf("%s: driver_connection_gen error - no function with handle"
397 " %" PRIun
" was found.\n", driver
->name
, handle
);
398 async_answer_0(icall
, ENOENT
);
402 if (fun
->conn_handler
!= NULL
) {
403 /* Driver has a custom connection handler. */
404 (*fun
->conn_handler
)(icall
, (void *)fun
);
410 * TODO - if the client is not a driver, check whether it is allowed to
415 /* Open device function */
416 if (fun
->ops
!= NULL
&& fun
->ops
->open
!= NULL
)
417 ret
= (*fun
->ops
->open
)(fun
);
420 async_answer_0(icall
, ret
);
425 async_accept_0(icall
);
429 async_get_call(&call
);
431 sysarg_t method
= IPC_GET_IMETHOD(call
);
434 /* Close device function */
435 if (fun
->ops
!= NULL
&& fun
->ops
->close
!= NULL
)
436 (*fun
->ops
->close
)(fun
);
437 async_answer_0(&call
, EOK
);
442 /* Convert ipc interface id to interface index */
444 int iface_idx
= DEV_IFACE_IDX(method
);
446 if (!is_valid_iface_idx(iface_idx
)) {
447 remote_handler_t
*default_handler
=
448 function_get_default_handler(fun
);
449 if (default_handler
!= NULL
) {
450 (*default_handler
)(fun
, &call
);
455 * Function has no such interface and
456 * default handler is not provided.
458 printf("%s: driver_connection_gen error - "
459 "invalid interface id %d.",
460 driver
->name
, iface_idx
);
461 async_answer_0(&call
, ENOTSUP
);
465 /* Calling one of the function's interfaces */
467 /* Get the interface ops structure. */
468 void *ops
= function_get_ops(fun
, iface_idx
);
470 printf("%s: driver_connection_gen error - ", driver
->name
);
471 printf("Function with handle %" PRIun
" has no interface "
472 "with id %d.\n", handle
, iface_idx
);
473 async_answer_0(&call
, ENOTSUP
);
478 * Get the corresponding interface for remote request
479 * handling ("remote interface").
481 const remote_iface_t
*rem_iface
= get_remote_iface(iface_idx
);
482 assert(rem_iface
!= NULL
);
484 /* get the method of the remote interface */
485 sysarg_t iface_method_idx
= IPC_GET_ARG1(call
);
486 remote_iface_func_ptr_t iface_method_ptr
=
487 get_remote_method(rem_iface
, iface_method_idx
);
488 if (iface_method_ptr
== NULL
) {
489 /* The interface has not such method */
490 printf("%s: driver_connection_gen error - "
491 "invalid interface method.", driver
->name
);
492 async_answer_0(&call
, ENOTSUP
);
497 * Call the remote interface's method, which will
498 * receive parameters from the remote client and it will
499 * pass it to the corresponding local interface method
500 * associated with the function by its driver.
502 (*iface_method_ptr
)(fun
, ops
, &call
);
506 static void driver_connection_driver(ipc_call_t
*icall
, void *arg
)
508 driver_connection_gen(icall
, true);
511 static void driver_connection_client(ipc_call_t
*icall
, void *arg
)
513 driver_connection_gen(icall
, false);
516 /** Create new device structure.
518 * @return The device structure.
520 static ddf_dev_t
*create_device(void)
524 dev
= calloc(1, sizeof(ddf_dev_t
));
528 refcount_init(&dev
->refcnt
);
533 /** Create new function structure.
535 * @return The device structure.
537 static ddf_fun_t
*create_function(void)
541 fun
= calloc(1, sizeof(ddf_fun_t
));
545 refcount_init(&fun
->refcnt
);
546 init_match_ids(&fun
->match_ids
);
547 link_initialize(&fun
->link
);
552 /** Delete device structure.
554 * @param dev The device structure.
556 static void delete_device(ddf_dev_t
*dev
)
558 if (dev
->parent_sess
)
559 async_hangup(dev
->parent_sess
);
560 if (dev
->driver_data
!= NULL
)
561 free(dev
->driver_data
);
567 /** Delete function structure.
569 * @param dev The device structure.
571 static void delete_function(ddf_fun_t
*fun
)
573 clean_match_ids(&fun
->match_ids
);
574 if (fun
->driver_data
!= NULL
)
575 free(fun
->driver_data
);
576 if (fun
->name
!= NULL
)
581 /** Increase device reference count. */
582 static void dev_add_ref(ddf_dev_t
*dev
)
584 refcount_up(&dev
->refcnt
);
587 /** Decrease device reference count.
589 * Free the device structure if the reference count drops to zero.
591 static void dev_del_ref(ddf_dev_t
*dev
)
593 if (refcount_down(&dev
->refcnt
))
597 /** Increase function reference count.
599 * This also increases reference count on the device. The device structure
600 * will thus not be deallocated while there are some associated function
603 static void fun_add_ref(ddf_fun_t
*fun
)
605 dev_add_ref(fun
->dev
);
606 refcount_up(&fun
->refcnt
);
609 /** Decrease function reference count.
611 * Free the function structure if the reference count drops to zero.
613 static void fun_del_ref(ddf_fun_t
*fun
)
615 ddf_dev_t
*dev
= fun
->dev
;
617 if (refcount_down(&fun
->refcnt
))
618 delete_function(fun
);
623 /** Allocate driver-specific device data. */
624 void *ddf_dev_data_alloc(ddf_dev_t
*dev
, size_t size
)
626 assert(dev
->driver_data
== NULL
);
628 void *data
= calloc(1, size
);
632 dev
->driver_data
= data
;
636 /** Return driver-specific device data. */
637 void *ddf_dev_data_get(ddf_dev_t
*dev
)
639 return dev
->driver_data
;
642 /** Get device handle. */
643 devman_handle_t
ddf_dev_get_handle(ddf_dev_t
*dev
)
648 /** Return device name.
651 * @return Device name. Valid as long as @a dev is valid.
653 const char *ddf_dev_get_name(ddf_dev_t
*dev
)
658 /** Return existing session with the parent function.
661 * @return Session with parent function or NULL upon failure
663 async_sess_t
*ddf_dev_parent_sess_get(ddf_dev_t
*dev
)
665 if (dev
->parent_sess
== NULL
) {
666 dev
->parent_sess
= devman_parent_device_connect(dev
->handle
,
670 return dev
->parent_sess
;
673 /** Set function name (if it was not specified when node was created.)
675 * @param dev Device whose name has not been set yet
676 * @param name Name, will be copied
677 * @return EOK on success, ENOMEM if out of memory
679 errno_t
ddf_fun_set_name(ddf_fun_t
*dev
, const char *name
)
681 assert(dev
->name
== NULL
);
683 dev
->name
= str_dup(name
);
684 if (dev
->name
== NULL
)
690 /** Get device to which function belongs. */
691 ddf_dev_t
*ddf_fun_get_dev(ddf_fun_t
*fun
)
696 /** Get function handle.
698 * XXX USB uses this, but its use should be eliminated.
700 devman_handle_t
ddf_fun_get_handle(ddf_fun_t
*fun
)
705 /** Create a DDF function node.
707 * Create a DDF function (in memory). Both child devices and external clients
708 * communicate with a device via its functions.
710 * The created function node is fully formed, but only exists in the memory
711 * of the client task. In order to be visible to the system, the function
712 * must be bound using ddf_fun_bind().
714 * This function should only fail if there is not enough free memory.
715 * Specifically, this function succeeds even if @a dev already has
716 * a (bound) function with the same name. @a name can be NULL in which
717 * case the caller will set the name later using ddf_fun_set_name().
718 * He must do this before binding the function.
720 * Type: A function of type fun_inner indicates that DDF should attempt
721 * to attach child devices to the function. fun_exposed means that
722 * the function should be exported to external clients (applications).
724 * @param dev Device to which we are adding function
725 * @param ftype Type of function (fun_inner or fun_exposed)
726 * @param name Name of function or NULL
728 * @return New function or @c NULL if memory is not available
730 ddf_fun_t
*ddf_fun_create(ddf_dev_t
*dev
, fun_type_t ftype
, const char *name
)
732 ddf_fun_t
*fun
= create_function();
737 dev_add_ref(fun
->dev
);
743 fun
->name
= str_dup(name
);
744 if (fun
->name
== NULL
) {
745 fun_del_ref(fun
); /* fun is destroyed */
753 /** Allocate driver-specific function data. */
754 void *ddf_fun_data_alloc(ddf_fun_t
*fun
, size_t size
)
756 assert(fun
->bound
== false);
757 assert(fun
->driver_data
== NULL
);
759 void *data
= calloc(1, size
);
763 fun
->driver_data
= data
;
767 /** Return driver-specific function data. */
768 void *ddf_fun_data_get(ddf_fun_t
*fun
)
770 return fun
->driver_data
;
773 /** Return function name.
775 * @param fun Function
776 * @return Function name. Valid as long as @a fun is valid.
778 const char *ddf_fun_get_name(ddf_fun_t
*fun
)
783 /** Destroy DDF function node.
785 * Destroy a function previously created with ddf_fun_create(). The function
788 * @param fun Function to destroy
791 void ddf_fun_destroy(ddf_fun_t
*fun
)
793 assert(fun
->bound
== false);
796 * Drop the reference added by ddf_fun_create(). This will deallocate
797 * the function as soon as all other references are dropped (i.e.
798 * as soon control leaves all driver entry points called in context
804 static void *function_get_ops(ddf_fun_t
*fun
, dev_inferface_idx_t idx
)
806 assert(is_valid_iface_idx(idx
));
807 if (fun
->ops
== NULL
)
810 return fun
->ops
->interfaces
[idx
];
813 /** Bind a function node.
815 * Bind the specified function to the system. This effectively makes
816 * the function visible to the system (uploads it to the server).
818 * This function can fail for several reasons. Specifically,
819 * it will fail if the device already has a bound function of
822 * @param fun Function to bind
824 * @return EOK on success or an error code
827 errno_t
ddf_fun_bind(ddf_fun_t
*fun
)
829 assert(fun
->bound
== false);
830 assert(fun
->name
!= NULL
);
831 assert(fun
->dev
!= NULL
);
833 add_to_functions_list(fun
);
834 errno_t res
= devman_add_function(fun
->name
, fun
->ftype
, &fun
->match_ids
,
835 fun
->dev
->handle
, &fun
->handle
);
837 remove_from_functions_list(fun
);
845 /** Unbind a function node.
847 * Unbind the specified function from the system. This effectively makes
848 * the function invisible to the system.
850 * @param fun Function to unbind
852 * @return EOK on success or an error code
855 errno_t
ddf_fun_unbind(ddf_fun_t
*fun
)
857 assert(fun
->bound
== true);
859 errno_t res
= devman_remove_function(fun
->handle
);
863 remove_from_functions_list(fun
);
871 * @param fun Function to online
873 * @return EOK on success or an error code
876 errno_t
ddf_fun_online(ddf_fun_t
*fun
)
878 assert(fun
->bound
== true);
880 errno_t res
= devman_drv_fun_online(fun
->handle
);
887 /** Offline function.
889 * @param fun Function to offline
891 * @return EOK on success or an error code
894 errno_t
ddf_fun_offline(ddf_fun_t
*fun
)
896 assert(fun
->bound
== true);
898 errno_t res
= devman_drv_fun_offline(fun
->handle
);
905 /** Add single match ID to inner function.
907 * Construct and add a single match ID to the specified function.
908 * Cannot be called when the function node is bound.
910 * @param fun Function
911 * @param match_id_str Match string
912 * @param match_score Match score
914 * @return EOK on success.
915 * @return ENOMEM if out of memory.
918 errno_t
ddf_fun_add_match_id(ddf_fun_t
*fun
, const char *match_id_str
,
921 assert(fun
->bound
== false);
922 assert(fun
->ftype
== fun_inner
);
924 match_id_t
*match_id
= create_match_id();
925 if (match_id
== NULL
)
928 match_id
->id
= str_dup(match_id_str
);
929 match_id
->score
= match_score
;
931 add_match_id(&fun
->match_ids
, match_id
);
935 /** Set function ops. */
936 void ddf_fun_set_ops(ddf_fun_t
*fun
, const ddf_dev_ops_t
*dev_ops
)
938 assert(fun
->conn_handler
== NULL
);
942 /** Set user-defined connection handler.
944 * This allows handling connections the non-devman way.
946 void ddf_fun_set_conn_handler(ddf_fun_t
*fun
, async_port_handler_t conn
)
948 assert(fun
->ops
== NULL
);
949 fun
->conn_handler
= conn
;
952 /** Get default handler for client requests */
953 static remote_handler_t
*function_get_default_handler(ddf_fun_t
*fun
)
955 if (fun
->ops
== NULL
)
957 return fun
->ops
->default_handler
;
960 /** Add exposed function to category.
962 * Must only be called when the function is bound.
965 errno_t
ddf_fun_add_to_category(ddf_fun_t
*fun
, const char *cat_name
)
967 assert(fun
->bound
== true);
968 assert(fun
->ftype
== fun_exposed
);
970 return devman_add_device_to_category(fun
->handle
, cat_name
);
973 errno_t
ddf_driver_main(const driver_t
*drv
)
976 * Remember the driver structure - driver_ops will be called by generic
977 * handler for incoming connections.
982 * Register driver with device manager using generic handler for
983 * incoming connections.
986 errno_t rc
= async_create_port(INTERFACE_DDF_DRIVER
, driver_connection_driver
,
989 printf("Error: Failed to create driver port.\n");
993 rc
= async_create_port(INTERFACE_DDF_DEVMAN
, driver_connection_devman
,
996 printf("Error: Failed to create devman port.\n");
1000 async_set_fallback_port_handler(driver_connection_client
, NULL
);
1002 rc
= devman_driver_register(driver
->name
);
1004 printf("Error: Failed to register driver with device manager "
1005 "(%s).\n", (rc
== EEXIST
) ? "driver already started" :
1011 /* Return success from the task since server has started. */
1012 rc
= task_retval(0);
1014 printf("Error: Failed returning task value.\n");
1020 /* Never reached. */