DRVMGR: added driver manager to cpukit/libdrvmgr

This commit is contained in:
Daniel Hellstrom
2011-11-28 09:52:03 +01:00
parent 02550220c5
commit e7fade3ac4
37 changed files with 3724 additions and 3 deletions

12
aclocal/enable-drvmgr.m4 Normal file
View File

@@ -0,0 +1,12 @@
AC_DEFUN([RTEMS_ENABLE_DRVMGR],
[
## AC_BEFORE([$0], [RTEMS_CHECK_DRVMGR_STARTUP])dnl
AC_ARG_ENABLE(drvmgr,
[AS_HELP_STRING([--enable-drvmgr],[enable Driver Manager at Startup])],
[case "${enableval}" in
yes) RTEMS_DRVMGR_STARTUP=yes ;;
no) RTEMS_DRVMGR_STARTUP=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for enable-drvmgr option) ;;
esac],[RTEMS_DRVMGR_STARTUP=yes])
])

View File

@@ -0,0 +1,12 @@
AC_DEFUN([RTEMS_ENABLE_DRVMGR],
[
## AC_BEFORE([$0], [RTEMS_CHECK_DRVMGR_STARTUP])dnl
AC_ARG_ENABLE(drvmgr,
[AS_HELP_STRING([--enable-drvmgr],[enable Driver Manager at Startup])],
[case "${enableval}" in
yes) RTEMS_DRVMGR_STARTUP=yes ;;
no) RTEMS_DRVMGR_STARTUP=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for enable-drvmgr option) ;;
esac],[RTEMS_DRVMGR_STARTUP=yes])
])

View File

@@ -0,0 +1,16 @@
/*
* This is a dummy bsp_driver_level_hook routine.
*
* COPYRIGHT (c) 2015.
* Cobham Gaisler.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp/bootcard.h>
void bsp_driver_level_hook( int level )
{
}

View File

@@ -57,6 +57,8 @@ void bsp_pretasking_hook(void);
void bsp_predriver_hook(void);
void bsp_driver_level_hook( int level );
void bsp_postdriver_hook(void);
void bsp_reset(void);

View File

@@ -20,6 +20,7 @@ RTEMS_ENABLE_MULTIPROCESSING
RTEMS_ENABLE_POSIX
RTEMS_ENABLE_NETWORKING
RTEMS_ENABLE_CXX
RTEMS_ENABLE_DRVMGR
RTEMS_ENV_RTEMSBSP

View File

@@ -28,6 +28,7 @@ RTEMS_ENABLE_RTEMS_DEBUG
RTEMS_ENABLE_RTEMSBSP
RTEMS_ENABLE_MULTILIB
RTEMS_ENABLE_PARAVIRT
RTEMS_ENABLE_DRVMGR
AC_ARG_ENABLE([docs],
[AS_HELP_STRING([--enable-docs],[enable building documentation

View File

@@ -8,6 +8,7 @@ SUBDIRS = . score rtems sapi posix
SUBDIRS += dev
SUBDIRS += libcrypt
SUBDIRS += libcsupport libblock libfs
SUBDIRS += libdrvmgr
SUBDIRS += libnetworking librpc
SUBDIRS += libpci
SUBDIRS += libi2c
@@ -238,6 +239,12 @@ include_rtems_HEADERS += libmisc/untar/untar.h
## fsmount
include_rtems_HEADERS += libmisc/fsmount/fsmount.h
## Driver manager
include_drvmgrdir = $(includedir)/drvmgr
include_drvmgr_HEADERS = libdrvmgr/drvmgr.h
include_drvmgr_HEADERS += libdrvmgr/drvmgr_confdefs.h
include_drvmgr_HEADERS += libdrvmgr/drvmgr_list.h
## HACK: doxygen filter.
EXTRA_DIST = doxy-filter

View File

@@ -0,0 +1,12 @@
dnl $Id: enable-drvmgr.m4,v 1.0
AC_DEFUN([RTEMS_ENABLE_DRVMGR],
[
AC_ARG_ENABLE(drvmgr,
AS_HELP_STRING(--enable-drvmgr,enable drvmgr at startup),
[case "${enableval}" in
yes) RTEMS_DRVMGR_STARTUP=yes ;;
no) RTEMS_DRVMGR_STARTUP=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for enable-drvmgr option) ;;
esac],[RTEMS_DRVMGR_STARTUP=yes])
])

View File

@@ -17,6 +17,7 @@ RTEMS_ENABLE_RTEMS_DEBUG
RTEMS_ENABLE_NETWORKING
RTEMS_ENABLE_PARAVIRT
RTEMS_ENABLE_PROFILING
RTEMS_ENABLE_DRVMGR
RTEMS_ENV_RTEMSCPU
RTEMS_CHECK_RTEMS_DEBUG
@@ -229,6 +230,11 @@ RTEMS_CPUOPT([RTEMS_NETWORKING],
[1],
[if networking is enabled])
RTEMS_CPUOPT([RTEMS_DRVMGR_STARTUP],
[test x"$enable_drvmgr" = xyes],
[1],
[if driver manager api is supported])
RTEMS_CPUOPT([RTEMS_VERSION],
[true],
["]_RTEMS_VERSION["],
@@ -453,6 +459,7 @@ score/cpu/v850/Makefile
score/cpu/no_cpu/Makefile
posix/Makefile
libblock/Makefile
libdrvmgr/Makefile
libfs/Makefile
libfs/src/nfsclient/Makefile
libgnat/Makefile

View File

@@ -0,0 +1,33 @@
##
## $Id: Makefile.am
##
include $(top_srcdir)/automake/compile.am
EXTRA_DIST=
noinst_LIBRARIES = libdrvmgr.a
libdrvmgr_a_SOURCES = drvmgr.c
libdrvmgr_a_SOURCES += drvmgr.h
libdrvmgr_a_SOURCES += drvmgr_by_name.c
libdrvmgr_a_SOURCES += drvmgr_by_id.c
libdrvmgr_a_SOURCES += drvmgr_dev_by_name.c
libdrvmgr_a_SOURCES += drvmgr_drvinf.c
libdrvmgr_a_SOURCES += drvmgr_init.c
libdrvmgr_a_SOURCES += drvmgr_confdefs.h
libdrvmgr_a_SOURCES += drvmgr_for_each_dev.c
libdrvmgr_a_SOURCES += drvmgr_for_each_list_dev.c
libdrvmgr_a_SOURCES += drvmgr_func.c
libdrvmgr_a_SOURCES += drvmgr_func_call.c
libdrvmgr_a_SOURCES += drvmgr_list.c
libdrvmgr_a_SOURCES += drvmgr_list.h
libdrvmgr_a_SOURCES += drvmgr_lock.c
libdrvmgr_a_SOURCES += drvmgr_print.c
libdrvmgr_a_SOURCES += drvmgr_res.c
libdrvmgr_a_SOURCES += drvmgr_rw.c
libdrvmgr_a_SOURCES += drvmgr_translate.c
libdrvmgr_a_SOURCES += drvmgr_translate_check.c
libdrvmgr_a_SOURCES += drvmgr_unregister.c
include $(top_srcdir)/automake/local.am

112
cpukit/libdrvmgr/README Normal file
View File

@@ -0,0 +1,112 @@
DRIVER MANAGER
==============
See documentation in Aeroflex Gaisler Driver manual.
INITIALIZATION
==============
The Driver Manager can be intialized in two different ways:
1. during RTEMS startup
2. started by user, typically in the Init task
The driver manager is initalized during RTEMS startup in the
rtems_initialize_device_drivers() function when RTEMS is
configured with driver manager support.
When RTEMS is not configured with the driver manager, the manager
may still be initialized by the user after system startup, typically
from the Init() task.
The main difference between the two ways is when interrupt
is enabled. Interrupt is enabled for the first time by RTEMS when
the Init task is started. This means, for the first case, that
drivers can not use interrupt services until after the
initialization phase is over and the user request services from
the drivers. For the second case of initialization, this means
that driver must take extra care during initalization when interrupt
is enabled so that spurious interrupts are not generated and that the
system does not hang in an infinite IRQ loop.
Most of the problems above are solved for the two methods by
specifying in which initialization levels IRQ handling is done.
See Level 1 and Level 2 below.
Other differences is that IRQ, System Clock Timer, debug Console
and Console can be initalized by the help of the driver manager
when initialized during start up. Between Level0 and Level1 the
RTEMS I/O Manager drivers are initialized. The LEON3 BSP has
therefore two different versions of the basic drivers.
LEVEL0
------
The level of uninitialized devices that have been united with a
driver.
LEVEL1 - FIND/RESET/IRQ Clear
-----------------------------
The driver is for the first time informed of the presence of a
device. Only basic initialization.
- Find all hardware needed for IRQ, Console, Timer and hardware
that need to be reset.
- Reset hardware, so that interrupts are not generated by mistake
when enabled later on.
- Init low level non-interrupt (polling-mode) services needed by
drivers init LEVEL2 and onwards, such as
* Debug UART console for printk()
* Timer API (non-IRQ)
* GPIO (non-IRQ)
* Special non-main memory configuration, washing
- Register IRQ controller at BSP IRQ library
- Register Timer for system clock
- Register Console UART
During this intialization level interrupts may not be registered,
enabled or disabled at the IRQ controller. But, all IRQ sources
should be cleared to avoid spurious interrupts later on.
AFTER LEVEL1 - if initialized during startup
--------------------------------------------
The statically configured drivers are initialized as normally by RTEMS. The
hardware was found in LEVEL1.
CONFIGURE_BSP_PREREQUISITE_DRIVERS may initialize IRQ driver, or
IRQ lib initialized when IRQ controller was registered during LEVEL1.
LEVEL2
------
Initialize other device drivers than IRQ, Timer, console:
- ISR can be registered, enabled, disabled at IRQ controller
(IRQ is still masked by CPU interrupt level if initialized during
RTEMS startup)
- Timer API that does not require IRQ can be used
- printf() can be used
For standard peripherals this is the first initialization.
LEVEL3
------
Initialize drivers that require features/APIs provided by drivers
in LEVEL2.
Such features may involve services that require IRQ to be implemented.
LEVEL4
------
Unused extra level.
LEVEL INACTIVE - NOT ENABLED DEVICES
------------------------------------
List of devices that experienced:
- no driver found for device (not united)
- ignored (not united with a driver, forced by user)
- an error was reported by device driver during initialization

643
cpukit/libdrvmgr/drvmgr.c Normal file

File diff suppressed because it is too large Load Diff

965
cpukit/libdrvmgr/drvmgr.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
/* Find driver by driver-ID
*
* COPYRIGHT (c) 2011.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <drvmgr/drvmgr.h>
#include "drvmgr_internal.h"
/* Get driver from driver name */
struct drvmgr_drv *drvmgr_drv_by_id(uint64_t id)
{
struct rtems_driver_manager *mgr = &drv_mgr;
struct drvmgr_drv *drv = NULL;
/* NOTE: No locking is needed here since Driver list is supposed to be
* initialized once during startup, we treat it as a static
* read-only list
*/
drv = DRV_LIST_HEAD(&mgr->drivers);
while (drv) {
if (drv->drv_id == id)
break;
drv = drv->next;
}
return drv;
}

