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
));
531 /** Create new function structure.
533 * @return The device structure.
535 static ddf_fun_t
*create_function(void)
539 fun
= calloc(1, sizeof(ddf_fun_t
));
543 init_match_ids(&fun
->match_ids
);
544 link_initialize(&fun
->link
);
549 /** Delete device structure.
551 * @param dev The device structure.
553 static void delete_device(ddf_dev_t
*dev
)
555 if (dev
->parent_sess
)
556 async_hangup(dev
->parent_sess
);
557 if (dev
->driver_data
!= NULL
)
558 free(dev
->driver_data
);
564 /** Delete function structure.
566 * @param dev The device structure.
568 static void delete_function(ddf_fun_t
*fun
)
570 clean_match_ids(&fun
->match_ids
);
571 if (fun
->driver_data
!= NULL
)
572 free(fun
->driver_data
);
573 if (fun
->name
!= NULL
)
578 /** Increase device reference count. */
579 static void dev_add_ref(ddf_dev_t
*dev
)
581 refcount_up(&dev
->refcnt
);
584 /** Decrease device reference count.
586 * Free the device structure if the reference count drops to zero.
588 static void dev_del_ref(ddf_dev_t
*dev
)
590 if (refcount_down(&dev
->refcnt
))
594 /** Increase function reference count.
596 * This also increases reference count on the device. The device structure
597 * will thus not be deallocated while there are some associated function
600 static void fun_add_ref(ddf_fun_t
*fun
)
602 dev_add_ref(fun
->dev
);
603 refcount_up(&fun
->refcnt
);
606 /** Decrease function reference count.
608 * Free the function structure if the reference count drops to zero.
610 static void fun_del_ref(ddf_fun_t
*fun
)
612 ddf_dev_t
*dev
= fun
->dev
;
614 if (refcount_down(&fun
->refcnt
))
615 delete_function(fun
);
620 /** Allocate driver-specific device data. */
621 void *ddf_dev_data_alloc(ddf_dev_t
*dev
, size_t size
)
623 assert(dev
->driver_data
== NULL
);
625 void *data
= calloc(1, size
);
629 dev
->driver_data
= data
;
633 /** Return driver-specific device data. */
634 void *ddf_dev_data_get(ddf_dev_t
*dev
)
636 return dev
->driver_data
;
639 /** Get device handle. */
640 devman_handle_t
ddf_dev_get_handle(ddf_dev_t
*dev
)
645 /** Return device name.
648 * @return Device name. Valid as long as @a dev is valid.
650 const char *ddf_dev_get_name(ddf_dev_t
*dev
)
655 /** Return existing session with the parent function.
658 * @return Session with parent function or NULL upon failure
660 async_sess_t
*ddf_dev_parent_sess_get(ddf_dev_t
*dev
)
662 if (dev
->parent_sess
== NULL
) {
663 dev
->parent_sess
= devman_parent_device_connect(dev
->handle
,
667 return dev
->parent_sess
;
670 /** Set function name (if it was not specified when node was created.)
672 * @param dev Device whose name has not been set yet
673 * @param name Name, will be copied
674 * @return EOK on success, ENOMEM if out of memory
676 errno_t
ddf_fun_set_name(ddf_fun_t
*dev
, const char *name
)
678 assert(dev
->name
== NULL
);
680 dev
->name
= str_dup(name
);
681 if (dev
->name
== NULL
)
687 /** Get device to which function belongs. */
688 ddf_dev_t
*ddf_fun_get_dev(ddf_fun_t
*fun
)
693 /** Get function handle.
695 * XXX USB uses this, but its use should be eliminated.
697 devman_handle_t
ddf_fun_get_handle(ddf_fun_t
*fun
)
702 /** Create a DDF function node.
704 * Create a DDF function (in memory). Both child devices and external clients
705 * communicate with a device via its functions.
707 * The created function node is fully formed, but only exists in the memory
708 * of the client task. In order to be visible to the system, the function
709 * must be bound using ddf_fun_bind().
711 * This function should only fail if there is not enough free memory.
712 * Specifically, this function succeeds even if @a dev already has
713 * a (bound) function with the same name. @a name can be NULL in which
714 * case the caller will set the name later using ddf_fun_set_name().
715 * He must do this before binding the function.
717 * Type: A function of type fun_inner indicates that DDF should attempt
718 * to attach child devices to the function. fun_exposed means that
719 * the function should be exported to external clients (applications).
721 * @param dev Device to which we are adding function
722 * @param ftype Type of function (fun_inner or fun_exposed)
723 * @param name Name of function or NULL
725 * @return New function or @c NULL if memory is not available
727 ddf_fun_t
*ddf_fun_create(ddf_dev_t
*dev
, fun_type_t ftype
, const char *name
)
729 ddf_fun_t
*fun
= create_function();
733 /* Add one reference that will be dropped by ddf_fun_destroy() */
741 fun
->name
= str_dup(name
);
742 if (fun
->name
== NULL
) {
743 delete_function(fun
);
751 /** Allocate driver-specific function data. */
752 void *ddf_fun_data_alloc(ddf_fun_t
*fun
, size_t size
)
754 assert(fun
->bound
== false);
755 assert(fun
->driver_data
== NULL
);
757 void *data
= calloc(1, size
);
761 fun
->driver_data
= data
;
765 /** Return driver-specific function data. */
766 void *ddf_fun_data_get(ddf_fun_t
*fun
)
768 return fun
->driver_data
;
771 /** Return function name.
773 * @param fun Function
774 * @return Function name. Valid as long as @a fun is valid.
776 const char *ddf_fun_get_name(ddf_fun_t
*fun
)
781 /** Destroy DDF function node.
783 * Destroy a function previously created with ddf_fun_create(). The function
786 * @param fun Function to destroy
789 void ddf_fun_destroy(ddf_fun_t
*fun
)
791 assert(fun
->bound
== false);
794 * Drop the reference added by ddf_fun_create(). This will deallocate
795 * the function as soon as all other references are dropped (i.e.
796 * as soon control leaves all driver entry points called in context
802 static void *function_get_ops(ddf_fun_t
*fun
, dev_inferface_idx_t idx
)
804 assert(is_valid_iface_idx(idx
));
805 if (fun
->ops
== NULL
)
808 return fun
->ops
->interfaces
[idx
];
811 /** Bind a function node.
813 * Bind the specified function to the system. This effectively makes
814 * the function visible to the system (uploads it to the server).
816 * This function can fail for several reasons. Specifically,
817 * it will fail if the device already has a bound function of
820 * @param fun Function to bind
822 * @return EOK on success or an error code
825 errno_t
ddf_fun_bind(ddf_fun_t
*fun
)
827 assert(fun
->bound
== false);
828 assert(fun
->name
!= NULL
);
829 assert(fun
->dev
!= NULL
);
831 add_to_functions_list(fun
);
832 errno_t res
= devman_add_function(fun
->name
, fun
->ftype
, &fun
->match_ids
,
833 fun
->dev
->handle
, &fun
->handle
);
835 remove_from_functions_list(fun
);
843 /** Unbind a function node.
845 * Unbind the specified function from the system. This effectively makes
846 * the function invisible to the system.
848 * @param fun Function to unbind
850 * @return EOK on success or an error code
853 errno_t
ddf_fun_unbind(ddf_fun_t
*fun
)
855 assert(fun
->bound
== true);
857 errno_t res
= devman_remove_function(fun
->handle
);
861 remove_from_functions_list(fun
);
869 * @param fun Function to online
871 * @return EOK on success or an error code
874 errno_t
ddf_fun_online(ddf_fun_t
*fun
)
876 assert(fun
->bound
== true);
878 errno_t res
= devman_drv_fun_online(fun
->handle
);
885 /** Offline function.
887 * @param fun Function to offline
889 * @return EOK on success or an error code
892 errno_t
ddf_fun_offline(ddf_fun_t
*fun
)
894 assert(fun
->bound
== true);
896 errno_t res
= devman_drv_fun_offline(fun
->handle
);
903 /** Add single match ID to inner function.
905 * Construct and add a single match ID to the specified function.
906 * Cannot be called when the function node is bound.
908 * @param fun Function
909 * @param match_id_str Match string
910 * @param match_score Match score
912 * @return EOK on success.
913 * @return ENOMEM if out of memory.
916 errno_t
ddf_fun_add_match_id(ddf_fun_t
*fun
, const char *match_id_str
,
919 assert(fun
->bound
== false);
920 assert(fun
->ftype
== fun_inner
);
922 match_id_t
*match_id
= create_match_id();
923 if (match_id
== NULL
)
926 match_id
->id
= str_dup(match_id_str
);
927 match_id
->score
= match_score
;
929 add_match_id(&fun
->match_ids
, match_id
);
933 /** Set function ops. */
934 void ddf_fun_set_ops(ddf_fun_t
*fun
, const ddf_dev_ops_t
*dev_ops
)
936 assert(fun
->conn_handler
== NULL
);
940 /** Set user-defined connection handler.
942 * This allows handling connections the non-devman way.
944 void ddf_fun_set_conn_handler(ddf_fun_t
*fun
, async_port_handler_t conn
)
946 assert(fun
->ops
== NULL
);
947 fun
->conn_handler
= conn
;
950 /** Get default handler for client requests */
951 static remote_handler_t
*function_get_default_handler(ddf_fun_t
*fun
)
953 if (fun
->ops
== NULL
)
955 return fun
->ops
->default_handler
;
958 /** Add exposed function to category.
960 * Must only be called when the function is bound.
963 errno_t
ddf_fun_add_to_category(ddf_fun_t
*fun
, const char *cat_name
)
965 assert(fun
->bound
== true);
966 assert(fun
->ftype
== fun_exposed
);
968 return devman_add_device_to_category(fun
->handle
, cat_name
);
971 errno_t
ddf_driver_main(const driver_t
*drv
)
974 * Remember the driver structure - driver_ops will be called by generic
975 * handler for incoming connections.
980 * Register driver with device manager using generic handler for
981 * incoming connections.
984 errno_t rc
= async_create_port(INTERFACE_DDF_DRIVER
, driver_connection_driver
,
987 printf("Error: Failed to create driver port.\n");
991 rc
= async_create_port(INTERFACE_DDF_DEVMAN
, driver_connection_devman
,
994 printf("Error: Failed to create devman port.\n");
998 async_set_fallback_port_handler(driver_connection_client
, NULL
);
1000 rc
= devman_driver_register(driver
->name
);
1002 printf("Error: Failed to register driver with device manager "
1003 "(%s).\n", (rc
== EEXIST
) ? "driver already started" :
1009 /* Return success from the task since server has started. */
1010 rc
= task_retval(0);
1012 printf("Error: Failed returning task value.\n");
1018 /* Never reached. */