forked from Imagelibrary/rtems
969 lines
37 KiB
C
969 lines
37 KiB
C
/* 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.org/license/LICENSE.
|
|
*/
|
|
|
|
#ifndef _DRIVER_MANAGER_H_
|
|
#define _DRIVER_MANAGER_H_
|
|
|
|
#include <rtems.h>
|
|
#include <drvmgr/drvmgr_list.h>
|
|
#include <stdint.h>
|
|
#include <rtems/score/basedefs.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 (*get_freq)(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 (*get_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 */
|
|
enum drvmgr_kt {
|
|
DRVMGR_KT_ANY = -1,
|
|
DRVMGR_KT_NONE = 0,
|
|
DRVMGR_KT_INT = 1,
|
|
DRVMGR_KT_STRING = 2,
|
|
DRVMGR_KT_POINTER = 3,
|
|
};
|
|
|
|
#define DRVMGR_KEY_EMPTY {NULL, DRVMGR_KT_NONE, {0}}
|
|
#define DRVMGR_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 */
|
|
enum drvmgr_kt 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 DRVMGR_OPS_NUM(x) (sizeof(x)/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.
|
|
*/
|
|
typedef void (*drvmgr_drv_reg_func)(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 DRVMGR_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 DRVMGR_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,
|
|
enum drvmgr_kt 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,
|
|
enum drvmgr_kt key_type);
|
|
|
|
/*** DRIVER INTERACE USED TO REQUEST INFORMATION/SERVICES FROM BUS DRIVER ***/
|
|
|
|
/*! Get parent bus */
|
|
RTEMS_INLINE_ROUTINE struct drvmgr_bus *drvmgr_get_parent(
|
|
struct drvmgr_dev *dev)
|
|
{
|
|
if (dev)
|
|
return dev->parent;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/*! Get Driver of device */
|
|
RTEMS_INLINE_ROUTINE 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
|