View File

@@ -0,0 +1,37 @@
/* Find driver by driver-name
*
* COPYRIGHT (c) 2011.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <string.h>
#include <drvmgr/drvmgr.h>
#include "drvmgr_internal.h"
/* Get driver from driver name */
struct drvmgr_drv *drvmgr_drv_by_name(const char *name)
{
struct rtems_driver_manager *mgr = &drv_mgr;
struct drvmgr_drv *drv = NULL;
if (!name)
return NULL;
/* NOTE: No locking is needed here since Driver list is supposed to be
* initialized once during startup, we treat it as a static
* read-only list
*/
drv = DRV_LIST_HEAD(&mgr->drivers);
while (drv) {
if (drv->name && (strcmp(drv->name, name) == 0))
break;
drv = drv->next;
}
return drv;
}

View File

@@ -0,0 +1,86 @@
/* Driver Manager Configuration file.
*
* COPYRIGHT (c) 2009.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
/*
* The configuration consist of an array with function pointers that
* register one or more drivers that will be used by the Driver Manger.
*
* The Functions are called in the order they are declared.
*
*/
#ifndef _DRIVER_MANAGER_CONFDEFS_H_
#define _DRIVER_MANAGER_CONFDEFS_H_
#include "drvmgr.h"
#ifdef __cplusplus
extern "C" {
#endif
extern struct drvmgr_drv_reg_func drvmgr_drivers[];
#ifdef CONFIGURE_INIT
#if 0 /* EXAMPLE: GPTIMER driver definition */
#define DRIVER_AMBAPP_GAISLER_GPTIMER_REG {gptimer_register_drv}
extern void gptimer_register_drv(void);
#endif
/* CONFIGURE DRIVER MANAGER */
struct drvmgr_drv_reg_func drvmgr_drivers[] = {
#if 0 /* EXAMPLE: GPTIMER Driver registration */
#ifdef CONFIGURE_DRIVER_AMBAPP_GAISLER_GPTIMER
DRIVER_AMBAPP_GAISLER_GPTIMER_REG,
#endif
#endif
/* Macros for adding custom drivers without needing to recompile
* kernel.
*/
#ifdef CONFIGURE_DRIVER_CUSTOM1
DRIVER_CUSTOM1_REG,
#endif
#ifdef CONFIGURE_DRIVER_CUSTOM2
DRIVER_CUSTOM2_REG,
#endif
#ifdef CONFIGURE_DRIVER_CUSTOM3
DRIVER_CUSTOM3_REG,
#endif
#ifdef CONFIGURE_DRIVER_CUSTOM4
DRIVER_CUSTOM4_REG,
#endif
#ifdef CONFIGURE_DRIVER_CUSTOM5
DRIVER_CUSTOM5_REG,
#endif
#ifdef CONFIGURE_DRIVER_CUSTOM6
DRIVER_CUSTOM6_REG,
#endif
#ifdef CONFIGURE_DRIVER_CUSTOM7
DRIVER_CUSTOM7_REG,
#endif
#ifdef CONFIGURE_DRIVER_CUSTOM8
DRIVER_CUSTOM8_REG,
#endif
#ifdef CONFIGURE_DRIVER_CUSTOM9
DRIVER_CUSTOM9_REG,
#endif
/* End array with NULL */
{NULL}
};
#endif /* CONFIGURE_INIT */
#ifdef __cplusplus
}
#endif
#endif /* _DRIVER_MANAGER_CONFDEFS_H_ */

View File

@@ -0,0 +1,34 @@
/* Find device by device name
*
* COPYRIGHT (c) 2011.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
*/
#include <string.h>
#include <drvmgr/drvmgr.h>
#include "drvmgr_internal.h"
static int dev_name_compare(struct drvmgr_dev *dev, void *arg)
{
const char *name = arg;
if (dev->name && (strcmp(dev->name, name) == 0))
return (int)dev;
else
return 0;
}
/* Get device by device name or bus name */
struct drvmgr_dev *drvmgr_dev_by_name(const char *name)
{
if (!name)
return NULL;
return (struct drvmgr_dev *)
drvmgr_for_each_dev(dev_name_compare, (void *)name, 0);
}

View File

