source: mainline/uspace/lib/drv/generic/driver.c@ 4c5deac

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4c5deac was 669e9b5, checked in by Jakub Jermar <jakub@…>, 9 years ago

Do not leak device name in delete_device().

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