forked from Imagelibrary/rtems
DRVMGR: added driver manager to cpukit/libdrvmgr
This commit is contained in:
12
aclocal/enable-drvmgr.m4
Normal file
12
aclocal/enable-drvmgr.m4
Normal 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])
|
||||
])
|
||||
12
c/src/aclocal/enable-drvmgr.m4
Normal file
12
c/src/aclocal/enable-drvmgr.m4
Normal 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])
|
||||
])
|
||||
16
c/src/lib/libbsp/shared/bspdriverlevelhook.c
Normal file
16
c/src/lib/libbsp/shared/bspdriverlevelhook.c
Normal 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 )
|
||||
{
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -20,6 +20,7 @@ RTEMS_ENABLE_MULTIPROCESSING
|
||||
RTEMS_ENABLE_POSIX
|
||||
RTEMS_ENABLE_NETWORKING
|
||||
RTEMS_ENABLE_CXX
|
||||
RTEMS_ENABLE_DRVMGR
|
||||
|
||||
RTEMS_ENV_RTEMSBSP
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
12
cpukit/aclocal/enable-drvmgr.m4
Normal file
12
cpukit/aclocal/enable-drvmgr.m4
Normal 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])
|
||||
])
|
||||
@@ -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
|
||||
|
||||
33
cpukit/libdrvmgr/Makefile.am
Normal file
33
cpukit/libdrvmgr/Makefile.am
Normal 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
112
cpukit/libdrvmgr/README
Normal 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
643
cpukit/libdrvmgr/drvmgr.c
Normal file
@@ -0,0 +1,643 @@
|
||||
/* Driver Manager 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <drvmgr/drvmgr.h>
|
||||
#include <drvmgr/drvmgr_confdefs.h>
|
||||
|
||||
#include "drvmgr_internal.h"
|
||||
|
||||
/* Enable debugging */
|
||||
/*#define DEBUG 1*/
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG(x...) printk(x)
|
||||
#else
|
||||
#define DBG(x...)
|
||||
#endif
|
||||
|
||||
struct rtems_driver_manager drv_mgr = {
|
||||
.level = 0,
|
||||
.initializing_objs = 0,
|
||||
.lock = 0,
|
||||
.root_dev = {0},
|
||||
.root_drv = NULL,
|
||||
|
||||
.drivers = LIST_INITIALIZER(struct drvmgr_drv, next),
|
||||
|
||||
.buses = {
|
||||
LIST_INITIALIZER(struct drvmgr_bus, next),
|
||||
LIST_INITIALIZER(struct drvmgr_bus, next),
|
||||
LIST_INITIALIZER(struct drvmgr_bus, next),
|
||||
LIST_INITIALIZER(struct drvmgr_bus, next),
|
||||
LIST_INITIALIZER(struct drvmgr_bus, next),
|
||||
},
|
||||
.buses_inactive = LIST_INITIALIZER(struct drvmgr_bus, next),
|
||||
|
||||
.devices = {
|
||||
LIST_INITIALIZER(struct drvmgr_dev, next),
|
||||
LIST_INITIALIZER(struct drvmgr_dev, next),
|
||||
LIST_INITIALIZER(struct drvmgr_dev, next),
|
||||
LIST_INITIALIZER(struct drvmgr_dev, next),
|
||||
LIST_INITIALIZER(struct drvmgr_dev, next),
|
||||
},
|
||||
.devices_inactive = LIST_INITIALIZER(struct drvmgr_dev, next),
|
||||
};
|
||||
|
||||
static int do_bus_init(
|
||||
struct rtems_driver_manager *mgr,
|
||||
struct drvmgr_bus *bus,
|
||||
int level);
|
||||
static int do_dev_init(
|
||||
struct rtems_driver_manager *mgr,
|
||||
struct drvmgr_dev *dev,
|
||||
int level);
|
||||
|
||||
/* DRIVER MANAGER */
|
||||
|
||||
void _DRV_Manager_init_level(int level)
|
||||
{
|
||||
struct rtems_driver_manager *mgr = &drv_mgr;
|
||||
|
||||
if (mgr->level >= level)
|
||||
return;
|
||||
|
||||
/* Set new Level */
|
||||
mgr->level = level;
|
||||
|
||||
/* Initialize buses and devices into this new level */
|
||||
drvmgr_init_update();
|
||||
}
|
||||
|
||||
/* Initialize Data structures of the driver manager and call driver
|
||||
* register functions configured by the user.
|
||||
*/
|
||||
void _DRV_Manager_initialization(void)
|
||||
{
|
||||
struct drvmgr_drv_reg_func *drvreg;
|
||||
|
||||
/* drv_mgr is already initialized statically by compiler except
|
||||
* the lock
|
||||
*/
|
||||
DRVMGR_LOCK_INIT();
|
||||
|
||||
/* Call driver register functions. */
|
||||
drvreg = &drvmgr_drivers[0];
|
||||
while (drvreg->drv_reg) {
|
||||
/* Make driver register */
|
||||
drvreg->drv_reg();
|
||||
drvreg++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Take ready devices and buses into the correct init level step by step.
|
||||
* Once a bus or a device has been registered there is no turning
|
||||
* back - they are taken to the level of the driver manager.
|
||||
*/
|
||||
void drvmgr_init_update(void)
|
||||
{
|
||||
struct rtems_driver_manager *mgr = &drv_mgr;
|
||||
struct drvmgr_bus *bus;
|
||||
struct drvmgr_dev *dev;
|
||||
int bus_might_been_registered;
|
||||
int level;
|
||||
|
||||
/* "Lock" to make sure we don't use up the stack and that the lists
|
||||
* remain consistent.
|
||||
*/
|
||||
DRVMGR_LOCK_WRITE();
|
||||
if (mgr->initializing_objs || (mgr->level == 0))
|
||||
goto out;
|
||||
mgr->initializing_objs = 1;
|
||||
|
||||
init_registered_buses:
|
||||
/* Take all buses and devices ready into the same stage
|
||||
* as the driver manager global level.
|
||||
*/
|
||||
for (level = 0; level < mgr->level; level++) {
|
||||
|
||||
bus_might_been_registered = 0;
|
||||
|
||||
/* Take buses into next level */
|
||||
|
||||
while ((bus = BUS_LIST_HEAD(&mgr->buses[level])) != NULL) {
|
||||
|
||||
/* Remove first in the list (will be inserted in
|
||||
* appropriate list by do_bus_init())
|
||||
*/
|
||||
drvmgr_list_remove_head(&mgr->buses[level]);
|
||||
|
||||
DRVMGR_UNLOCK();
|
||||
|
||||
/* Initialize Bus, this will register devices on
|
||||
* the bus. Take bus into next level.
|
||||
*/
|
||||
do_bus_init(mgr, bus, level+1);
|
||||
|
||||
DRVMGR_LOCK_WRITE();
|
||||
}
|
||||
|
||||
/* Take devices into next level */
|
||||
while ((dev = DEV_LIST_HEAD(&mgr->devices[level])) != NULL) {
|
||||
|
||||
/* Always process first in list */
|
||||
dev = DEV_LIST_HEAD(&mgr->devices[level]);
|
||||
|
||||
/* Remove first in the list (will be inserted in
|
||||
* appropriate list by do_dev_init())
|
||||
*/
|
||||
drvmgr_list_remove_head(&mgr->devices[level]);
|
||||
|
||||
DRVMGR_UNLOCK();
|
||||
|
||||
/* Initialize Device, this may register a new bus */
|
||||
do_dev_init(mgr, dev, level+1);
|
||||
|
||||
DRVMGR_LOCK_WRITE();
|
||||
|
||||
bus_might_been_registered = 1;
|
||||
}
|
||||
|
||||
/* Make sure all buses registered and ready are taken at
|
||||
* the same time into init level N.
|
||||
*/
|
||||
if (bus_might_been_registered)
|
||||
goto init_registered_buses;
|
||||
}
|
||||
|
||||
/* Release bus/device initialization "Lock" */
|
||||
mgr->initializing_objs = 0;
|
||||
|
||||
out:
|
||||
DRVMGR_UNLOCK();
|
||||
}
|
||||
|
||||
/* Take bus into next level */
|
||||
static int do_bus_init(
|
||||
struct rtems_driver_manager *mgr,
|
||||
struct drvmgr_bus *bus,
|
||||
int level)
|
||||
{
|
||||
int (*init)(struct drvmgr_bus *);
|
||||
|
||||
/* If bridge device has failed during initialization, the bus is not
|
||||
* initialized further.
|
||||
*/
|
||||
if (bus->dev->state & DEV_STATE_INIT_FAILED) {
|
||||
bus->state |= BUS_STATE_DEPEND_FAILED;
|
||||
goto inactivate_out;
|
||||
}
|
||||
|
||||
if (bus->ops && (init = bus->ops->init[level-1])) {
|
||||
/* Note: This init1 function may register new devices */
|
||||
bus->error = init(bus);
|
||||
if (bus->error != DRVMGR_OK) {
|
||||
/* An error of some kind during bus initialization.
|
||||
*
|
||||
* Child devices and their buses are not inactived
|
||||
* directly here, instead they will all be catched by
|
||||
* do_dev_init() and do_bus_init() by checking if
|
||||
* parent or bridge-device failed. We know that
|
||||
* initialization will happen later for those devices.
|
||||
*/
|
||||
goto inactivate_out;
|
||||
}
|
||||
}
|
||||
|
||||
DRVMGR_LOCK_WRITE();
|
||||
|
||||
/* Bus taken into the new level */
|
||||
bus->level = level;
|
||||
|
||||
/* Put bus into list of buses reached level 'level'.
|
||||
* Put at end of bus list so that init[N+1]() calls comes
|
||||
* in the same order as init[N]()
|
||||
*/
|
||||
drvmgr_list_add_tail(&mgr->buses[level], bus);
|
||||
|
||||
DRVMGR_UNLOCK();
|
||||
|
||||
return 0;
|
||||
|
||||
inactivate_out:
|
||||
DRVMGR_LOCK_WRITE();
|
||||
bus->state |= BUS_STATE_INIT_FAILED;
|
||||
bus->state |= BUS_STATE_LIST_INACTIVE;
|
||||
drvmgr_list_add_head(&mgr->buses_inactive, bus);
|
||||
DRVMGR_UNLOCK();
|
||||
|
||||
DBG("do_bus_init(%d): (DEV: %s) failed\n", level, bus->dev->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Take device to initialization level 1 */
|
||||
static int do_dev_init(
|
||||
struct rtems_driver_manager *mgr,
|
||||
struct drvmgr_dev *dev,
|
||||
int level)
|
||||
{
|
||||
int (*init)(struct drvmgr_dev *);
|
||||
|
||||
/* Try to allocate Private Device Structure for driver if driver
|
||||
* requests for this feature.
|
||||
*/
|
||||
if (dev->drv && dev->drv->dev_priv_size && !dev->priv) {
|
||||
dev->priv = malloc(dev->drv->dev_priv_size);
|
||||
memset(dev->priv, 0, dev->drv->dev_priv_size);
|
||||
}
|
||||
|
||||
/* If parent bus has failed during initialization,
|
||||
* the device is not initialized further.
|
||||
*/
|
||||
if (dev->parent && (dev->parent->state & BUS_STATE_INIT_FAILED)) {
|
||||
dev->state |= DEV_STATE_DEPEND_FAILED;
|
||||
goto inactivate_out;
|
||||
}
|
||||
|
||||
/* Call Driver's Init Routine */
|
||||
if (dev->drv && (init = dev->drv->ops->init[level-1])) {
|
||||
/* Note: This init function may register new devices */
|
||||
dev->error = init(dev);
|
||||
if (dev->error != DRVMGR_OK) {
|
||||
/* An error of some kind has occured in the
|
||||
* driver/device, the failed device is put into the
|
||||
* inactive list, this way Init2,3 and/or 4 will not
|
||||
* be called for this device.
|
||||
*
|
||||
* The device is not removed from the bus (not
|
||||
* unregistered). The driver can be used to find
|
||||
* device information and debugging for example even
|
||||
* if device initialization failed.
|
||||
*
|
||||
* Child buses and their devices are not inactived
|
||||
* directly here, instead they will all be catched by
|
||||
* do_dev_init() and do_bus_init() by checking if
|
||||
* parent or bridge-device failed. We know that
|
||||
* initialization will happen later for those devices.
|
||||
*/
|
||||
goto inactivate_out;
|
||||
}
|
||||
}
|
||||
|
||||
DRVMGR_LOCK_WRITE();
|
||||
/* Dev taken into new level */
|
||||
dev->level = level;
|
||||
|
||||
/* Put at end of device list so that init[N+1]() calls comes
|
||||
* in the same order as init[N]()
|
||||
*/
|
||||
drvmgr_list_add_tail(&mgr->devices[level], dev);
|
||||
DRVMGR_UNLOCK();
|
||||
|
||||
return 0;
|
||||
|
||||
inactivate_out:
|
||||
DRVMGR_LOCK_WRITE();
|
||||
dev->state |= DEV_STATE_INIT_FAILED;
|
||||
dev->state |= DEV_STATE_LIST_INACTIVE;
|
||||
drvmgr_list_add_head(&mgr->devices_inactive, dev);
|
||||
DRVMGR_UNLOCK();
|
||||
|
||||
DBG("do_dev_init(%d): DRV: %s (DEV: %s) failed\n",
|
||||
level, dev->drv->name, dev->name);
|
||||
|
||||
return 1; /* Failed to take device into requested level */
|
||||
}
|
||||
|
||||
/* Register Root device driver */
|
||||
int drvmgr_root_drv_register(struct drvmgr_drv *drv)
|
||||
{
|
||||
struct rtems_driver_manager *mgr = &drv_mgr;
|
||||
struct drvmgr_dev *root = &mgr->root_dev;
|
||||
|
||||
if (mgr->root_drv) {
|
||||
/* Only possible to register root device once */
|
||||
return DRVMGR_FAIL;
|
||||
}
|
||||
|
||||
/* Set root device driver */
|
||||
drv->next = NULL;
|
||||
mgr->root_drv = drv;
|
||||
|
||||
/* Init root device non-NULL fields */
|
||||
root->minor_drv = -1;
|
||||
root->minor_bus = 0;
|
||||
root->businfo = mgr;
|
||||
root->name = "root bus";
|
||||
/* Custom Driver association */
|
||||
root->drv = mgr->root_drv;
|
||||
|
||||
/* This registers the root device and a bus */
|
||||
drvmgr_dev_register(root);
|
||||
|
||||
return DRVMGR_OK;
|
||||
}
|
||||
|
||||
/* Register a driver */
|
||||
int drvmgr_drv_register(struct drvmgr_drv *drv)
|
||||
{
|
||||
struct rtems_driver_manager *mgr = &drv_mgr;
|
||||
|
||||
/* All drivers must have been registered before start of init,
|
||||
* because the manager does not scan all existing devices to find
|
||||
* suitable hardware for this driver, and it is not protected with
|
||||
* a lock therefore.
|
||||
*/
|
||||
if (mgr->level > 0)
|
||||
return -1;
|
||||
|
||||
drv->obj_type = DRVMGR_OBJ_DRV;
|
||||
|
||||
/* Put driver into list of registered drivers */
|
||||
drvmgr_list_add_head(&mgr->drivers, drv);
|
||||
|
||||
/* TODO: we could scan for devices that this new driver has support
|
||||
* for. However, at this stage we assume that all drivers are
|
||||
* registered before devices are registered.
|
||||
*
|
||||
* LOCK: From the same assumsion locking the driver list is not needed
|
||||
* either.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Insert a device into a driver's device list and assign a driver minor number
|
||||
* to the device.
|
||||
*
|
||||
* The devices are ordered by their minor number (sorted linked list of devices)
|
||||
* the minor number is found by looking for a gap or at the end.
|
||||
*/
|
||||
static void drvmgr_insert_dev_into_drv(
|
||||
struct drvmgr_drv *drv,
|
||||
struct drvmgr_dev *dev)
|
||||
{
|
||||
struct drvmgr_dev *curr, **pprevnext;
|
||||
int minor;
|
||||
|
||||
minor = 0;
|
||||
pprevnext = &drv->dev;
|
||||
curr = drv->dev;
|
||||
|
||||
while (curr) {
|
||||
if (minor < curr->minor_drv) {
|
||||
/* Found a gap. Insert new device between prev
|
||||
* and curr. */
|
||||
break;
|
||||
}
|
||||
minor++;
|
||||
pprevnext = &curr->next_in_drv;
|
||||
curr = curr->next_in_drv;
|
||||
}
|
||||
dev->next_in_drv = curr;
|
||||
*pprevnext = dev;
|
||||
|
||||
/* Set minor */
|
||||
dev->minor_drv = minor;
|
||||
drv->dev_cnt++;
|
||||
}
|
||||
|
||||
/* Insert a device into a bus device list and assign a bus minor number to the
|
||||
* device.
|
||||
*
|
||||
* The devices are ordered by their minor number (sorted linked list of devices)
|
||||
* and by their registeration order if not using the same driver.
|
||||
*
|
||||
* The minor number is found by looking for a gap or at the end.
|
||||
*/
|
||||
static void drvmgr_insert_dev_into_bus(
|
||||
struct drvmgr_bus *bus,
|
||||
struct drvmgr_dev *dev)
|
||||
{
|
||||
struct drvmgr_dev *curr, **pprevnext;
|
||||
int minor;
|
||||
|
||||
minor = 0;
|
||||
pprevnext = &bus->children;
|
||||
curr = bus->children;
|
||||
|
||||
while (curr) {
|
||||
if (dev->drv && (dev->drv == curr->drv)) {
|
||||
if (minor < curr->minor_bus) {
|
||||
/* Found a gap. Insert new device between prev
|
||||
* and curr. */
|
||||
break;
|
||||
}
|
||||
minor++;
|
||||
}
|
||||
pprevnext = &curr->next_in_bus;
|
||||
curr = curr->next_in_bus;
|
||||
}
|
||||
dev->next_in_bus = curr;
|
||||
*pprevnext = dev;
|
||||
|
||||
/* Set minor. Devices without driver are given -1 */
|
||||
if (dev->drv == NULL)
|
||||
minor = -1;
|
||||
dev->minor_bus = minor;
|
||||
bus->dev_cnt++;
|
||||
}
|
||||
|
||||
/* Try to find a driver for a device (unite a device with driver).
|
||||
* a device with a driver
|
||||
*/
|
||||
static struct drvmgr_drv *drvmgr_dev_find_drv(
|
||||
struct drvmgr_dev *dev)
|
||||
{
|
||||
struct rtems_driver_manager *mgr = &drv_mgr;
|
||||
struct drvmgr_drv *drv;
|
||||
|
||||
/* 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
|
||||
*/
|
||||
|
||||
/* Try to find a driver that can handle this device */
|
||||
for (drv = DRV_LIST_HEAD(&mgr->drivers); drv; drv = drv->next)
|
||||
if (dev->parent->ops->unite(drv, dev) == 1)
|
||||
break;
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
/* Register a device */
|
||||
int drvmgr_dev_register(struct drvmgr_dev *dev)
|
||||
{
|
||||
struct rtems_driver_manager *mgr = &drv_mgr;
|
||||
struct drvmgr_drv *drv;
|
||||
struct drvmgr_bus *bus = dev->parent;
|
||||
struct drvmgr_key *keys;
|
||||
struct drvmgr_list *init_list = &mgr->devices_inactive;
|
||||
|
||||
DBG("DEV_REG: %s at bus \"%s\"\n", dev->name,
|
||||
bus && bus->dev && bus->dev->name ? bus->dev->name : "UNKNOWN");
|
||||
|
||||
/* Custom driver assocation? */
|
||||
if (dev->drv) {
|
||||
drv = dev->drv;
|
||||
DBG("CUSTOM ASSOCIATION (%s to %s)\n", dev->name, drv->name);
|
||||
} else {
|
||||
/* Try to find a driver that can handle this device */
|
||||
dev->drv = drv = drvmgr_dev_find_drv(dev);
|
||||
}
|
||||
|
||||
DRVMGR_LOCK_WRITE();
|
||||
|
||||
/* Assign Bus Minor number and put into bus device list
|
||||
* unless root device.
|
||||
*/
|
||||
if (bus)
|
||||
drvmgr_insert_dev_into_bus(bus, dev);
|
||||
|
||||
if (!drv) {
|
||||
/* No driver found that can handle this device, put into
|
||||
* inactive list
|
||||
*/
|
||||
dev->minor_drv = -1;
|
||||
dev->state |= DEV_STATE_LIST_INACTIVE;
|
||||
} else {
|
||||
/* United device with driver.
|
||||
* Put the device on the registered device list
|
||||
*/
|
||||
dev->state |= DEV_STATE_UNITED;
|
||||
|
||||
/* Check if user want to skip this core. This is not a
|
||||
* normal request, however in a multi-processor system
|
||||
* the two(or more) RTEMS instances must not use the same
|
||||
* devices in a system, not reporting a device to
|
||||
* it's driver will effectively accomplish this. In a
|
||||
* non Plug & Play system one can easily avoid this
|
||||
* problem by not report the core, but in a Plug & Play
|
||||
* system the bus driver will report all found cores.
|
||||
*
|
||||
* To stop the two RTEMS instances from using the same
|
||||
* device the user can simply define a resource entry
|
||||
* for a certain device but set the keys field to NULL.
|
||||
*/
|
||||
if (drvmgr_keys_get(dev, &keys) == 0 && keys == NULL) {
|
||||
/* Found Driver resource entry point
|
||||
* for this device, it was NULL, this
|
||||
* indicates to skip the core.
|
||||
*
|
||||
* We put it into the inactive list
|
||||
* marking it as ignored.
|
||||
*/
|
||||
dev->state |= DEV_STATE_IGNORED;
|
||||
} else {
|
||||
/* Assign Driver Minor number and put into driver's
|
||||
* device list
|
||||
*/
|
||||
drvmgr_insert_dev_into_drv(drv, dev);
|
||||
|
||||
/* Just register device, it will be initialized
|
||||
* later together with bus.
|
||||
*
|
||||
* At the end of the list (breadth first search)
|
||||
*/
|
||||
init_list = &mgr->devices[0];
|
||||
|
||||
DBG("Registered %s (DRV: %s) on %s\n",
|
||||
dev->name, drv->name,
|
||||
bus ? bus->dev->name : "NO PARENT");
|
||||
}
|
||||
}
|
||||
|
||||
drvmgr_list_add_tail(init_list, dev);
|
||||
|
||||
DRVMGR_UNLOCK();
|
||||
|
||||
/* Trigger Device initialization if not root device and
|
||||
* has a driver
|
||||
*/
|
||||
if (bus && dev->drv)
|
||||
drvmgr_init_update();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register a bus */
|
||||
int drvmgr_bus_register(struct drvmgr_bus *bus)
|
||||
{
|
||||
struct rtems_driver_manager *mgr = &drv_mgr;
|
||||
struct drvmgr_bus *bus_up;
|
||||
|
||||
/* Get bus architecture depth - the distance from root bus */
|
||||
bus->depth = 0;
|
||||
bus_up = bus->dev->parent;
|
||||
while (bus_up) {
|
||||
bus->depth++;
|
||||
bus_up = bus_up->dev->parent;
|
||||
}
|
||||
|
||||
DRVMGR_LOCK_WRITE();
|
||||
|
||||
/* Put driver into list of found buses */
|
||||
drvmgr_list_add_tail(&mgr->buses[0], bus);
|
||||
|
||||
DRVMGR_UNLOCK();
|
||||
|
||||
/* Take bus into level1 and so on */
|
||||
drvmgr_init_update();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate memory for a Device structure */
|
||||
int drvmgr_alloc_dev(struct drvmgr_dev **pdev, int extra)
|
||||
{
|
||||
struct drvmgr_dev *dev;
|
||||
int size;
|
||||
|
||||
size = ((sizeof(struct drvmgr_dev) + 3) & ~0x3) + extra;
|
||||
dev = (struct drvmgr_dev *)calloc(size, 1);
|
||||
if (!dev) {
|
||||
/* Failed to allocate device structure - critical error */
|
||||
rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
|
||||
}
|
||||
*pdev = dev;
|
||||
dev->obj_type = DRVMGR_OBJ_DEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate memory for a Bus structure */
|
||||
int drvmgr_alloc_bus(struct drvmgr_bus **pbus, int extra)
|
||||
{
|
||||
struct drvmgr_bus *bus;
|
||||
int size;
|
||||
|
||||
size = ((sizeof(struct drvmgr_bus) + 3) & ~0x3) + extra;
|
||||
bus = (struct drvmgr_bus *)calloc(size, 1);
|
||||
if (!bus) {
|
||||
/* Failed to allocate device structure - critical error */
|
||||
rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
|
||||
}
|
||||
*pbus = bus;
|
||||
bus->obj_type = DRVMGR_OBJ_BUS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add driver resources to a bus instance */
|
||||
void drvmgr_bus_res_add(struct drvmgr_bus *bus,
|
||||
struct drvmgr_bus_res *bres)
|
||||
{
|
||||
/* insert first in bus resource list. Locking isn't needed since
|
||||
* resources can only be added before resource requests are made.
|
||||
* When bus has been registered resources are considered a read-only
|
||||
* tree.
|
||||
*/
|
||||
bres->next = bus->reslist;
|
||||
bus->reslist = bres;
|
||||
}
|
||||
965
cpukit/libdrvmgr/drvmgr.h
Normal file
965
cpukit/libdrvmgr/drvmgr.h
Normal file
@@ -0,0 +1,965 @@
|
||||
/* Driver Manager Interface.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _DRIVER_MANAGER_H_
|
||||
#define _DRIVER_MANAGER_H_
|
||||
|
||||
#include <rtems.h>
|
||||
#include <drvmgr/drvmgr_list.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*** Configure Driver manager ***/
|
||||
|
||||
/* Define the number of initialization levels of device drivers */
|
||||
#define DRVMGR_LEVEL_MAX 4
|
||||
|
||||
/* Default to use semahpores for protection. Initialization works without
|
||||
* locks and after initialization too if devices are not removed.
|
||||
*/
|
||||
#ifndef DRVMGR_USE_LOCKS
|
||||
#define DRVMGR_USE_LOCKS 1
|
||||
#endif
|
||||
|
||||
struct drvmgr_dev; /* Device */
|
||||
struct drvmgr_bus; /* Bus */
|
||||
struct drvmgr_drv; /* Driver */
|
||||
|
||||
/*** List Interface shortcuts ***/
|
||||
#define BUS_LIST_HEAD(list) LIST_HEAD(list, struct drvmgr_bus)
|
||||
#define BUS_LIST_TAIL(list) LIST_TAIL(list, struct drvmgr_bus)
|
||||
#define DEV_LIST_HEAD(list) LIST_HEAD(list, struct drvmgr_dev)
|
||||
#define DEV_LIST_TAIL(list) LIST_TAIL(list, struct drvmgr_dev)
|
||||
#define DRV_LIST_HEAD(list) LIST_HEAD(list, struct drvmgr_drv)
|
||||
#define DRV_LIST_TAIL(list) LIST_TAIL(list, struct drvmgr_drv)
|
||||
|
||||
/*** Bus indentification ***/
|
||||
#define DRVMGR_BUS_TYPE_NONE 0 /* Not a valid bus */
|
||||
#define DRVMGR_BUS_TYPE_ROOT 1 /* Hard coded bus */
|
||||
#define DRVMGR_BUS_TYPE_PCI 2 /* PCI bus */
|
||||
#define DRVMGR_BUS_TYPE_AMBAPP 3 /* AMBA Plug & Play bus */
|
||||
#define DRVMGR_BUS_TYPE_LEON2_AMBA 4 /* LEON2 hardcoded bus */
|
||||
#define DRVMGR_BUS_TYPE_AMBAPP_DIST 5 /* Distibuted AMBA Plug & Play bus accessed using a communication interface */
|
||||
#define DRVMGR_BUS_TYPE_SPW_RMAP 6 /* SpaceWire Network bus */
|
||||
#define DRVMGR_BUS_TYPE_AMBAPP_RMAP 7 /* SpaceWire RMAP accessed AMBA Plug & Play bus */
|
||||
|
||||
enum {
|
||||
DRVMGR_OBJ_NONE = 0,
|
||||
DRVMGR_OBJ_DRV = 1,
|
||||
DRVMGR_OBJ_BUS = 2,
|
||||
DRVMGR_OBJ_DEV = 3,
|
||||
};
|
||||
|
||||
/*** Driver indentification ***
|
||||
*
|
||||
* 64-bit identification integer definition
|
||||
* * Bus ID 8-bit [7..0]
|
||||
* * Reserved 8-bit field [63..56]
|
||||
* * Device ID specific for bus type 48-bit [55..8] (Different buses have
|
||||
* different unique identifications for hardware/driver.)
|
||||
*
|
||||
* ID Rules
|
||||
* * A root bus driver must always have device ID set to 0. There can only by
|
||||
* one root bus driver for a certain bus type.
|
||||
* * A Driver ID must identify a unique hardware core
|
||||
*
|
||||
*/
|
||||
|
||||
/* Bus ID Mask */
|
||||
#define DRIVER_ID_BUS_MASK 0x00000000000000FFULL
|
||||
|
||||
/* Reserved Mask for future use */
|
||||
#define DRIVER_ID_RSV_MASK 0xFF00000000000000ULL
|
||||
|
||||
/* Reserved Mask for future use */
|
||||
#define DRIVER_ID_DEV_MASK 0x00FFFFFFFFFFFF00ULL
|
||||
|
||||
/* Set Bus ID Mask. */
|
||||
#define DRIVER_ID(busid, devid) ((unsigned long long) \
|
||||
((((unsigned long long)(devid) << 8) & DRIVER_ID_DEV_MASK) | \
|
||||
((unsigned long long)(busid) & DRIVER_ID_BUS_MASK)))
|
||||
|
||||
/* Get IDs */
|
||||
#define DRIVER_BUSID_GET(id) ((unsigned long long)(id) & DRIVER_ID_BUS_MASK)
|
||||
#define DRIVER_DEVID_GET(id) (((unsigned long long)(id) & DRIVER_ID_DEV_MASK) >> 8)
|
||||
|
||||
#define DRIVER_ROOTBUS_ID(bus_type) DRIVER_ID(bus_type, 0)
|
||||
|
||||
/*** Root Bus drivers ***/
|
||||
|
||||
/* Generic Hard coded Root bus: Driver ID */
|
||||
#define DRIVER_ROOT_ID DRIVER_ROOTBUS_ID(DRVMGR_BUS_TYPE_ROOT)
|
||||
|
||||
/* PCI Plug & Play bus: Driver ID */
|
||||
#define DRIVER_PCIBUS_ID DRIVER_ROOTBUS_ID(DRVMGR_BUS_TYPE_PCI)
|
||||
|
||||
/* AMBA Plug & Play bus: Driver ID */
|
||||
#define DRIVER_GRLIB_AMBAPP_ID DRIVER_ROOTBUS_ID(DRVMGR_BUS_TYPE_AMBAPP)
|
||||
|
||||
/* AMBA Hard coded bus: Driver ID */
|
||||
#define DRIVER_LEON2_AMBA_ID DRIVER_ROOTBUS_ID(DRVMGR_BUS_TYPE_LEON2_AMBA)
|
||||
|
||||
/* Distributed AMBA Plug & Play bus: Driver ID */
|
||||
#define DRIVER_AMBAPP_DIST_ID DRIVER_ROOTBUS_ID(DRVMGR_BUS_TYPE_AMBAPP_DIST)
|
||||
|
||||
/*! Bus parameters used by driver interface functions to aquire information
|
||||
* about bus. All Bus drivers should implement the operation 'get_params' so
|
||||
* that the driver interface routines can access bus dependent information in
|
||||
* an non-dependent way.
|
||||
*/
|
||||
struct drvmgr_bus_params {
|
||||
char *dev_prefix; /*!< Optional name prefix */
|
||||
};
|
||||
|
||||
/* Interrupt Service Routine (ISR) */
|
||||
typedef void (*drvmgr_isr)(void *arg);
|
||||
|
||||
/*! Bus operations */
|
||||
struct drvmgr_bus_ops {
|
||||
/* Functions used internally within driver manager */
|
||||
int (*init[DRVMGR_LEVEL_MAX])(struct drvmgr_bus *);
|
||||
int (*remove)(struct drvmgr_bus *);
|
||||
int (*unite)(struct drvmgr_drv *, struct drvmgr_dev *); /*!< Unite Hardware Device with Driver */
|
||||
|
||||
/* Functions called indirectly from drivers */
|
||||
int (*int_register)(struct drvmgr_dev *, int index, const char *info, drvmgr_isr isr, void *arg);
|
||||
int (*int_unregister)(struct drvmgr_dev *, int index, drvmgr_isr isr, void *arg);
|
||||
int (*int_clear)(struct drvmgr_dev *, int index);
|
||||
int (*int_mask)(struct drvmgr_dev *, int index);
|
||||
int (*int_unmask)(struct drvmgr_dev *, int index);
|
||||
|
||||
/* Get Parameters */
|
||||
int (*get_params)(struct drvmgr_dev *, struct drvmgr_bus_params *);
|
||||
/* Get Frequency of Bus */
|
||||
int (*freq_get)(struct drvmgr_dev*, int, unsigned int*);
|
||||
/*! Function called to request information about a device. The bus
|
||||
* driver interpret the bus-specific information about the device.
|
||||
*/
|
||||
void (*info_dev)(struct drvmgr_dev *, void (*print)(void *p, char *str), void *p);
|
||||
};
|
||||
#define BUS_OPS_NUM (sizeof(struct drvmgr_bus_ops)/sizeof(void (*)(void)))
|
||||
|
||||
struct drvmgr_func {
|
||||
int funcid;
|
||||
void *func;
|
||||
};
|
||||
#define DRVMGR_FUNC(_ID_, _FUNC_) {(int)(_ID_), (void *)(_FUNC_)}
|
||||
#define DRVMGR_FUNC_END {0, NULL}
|
||||
|
||||
/*** Resource definitions ***
|
||||
*
|
||||
* Overview of structures:
|
||||
* All bus resources entries (_bus_res) are linked together per bus
|
||||
* (bus_info->reslist). One bus resource entry has a pointer to an array of
|
||||
* driver resources (_drv_res). One driver resouces is made out of an array
|
||||
* of keys (drvmgr_key). All keys belongs to the same driver and harwdare
|
||||
* device. Each key has a Name, Type ID and Data interpreted differently
|
||||
* depending on the Type ID (union drvmgr_key_value).
|
||||
*
|
||||
*/
|
||||
|
||||
/* Key Data Types */
|
||||
#define KEY_TYPE_NONE 0
|
||||
#define KEY_TYPE_INT 1
|
||||
#define KEY_TYPE_STRING 2
|
||||
#define KEY_TYPE_POINTER 3
|
||||
|
||||
#define KEY_EMPTY {NULL, KEY_TYPE_NONE, {0}}
|
||||
#define RES_EMPTY {0, 0, NULL}
|
||||
#define MMAP_EMPTY {0, 0, 0}
|
||||
|
||||
/*! Union of different values */
|
||||
union drvmgr_key_value {
|
||||
unsigned int i; /*!< Key data type UNSIGNED INTEGER */
|
||||
char *str; /*!< Key data type STRING */
|
||||
void *ptr; /*!< Key data type ADDRESS/POINTER */
|
||||
};
|
||||
|
||||
/* One key. One Value. Holding information relevant to the driver. */
|
||||
struct drvmgr_key {
|
||||
char *key_name; /* Name of key */
|
||||
int key_type; /* How to interpret key_value */
|
||||
union drvmgr_key_value key_value; /* The value or pointer to value */
|
||||
};
|
||||
|
||||
/*! Driver resource entry, Driver resources for a certain device instance,
|
||||
* containing a number of keys where each key hold the data of interest.
|
||||
*/
|
||||
struct drvmgr_drv_res {
|
||||
uint64_t drv_id; /*!< Identifies the driver this resource is aiming */
|
||||
int minor_bus; /*!< Indentifies a specfic device */
|
||||
struct drvmgr_key *keys; /*!< First key in key array, ended with KEY_EMPTY */
|
||||
};
|
||||
|
||||
/*! Bus resource list node */
|
||||
struct drvmgr_bus_res {
|
||||
struct drvmgr_bus_res *next; /*!< Next resource node in list */
|
||||
struct drvmgr_drv_res resource[]; /*!< Array of resources, one per device instance */
|
||||
};
|
||||
|
||||
/*! MAP entry. Describes an linear address space translation. Untranslated
|
||||
* Start, Translated Start and length.
|
||||
*
|
||||
* Used by bus drivers to describe the address translation needed for
|
||||
* the translation driver interface.
|
||||
*/
|
||||
struct drvmgr_map_entry {
|
||||
char *name; /*!< Map Name */
|
||||
unsigned int size; /*!< Size of map window */
|
||||
char *from_adr; /*!< Start address of access window used
|
||||
* to reach into remote bus */
|
||||
char *to_adr; /*!< Start address of remote system
|
||||
* address range */
|
||||
};
|
||||
#define DRVMGR_TRANSLATE_ONE2ONE NULL
|
||||
#define DRVMGR_TRANSLATE_NO_BRIDGE ((void *)1) /* No bridge, error */
|
||||
|
||||
/*! Bus information. Describes a bus. */
|
||||
struct drvmgr_bus {
|
||||
int obj_type; /*!< DRVMGR_OBJ_BUS */
|
||||
unsigned char bus_type; /*!< Type of bus */
|
||||
unsigned char depth; /*!< Bus level distance from root bus */
|
||||
struct drvmgr_bus *next; /*!< Next Bus */
|
||||
struct drvmgr_dev *dev; /*!< Bus device, the hardware... */
|
||||
void *priv; /*!< Private data structure used by BUS driver */
|
||||
struct drvmgr_dev *children; /*!< Hardware devices on this bus */
|
||||
struct drvmgr_bus_ops *ops; /*!< Bus operations supported by this bus driver */
|
||||
struct drvmgr_func *funcs; /*!< Extra operations */
|
||||
int dev_cnt; /*!< Number of devices this bus has */
|
||||
struct drvmgr_bus_res *reslist; /*!< Bus resources, head of a linked list of resources. */
|
||||
struct drvmgr_map_entry *maps_up; /*!< Map Translation, array of address spaces upstreams to CPU */
|
||||
struct drvmgr_map_entry *maps_down; /*!< Map Translation, array of address spaces downstreams to Hardware */
|
||||
|
||||
/* Bus status */
|
||||
int level; /*!< Initialization Level of Bus */
|
||||
int state; /*!< Init State of Bus, BUS_STATE_* */
|
||||
int error; /*!< Return code from bus->ops->initN() */
|
||||
};
|
||||
|
||||
/* States of a bus */
|
||||
#define BUS_STATE_INIT_FAILED 0x00000001 /* Initialization Failed */
|
||||
#define BUS_STATE_LIST_INACTIVE 0x00001000 /* In inactive bus list */
|
||||
#define BUS_STATE_DEPEND_FAILED 0x00000004 /* Device init failed */
|
||||
|
||||
/* States of a device */
|
||||
#define DEV_STATE_INIT_FAILED 0x00000001 /* Initialization Failed */
|
||||
#define DEV_STATE_INIT_DONE 0x00000002 /* All init levels completed */
|
||||
#define DEV_STATE_DEPEND_FAILED 0x00000004 /* Parent Bus init failed */
|
||||
#define DEV_STATE_UNITED 0x00000100 /* Device United with Device Driver */
|
||||
#define DEV_STATE_REMOVED 0x00000200 /* Device has been removed (unregistered) */
|
||||
#define DEV_STATE_IGNORED 0x00000400 /* Device was ignored according to user's request, the device
|
||||
* was never reported to it's driver (as expected).
|
||||
*/
|
||||
#define DEV_STATE_LIST_INACTIVE 0x00001000 /* In inactive device list */
|
||||
|
||||
/*! Device information */
|
||||
struct drvmgr_dev {
|
||||
int obj_type; /*!< DRVMGR_OBJ_DEV */
|
||||
struct drvmgr_dev *next; /*!< Next device */
|
||||
struct drvmgr_dev *next_in_bus; /*!< Next device on the same bus */
|
||||
struct drvmgr_dev *next_in_drv; /*!< Next device using the same driver */
|
||||
|
||||
struct drvmgr_drv *drv; /*!< The driver owning this device */
|
||||
struct drvmgr_bus *parent; /*!< Bus that this device resides on */
|
||||
short minor_drv; /*!< Device number within driver */
|
||||
short minor_bus; /*!< Device number on bus (for device separation) */
|
||||
char *name; /*!< Name of Device Hardware */
|
||||
void *priv; /*!< Pointer to driver private device structure */
|
||||
void *businfo; /*!< Host bus specific information */
|
||||
struct drvmgr_bus *bus; /*!< Pointer to bus, set only if this is a bridge */
|
||||
|
||||
/* Device Status */
|
||||
unsigned int state; /*!< State of device, see DEV_STATE_* */
|
||||
int level; /*!< Init Level */
|
||||
int error; /*!< Error state returned by driver */
|
||||
};
|
||||
|
||||
/*! Driver operations, function pointers. */
|
||||
struct drvmgr_drv_ops {
|
||||
int (*init[DRVMGR_LEVEL_MAX])(struct drvmgr_dev *); /*! Function doing Init Stage 1 of a hardware device */
|
||||
int (*remove)(struct drvmgr_dev *); /*! Function called when device instance is to be removed */
|
||||
int (*info)(struct drvmgr_dev *, void (*print)(void *p, char *str), void *p, int, char *argv[]);/*! Function called to request information about a device or driver */
|
||||
};
|
||||
#define DRV_OPS_NUM (sizeof(struct drvmgr_drv_ops)/sizeof(void (*)(void)))
|
||||
|
||||
/*! Device driver description */
|
||||
struct drvmgr_drv {
|
||||
int obj_type; /*!< DRVMGR_OBJ_DRV */
|
||||
struct drvmgr_drv *next; /*!< Next Driver */
|
||||
struct drvmgr_dev *dev; /*!< Devices using this driver */
|
||||
|
||||
uint64_t drv_id; /*!< Unique Driver ID */
|
||||
char *name; /*!< Name of Driver */
|
||||
int bus_type; /*!< Type of Bus this driver supports */
|
||||
struct drvmgr_drv_ops *ops; /*!< Driver operations */
|
||||
struct drvmgr_func *funcs; /*!< Extra Operations */
|
||||
unsigned int dev_cnt; /*!< Number of devices in dev */
|
||||
unsigned int dev_priv_size; /*!< If non-zero DRVMGR will allocate memory for dev->priv */
|
||||
};
|
||||
|
||||
/*! Structure defines a function pointer called when driver manager is ready
|
||||
* for drivers to register themselfs. Used to select drivers available to the
|
||||
* driver manager.
|
||||
*/
|
||||
struct drvmgr_drv_reg_func {
|
||||
void (*drv_reg)(void);
|
||||
};
|
||||
|
||||
/*** DRIVER | DEVICE | BUS FUNCTIONS ***/
|
||||
|
||||
/* Return Codes */
|
||||
enum {
|
||||
DRVMGR_OK = 0, /* Sucess */
|
||||
DRVMGR_NOMEM = 1, /* Memory allocation error */
|
||||
DRVMGR_EIO = 2, /* I/O error */
|
||||
DRVMGR_EINVAL = 3, /* Invalid parameter */
|
||||
DRVMGR_ENOSYS = 4,
|
||||
DRVMGR_TIMEDOUT = 5, /* Operation timeout error */
|
||||
DRVMGR_EBUSY = 6,
|
||||
DRVMGR_ENORES = 7, /* Not enough resources */
|
||||
DRVMGR_FAIL = -1 /* Unspecified failure */
|
||||
};
|
||||
|
||||
/*! Initialize data structures of the driver management system.
|
||||
* Calls predefined register driver functions so that drivers can
|
||||
* register themselves.
|
||||
*/
|
||||
extern void _DRV_Manager_initialization(void);
|
||||
|
||||
/*! Take all devices into init level 'level', all devices registered later
|
||||
* will directly be taken into this level as well, ensuring that all
|
||||
* registerd devices has been taken into the level.
|
||||
*
|
||||
*/
|
||||
extern void _DRV_Manager_init_level(int level);
|
||||
|
||||
/*! This function must be defined by the BSP when the driver manager is enabled
|
||||
* and initialized during BSP initialization. The function is called after a
|
||||
* init level is reached the first time by the driver manager.
|
||||
*/
|
||||
extern void bsp_driver_level_hook(int level);
|
||||
|
||||
/*! Init driver manager all in one go, will call _DRV_Manager_initialization(),
|
||||
* then _DRV_Manager_init_level([1..DRVMGR_LEVEL_MAX]).
|
||||
* Typically called from Init task when user wants to initilize driver
|
||||
* manager after startup, otherwise not used.
|
||||
*/
|
||||
extern int drvmgr_init(void);
|
||||
|
||||
/* Take registered buses and devices into the correct init level,
|
||||
* this function is called from _init_level() so normally
|
||||
* we don't need to call it directly.
|
||||
*/
|
||||
extern void drvmgr_init_update(void);
|
||||
|
||||
/*! Register Root Bus device driver */
|
||||
extern int drvmgr_root_drv_register(struct drvmgr_drv *drv);
|
||||
|
||||
/*! Register a driver */
|
||||
extern int drvmgr_drv_register(struct drvmgr_drv *drv);
|
||||
|
||||
/*! Register a device */
|
||||
extern int drvmgr_dev_register(struct drvmgr_dev *dev);
|
||||
|
||||
/*! Remove a device, and all its children devices if device is a bus device. The
|
||||
* device driver will be requested to remove the device and once gone from bus,
|
||||
* device and driver list the device is put into a inactive list for debugging
|
||||
* (this is optional by using remove argument).
|
||||
*
|
||||
* Removing the Root Bus Device is not supported.
|
||||
*
|
||||
* \param remove If non-zero the device will be deallocated, and not put into
|
||||
* the inacitve list.
|
||||
*/
|
||||
extern int drvmgr_dev_unregister(struct drvmgr_dev *dev);
|
||||
|
||||
/*! Register a bus */
|
||||
extern int drvmgr_bus_register(struct drvmgr_bus *bus);
|
||||
|
||||
/*! Unregister a bus */
|
||||
extern int drvmgr_bus_unregister(struct drvmgr_bus *bus);
|
||||
|
||||
/*! Unregister all child devices of 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
|
||||
*/
|
||||
extern int drvmgr_children_unregister(struct drvmgr_bus *bus);
|
||||
|
||||
/* Separate a device from the driver it has been united with */
|
||||
extern int drvmgr_dev_drv_separate(struct drvmgr_dev *dev);
|
||||
|
||||
/*! Allocate a device structure, if no memory available
|
||||
* rtems_error_fatal_occurred is called.
|
||||
* The 'extra' argment tells how many bytes extra space is to be allocated after
|
||||
* the device structure, this is typically used for "businfo" structures. The extra
|
||||
* space is always aligned to a 4-byte boundary.
|
||||
*/
|
||||
extern int drvmgr_alloc_dev(struct drvmgr_dev **pdev, int extra);
|
||||
|
||||
/*! Allocate a bus structure, if no memory available rtems_error_fatal_occurred
|
||||
* is called.
|
||||
* The 'extra' argment tells how many bytes extra space is to be allocated after
|
||||
* the device structure, this is typically used for "businfo" structures. The
|
||||
* extra space is always aligned to a 4-byte boundary.
|
||||
*/
|
||||
extern int drvmgr_alloc_bus(struct drvmgr_bus **pbus, int extra);
|
||||
|
||||
/*** DRIVER RESOURCE FUNCTIONS ***/
|
||||
|
||||
/*! Add resources to a bus, typically used by a bus driver.
|
||||
*
|
||||
* \param bus The Bus to add the resources to.
|
||||
* \param res An array with Driver resources, all together are called bus
|
||||
* resources.
|
||||
*/
|
||||
extern void drvmgr_bus_res_add(struct drvmgr_bus *bus,
|
||||
struct drvmgr_bus_res *bres);
|
||||
|
||||
/*! Find all the resource keys for a device among all driver resources on a
|
||||
* bus. Typically used by a device driver to get configuration options.
|
||||
*
|
||||
* \param dev Device to find resources for
|
||||
* \param key Location where the pointer to the driver resource array (drvmgr_drv_res->keys) is stored.
|
||||
*/
|
||||
extern int drvmgr_keys_get(struct drvmgr_dev *dev, struct drvmgr_key **keys);
|
||||
|
||||
/*! Return the one key that matches key name from a driver keys array. The keys
|
||||
* can be obtained using drvmgr_keys_get().
|
||||
*
|
||||
* \param keys An array of keys ended with KEY_EMPTY to search among.
|
||||
* \param key_name Name of key to search for among the keys.
|
||||
*/
|
||||
extern struct drvmgr_key *drvmgr_key_get(struct drvmgr_key *keys, char *key_name);
|
||||
|
||||
/*! Extract key value from the key in the keys array matching name and type.
|
||||
*
|
||||
* This function calls drvmgr_keys_get to get the key requested (from key
|
||||
* name), then determines if the type is correct. A pointer to the key value
|
||||
* is returned.
|
||||
*
|
||||
* \param keys An array of keys ended with KEY_EMPTY to search among.
|
||||
* \param key_name Name of key to search for among the keys.
|
||||
* \param key_type Data Type of value. INTEGER, ADDRESS, STRING.
|
||||
* \return Returns NULL if no value found matching Key Name and Key
|
||||
* Type.
|
||||
*/
|
||||
extern union drvmgr_key_value *drvmgr_key_val_get(
|
||||
struct drvmgr_key *keys,
|
||||
char *key_name,
|
||||
int key_type);
|
||||
|
||||
/*! Get key value from the bus resources matching [device, key name, key type]
|
||||
* if no matching key is found NULL is returned.
|
||||
*
|
||||
* This is typically used by device drivers to find a particular device
|
||||
* resource.
|
||||
*
|
||||
* \param dev The device to search resource for.
|
||||
* \param key_name The key name to search for
|
||||
* \param key_type The key type expected.
|
||||
* \return Returns NULL if no value found matching Key Name and
|
||||
* Key Type was found for device.
|
||||
*/
|
||||
extern union drvmgr_key_value *drvmgr_dev_key_get(
|
||||
struct drvmgr_dev *dev,
|
||||
char *key_name,
|
||||
int key_type);
|
||||
|
||||
/*** DRIVER INTERACE USED TO REQUEST INFORMATION/SERVICES FROM BUS DRIVER ***/
|
||||
|
||||
/*! Get parent bus */
|
||||
static inline struct drvmgr_bus *drvmgr_get_parent(struct drvmgr_dev *dev)
|
||||
{
|
||||
if (dev)
|
||||
return dev->parent;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Get Driver of device */
|
||||
static inline struct drvmgr_drv *drvmgr_get_drv(struct drvmgr_dev *dev)
|
||||
{
|
||||
if (dev)
|
||||
return dev->drv;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Calls func() for every device found in the device tree, regardless of
|
||||
* device state or if a driver is assigned. With the options argument the user
|
||||
* can decide to do either a depth-first or a breadth-first search.
|
||||
*
|
||||
* If the function func() returns a non-zero value then for_each_dev will
|
||||
* return imediatly with the same return value as func() returned.
|
||||
*
|
||||
* \param func Function called on each device
|
||||
* \param arg Custom function argument
|
||||
* \param options Search Options, see DRVMGR_FED_*
|
||||
*
|
||||
*/
|
||||
#define DRVMGR_FED_BF 1 /* Breadth-first search */
|
||||
#define DRVMGR_FED_DF 0 /* Depth first search */
|
||||
extern int drvmgr_for_each_dev(
|
||||
int (*func)(struct drvmgr_dev *dev, void *arg),
|
||||
void *arg,
|
||||
int options);
|
||||
|
||||
/*! Get Device pointer from Driver and Driver minor number
|
||||
*
|
||||
* \param drv Driver the device is united with.
|
||||
* \param minor Driver minor number assigned to device.
|
||||
* \param pdev Location where the Device point will be stored.
|
||||
* \return Zero on success. -1 on failure, when device was not
|
||||
* found in driver device list.
|
||||
*/
|
||||
extern int drvmgr_get_dev(
|
||||
struct drvmgr_drv *drv,
|
||||
int minor,
|
||||
struct drvmgr_dev **pdev);
|
||||
|
||||
/*! Get Bus frequency in Hertz. Frequency is stored into address of freq_hz.
|
||||
*
|
||||
* \param dev The Device to get Bus frequency for.
|
||||
* \param options Bus-type specific options
|
||||
* \param freq_hz Location where Bus Frequency will be stored.
|
||||
*/
|
||||
extern int drvmgr_freq_get(
|
||||
struct drvmgr_dev *dev,
|
||||
int options,
|
||||
unsigned int *freq_hz);
|
||||
|
||||
/*! Return 0 if dev is not located on the root bus, 1 if on root bus */
|
||||
extern int drvmgr_on_rootbus(struct drvmgr_dev *dev);
|
||||
|
||||
/*! Get device name prefix, this name can be used to register a unique name in
|
||||
* the bus->error filesystem or to get an idea where the device is located.
|
||||
*
|
||||
* \param dev The Device to get the device Prefix for.
|
||||
* \param dev_prefix Location where the prefix will be stored.
|
||||
*/
|
||||
extern int drvmgr_get_dev_prefix(struct drvmgr_dev *dev, char *dev_prefix);
|
||||
|
||||
/*! Register a shared interrupt handler. Since this service is shared among
|
||||
* interrupt drivers/handlers the handler[arg] must be installed before the
|
||||
* interrupt can be cleared or disabled. The handler is by default disabled
|
||||
* after registration.
|
||||
*
|
||||
* \param index Index is used to identify the IRQ number if hardware has
|
||||
* multiple IRQ sources. Normally Index is set to 0 to
|
||||
* indicated the first and only IRQ source.
|
||||
* A negative index is interpreted as a absolute bus IRQ
|
||||
* number.
|
||||
* \param isr Interrupt Service Routine.
|
||||
* \param arg Optional ISR argument.
|
||||
*/
|
||||
extern int drvmgr_interrupt_register(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
const char *info,
|
||||
drvmgr_isr isr,
|
||||
void *arg);
|
||||
|
||||
/*! Unregister an interrupt handler. This also disables the interrupt before
|
||||
* unregistering the interrupt handler.
|
||||
* \param index Index is used to identify the IRQ number if hardware has
|
||||
* multiple IRQ sources. Normally Index is set to 0 to
|
||||
* indicated the first and only IRQ source.
|
||||
* A negative index is interpreted as a absolute bus IRQ
|
||||
* number.
|
||||
* \param isr Interrupt Service Routine, previously registered.
|
||||
* \param arg Optional ISR argument, previously registered.
|
||||
*/
|
||||
extern int drvmgr_interrupt_unregister(
|
||||
struct drvmgr_dev *dev,
|
||||
int index,
|
||||
drvmgr_isr isr,
|
||||
void *arg);
|
||||
|
||||
/*! Clear (ACK) pending interrupt
|
||||
*
|
||||
* \param dev Device to clear interrupt for.
|
||||
* \param index Index is used to identify the IRQ number if hardware has multiple IRQ sources.
|
||||
* Normally Index is set to 0 to indicated the first and only IRQ source.
|
||||
* A negative index is interpreted as a absolute bus IRQ number.
|
||||
* \param isr Interrupt Service Routine, previously registered.
|
||||
* \param arg Optional ISR argument, previously registered.
|
||||
*/
|
||||
extern int drvmgr_interrupt_clear(
|
||||
struct drvmgr_dev *dev,
|
||||
int index);
|
||||
|
||||
/*! Force unmasking/enableing an interrupt on the interrupt controller, this is not normally used,
|
||||
* if used the caller has masked/disabled the interrupt just before.
|
||||
*
|
||||
* \param dev Device to clear interrupt for.
|
||||
* \param index Index is used to identify the IRQ number if hardware has multiple IRQ sources.
|
||||
* Normally Index is set to 0 to indicated the first and only IRQ source.
|
||||
* A negative index is interpreted as a absolute bus IRQ number.
|
||||
* \param isr Interrupt Service Routine, previously registered.
|
||||
* \param arg Optional ISR argument, previously registered.
|
||||
*/
|
||||
extern int drvmgr_interrupt_unmask(
|
||||
struct drvmgr_dev *dev,
|
||||
int index);
|
||||
|
||||
/*! Force masking/disable an interrupt on the interrupt controller, this is not normally performed
|
||||
* since this will stop all other (shared) ISRs to be disabled until _unmask() is called.
|
||||
*
|
||||
* \param dev Device to mask interrupt for.
|
||||
* \param index Index is used to identify the IRQ number if hardware has multiple IRQ sources.
|
||||
* Normally Index is set to 0 to indicated the first and only IRQ source.
|
||||
* A negative index is interpreted as a absolute bus IRQ number.
|
||||
*/
|
||||
extern int drvmgr_interrupt_mask(
|
||||
struct drvmgr_dev *dev,
|
||||
int index);
|
||||
|
||||
/*! drvmgr_translate() translation options */
|
||||
enum drvmgr_tr_opts {
|
||||
/* Translate CPU RAM Address (input) to DMA unit accessible address
|
||||
* (output), this is an upstreams translation in reverse order.
|
||||
*
|
||||
* Typical Usage:
|
||||
* It is common to translate a CPU accessible RAM address to an
|
||||
* address that DMA units can access over bridges.
|
||||
*/
|
||||
CPUMEM_TO_DMA = 0x0,
|
||||
|
||||
/* Translate DMA Unit Accessible address mapped to CPU RAM (input) to
|
||||
* CPU accessible address (output). This is an upstreams translation.
|
||||
*
|
||||
* Typical Usage (not often used):
|
||||
* The DMA unit descriptors contain pointers to DMA buffers located at
|
||||
* CPU RAM addresses that the DMA unit can access, the CPU processes
|
||||
* the descriptors and want to access the data but a translation back
|
||||
* to CPU address is required.
|
||||
*/
|
||||
CPUMEM_FROM_DMA = 0x1,
|
||||
|
||||
/* Translate DMA Memory Address (input) to CPU accessible address
|
||||
* (output), this is a downstreams translation in reverse order.
|
||||
*
|
||||
* Typical Usage:
|
||||
* A PCI network card puts packets into its memory not doing DMA over
|
||||
* PCI, in order for the CPU to access them the PCI address must be
|
||||
* translated.
|
||||
*/
|
||||
DMAMEM_TO_CPU = 0x2,
|
||||
|
||||
/* Translate CPU accessible address (input) mapped to DMA Memory Address
|
||||
* to DMA Unit accessible address (output). This is a downstreams
|
||||
* translation.
|
||||
*/
|
||||
DMAMEM_FROM_CPU = 0x3,
|
||||
};
|
||||
#define DRVMGR_TR_REVERSE 0x1 /* do reverse translation direction order */
|
||||
#define DRVMGR_TR_PATH 0x2 /* 0x0=down-stream 0x2=up-stream address path */
|
||||
|
||||
/*! Translate an address on one bus to an address on another bus.
|
||||
*
|
||||
* The device determines source or destination bus, the root bus is always
|
||||
* the other bus. It is assumed that the CPU is located on the root bus or
|
||||
* that it can access it without address translation (mapped 1:1). The CPU
|
||||
* is thus assumed to be located on level 0 top most in the bus hierarchy.
|
||||
*
|
||||
* If no map is present in the bus driver src_address is translated 1:1
|
||||
* (just copied).
|
||||
*
|
||||
* Addresses are typically converted up-streams from the DMA unit towards the
|
||||
* CPU (DMAMEM_TO_CPU) or down-streams towards DMA hardware from the CPU
|
||||
* (CPUMEM_TO_DMA) over one or multiple bridges depending on bus architecture.
|
||||
* See 'enum drvmgr_tr_opts' for other translation direction options.
|
||||
* For example:
|
||||
* Two common operations is to translate a CPU accessible RAM address to an
|
||||
* address that DMA units can access (dev=DMA-unit, CPUMEM_TO_DMA,
|
||||
* src_address=CPU-RAM-ADR) and to translate an address of a PCI resource for
|
||||
* example RAM mapped into a PCI BAR to an CPU accessible address
|
||||
* (dev=PCI-device, DMAMEM_TO_CPU, src_address=PCI-BAR-ADR).
|
||||
*
|
||||
* Source address is translated and the result is put into *dst_address, if
|
||||
* the address is not accessible on the other bus -1 is returned.
|
||||
*
|
||||
* \param dev Device to translate addresses for
|
||||
* \param options Tanslation direction options, see enum drvmgr_tr_opts
|
||||
* \param src_address Address to translate
|
||||
* \param dst_address Location where translated address is stored
|
||||
*
|
||||
* Returns 0 if unable to translate. The remaining length from the given
|
||||
* address of the map is returned on success, for example if a map starts
|
||||
* at 0x40000000 of size 0x100000 the result will be 0x40000 if the address
|
||||
* was translated into 0x400C0000.
|
||||
* If dev is on root-bus no translation is performed 0xffffffff is returned
|
||||
* and src_address is stored in *dst_address.
|
||||
*/
|
||||
extern unsigned int drvmgr_translate(
|
||||
struct drvmgr_dev *dev,
|
||||
unsigned int options,
|
||||
void *src_address,
|
||||
void **dst_address);
|
||||
|
||||
/* Translate addresses between buses, used internally to implement
|
||||
* drvmgr_translate. Function is not limited to translate from/to root bus
|
||||
* where CPU is resident, however buses must be on a straight path relative
|
||||
* to each other (parent of parent of parent and so on).
|
||||
*
|
||||
* \param from src_address is given for this bus
|
||||
* \param to src_address is translated to this bus
|
||||
* \param reverse Selects translation method, if map entries are used in
|
||||
* the reverse order (map_up->to is used as map_up->from)
|
||||
* \param src_address Address to be translated
|
||||
* \param dst_address Translated address is stored here on success (return=0)
|
||||
*
|
||||
* Returns 0 if unable to translate. The remaining length from the given
|
||||
* address of the map is returned on success and the result is stored into
|
||||
* *dst_address. For example if a map starts at 0x40000000 of size 0x100000
|
||||
* the result will be 0x40000 if the address was translated into 0x400C0000.
|
||||
* If dev is on root-bus no translation is performed 0xffffffff is returned.
|
||||
* and src_address is stored in *dst_address.
|
||||
*/
|
||||
extern unsigned int drvmgr_translate_bus(
|
||||
struct drvmgr_bus *from,
|
||||
struct drvmgr_bus *to,
|
||||
int reverse,
|
||||
void *src_address,
|
||||
void **dst_address);
|
||||
|
||||
/* Calls drvmgr_translate() to translate an address range and checks the result,
|
||||
* a printout is generated if the check fails. All parameters are passed on to
|
||||
* drvmgr_translate() except for size, see paramters of drvmgr_translate().
|
||||
*
|
||||
* If size=0 only the starting address is not checked.
|
||||
*
|
||||
* If mapping failes a non-zero result is returned.
|
||||
*/
|
||||
extern int drvmgr_translate_check(
|
||||
struct drvmgr_dev *dev,
|
||||
unsigned int options,
|
||||
void *src_address,
|
||||
void **dst_address,
|
||||
unsigned int size);
|
||||
|
||||
/*! Get function pointer from Device Driver or Bus Driver.
|
||||
*
|
||||
* Returns 0 if function is available
|
||||
*/
|
||||
extern int drvmgr_func_get(void *obj, int funcid, void **func);
|
||||
|
||||
/*! Lookup function and call it directly with the four optional arguments */
|
||||
extern int drvmgr_func_call(void *obj, int funcid, void *a, void *b, void *c, void *d);
|
||||
|
||||
/* Builds a Function ID.
|
||||
*
|
||||
* Used to request optional functions by a bus or device driver
|
||||
*/
|
||||
#define DRVMGR_FUNCID(major, minor) ((((major) & 0xfff) << 20) | ((minor) & 0xfffff))
|
||||
#define DRVMGR_FUNCID_NONE 0
|
||||
#define DRVMGR_FUNCID_END DRVMGR_FUNCID(DRVMGR_FUNCID_NONE, 0)
|
||||
|
||||
/* Major Function ID. Most significant 12-bits. */
|
||||
enum {
|
||||
FUNCID_NONE = 0x000,
|
||||
FUNCID_RW = 0x001, /* Read/Write functions */
|
||||
};
|
||||
|
||||
/* Select Sub-Function Read/Write function by ID */
|
||||
#define RW_SIZE_1 0x00001 /* Access Size */
|
||||
#define RW_SIZE_2 0x00002
|
||||
#define RW_SIZE_4 0x00004
|
||||
#define RW_SIZE_8 0x00008
|
||||
#define RW_SIZE_ANY 0x00000
|
||||
#define RW_SIZE(id) ((unsigned int)(id) & 0xf)
|
||||
|
||||
#define RW_DIR_ANY 0x00000 /* Access Direction */
|
||||
#define RW_READ 0x00000 /* Read */
|
||||
#define RW_WRITE 0x00010 /* Write */
|
||||
#define RW_SET 0x00020 /* Write with same value (memset) */
|
||||
#define RW_DIR(id) (((unsigned int)(id) >> 4) & 0x3)
|
||||
|
||||
#define RW_RAW 0x00000 /* Raw access - no swapping (machine default) */
|
||||
#define RW_LITTLE 0x00040 /* Little Endian */
|
||||
#define RW_BIG 0x00080 /* Big Endian */
|
||||
#define RW_ENDIAN(id) (((unsigned int)(id) >> 6) & 0x3)
|
||||
|
||||
#define RW_TYPE_ANY 0x00000 /* Access type */
|
||||
#define RW_REG 0x00100
|
||||
#define RW_MEM 0x00200
|
||||
#define RW_MEMREG 0x00300
|
||||
#define RW_CFG 0x00400
|
||||
#define RW_TYPE(id) (((unsigned int)(id) >> 8) & 0xf)
|
||||
|
||||
#define RW_ARG 0x01000 /* Optional Argument */
|
||||
#define RW_ERR 0x02000 /* Optional Error Handler */
|
||||
|
||||
/* Build a Read/Write function ID */
|
||||
#define DRVMGR_RWFUNC(minor) DRVMGR_FUNCID(FUNCID_RW, minor)
|
||||
|
||||
/* Argument to Read/Write functions, the "void *arg" pointer is returned by
|
||||
* RW_ARG. If NULL is returned no argument is needed.
|
||||
*/
|
||||
struct drvmgr_rw_arg {
|
||||
void *arg;
|
||||
struct drvmgr_dev *dev;
|
||||
};
|
||||
|
||||
/* Standard Read/Write function types */
|
||||
typedef uint8_t (*drvmgr_r8)(uint8_t *srcadr);
|
||||
typedef uint16_t (*drvmgr_r16)(uint16_t *srcadr);
|
||||
typedef uint32_t (*drvmgr_r32)(uint32_t *srcadr);
|
||||
typedef uint64_t (*drvmgr_r64)(uint64_t *srcadr);
|
||||
typedef void (*drvmgr_w8)(uint8_t *dstadr, uint8_t data);
|
||||
typedef void (*drvmgr_w16)(uint16_t *dstadr, uint16_t data);
|
||||
typedef void (*drvmgr_w32)(uint32_t *dstadr, uint32_t data);
|
||||
typedef void (*drvmgr_w64)(uint64_t *dstadr, uint64_t data);
|
||||
/* READ/COPY a memory area located on bus into CPU memory.
|
||||
* From 'src' (remote) to the destination 'dest' (local), n=number of bytes
|
||||
*/
|
||||
typedef int (*drvmgr_rmem)(void *dest, const void *src, int n);
|
||||
/* WRITE/COPY a user buffer located in CPU memory to a location on the bus.
|
||||
* From 'src' (local) to the destination 'dest' (remote), n=number of bytes
|
||||
*/
|
||||
typedef int (*drvmgr_wmem)(void *dest, const void *src, int n);
|
||||
/* Set a memory area to the byte value given in c, see LIBC memset(). Memset is
|
||||
* implemented by calling wmem() multiple times with a "large" buffer.
|
||||
*/
|
||||
typedef int (*drvmgr_memset)(void *dstadr, int c, size_t n);
|
||||
|
||||
/* Read/Write function types with additional argument */
|
||||
typedef uint8_t (*drvmgr_r8_arg)(uint8_t *srcadr, void *a);
|
||||
typedef uint16_t (*drvmgr_r16_arg)(uint16_t *srcadr, void *a);
|
||||
typedef uint32_t (*drvmgr_r32_arg)(uint32_t *srcadr, void *a);
|
||||
typedef uint64_t (*drvmgr_r64_arg)(uint64_t *srcadr, void *a);
|
||||
typedef void (*drvmgr_w8_arg)(uint8_t *dstadr, uint8_t data, void *a);
|
||||
typedef void (*drvmgr_w16_arg)(uint16_t *dstadr, uint16_t data, void *a);
|
||||
typedef void (*drvmgr_w32_arg)(uint32_t *dstadr, uint32_t data, void *a);
|
||||
typedef void (*drvmgr_w64_arg)(uint64_t *dstadr, uint64_t data, void *a);
|
||||
typedef int (*drvmgr_rmem_arg)(void *dest, const void *src, int n, void *a);
|
||||
typedef int (*drvmgr_wmem_arg)(void *dest, const void *src, int n, void *a);
|
||||
typedef int (*drvmgr_memset_arg)(void *dstadr, int c, size_t n, void *a);
|
||||
|
||||
/* Report an error to the parent bus of the device */
|
||||
typedef void (*drvmgr_rw_err)(struct drvmgr_rw_arg *a, struct drvmgr_bus *bus,
|
||||
int funcid, void *adr);
|
||||
|
||||
/* Helper function for buses that implement the memset() over wmem() */
|
||||
extern void drvmgr_rw_memset(
|
||||
void *dstadr,
|
||||
int c,
|
||||
size_t n,
|
||||
void *a,
|
||||
drvmgr_wmem_arg wmem
|
||||
);
|
||||
|
||||
/*** PRINT INFORMATION ABOUT DRIVER MANAGER ***/
|
||||
|
||||
/*! Calls func() for every device found matching the search requirements of
|
||||
* set_mask and clr_mask. Each bit set in set_mask must be set in the
|
||||
* device state bit mask (dev->state), and Each bit in the clr_mask must
|
||||
* be cleared in the device state bit mask (dev->state). There are three
|
||||
* special cases:
|
||||
*
|
||||
* 1. If state_set_mask and state_clr_mask are zero the state bits are
|
||||
* ignored and all cores are treated as a match.
|
||||
*
|
||||
* 2. If state_set_mask is zero the function func will not be called due to
|
||||
* a bit being set in the state mask.
|
||||
*
|
||||
* 3. If state_clr_mask is zero the function func will not be called due to
|
||||
* a bit being cleared in the state mask.
|
||||
*
|
||||
* If the function func() returns a non-zero value then for_each_dev will
|
||||
* return imediatly with the same return value as func() returned.
|
||||
*
|
||||
* \param devlist The list to iterate though searching for devices.
|
||||
* \param state_set_mask Defines the bits that must be set in dev->state
|
||||
* \param state_clr_mask Defines the bits that must be cleared in dev->state
|
||||
* \param func Function called on each
|
||||
*
|
||||
*/
|
||||
extern 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);
|
||||
|
||||
/* Print all devices */
|
||||
#define PRINT_DEVS_FAILED 0x01 /* Failed during initialization */
|
||||
#define PRINT_DEVS_ASSIGNED 0x02 /* Driver assigned */
|
||||
#define PRINT_DEVS_UNASSIGNED 0x04 /* Driver not assigned */
|
||||
#define PRINT_DEVS_IGNORED 0x08 /* Device ignored on user's request */
|
||||
#define PRINT_DEVS_ALL (PRINT_DEVS_FAILED | \
|
||||
PRINT_DEVS_ASSIGNED | \
|
||||
PRINT_DEVS_UNASSIGNED |\
|
||||
PRINT_DEVS_IGNORED)
|
||||
|
||||
/*! Print number of devices, buses and drivers */
|
||||
extern void drvmgr_summary(void);
|
||||
|
||||
/*! Print devices with certain condictions met according to 'options' */
|
||||
extern void drvmgr_print_devs(unsigned int options);
|
||||
|
||||
/*! Print device/bus topology */
|
||||
extern void drvmgr_print_topo(void);
|
||||
|
||||
/*! Print the memory usage
|
||||
* Only accounts for data structures. Not for the text size.
|
||||
*/
|
||||
extern void drvmgr_print_mem(void);
|
||||
|
||||
#define OPTION_DEV_GENINFO 0x00000001
|
||||
#define OPTION_DEV_BUSINFO 0x00000002
|
||||
#define OPTION_DEV_DRVINFO 0x00000004
|
||||
#define OPTION_DRV_DEVS 0x00000100
|
||||
#define OPTION_BUS_DEVS 0x00010000
|
||||
#define OPTION_RECURSIVE 0x01000000
|
||||
#define OPTION_INFO_ALL 0xffffffff
|
||||
|
||||
/*! Print information about a driver manager object (device, driver, bus) */
|
||||
extern void drvmgr_info(void *id, unsigned int options);
|
||||
|
||||
/*! Get information about a device */
|
||||
extern void drvmgr_info_dev(struct drvmgr_dev *dev, unsigned int options);
|
||||
|
||||
/*! Get information about a bus */
|
||||
extern void drvmgr_info_bus(struct drvmgr_bus *bus, unsigned int options);
|
||||
|
||||
/*! Get information about a driver */
|
||||
extern void drvmgr_info_drv(struct drvmgr_drv *drv, unsigned int options);
|
||||
|
||||
/*! Get information about all devices on a bus */
|
||||
extern void drvmgr_info_devs_on_bus(struct drvmgr_bus *bus, unsigned int options);
|
||||
|
||||
/*! Get information about all devices in the system (on all buses) */
|
||||
extern void drvmgr_info_devs(unsigned int options);
|
||||
|
||||
/*! Get information about all drivers in the system */
|
||||
extern void drvmgr_info_drvs(unsigned int options);
|
||||
|
||||
/*! Get information about all buses in the system */
|
||||
extern void drvmgr_info_buses(unsigned int options);
|
||||
|
||||
/*! Get Driver by Driver ID */
|
||||
extern struct drvmgr_drv *drvmgr_drv_by_id(uint64_t id);
|
||||
|
||||
/*! Get Driver by Driver Name */
|
||||
extern struct drvmgr_drv *drvmgr_drv_by_name(const char *name);
|
||||
|
||||
/*! Get Device by Device Name */
|
||||
extern struct drvmgr_dev *drvmgr_dev_by_name(const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
33
cpukit/libdrvmgr/drvmgr_by_id.c
Normal file
33
cpukit/libdrvmgr/drvmgr_by_id.c
Normal 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;
|
||||
}
|
||||
37
cpukit/libdrvmgr/drvmgr_by_name.c
Normal file
37
cpukit/libdrvmgr/drvmgr_by_name.c
Normal 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;
|
||||
}
|
||||
86
cpukit/libdrvmgr/drvmgr_confdefs.h
Normal file
86
cpukit/libdrvmgr/drvmgr_confdefs.h
Normal 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_ */
|
||||
34
cpukit/libdrvmgr/drvmgr_dev_by_name.c
Normal file
34
cpukit/libdrvmgr/drvmgr_dev_by_name.c
Normal 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);
|
||||
}
|
||||
148
cpukit/libdrvmgr/drvmgr_drvinf.c
Normal file
148
cpukit/libdrvmgr/drvmgr_drvinf.c
Normal 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, ¶ms);
|
||||
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;
|
||||
}
|
||||
104
cpukit/libdrvmgr/drvmgr_for_each_dev.c
Normal file
104
cpukit/libdrvmgr/drvmgr_for_each_dev.c
Normal 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;
|
||||
}
|
||||
44
cpukit/libdrvmgr/drvmgr_for_each_list_dev.c
Normal file
44
cpukit/libdrvmgr/drvmgr_for_each_list_dev.c
Normal 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;
|
||||
}
|
||||
42
cpukit/libdrvmgr/drvmgr_func.c
Normal file
42
cpukit/libdrvmgr/drvmgr_func.c
Normal 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;
|
||||
}
|
||||
21
cpukit/libdrvmgr/drvmgr_func_call.c
Normal file
21
cpukit/libdrvmgr/drvmgr_func_call.c
Normal 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);
|
||||
}
|
||||
26
cpukit/libdrvmgr/drvmgr_init.c
Normal file
26
cpukit/libdrvmgr/drvmgr_init.c
Normal 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;
|
||||
}
|
||||
70
cpukit/libdrvmgr/drvmgr_internal.h
Normal file
70
cpukit/libdrvmgr/drvmgr_internal.h
Normal 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
|
||||
67
cpukit/libdrvmgr/drvmgr_list.c
Normal file
67
cpukit/libdrvmgr/drvmgr_list.c
Normal 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;
|
||||
}
|
||||
79
cpukit/libdrvmgr/drvmgr_list.h
Normal file
79
cpukit/libdrvmgr/drvmgr_list.h
Normal 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
|
||||
38
cpukit/libdrvmgr/drvmgr_lock.c
Normal file
38
cpukit/libdrvmgr/drvmgr_lock.c
Normal 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;
|
||||
}
|
||||
457
cpukit/libdrvmgr/drvmgr_print.c
Normal file
457
cpukit/libdrvmgr/drvmgr_print.c
Normal 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;
|
||||
}
|
||||
}
|
||||
102
cpukit/libdrvmgr/drvmgr_res.c
Normal file
102
cpukit/libdrvmgr/drvmgr_res.c
Normal 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);
|
||||
}
|
||||
52
cpukit/libdrvmgr/drvmgr_rw.c
Normal file
52
cpukit/libdrvmgr/drvmgr_rw.c
Normal 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);
|
||||
}
|
||||
149
cpukit/libdrvmgr/drvmgr_translate.c
Normal file
149
cpukit/libdrvmgr/drvmgr_translate.c
Normal 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);
|
||||
}
|
||||
35
cpukit/libdrvmgr/drvmgr_translate_check.c
Normal file
35
cpukit/libdrvmgr/drvmgr_translate_check.c
Normal 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;
|
||||
}
|
||||
186
cpukit/libdrvmgr/drvmgr_unregister.c
Normal file
186
cpukit/libdrvmgr/drvmgr_unregister.c
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user