@@ -0,0 +1,148 @@
/* Driver Manager Driver Interface Implementation.
*
* COPYRIGHT (c) 2009.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
*/
/*
* This is the part the device driver API, the functions rely on that the
* parent bus driver has implemented the neccessary operations correctly.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <drvmgr/drvmgr.h>
#include "drvmgr_internal.h"
/* Get device pointer from knowing the Driver and the Driver minor
* that was assigned to it
*/
int drvmgr_get_dev(
struct drvmgr_drv *drv,
int minor,
struct drvmgr_dev **pdev)
{
struct drvmgr_dev *dev;
if (!drv)
return -1;
DRVMGR_LOCK_READ();
dev = drv->dev;
while (dev) {
if (dev->minor_drv == minor)
break;
dev = dev->next_in_drv;
}
DRVMGR_UNLOCK();
if (!dev)
return -1;
if (pdev)
*pdev = dev;
return 0;
}
/* Get Bus frequency in HZ from bus driver */
int drvmgr_freq_get(
struct drvmgr_dev *dev,
int options,
unsigned int *freq_hz)
{
if (!dev || !dev->parent || !dev->parent->ops->freq_get)
return -1;
return dev->parent->ops->freq_get(dev, options, freq_hz);
}
/* Get driver prefix */
int drvmgr_get_dev_prefix(struct drvmgr_dev *dev, char *dev_prefix)
{
struct drvmgr_bus_params params;
if (!dev || !dev->parent || !dev->parent->ops->get_params)
return -1;
dev->parent->ops->get_params(dev, &params);
if (!params.dev_prefix)
return -1;
if (dev_prefix)
strcpy(dev_prefix, params.dev_prefix);
return 0;
}
/* Register an interrupt */
int drvmgr_interrupt_register(
struct drvmgr_dev *dev,
int index,
const char *info,
drvmgr_isr isr,
void *arg)
{
if (!dev || !dev->parent || !dev->parent->ops->int_register)
return -1;
if (!isr)
return -1;
return dev->parent->ops->int_register(dev, index, info, isr, arg);
}
/* Unregister an interrupt */
int drvmgr_interrupt_unregister(
struct drvmgr_dev *dev,
int index,
drvmgr_isr isr,
void *arg)
{
if (!dev || !dev->parent || !dev->parent->ops->int_unregister)
return -1;
if (!isr)
return -1;
return dev->parent->ops->int_unregister(dev, index, isr, arg);
}
int drvmgr_interrupt_clear(
struct drvmgr_dev *dev,
int index)
{
if (!dev || !dev->parent || !dev->parent->ops->int_clear)
return -1;
return dev->parent->ops->int_clear(dev, index);
}
int drvmgr_interrupt_unmask(
struct drvmgr_dev *dev,
int index)
{
if (!dev || !dev->parent || !dev->parent->ops->int_unmask)
return -1;
return dev->parent->ops->int_unmask(dev, index);
}
int drvmgr_interrupt_mask(
struct drvmgr_dev *dev,
int index)
{
if (!dev || !dev->parent || !dev->parent->ops->int_mask)
return -1;
return dev->parent->ops->int_mask(dev, index);
}
int drvmgr_on_rootbus(struct drvmgr_dev *dev)
{
if (dev->parent && dev->parent->dev && dev->parent->dev->parent)
return 0;
else
return 1;
}

View File

@@ -0,0 +1,104 @@
/* Iterate over device tree topology, breadth or depth-first
*
* COPYRIGHT (c) 2009.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <string.h>
#include <drvmgr/drvmgr.h>
#include <drvmgr/drvmgr_list.h>
#include "drvmgr_internal.h"
/* Traverse device tree breadth-first. Supports up to 31 buses */
static int drvmgr_for_each_dev_breadth(
int (*func)(struct drvmgr_dev *dev, void *arg),
void *arg
)
{
int ret = 0, i, pos;
struct drvmgr_bus *bus, *buses[32];
struct drvmgr_dev *dev;
pos = 0;
memset(&buses[0], 0, sizeof(buses));
buses[pos++] = drv_mgr.root_dev.bus; /* Get root bus */
for (i = 0, bus = buses[0]; buses[i]; i++, bus = buses[i]) {
dev = bus->children;
while (dev) {
ret = func(dev, arg);
if (ret != 0)
break;
if (dev->bus && pos < 31)
buses[pos++] = dev->bus;
dev = dev->next_in_bus;
}
}
return ret;
}
/* Traverse device tree depth-first. */
static int drvmgr_for_each_dev_depth(
int (*func)(struct drvmgr_dev *dev, void *arg),
void *arg
)
{
int ret = 0;
struct drvmgr_dev *dev;
/* Get first device */
dev = drv_mgr.root_dev.bus->children;
while (dev) {
ret = func(dev, arg);
if (ret != 0)
break;
if (dev->bus && dev->bus->children) {
dev = dev->bus->children;
} else {
next_dev:
if (dev->next_in_bus == NULL) {
/* Step up one level... back to parent bus */
dev = dev->parent->dev;
if (dev == &drv_mgr.root_dev)
break;
goto next_dev;
} else {
dev = dev->next_in_bus;
}
}
}
return ret;
}
/* Traverse device tree depth-first or breadth-first */
int drvmgr_for_each_dev(
int (*func)(struct drvmgr_dev *dev, void *arg),
void *arg,
int options
)
{
int ret;
DRVMGR_LOCK_READ();
/* Get Root Device */
if (drv_mgr.root_dev.bus->children != NULL) {
if (options & DRVMGR_FED_BF)
ret = drvmgr_for_each_dev_breadth(func, arg);
else
ret = drvmgr_for_each_dev_depth(func, arg);
} else
ret = 0;
DRVMGR_UNLOCK();
return ret;
}

View File

@@ -0,0 +1,44 @@
/* Iterate over one list of devices used internally by driver manager
*
* COPYRIGHT (c) 2009.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <drvmgr/drvmgr.h>
#include <drvmgr/drvmgr_list.h>
#include "drvmgr_internal.h"
int drvmgr_for_each_listdev(
struct drvmgr_list *devlist,
unsigned int state_set_mask,
unsigned int state_clr_mask,
int (*func)(struct drvmgr_dev *dev, void *arg),
void *arg
)
{
struct drvmgr_dev *dev;
int ret = 0;
DRVMGR_LOCK_READ();
/* Get First Device */
dev = DEV_LIST_HEAD(devlist);
while (dev) {
if (((state_set_mask != 0) && ((dev->state & state_set_mask) == state_set_mask)) ||
((state_clr_mask != 0) && ((dev->state & state_clr_mask) == 0)) ||
((state_set_mask == 0) && (state_clr_mask == 0))) {
ret = func(dev, arg);
if (ret != 0)
break;
}
dev = dev->next;
}
DRVMGR_UNLOCK();
return ret;
}

View File

@@ -0,0 +1,42 @@
/* Driver Manager optional dynamic function interface
*
* COPYRIGHT (c) 2011.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <drvmgr/drvmgr.h>
/* Get Function from Function ID */
int drvmgr_func_get(void *obj, int funcid, void **func)
{
int objtype;
struct drvmgr_func *f;
if (!obj)
return DRVMGR_FAIL;
objtype = *(int *)obj;
if (objtype == DRVMGR_OBJ_BUS)
f = ((struct drvmgr_bus *)obj)->funcs;
else if (objtype == DRVMGR_OBJ_DRV)
f = ((struct drvmgr_drv *)obj)->funcs;
else
return DRVMGR_FAIL;
if (f == NULL)
return DRVMGR_FAIL;
while (f->funcid != DRVMGR_FUNCID_NONE) {
if (f->funcid == funcid) {
*func = f->func;
return DRVMGR_OK;
}
f++;
}
return DRVMGR_FAIL;
}

View File

@@ -0,0 +1,21 @@
/* Driver Manager optional dynamic function interface
*
* COPYRIGHT (c) 2011.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <drvmgr/drvmgr.h>
/* Lookup function from function ID and call it using given arguments */
int drvmgr_func_call(void *obj, int funcid, void *a, void *b, void *c, void *d)
{
int (*func)(void *arg1, void *arg2, void *arg3, void *arg4) = NULL;
if (drvmgr_func_get(obj, funcid, (void *)&func) != DRVMGR_OK)
return DRVMGR_FAIL;
return func(a, b, c, d);
}

View File

