summaryrefslogtreecommitdiffstats
path: root/pcilib/register.c
diff options
context:
space:
mode:
Diffstat (limited to 'pcilib/register.c')
-rw-r--r--pcilib/register.c67
1 files changed, 56 insertions, 11 deletions
diff --git a/pcilib/register.c b/pcilib/register.c
index 3a60800..30505ae 100644
--- a/pcilib/register.c
+++ b/pcilib/register.c
@@ -11,22 +11,28 @@
#include <arpa/inet.h>
#include <errno.h>
#include <assert.h>
+#include <alloca.h>
#include "pci.h"
#include "bank.h"
#include "tools.h"
#include "error.h"
-
+#include "property.h"
int pcilib_add_registers(pcilib_t *ctx, pcilib_model_modification_flags_t flags, size_t n, const pcilib_register_description_t *registers, pcilib_register_t *ids) {
// DS: Overrride existing registers
// Registers identified by addr + offset + size + type or name
-
+ int err;
+ size_t size;
pcilib_register_t i;
+
pcilib_register_description_t *regs;
pcilib_register_context_t *reg_ctx;
- size_t size;
+
+ pcilib_register_bank_t bank = PCILIB_REGISTER_BANK_INVALID;
+ pcilib_register_bank_addr_t bank_addr = (pcilib_register_bank_addr_t)-1;
+ pcilib_register_bank_t *banks;
if (!n) {
for (n = 0; registers[n].bits; n++);
@@ -59,13 +65,43 @@ int pcilib_add_registers(pcilib_t *ctx, pcilib_model_modification_flags_t flags,
ctx->alloc_reg = size;
}
+ banks = (pcilib_register_bank_t*)alloca(n * sizeof(pcilib_register_bank_t));
+ if (!banks) return PCILIB_ERROR_MEMORY;
+
+ for (i = 0; i < n; i++) {
+ if (registers[i].bank != bank_addr) {
+ bank_addr = registers[i].bank;
+ bank = pcilib_find_register_bank_by_addr(ctx, bank_addr);
+ if (bank == PCILIB_REGISTER_BANK_INVALID) {
+ pcilib_error("Invalid bank address (0x%lx) is specified for register %s", bank_addr, registers[i].name);
+ return PCILIB_ERROR_INVALID_BANK;
+ }
+ }
+
+/*
+ // No hash so far, will iterate.
+ pcilib_register_t reg = pcilib_find_register(ctx, ctx->banks[bank].name, registers[i].name);
+ if (reg != PCILIB_REGISTER_INVALID) {
+ pcilib_error("Register %s is already defined in the model", registers[i].name);
+ return PCILIB_ERROR_EXIST;
+ }
+*/
+
+ banks[i] = bank;
+ }
+
+ err = pcilib_add_register_properties(ctx, n, banks, registers);
+ if (err) return err;
+
for (i = 0; i < n; i++) {
pcilib_register_context_t *cur = &ctx->register_ctx[ctx->num_reg + i];
+
cur->reg = ctx->num_reg + i;
cur->name = registers[i].name;
+ cur->bank = banks[i];
HASH_ADD_KEYPTR(hh, ctx->reg_hash, cur->name, strlen(cur->name), cur);
}
-
+
memcpy(ctx->registers + ctx->num_reg, registers, n * sizeof(pcilib_register_description_t));
memset(ctx->registers + ctx->num_reg + n, 0, sizeof(pcilib_register_description_t));
@@ -78,26 +114,35 @@ int pcilib_add_registers(pcilib_t *ctx, pcilib_model_modification_flags_t flags,
ctx->num_reg += n;
-
return 0;
}
-void pcilib_clean_registers(pcilib_t *ctx) {
+void pcilib_clean_registers(pcilib_t *ctx, pcilib_register_t start) {
pcilib_register_t reg;
+ pcilib_register_context_t *reg_ctx, *tmp;
+
+ if (start) {
+ HASH_ITER(hh, ctx->reg_hash, reg_ctx, tmp) {
+ if (reg_ctx->reg >= start) {
+ HASH_DEL(ctx->reg_hash, reg_ctx);
+ }
+ }
+ } else {
+ HASH_CLEAR(hh, ctx->reg_hash);
+ }
- HASH_CLEAR(hh, ctx->reg_hash);
- for (reg = 0; reg < ctx->num_reg; reg++) {
+ for (reg = start; reg < ctx->num_reg; reg++) {
if (ctx->register_ctx[reg].views)
free(ctx->register_ctx[reg].views);
}
if (ctx->registers)
- memset(ctx->registers, 0, sizeof(pcilib_register_description_t));
+ memset(&ctx->registers[start], 0, sizeof(pcilib_register_description_t));
if (ctx->register_ctx)
- memset(ctx->register_ctx, 0, ctx->alloc_reg * sizeof(pcilib_register_context_t));
+ memset(&ctx->register_ctx[start], 0, (ctx->alloc_reg - start) * sizeof(pcilib_register_context_t));
- ctx->num_reg = 0;
+ ctx->num_reg = start;
}
static int pcilib_read_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, pcilib_register_size_t offset, pcilib_register_size_t bits, pcilib_register_value_t *buf) {