diff options
Diffstat (limited to 'pcilib')
-rw-r--r-- | pcilib/CMakeLists.txt | 6 | ||||
-rw-r--r-- | pcilib/bank.c | 36 | ||||
-rw-r--r-- | pcilib/bank.h | 6 | ||||
-rw-r--r-- | pcilib/export.c | 3 | ||||
-rw-r--r-- | pcilib/pci.c | 73 | ||||
-rw-r--r-- | pcilib/pci.h | 3 | ||||
-rw-r--r-- | pcilib/plugin.c | 101 | ||||
-rw-r--r-- | pcilib/plugin.h | 10 | ||||
-rw-r--r-- | pcilib/register.c | 2 | ||||
-rw-r--r-- | pcilib/register.h | 3 |
10 files changed, 206 insertions, 37 deletions
diff --git a/pcilib/CMakeLists.txt b/pcilib/CMakeLists.txt index df3dcd9..70bd5f0 100644 --- a/pcilib/CMakeLists.txt +++ b/pcilib/CMakeLists.txt @@ -3,9 +3,9 @@ include_directories( ${CMAKE_SOURCE_DIR}/pcilib ) -set(HEADERS pcilib.h pci.h export.h model.h bank.h register.h kmem.h irq.h dma.h event.h tools.h error.h config.h) -add_library(pcilib SHARED pci.c export.c model.c bank.c register.c kmem.c irq.c dma.c event.c tools.c error.c) -target_link_libraries(pcilib dma protocols ${CMAKE_THREAD_LIBS_INIT} ${UFODECODE_LIBRARIES} ) +set(HEADERS pcilib.h pci.h export.h model.h bank.h register.h kmem.h irq.h dma.h event.h plugin.h tools.h error.h config.h) +add_library(pcilib SHARED pci.c export.c model.c bank.c register.c kmem.c irq.c dma.c event.c plugin.c tools.c error.c) +target_link_libraries(pcilib dma protocols ${CMAKE_THREAD_LIBS_INIT} ${UFODECODE_LIBRARIES} ${CMAKE_DL_LIBS}) add_dependencies(pcilib dma protocols) install(TARGETS pcilib diff --git a/pcilib/bank.c b/pcilib/bank.c index 91bd161..dbbb427 100644 --- a/pcilib/bank.c +++ b/pcilib/bank.c @@ -78,7 +78,7 @@ void pcilib_free_register_banks(pcilib_t *ctx) { int pcilib_add_register_banks(pcilib_t *ctx, size_t n, const pcilib_register_bank_description_t *banks) { - // DS: What we are doing if bank exists? + // DS: Override existing banks if (!n) { for (n = 0; banks[n].access; n++); @@ -87,7 +87,6 @@ int pcilib_add_register_banks(pcilib_t *ctx, size_t n, const pcilib_register_ban if ((ctx->num_banks + n + 1) > PCILIB_MAX_REGISTER_BANKS) return PCILIB_ERROR_TOOBIG; - memset(ctx->banks + ctx->num_banks + n, 0, sizeof(pcilib_register_bank_description_t)); memcpy(ctx->banks + ctx->num_banks, banks, n * sizeof(pcilib_register_bank_description_t)); ctx->num_banks += n; @@ -101,6 +100,39 @@ int pcilib_add_register_banks(pcilib_t *ctx, size_t n, const pcilib_register_ban return 0; } +int pcilib_add_register_protocols(pcilib_t *ctx, size_t n, const pcilib_register_protocol_description_t *protocols) { + // DS: Override existing banks + + if (!n) { + for (n = 0; protocols[n].api; n++); + } + + if ((ctx->num_protocols + n + 1) > PCILIB_MAX_REGISTER_PROTOCOLS) + return PCILIB_ERROR_TOOBIG; + + memcpy(ctx->protocols + ctx->num_protocols, protocols, n * sizeof(pcilib_register_protocol_description_t)); + ctx->num_protocols += n; + + return 0; +} + + +int pcilib_add_register_ranges(pcilib_t *ctx, size_t n, const pcilib_register_range_t *ranges) { + // DS: Override existing banks + + if (!n) { + for (n = 0; ranges[n].end; n++); + } + + if ((ctx->num_ranges + n + 1) > PCILIB_MAX_REGISTER_RANGES) + return PCILIB_ERROR_TOOBIG; + + memcpy(ctx->ranges + ctx->num_ranges, ranges, n * sizeof(pcilib_register_range_t)); + ctx->num_ranges += n; + + return 0; +} + pcilib_register_bank_t pcilib_find_register_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank) { pcilib_register_bank_t i; const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); diff --git a/pcilib/bank.h b/pcilib/bank.h index f673169..995d38f 100644 --- a/pcilib/bank.h +++ b/pcilib/bank.h @@ -16,9 +16,6 @@ #define PCILIB_REGISTER_PROTOCOL_DMA 96 /**< First PROTOCOL address to be used by DMA engines */ #define PCILIB_REGISTER_PROTOCOL_DYNAMIC 128 /**< First PROTOCOL address to be used by plugins */ -#define PCILIB_REGISTER_NO_BITS 0 -#define PCILIB_REGISTER_ALL_BITS ((pcilib_register_value_t)-1) - typedef uint8_t pcilib_register_bank_t; /**< Type holding the bank position within the field listing register banks in the model */ typedef uint8_t pcilib_register_bank_addr_t; /**< Type holding the bank address number */ typedef uint8_t pcilib_register_protocol_t; /**< Type holding the protocol position within the field listing register protocols in the model */ @@ -89,7 +86,10 @@ struct pcilib_register_bank_context_s { // we don't copy strings, they should be statically allocated int pcilib_init_register_banks(pcilib_t *ctx); void pcilib_free_register_banks(pcilib_t *ctx); + int pcilib_add_register_banks(pcilib_t *ctx, size_t n, const pcilib_register_bank_description_t *banks); +int pcilib_add_register_protocols(pcilib_t *ctx, size_t n, const pcilib_register_protocol_description_t *protocols); +int pcilib_add_register_ranges(pcilib_t *ctx, size_t n, const pcilib_register_range_t *ranges); pcilib_register_bank_t pcilib_find_register_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank); pcilib_register_bank_t pcilib_find_register_bank_by_name(pcilib_t *ctx, const char *bankname); diff --git a/pcilib/export.c b/pcilib/export.c index 2027870..590a8ff 100644 --- a/pcilib/export.c +++ b/pcilib/export.c @@ -20,13 +20,12 @@ const pcilib_register_protocol_description_t pcilib_protocols[] = { #include "dma/nwl.h" #include "dma/ipe.h" -/* + const pcilib_dma_description_t pcilib_ipedma = { &ipe_dma_api, ipe_dma_banks, ipe_dma_registers, ipe_dma_engines, NULL, NULL, "ipedma", "DMA engine developed by M. Caselle" }; const pcilib_dma_description_t pcilib_nwldma = { &nwl_dma_api, nwl_dma_banks, nwl_dma_registers, NULL, NULL, NULL, "nwldma", "North West Logic DMA Engine" }; -*/ const pcilib_dma_description_t pcilib_dma[] = { { &ipe_dma_api, ipe_dma_banks, ipe_dma_registers, ipe_dma_engines, NULL, NULL, "ipedma", "DMA engine developed by M. Caselle" }, diff --git a/pcilib/pci.c b/pcilib/pci.c index 426ae91..6eedbfe 100644 --- a/pcilib/pci.c +++ b/pcilib/pci.c @@ -20,56 +20,74 @@ #include "tools.h" #include "error.h" #include "model.h" +#include "plugin.h" static int pcilib_detect_model(pcilib_t *ctx, const char *model) { int i, j; - // Registers & Banks must be copied! + const pcilib_model_description_t *model_info = NULL; + const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx); - if (model) { - // Check for DMA models + model_info = pcilib_find_plugin_model(ctx, board_info->vendor_id, board_info->device_id, model); + if (model_info) { + memcpy(&ctx->model_info, model_info, sizeof(pcilib_model_description_t)); + memcpy(&ctx->dma, model_info->dma, sizeof(pcilib_dma_description_t)); + } else if (model) { + // If not found, check for DMA models for (i = 0; pcilib_dma[i].name; i++) { if (!strcasecmp(model, pcilib_dma[i].name)) break; } if (pcilib_dma[i].api) { + model_info = &ctx->model_info; memcpy(&ctx->dma, &pcilib_dma[i], sizeof(pcilib_dma_description_t)); ctx->model_info.dma = &ctx->dma; + } + } - if (pcilib_dma[i].banks) - pcilib_add_register_banks(ctx, 0, pcilib_dma[i].banks); - - if (pcilib_dma[i].registers) - pcilib_add_registers(ctx, 0, pcilib_dma[i].registers); + // Precedens of register configuration: DMA/Event Initialization (top), XML, Event Description, DMA Description (least) + if (model_info) { + const pcilib_dma_description_t *dma = model_info->dma; + + if (dma) { + if (dma->banks) + pcilib_add_register_banks(ctx, 0, dma->banks); + + if (dma->registers) + pcilib_add_registers(ctx, 0, dma->registers); - if (pcilib_dma[i].engines) { - for (j = 0; pcilib_dma[i].engines[j].addr_bits; j++) - memcpy(ctx->engines, pcilib_dma[i].engines, j * sizeof(pcilib_dma_engine_description_t)); + if (dma->engines) { + for (j = 0; dma->engines[j].addr_bits; j++); + memcpy(ctx->engines, dma->engines, j * sizeof(pcilib_dma_engine_description_t)); ctx->num_engines = j; } else ctx->dma.engines = ctx->engines; - - return 0; } - // Check for XML models (DMA + XML registers) + if (model_info->protocols) + pcilib_add_register_protocols(ctx, 0, model_info->protocols); + + if (model_info->banks) + pcilib_add_register_banks(ctx, 0, model_info->banks); - // Check for specified model - - // Iterate other all other models + if (model_info->registers) + pcilib_add_registers(ctx, 0, model_info->registers); + + if (model_info->ranges) + pcilib_add_register_ranges(ctx, 0, model_info->ranges); } + // Load XML registers + // Check for all installed models // memcpy(&ctx->model_info, model, sizeof(pcilib_model_description_t)); // how we reconcile the banks from event model and dma description? The banks specified in the DMA description should override corresponding banks of events... - if (model) + if ((model)&&(!model_info)/*&&(no xml)*/) return PCILIB_ERROR_NOTFOUND; - // Otherwise, simple pci access (all model members are set to NULL) - return 0; } @@ -113,11 +131,7 @@ pcilib_t *pcilib_open(const char *device, const char *model) { for (i = 0; pcilib_protocols[i].api; i++); memcpy(ctx->protocols, pcilib_protocols, i * sizeof(pcilib_register_protocol_description_t)); - - ctx->model_info.registers = ctx->registers; - ctx->model_info.banks = ctx->banks; - ctx->model_info.protocols = ctx->protocols; - ctx->model_info.ranges = ctx->ranges; + ctx->num_protocols = i; err = pcilib_detect_model(ctx, model); if (err) { @@ -131,6 +145,12 @@ pcilib_t *pcilib_open(const char *device, const char *model) { return NULL; } + ctx->model_info.registers = ctx->registers; + ctx->model_info.banks = ctx->banks; + ctx->model_info.protocols = ctx->protocols; + ctx->model_info.ranges = ctx->ranges; + + err = pcilib_init_register_banks(ctx); if (err) { pcilib_error("Error (%i) initializing regiser banks\n", err); @@ -451,6 +471,9 @@ void pcilib_close(pcilib_t *ctx) { pcilib_free_register_banks(ctx); + if (ctx->event_plugin) + pcilib_plugin_close(ctx->event_plugin); + if (ctx->kmem_list) { pcilib_warning("Not all kernel buffers are properly cleaned"); diff --git a/pcilib/pci.h b/pcilib/pci.h index 2e2b509..b53c70b 100644 --- a/pcilib/pci.h +++ b/pcilib/pci.h @@ -40,11 +40,12 @@ struct pcilib_s { pcilib_kmem_list_t *kmem_list; /**< List of currently allocated kernel memory */ char *model; /**< Requested model */ + void *event_plugin; /**< Currently loaded event engine */ pcilib_model_description_t model_info; /**< Current model description combined from the information returned by the event plugin and all dynamic sources (XML, DMA registers, etc.). Contains only pointers, no deep copy of information returned by event plugin */ size_t num_banks_init; /**< Number of initialized banks */ size_t num_reg, alloc_reg; /**< Number of registered and allocated registers */ - size_t num_banks, num_ranges; /**< Number of registered banks and register ranges */ + size_t num_banks, num_protocols, num_ranges; /**< Number of registered banks, protocols, and register ranges */ size_t num_engines; /**> Number of configured DMA engines */ pcilib_register_description_t *registers; /**< List of currently defined registers (from all sources) */ pcilib_register_bank_description_t banks[PCILIB_MAX_REGISTER_BANKS + 1]; /**< List of currently defined register banks (from all sources) */ diff --git a/pcilib/plugin.c b/pcilib/plugin.c new file mode 100644 index 0000000..663bb27 --- /dev/null +++ b/pcilib/plugin.c @@ -0,0 +1,101 @@ +#include <stdio.h> +#include <stdlib.h> +#include <dlfcn.h> +#include <dirent.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> + +#include "model.h" +#include "pci.h" +#include "config.h" + +void *pcilib_plugin_load(const char *name) { + void *plug; + char *fullname; + const char *path; + + path = getenv("PCILIB_PLUGIN_DIR"); + if (!path) path = PCILIB_PLUGIN_DIR; + + fullname = malloc(strlen(path) + strlen(name) + 2); + if (!fullname) return NULL; + + sprintf(fullname, "%s/%s", path, name); + + plug = dlopen(fullname, RTLD_LAZY|RTLD_LOCAL); + free(fullname); + + return plug; +} + +void pcilib_plugin_close(void *plug) { + if (plug) + dlclose(plug); + +} + +void *pcilib_plugin_get_symbol(void *plug, const char *symbol) { + if ((!plug)||(!symbol)) return NULL; + return dlsym(plug, symbol); +} + +const pcilib_model_description_t *pcilib_get_plugin_model(pcilib_t *pcilib, void *plug, unsigned short vendor_id, unsigned short device_id, const char *model) { + void *get_model; + + if (!plug) return NULL; + + get_model = dlsym(plug, "pcilib_get_event_model"); + if (!get_model) return NULL; + + return ((const pcilib_model_description_t *(*)(pcilib_t *pcilib, unsigned short vendor_id, unsigned short device_id, const char *model))get_model)(pcilib, vendor_id, device_id, model); +} + +const pcilib_model_description_t *pcilib_find_plugin_model(pcilib_t *pcilib, unsigned short vendor_id, unsigned short device_id, const char *model) { + DIR *dir; + const char *path; + struct dirent *entry; + + void *plugin; + const pcilib_model_description_t *model_info = NULL; + + + path = getenv("PCILIB_PLUGIN_DIR"); + if (!path) path = PCILIB_PLUGIN_DIR; + + if (model) { + plugin = pcilib_plugin_load(model); + if (plugin) { + model_info = pcilib_get_plugin_model(pcilib, plugin, vendor_id, device_id, model); + if (model_info) { + pcilib->event_plugin = plugin; + return model_info; + } + pcilib_plugin_close(plugin); + } + } + + dir = opendir(path); + if (!dir) return NULL; + + while ((entry = readdir(dir))) { + const char *suffix = strstr(entry->d_name, ".so"); + if ((!suffix)||(strlen(suffix) != 3)) continue; + + if ((model)&&(!strcmp(entry->d_name, model))) + continue; + + plugin = pcilib_plugin_load(entry->d_name); + if (plugin) { + model_info = pcilib_get_plugin_model(pcilib, plugin, vendor_id, device_id, model); + if (model_info) { + pcilib->event_plugin = plugin; + break; + } + pcilib_plugin_close(plugin); + } + } + + closedir(dir); + return model_info; +} diff --git a/pcilib/plugin.h b/pcilib/plugin.h new file mode 100644 index 0000000..774fda5 --- /dev/null +++ b/pcilib/plugin.h @@ -0,0 +1,10 @@ +#ifndef _PCILIB_PLUGIN_H +#define _PCILIB_PLUGIN_H + +void *pcilib_plugin_load(const char *name); +void pcilib_plugin_close(void *plug); +void *pcilib_plugin_get_symbol(void *plug, const char *symbol); +const pcilib_model_description_t *pcilib_get_plugin_model(pcilib_t *pcilib, void *plug, unsigned short vendor_id, unsigned short device_id, const char *model); +const pcilib_model_description_t *pcilib_find_plugin_model(pcilib_t *pcilib, unsigned short vendor_id, unsigned short device_id, const char *model); + +#endif /* _PCILIB_PLUGIN_H */ diff --git a/pcilib/register.c b/pcilib/register.c index 8d138b8..586dded 100644 --- a/pcilib/register.c +++ b/pcilib/register.c @@ -20,7 +20,7 @@ int pcilib_add_registers(pcilib_t *ctx, size_t n, const pcilib_register_description_t *registers) { - // DS: What we are doing if register exists? + // DS: Overrride existing registers pcilib_register_description_t *regs; size_t size; diff --git a/pcilib/register.h b/pcilib/register.h index 89673ec..7514943 100644 --- a/pcilib/register.h +++ b/pcilib/register.h @@ -4,6 +4,9 @@ #include <pcilib.h> #include <pcilib/bank.h> +#define PCILIB_REGISTER_NO_BITS 0 +#define PCILIB_REGISTER_ALL_BITS ((pcilib_register_value_t)-1) + typedef enum { PCILIB_REGISTER_R = 1, /**< reading from register is allowed */ PCILIB_REGISTER_W = 2, /**< normal writting to register is allowed */ |