@@ -0,0 +1,26 @@
/* Driver Manager Initialization
*
* COPYRIGHT (c) 2009.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <drvmgr/drvmgr.h>
/* Init driver manager - all in one go. Typically called from Init task when
* user wants to initilize driver manager after startup, otherwise not used.
*/
int drvmgr_init(void)
{
int level;
_DRV_Manager_initialization();
for (level = 1; level <= DRVMGR_LEVEL_MAX; level++)
_DRV_Manager_init_level(level);
return 0;
}

View File

@@ -0,0 +1,70 @@
/* Private driver manager declarations
*
* COPYRIGHT (c) 2009.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
/* Structure hold all information the driver manager needs to know of. Used
* internally by Driver Manager routines.
*/
struct rtems_driver_manager {
int level;
int initializing_objs;
/* Device tree Lock */
rtems_id lock;
/* The first device - The root device and it's driver */
struct drvmgr_drv *root_drv;
struct drvmgr_dev root_dev;
/*!< Linked list of all registered drivers */
struct drvmgr_list drivers;
/* Buses that reached a certain initialization level.
* Lists by Level:
* N=0 - Not intialized, just registered
* N=1..MAX-1 - Reached init level N
* N=MAX - Successfully initialized bus
*/
struct drvmgr_list buses[DRVMGR_LEVEL_MAX+1];
/* Buses failed to initialize or has been removed by not freed */
struct drvmgr_list buses_inactive;
/* Devices that reached a certain initialization level.
* Lists by Level:
* N=0 - Not intialized, just registered
* N=1..MAX-1 - Reached init level N
* N=MAX - Successfully initialized device
*/
struct drvmgr_list devices[DRVMGR_LEVEL_MAX+1];
/*!< Devices failed to initialize, removed, ignored, no driver */
struct drvmgr_list devices_inactive;
};
extern struct rtems_driver_manager drv_mgr;
extern void _DRV_Manager_Lock(void);
extern void _DRV_Manager_Unlock(void);
extern int _DRV_Manager_Init_Lock(void);
/* The best solution is to implement the locking with a RW lock, however there
* is no such API available. Care must be taken so that dead-lock isn't created
* for example in recursive functions.
*/
#if defined(DRVMGR_USE_LOCKS) && (DRVMGR_USE_LOCKS == 1)
#define DRVMGR_LOCK_INIT() _DRV_Manager_Init_Lock()
#define DRVMGR_LOCK_WRITE() _DRV_Manager_Lock()
#define DRVMGR_LOCK_READ() _DRV_Manager_Lock()
#define DRVMGR_UNLOCK() _DRV_Manager_Unlock()
#else
/* no locking */
#define DRVMGR_LOCK_INIT()
#define DRVMGR_LOCK_WRITE()
#define DRVMGR_LOCK_READ()
#define DRVMGR_UNLOCK()
#endif

View File

@@ -0,0 +1,67 @@
/* Driver Manager List Interface Implementation.
*
* COPYRIGHT (c) 2009.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <stdlib.h>
#include <drvmgr/drvmgr_list.h>
/* LIST interface */
void drvmgr_list_init(struct drvmgr_list *list, int offset)
{
list->head = list->tail = NULL;
list->ofs = offset;
}
void drvmgr_list_empty(struct drvmgr_list *list)
{
list->head = list->tail = NULL;
}
void drvmgr_list_add_head(struct drvmgr_list *list, void *entry)
{
LIST_FIELD(list, entry) = list->head;
if (list->head == NULL)
list->tail = entry;
list->head = entry;
}
void drvmgr_list_add_tail(struct drvmgr_list *list, void *entry)
{
if (list->tail == NULL)
list->head = entry;
else
LIST_FIELD(list, list->tail) = entry;
LIST_FIELD(list, entry) = NULL;
list->tail = entry;
}
void drvmgr_list_remove_head(struct drvmgr_list *list)
{
list->head = LIST_FIELD(list, list->head);
if (list->head == NULL)
list->tail = NULL;
}
void drvmgr_list_remove(struct drvmgr_list *list, void *entry)
{
void **prevptr = &list->head;
void *curr, *prev;
prev = NULL;
curr = list->head;
while (curr != entry) {
prev = curr;
prevptr = &LIST_FIELD(list, curr);
curr = LIST_FIELD(list, curr);
}
*prevptr = LIST_FIELD(list, entry);
if (list->tail == entry)
list->tail = prev;
}

View File

