diff options
Diffstat (limited to 'cpukit/libdrvmgr/drvmgr.h')
-rw-r--r-- | cpukit/libdrvmgr/drvmgr.h | 965 |
1 files changed, 965 insertions, 0 deletions
diff --git a/cpukit/libdrvmgr/drvmgr.h b/cpukit/libdrvmgr/drvmgr.h new file mode 100644 index 0000000000..f091728e49 --- /dev/null +++ b/cpukit/libdrvmgr/drvmgr.h @@ -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 |