@@ -0,0 +1,79 @@
/* Linked list help functions used by driver manager.
*
* COPYRIGHT (c) 2009.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
/*
* Help functions for the Driver Manager. Implements a singly linked list
* with head and tail pointers for fast insertions/deletions to head and
* tail in list.
*/
#ifndef _DRVIVER_MANAGER_LIST_H_
#define _DRVIVER_MANAGER_LIST_H_
#ifdef __cplusplus
extern "C" {
#endif
/*! List description, Singly link list with head and tail pointers. */
struct drvmgr_list {
void *head; /*!< First entry in queue */
void *tail; /*!< Last entry in queue */
int ofs; /*!< Offset into head and tail to find next field */
};
/* Static initialization of list */
#define LIST_INITIALIZER(type, field) {NULL, NULL, offsetof(type, field)}
/* Return the first element in list */
#define LIST_HEAD(list, type) ((type *)(list)->head)
/* Return the last element in list */
#define LIST_TAIL(list, type) ((type *)(list)->tail)
/* Get the next pointer of an entry */
#define LIST_FIELD(list, entry) (*(void **)((char *)(entry) + (list)->ofs))
/* Return the next emlement in list */
#define LIST_NEXT(list, entry, type) ((type *)(LIST_FIELD(list, entry)))
/* Iterate through all entries in list */
#define LIST_FOR_EACH(list, entry, type) \
for (entry = LIST_HEAD(list, type); \
entry; \
entry = LIST_NEXT(list, entry, type))
/*! Initialize a list during runtime
*
* \param list The list to initialize
* \param offset The number of bytes into the entry structure the next pointer
* is found
*/
extern void drvmgr_list_init(struct drvmgr_list *list, int offset);
/*! Clear list */
extern void drvmgr_list_empty(struct drvmgr_list *list);
/*! Add entry to front of list */
extern void drvmgr_list_add_head(struct drvmgr_list *list, void *entry);
/*! Add entry to end of list */
extern void drvmgr_list_add_tail(struct drvmgr_list *list, void *entry);
/*! Remove entry from front of list */
extern void drvmgr_list_remove_head(struct drvmgr_list *list);
/*! Remove entry from anywhere in list */
extern void drvmgr_list_remove(struct drvmgr_list *list, void *entry);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,38 @@
/* Driver Manager Internal locking implementation
*
* COPYRIGHT (c) 2009.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <rtems.h>
#include <drvmgr/drvmgr.h>
#include "drvmgr_internal.h"
void _DRV_Manager_Lock(void)
{
rtems_semaphore_obtain(drv_mgr.lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
}
void _DRV_Manager_Unlock(void)
{
rtems_semaphore_release(drv_mgr.lock);
}
int _DRV_Manager_Init_Lock(void)
{
int rc;
rc = rtems_semaphore_create(
rtems_build_name('D', 'R', 'V', 'M'),
1,
RTEMS_DEFAULT_ATTRIBUTES,
0,
&drv_mgr.lock);
if (rc != RTEMS_SUCCESSFUL)
return -1;
return 0;
}

View File

@@ -0,0 +1,457 @@
/* Driver Manager Information printing Interface Implementation
*
* COPYRIGHT (c) 2009.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
/*
* These functions print stuff about the driver manager, what devices were
* found and were united with a driver, the Bus topology, memory taken, etc.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <drvmgr/drvmgr.h>
#include "drvmgr_internal.h"
typedef void (*fun_ptr)(void);
static int print_dev_found(struct drvmgr_dev *dev, void *arg)
{
char **pparg = arg;
if (pparg && *pparg) {
printf(*pparg);
*pparg = NULL;
}
printf(" DEV %p %s on bus %p\n", dev,
dev->name ? dev->name : "NO_NAME", dev->parent);
return 0; /* Continue to next device */
}
void drvmgr_print_devs(unsigned int options)
{
struct rtems_driver_manager *mgr = &drv_mgr;
char *parg;
/* Print Drivers */
if (options & PRINT_DEVS_ASSIGNED) {
parg = " --- DEVICES ASSIGNED TO DRIVER ---\n";
drvmgr_for_each_listdev(&mgr->devices[DRVMGR_LEVEL_MAX],
DEV_STATE_UNITED, 0, print_dev_found, &parg);
if (parg != NULL)
printf("\n NO DEVICES WERE ASSIGNED A DRIVER\n");
}
if (options & PRINT_DEVS_UNASSIGNED) {
parg = "\n --- DEVICES WITHOUT DRIVER ---\n";
drvmgr_for_each_listdev(&mgr->devices_inactive, 0,
DEV_STATE_UNITED, print_dev_found, &parg);
if (parg != NULL)
printf("\n NO DEVICES WERE WITHOUT DRIVER\n");
}
if (options & PRINT_DEVS_FAILED) {
parg = "\n --- DEVICES FAILED TO INITIALIZE ---\n";
drvmgr_for_each_listdev(&mgr->devices_inactive,
DEV_STATE_INIT_FAILED, 0, print_dev_found, &parg);
if (parg != NULL)
printf("\n NO DEVICES FAILED TO INITIALIZE\n");
}
if (options & PRINT_DEVS_IGNORED) {
parg = "\n --- DEVICES IGNORED ---\n";
drvmgr_for_each_listdev(&mgr->devices_inactive,
DEV_STATE_IGNORED, 0, print_dev_found, &parg);
if (parg != NULL)
printf("\n NO DEVICES WERE IGNORED\n");
}
printf("\n\n");
}
static int drvmgr_topo_func(struct drvmgr_dev *dev, void *arg)
{
char prefix[32];
int depth = dev->parent->depth;
if (depth > 30)
return 0; /* depth more than 30 not supported */
memset(prefix, ' ', depth + 1);
prefix[depth + 1] = '\0';
printf(" %s|-> DEV %p %s\n", prefix, dev,
dev->name ? dev->name : "NO_NAME");
return 0;
}
void drvmgr_print_topo(void)
{
/* Print Bus topology */
printf(" --- BUS TOPOLOGY ---\n");
drvmgr_for_each_dev(drvmgr_topo_func, NULL, DRVMGR_FED_DF);
printf("\n\n");
}
/* Print the memory usage */
void drvmgr_print_mem(void)
{
struct rtems_driver_manager *mgr = &drv_mgr;
struct drvmgr_bus *bus;
struct drvmgr_dev *dev;
struct drvmgr_drv *drv;
struct drvmgr_bus_res *node;
struct drvmgr_drv_res *res;
struct drvmgr_key *key;
unsigned int busmem = 0;
unsigned int devmem = 0;
unsigned int drvmem = 0;
unsigned int resmem = 0;
unsigned int devprivmem = 0;
DRVMGR_LOCK_READ();
bus = BUS_LIST_HEAD(&mgr->buses[DRVMGR_LEVEL_MAX]);
while (bus) {
busmem += sizeof(struct drvmgr_bus);
/* Get size of resources on this bus */
node = bus->reslist;
while (node) {
resmem += sizeof(struct drvmgr_bus_res);
res = node->resource;
while (res->keys) {
resmem += sizeof(struct drvmgr_drv_res);
key = res->keys;
while (key->key_type != KEY_TYPE_NONE) {
resmem += sizeof
(struct drvmgr_key);
key++;
}
resmem += sizeof(struct drvmgr_key);
res++;
}
node = node->next;
}
bus = bus->next;
}
drv = DRV_LIST_HEAD(&mgr->drivers);
while (drv) {
drvmem += sizeof(struct drvmgr_drv);
drv = drv->next;
}
dev = DEV_LIST_HEAD(&mgr->devices[DRVMGR_LEVEL_MAX]);
while (dev) {
devmem += sizeof(struct drvmgr_dev);
if (dev->drv && dev->drv->dev_priv_size > 0)
devprivmem += dev->drv->dev_priv_size;
dev = dev->next;
}
DRVMGR_UNLOCK();
printf(" --- MEMORY USAGE ---\n");
printf(" BUS: %d bytes\n", busmem);
printf(" DRV: %d bytes\n", drvmem);
printf(" DEV: %d bytes\n", devmem);
printf(" DEV private: %d bytes\n", devprivmem);
printf(" RES: %d bytes\n", resmem);
printf(" TOTAL: %d bytes\n",
busmem + drvmem + devmem + devprivmem + resmem);
printf("\n\n");
}
/* Print the memory usage */
void drvmgr_summary(void)
{
struct rtems_driver_manager *mgr = &drv_mgr;
struct drvmgr_bus *bus;
struct drvmgr_dev *dev;
struct drvmgr_drv *drv;
int i, buscnt = 0, devcnt = 0, drvcnt = 0;
printf(" --- SUMMARY ---\n");
drv = DRV_LIST_HEAD(&mgr->drivers);
while (drv) {
drvcnt++;
drv = drv->next;
}
printf(" NUMBER OF DRIVERS: %d\n", drvcnt);
DRVMGR_LOCK_READ();
for (i = 0; i <= DRVMGR_LEVEL_MAX; i++) {
buscnt = 0;
bus = BUS_LIST_HEAD(&mgr->buses[i]);
while (bus) {
buscnt++;
bus = bus->next;
}
if (buscnt > 0) {
printf(" NUMBER OF BUSES IN LEVEL[%d]: %d\n",
i, buscnt);
}
}
for (i = 0; i <= DRVMGR_LEVEL_MAX; i++) {
devcnt = 0;
dev = DEV_LIST_HEAD(&mgr->devices[i]);
while (dev) {
devcnt++;
dev = dev->next;
}
if (devcnt > 0) {
printf(" NUMBER OF DEVS IN LEVEL[%d]: %d\n",
i, devcnt);
}
}
DRVMGR_UNLOCK();
printf("\n\n");
}
static void print_info(void *p, char *str)
{
printf(" ");
puts(str);
}
void drvmgr_info_dev(struct drvmgr_dev *dev, unsigned int options)
{
if (!dev)
return;
printf(" -- DEVICE %p --\n", dev);
if (options & OPTION_DEV_GENINFO) {
printf(" PARENT BUS: %p\n", dev->parent);
printf(" NAME: %s\n", dev->name ? dev->name : "NO_NAME");
printf(" STATE: 0x%08x\n", dev->state);
if (dev->bus)
printf(" BRIDGE TO: %p\n", dev->bus);
printf(" INIT LEVEL: %d\n", dev->level);
printf(" ERROR: %d\n", dev->error);
printf(" MINOR BUS: %d\n", dev->minor_bus);
if (dev->drv) {
printf(" MINOR DRV: %d\n", dev->minor_drv);
printf(" DRIVER: %p (%s)\n", dev->drv,
dev->drv->name ? dev->drv->name : "NO_NAME");
printf(" PRIVATE: %p\n", dev->priv);
}
}
if (options & OPTION_DEV_BUSINFO) {
printf(" --- DEVICE INFO FROM BUS DRIVER ---\n");
if (!dev->parent)
printf(" !! device has no parent bus !!\n");
else if (dev->parent->ops->info_dev)
dev->parent->ops->info_dev(dev, print_info, NULL);
else
printf(" Bus doesn't implement info_dev func\n");
}
if (options & OPTION_DEV_DRVINFO) {
if (dev->drv) {
printf(" --- DEVICE INFO FROM DEVICE DRIVER ---\n");
if (dev->drv->ops->info)
dev->drv->ops->info(dev, print_info, NULL, 0, 0);
else
printf(" Driver doesn't implement info func\n");
}
}
}
static void drvmgr_info_bus_map(struct drvmgr_map_entry *map)
{
if (map == NULL)
printf(" Addresses mapped 1:1\n");
else if (map == DRVMGR_TRANSLATE_NO_BRIDGE)
printf(" No bridge in this direction\n");
else {
while (map->size != 0) {
printf(" 0x%08lx-0x%08lx => 0x%08lx-0x%08lx %s\n",
(unsigned long)map->from_adr,
(unsigned long)(map->from_adr + map->size - 1),
(unsigned long)map->to_adr,
(unsigned long)(map->to_adr + map->size - 1),
map->name ? map->name : "no label");
map++;
}
}
}
void drvmgr_info_bus(struct drvmgr_bus *bus, unsigned int options)
{
struct drvmgr_dev *dev;
/* Print Driver */
printf("-- BUS %p --\n", bus);
printf(" BUS TYPE: %d\n", bus->bus_type);
printf(" DEVICE: %p (%s)\n", bus->dev,
bus->dev->name ? bus->dev->name : "NO_NAME");
printf(" OPS: %p\n", bus->ops);
printf(" CHILDREN: %d devices\n", bus->dev_cnt);
printf(" LEVEL: %d\n", bus->level);
printf(" STATE: 0x%08x\n", bus->state);
printf(" ERROR: %d\n", bus->error);
/* Print address mappings up- (to parent) and down- (from parent to
* this bus) stream the bridge of this bus
*/
printf(" DOWN STREAMS BRIDGE MAPPINGS (from parent to this bus)\n");
drvmgr_info_bus_map(bus->maps_down);
printf(" UP STREAMS BRIDGE MAPPINGS (from this bus to parent)\n");
drvmgr_info_bus_map(bus->maps_up);
/* Print Devices on this bus? */
if (options & OPTION_BUS_DEVS) {
printf(" CHILDREN:\n");
DRVMGR_LOCK_READ();
dev = bus->children;
while (dev) {
printf(" |- DEV[%02d]: %p %s\n", dev->minor_bus,
dev, dev->name ? dev->name : "NO_NAME");
dev = dev->next_in_bus;
}
DRVMGR_UNLOCK();
}
}
char *drv_ops_names[DRV_OPS_NUM] = {
"init[1]:",
"init[2]:",
"init[3]:",
"init[4]:",
"remove: ",
"info: "
};
void drvmgr_info_drv(struct drvmgr_drv *drv, unsigned int options)
{
struct drvmgr_dev *dev;
fun_ptr *ppfunc;
int i;
/* Print Driver */
printf(" -- DRIVER %p --\n", drv);
printf(" DRIVER ID: 0x%llx\n", drv->drv_id);
printf(" NAME: %s\n", drv->name ? drv->name : "NO_NAME");
printf(" BUS TYPE: %d\n", drv->bus_type);
printf(" OPERATIONS:\n");
for (i = 0, ppfunc = (fun_ptr *)&drv->ops->init[0]; i<DRV_OPS_NUM; i++)
printf(" %s %p\n", drv_ops_names[i], ppfunc[i]);
printf(" NO. DEVICES: %d\n", drv->dev_cnt);
/* Print devices united with this driver? */
if (options & OPTION_DRV_DEVS) {
DRVMGR_LOCK_READ();
dev = drv->dev;
while (dev) {
printf(" DEV[%02d]: %p %s\n", dev->minor_drv,
dev, dev->name ? dev->name : "NO_NAME");
dev = dev->next_in_drv;
}
DRVMGR_UNLOCK();
}
}
void (*info_obj[3])(void *obj, unsigned int) = {
/* DRVMGR_OBJ_DRV */ (void (*)(void *, unsigned int))drvmgr_info_drv,
/* DRVMGR_OBJ_BUS */ (void (*)(void *, unsigned int))drvmgr_info_bus,
/* DRVMGR_OBJ_DEV */ (void (*)(void *, unsigned int))drvmgr_info_dev,
};
/* Get information about a device/bus/driver */
void drvmgr_info(void *id, unsigned int options)
{
int obj_type;
void (*func)(void *, unsigned int);
if (!id)
return;
obj_type = *(int *)id;
if ((obj_type < DRVMGR_OBJ_DRV) || (obj_type > DRVMGR_OBJ_DEV))
return;
func = info_obj[obj_type - 1];
func(id, options);
}
void drvmgr_info_devs_on_bus(struct drvmgr_bus *bus, unsigned int options)
{
struct drvmgr_dev *dev;
/* Print All Devices on Bus */
printf("\n\n -= All Devices on BUS %p =-\n\n", bus);
dev = bus->children;
while (dev) {
drvmgr_info_dev(dev, options);
puts("");
dev = dev->next_in_bus;
}
if ((options & OPTION_RECURSIVE) == 0)
return;
/* This device provides a bus, print the bus */
dev = bus->children;
while (dev) {
if (dev->bus)
drvmgr_info_devs_on_bus(dev->bus, options);
dev = dev->next_in_bus;
}
}
void drvmgr_info_devs(unsigned int options)
{
struct rtems_driver_manager *mgr = &drv_mgr;
struct drvmgr_dev *dev;
/* Print device information of all devices and their child devices */
dev = &mgr->root_dev;
drvmgr_info_devs_on_bus(dev->bus, options);
printf("\n\n");
}
void drvmgr_info_drvs(unsigned int options)
{
struct rtems_driver_manager *mgr = &drv_mgr;
struct drvmgr_drv *drv;
drv = DRV_LIST_HEAD(&mgr->drivers);
while (drv) {
drvmgr_info_drv(drv, options);
puts("\n");
drv = drv->next;
}
}
void drvmgr_info_buses(unsigned int options)
{
struct rtems_driver_manager *mgr = &drv_mgr;
struct drvmgr_bus *bus;
bus = BUS_LIST_HEAD(&mgr->buses[DRVMGR_LEVEL_MAX]);
while (bus) {
drvmgr_info_bus(bus, options);
puts("\n");
bus = bus->next;
}
}

View File

@@ -0,0 +1,102 @@
/* Driver Manager Driver Resource Interface Implementation.
*
* COPYRIGHT (c) 2009.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <string.h>
#include <drvmgr/drvmgr.h>
/* Find all the resource keys for a device among all bus resources */
int drvmgr_keys_get(struct drvmgr_dev *dev, struct drvmgr_key **keys)
{
struct drvmgr_bus *bus;
struct drvmgr_bus_res *node;
struct drvmgr_drv_res *res;
uint64_t drv_id;
bus = dev->parent;
if (!bus || !dev->drv)
return -1;
drv_id = dev->drv->drv_id;
/* Loop all resource arrays */
node = bus->reslist;
while (node) {
/* Find driver ID in resource array */
res = &node->resource[0];
while (res->drv_id) {
if (res->drv_id == drv_id) {
/* Found resource matching driver, now check
* that this resource is for this device.
*/
if (dev->minor_bus == res->minor_bus) {
/* Matching driver and core number */
if (keys)
*keys = res->keys;
return 0;
}
}
res++;
}
node = node->next;
}
if (keys)
*keys = NULL;
return 1;
}
/* Return key that matches key name */
struct drvmgr_key *drvmgr_key_get(
struct drvmgr_key *keys,
char *key_name)
{
struct drvmgr_key *key;
if (!keys)
return NULL;
key = keys;
while (key->key_type != KEY_TYPE_NONE) {
if (strcmp(key_name, key->key_name) == 0)
return key;
key++;
}
return NULL;
}
union drvmgr_key_value *drvmgr_key_val_get(
struct drvmgr_key *keys,
char *key_name,
int key_type)
{
struct drvmgr_key *key_match;
key_match = drvmgr_key_get(keys, key_name);
if (key_match) {
/* Found key, put pointer to value into */
if ((key_type == -1) || (key_match->key_type == key_type))
return &key_match->key_value;
}
return NULL;
}
union drvmgr_key_value *drvmgr_dev_key_get(
struct drvmgr_dev *dev,
char *key_name,
int key_type)
{
struct drvmgr_key *keys = NULL;
/* Find first entry in key array for the device */
if (drvmgr_keys_get(dev, &keys))
return NULL;
/* Find a specific key among the device keys */
return drvmgr_key_val_get(keys, key_name, key_type);
}

View File

@@ -0,0 +1,52 @@
/* Driver Manager Read/Write Interface Implementation.
*
* COPYRIGHT (c) 2009.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <string.h>
#include <drvmgr/drvmgr.h>
/* Set a range of memory in 128 byte chunks.
* This call will take 128 bytes for buffer on stack
*/
void drvmgr_rw_memset(
void *dstadr,
int c,
size_t n,
void *a,
drvmgr_wmem_arg wmem
)
{
unsigned long long buf[16+1]; /* Extra bytes after data are reserved
* for optimizations by write_mem */
int txlen;
char *adr;
if (n <= 0)
return;
if (n > sizeof(unsigned long long)*16)
txlen = sizeof(unsigned long long)*16;
else
txlen = n;
memset(buf, c, txlen);
adr = dstadr;
do {
wmem(adr, (const void *)&buf[0], txlen, a);
adr += txlen;
n -= txlen;
/* next length to transmitt */
if (n > 16*sizeof(unsigned long long))
txlen = 16*sizeof(unsigned long long);
else
txlen = n;
} while (n > 0);
}

View File

@@ -0,0 +1,149 @@
/* Driver Manager Driver Translate Interface Implementation
*
* COPYRIGHT (c) 2010.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
/*
* Used by device drivers. The functions rely on that the parent bus driver
* has implemented the neccessary operations correctly.
*
* The translate functions are used to translate addresses between buses
* for DMA cores located on a "remote" bus, or for memory-mapped obtaining
* an address that can be used to access an remote bus.
*
* For example, PCI I/O might be memory-mapped at the PCI Host bridge,
* say address 0xfff10000-0xfff1ffff is mapped to the PCI I/O address
* of 0x00000000-0x0000ffff. The PCI Host bridge driver may then set up
* a map so that a driver that get PCI address 0x100 can translate that
* into 0xfff10100.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <drvmgr/drvmgr.h>
#include "drvmgr_internal.h"
unsigned int drvmgr_translate_bus(
struct drvmgr_bus *from,
struct drvmgr_bus *to,
int reverse,
void *src_address,
void **dst_address)
{
struct drvmgr_bus *path[16];
int dir, levels, i;
void *dst, *from_adr, *to_adr;
struct drvmgr_map_entry *map;
struct drvmgr_bus *bus;
unsigned int sz;
struct drvmgr_bus *bus_bot, *bus_top;
dst = src_address;
sz = 0xffffffff;
if (from == to) /* no need translating addresses when on same bus */
goto out;
/* Always find translation path from remote bus towards root bus. All
* buses have root bus has parent at some level
*/
if (from->depth > to->depth) {
bus_bot = from;
bus_top = to;
dir = 0;
} else {
bus_bot = to;
bus_top = from;
dir = 1;
}
levels = bus_bot->depth - bus_top->depth;
if (levels >= 16)
return 0; /* Does not support such a big depth */
i = 0;
while ((bus_bot != NULL) && bus_bot != bus_top) {
if (dir)
path[(levels - 1) - i] = bus_bot;
else
path[i] = bus_bot;
i++;
bus_bot = bus_bot->dev->parent;
}
if (bus_bot == NULL)
return 0; /* from -> to is not linearly connected */
for (i = 0; i < levels; i++) {
bus = path[i];
if ((dir && reverse) || (!dir && !reverse))
map = bus->maps_up;
else
map = bus->maps_down;
if (map == NULL)
continue; /* No translation needed - 1:1 mapping */
if (map == DRVMGR_TRANSLATE_NO_BRIDGE) {
sz = 0;
break; /* No bridge interface in this direction */
}
while (map->size != 0) {
if (reverse) {
/* Opposite direction */
from_adr = map->to_adr;
to_adr = map->from_adr;
} else {
from_adr = map->from_adr;
to_adr = map->to_adr;
}
if ((dst >= from_adr) &&
(dst <= (from_adr + (map->size - 1)))) {
if (((from_adr + (map->size - 1)) - dst) < sz)
sz = (from_adr + (map->size - 1)) - dst;
dst = (dst - from_adr) + to_adr;
break;
}
map++;
}
/* quit if no matching translation information */
if (map->size == 0) {
sz = 0;
break;
}
}
out:
if (dst_address)
*dst_address = dst;
return sz;
}
unsigned int drvmgr_translate(
struct drvmgr_dev *dev,
unsigned int options,
void *src_address,
void **dst_address)
{
struct drvmgr_bus *to, *from;
int rev = 0;
rev = (~options) & 1;
if ((options == CPUMEM_TO_DMA) || (options == DMAMEM_FROM_CPU)) {
from = drv_mgr.root_dev.bus;
to = dev->parent;
} else { /* CPUMEM_FROM_DMA || DMAMEM_TO_CPU */
from = dev->parent;
to = drv_mgr.root_dev.bus;
}
return drvmgr_translate_bus(from, to, rev, src_address, dst_address);
}

View File

@@ -0,0 +1,35 @@
/* Driver Manager Driver Translate Interface Implementation
*
* COPYRIGHT (c) 2010.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <drvmgr/drvmgr.h>
/* Calls drvmgr_translate() to translate an address range and check the result,
* a printout is generated if the check fails. See paramters of
* drvmgr_translate().
* If size=0 only the starting address is not checked.
*/
int drvmgr_translate_check(
struct drvmgr_dev *dev,
unsigned int options,
void *src_address,
void **dst_address,
unsigned int size)
{
unsigned int max;
max = drvmgr_translate(dev, options, src_address, dst_address);
if (max == 0 || (max < size && (size != 0))) {
printk(" ### dev %p (%s) failed mapping %p\n",
dev, dev->name ? dev->name : "unnamed", src_address);
return -1;
}
return 0;
}

View File

@@ -0,0 +1,186 @@
/* Driver Manager Device Unregister (removal) implementation
*
* COPYRIGHT (c) 2011.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#include <stdlib.h>
#include <drvmgr/drvmgr.h>
#include <drvmgr/drvmgr_list.h>
#include "drvmgr_internal.h"
/* Unregister all children on a bus.
*
* This function is called from the bus driver, from a "safe" state where
* devices will not be added or removed on this particular bus at this time
*/
int drvmgr_children_unregister(struct drvmgr_bus *bus)
{
int err;
while (bus->children != NULL) {
err = drvmgr_dev_unregister(bus->children);
if (err != DRVMGR_OK) {
/* An error occured */
bus->children->error = err;
return err;
}
}
return DRVMGR_OK;
}
/* Unregister a BUS and all it's devices.
*
* It is up to the bus driver to remove all it's devices, either manually
* one by one calling drvmgr_dev_unregister(), or by letting the driver
* manager unregister all children by calling drvmgr_children_unregister().
*/
int drvmgr_bus_unregister(struct drvmgr_bus *bus)
{
struct rtems_driver_manager *mgr = &drv_mgr;
struct drvmgr_list *list;
if (bus->ops->remove == NULL)
return DRVMGR_ENOSYS;
/* Call Bus driver to clean things up, it must remove all children */
bus->error = bus->ops->remove(bus);
if (bus->error != DRVMGR_OK)
return bus->error;
/* Check that bus driver has done its job and removed all children */
if (bus->children != NULL)
return DRVMGR_FAIL;
/* Remove References to bus */
bus->dev->bus = NULL;
DRVMGR_LOCK_WRITE();
/* Remove bus from bus-list */
if (bus->state & BUS_STATE_LIST_INACTIVE)
list = &mgr->buses_inactive;
else
list = &mgr->buses[bus->level];
drvmgr_list_remove(list, bus);
DRVMGR_UNLOCK();
/* All references to this bus has been removed at this point */
free(bus);
return DRVMGR_OK;
}
/* Separate Driver and Device from each other */
int drvmgr_dev_drv_separate(struct drvmgr_dev *dev)
{
struct rtems_driver_manager *mgr = &drv_mgr;
struct drvmgr_dev *subdev, **pprev;
int rc;
/* Remove children if this device exports a bus of devices. All
* children must be removed first as they depend upon the bus
* services this bridge provide.
*/
if (dev->bus) {
rc = drvmgr_bus_unregister(dev->bus);
if (rc != DRVMGR_OK)
return rc;
}
if (dev->drv == NULL)
return DRVMGR_OK;
/* Remove device by letting assigned driver take care of hardware
* issues
*/
if (!dev->drv->ops->remove) {
/* No remove function is considered severe when someone
* is trying to remove the device
*/
return DRVMGR_ENOSYS;
}
dev->error = dev->drv->ops->remove(dev);
if (dev->error != DRVMGR_OK)
return DRVMGR_FAIL;
DRVMGR_LOCK_WRITE();
/* Delete device from driver's device list */
pprev = &dev->drv->dev;
subdev = dev->drv->dev;
while (subdev != dev) {
pprev = &subdev->next_in_drv;
subdev = subdev->next_in_drv;
}
*pprev = subdev->next_in_drv;
dev->drv->dev_cnt--;
/* Move device to inactive list */
drvmgr_list_remove(&mgr->devices[dev->level], dev);
dev->level = 0;
dev->state &= ~(DEV_STATE_UNITED|DEV_STATE_INIT_DONE);
dev->state |= DEV_STATE_LIST_INACTIVE;
drvmgr_list_add_tail(&mgr->devices_inactive, dev);
DRVMGR_UNLOCK();
/* Free Device Driver Private memory if allocated previously by
* Driver manager.
*/
if (dev->drv->dev_priv_size && dev->priv) {
free(dev->priv);
dev->priv = NULL;
}
dev->drv = NULL;
return DRVMGR_OK;
}
/* Unregister device,
* - let assigned driver handle deletion
* - remove from device list
* - remove from driver list
* - remove from bus list
*/
int drvmgr_dev_unregister(struct drvmgr_dev *dev)
{
struct rtems_driver_manager *mgr = &drv_mgr;
struct drvmgr_dev *subdev, **pprev;
int err;
/* Separate device from driver, if the device is united with a driver.
*
* If this device is a bridge all child buses/devices are also removed.
*/
err = drvmgr_dev_drv_separate(dev);
if (err != DRVMGR_OK)
return err;
DRVMGR_LOCK_WRITE();
/* Remove it from inactive list */
drvmgr_list_remove(&mgr->devices_inactive, dev);
/* Remove device from parent bus list (no check if dev not in list) */
pprev = &dev->parent->children;
subdev = dev->parent->children;
while (subdev != dev) {
pprev = &subdev->next_in_bus;
subdev = subdev->next_in_bus;
}
*pprev = subdev->next_in_bus;
dev->parent->dev_cnt--;
DRVMGR_UNLOCK();
/* All references to this device has been removed at this point */
free(dev);
return DRVMGR_OK;
}

View File

@@ -527,3 +527,20 @@ $(PROJECT_INCLUDE)/rtems/fsmount.h: libmisc/fsmount/fsmount.h $(PROJECT_INCLUDE)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/fsmount.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/fsmount.h
$(PROJECT_INCLUDE)/drvmgr/$(dirstamp):
@$(MKDIR_P) $(PROJECT_INCLUDE)/drvmgr
@: > $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
PREINSTALL_DIRS += $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
$(PROJECT_INCLUDE)/drvmgr/drvmgr.h: libdrvmgr/drvmgr.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/drvmgr.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/drvmgr.h
$(PROJECT_INCLUDE)/drvmgr/drvmgr_confdefs.h: libdrvmgr/drvmgr_confdefs.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/drvmgr_confdefs.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/drvmgr_confdefs.h
$(PROJECT_INCLUDE)/drvmgr/drvmgr_list.h: libdrvmgr/drvmgr_list.h $(PROJECT_INCLUDE)/drvmgr/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/drvmgr/drvmgr_list.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/drvmgr/drvmgr_list.h

View File

@@ -161,6 +161,15 @@ const rtems_libio_helper rtems_fs_init_helper =
*/
#define CONFIGURE_LIBIO_POSIX_KEYS 1
/**
* Driver Manager Configuration
*/
#ifdef RTEMS_DRVMGR_STARTUP
#define CONFIGURE_DRVMGR_SEMAPHORES 1
#else
#define CONFIGURE_DRVMGR_SEMAPHORES 0
#endif
#ifdef CONFIGURE_INIT
rtems_libio_t rtems_libio_iops[CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS];
@@ -2170,7 +2179,7 @@ const rtems_libio_helper rtems_fs_init_helper =
(CONFIGURE_MAXIMUM_SEMAPHORES + CONFIGURE_LIBIO_SEMAPHORES + \
CONFIGURE_TERMIOS_SEMAPHORES + CONFIGURE_LIBBLOCK_SEMAPHORES + \
CONFIGURE_SEMAPHORES_FOR_FILE_SYSTEMS + \
CONFIGURE_NETWORKING_SEMAPHORES)
CONFIGURE_NETWORKING_SEMAPHORES + CONFIGURE_DRVMGR_SEMAPHORES)
/**
* This macro is calculated to specify the memory required for

View File

@@ -56,6 +56,10 @@
#include <rtems/rtems/rtemsapi.h>
#include <rtems/posix/posixapi.h>
#ifdef RTEMS_DRVMGR_STARTUP
#include <drvmgr/drvmgr.h>
#endif
Objects_Information *_Internal_Objects[ OBJECTS_INTERNAL_CLASSES_LAST + 1 ];
void rtems_initialize_data_structures(void)
@@ -161,6 +165,9 @@ void rtems_initialize_data_structures(void)
void rtems_initialize_before_drivers(void)
{
#ifdef RTEMS_DRVMGR_STARTUP
_DRV_Manager_initialization();
#endif
#if defined(RTEMS_MULTIPROCESSING)
_MPCI_Create_server();
@@ -182,8 +189,64 @@ void rtems_initialize_device_drivers(void)
* NOTE: The MPCI may be build upon a device driver.
*/
#ifdef RTEMS_DRVMGR_STARTUP
/* BSPs has already registered their "root bus" driver in the
* bsp_predriver hook or so.
*
* Init Drivers to Level 1, constraints:
* - Interrupts and system clock timer does not work.
* - malloc() work, however other memory services may not
* have been initialized yet.
* - initializes most basic stuff
*
* Typical setup in Level 1:
* - Find most devices in system, do PCI scan and configuration.
* - Reset hardware if needed.
* - Install IRQ driver
* - Install Timer driver
* - Install console driver and debug printk()
* - Install extra memory.
*/
_DRV_Manager_init_level(1);
bsp_driver_level_hook(1);
#endif
/* Initialize I/O drivers.
*
* Driver Manager note:
* All drivers may not be registered yet. Drivers will dynamically
* be initialized when registered in level 2,3 and 4.
*/
_IO_Initialize_all_drivers();
#ifdef RTEMS_DRVMGR_STARTUP
/* Init Drivers to Level 2, constraints:
* - Interrupts can be registered and enabled.
* - System Clock is running
* - Console may be used.
*
* This is typically where drivers are initialized
* for the first time.
*/
_DRV_Manager_init_level(2);
bsp_driver_level_hook(2);
/* Init Drivers to Level 3
*
* This is typically where normal drivers are initialized
* for the second time, they may depend on other drivers
* API inited in level 2
*/
_DRV_Manager_init_level(3);
bsp_driver_level_hook(3);
/* Init Drivers to Level 4,
* Init drivers that depend on services initialized in Level 3
*/
_DRV_Manager_init_level(4);
bsp_driver_level_hook(4);
#endif
#if defined(RTEMS_MULTIPROCESSING)
if ( _System_state_Is_multiprocessing ) {
_MPCI_Initialization();

View File

@@ -63,10 +63,9 @@ TMP_LIBS += ../libmisc/libutf8proc.a
endif
TMP_LIBS += ../libmisc/libuuid.a
TMP_LIBS += ../libi2c/libi2c.a
TMP_LIBS += ../libpci/libpci.a
TMP_LIBS += ../libdrvmgr/libdrvmgr.a
if LIBNETWORKING
TMP_LIBS += ../libnetworking/libnetworking.a