--- /dev/null
+/*******************************************************************
+ Key Value Persistent Storage
+
+ keyvalpb.c - key value parameters block
+
+ (C) Copyright 2003-2005 by Pavel Pisa - Originator
+ (C) Copyright 2004-2005 by Petr Smolik - Originator
+
+ The uLan utilities library can be used, copied and modified under
+ next licenses
+ - GPL - GNU General Public License
+ - LGPL - GNU Lesser General Public License
+ - MPL - Mozilla Public License
+ - and other licenses added by project originators
+ Code can be modified and re-distributed under any combination
+ of the above listed licenses. If contributor does not agree with
+ some of the licenses, he/she can delete appropriate line.
+ Warning, if you delete all lines, you are not allowed to
+ distribute source code and/or binaries utilizing code.
+
+ See files COPYING and README for details.
+
+ *******************************************************************/
+
+#include <string.h>
+#include "keyvalpb.h"
+
+/*
+ * kvpb_memsum - Compute checksum of given memory area
+ * @base: Pointer to the base of of the region
+ * @size: Size of utilized part of the region
+ *
+ * Return Value: Computed checksum value
+ * File: keyvalpb.c
+ */
+kvpb_sum_t kvpb_memsum(KVPB_DPTRTYPE uint8_t *base, kvpb_size_t size)
+{
+ KVPB_LOCALDATA kvpb_sum_t sum=0;
+ KVPB_DPTRTYPE uint16_t *p=(KVPB_DPTRTYPE uint16_t *)base;
+ size=(size+1)>>1;
+ while(size--){
+ sum+=*(p++);
+ }
+ sum&=KVPB_SUM_MASK;
+ sum|=KVPB_SUM_OKVAL;
+ return sum;
+}
+
+#ifndef KVPB_WITHOUT_HADLE
+/*
+ * kvpb_get_psum - Get pointer to the region check sum
+ * @kvpb_block: Pointer to the KVPB access information/state structure
+ * @base: Pointer to the base of of the region
+ * @size: Size of one data block region
+ *
+ * Return Value: Pointer to the actual region check sum placement
+ * File: keyvalpb.c
+ */
+KVPB_DPTRTYPE kvpb_sum_t *kvpb_get_psum(kvpb_block_t *kvpb_block,
+ KVPB_DPTRTYPE uint8_t *base, kvpb_size_t size)
+#else
+KVPB_DPTRTYPE kvpb_sum_t *__kvpb_get_psum(
+ KVPB_DPTRTYPE uint8_t *base, kvpb_size_t size)
+#endif
+{
+ KVPB_DPTRTYPE kvpb_sum_t *psum;
+ psum=kvpb_psum_align(kvpb_block,(KVPB_DPTRTYPE kvpb_sum_t*)(base+size)-1);
+ while((KVPB_DPTRTYPE uint8_t*)psum>=base) {
+ if (*kvpb_psum_valid_loc(kvpb_block,psum)!=0)
+ return psum;
+ psum=kvpb_psum_align(kvpb_block,psum-1);
+ }
+ return NULL;
+}
+
+#ifndef KVPB_WITHOUT_HADLE
+/*
+ * kvpb_get_cfk - Get space where to place new key-value pair
+ * @kvpb_block: Pointer to the KVPB access information/state structure
+ * @mode: 0 .. work on active/valid data region;
+ * 1 .. work on the first copy/region, 2 .. work on the second copy/region
+ * @size: Size of required space for stored value
+ *
+ * Return Value: Pointer where next pair should be stored or %NULL
+ * File: keyvalpb.c
+ */
+KVPB_DPTRTYPE kvpb_key_t *kvpb_get_cfk(kvpb_block_t *kvpb_block,uint8_t mode,int size)
+#else
+KVPB_DPTRTYPE kvpb_key_t *__kvpb_get_cfk(uint8_t mode,int size)
+#endif
+{
+ KVPB_DPTRTYPE kvpb_sum_t *psum;
+ KVPB_DPTRTYPE uint8_t *p;
+ KVPB_DPTRTYPE uint8_t *r;
+ p=kvpb_region_base(kvpb_block,0);
+ size=kvpb_chunk_align(kvpb_block,size+sizeof(kvpb_key_t))+
+ (kvpb_block->flags&KVPB_DESC_CHUNKWO?kvpb_chunk_size(kvpb_block):0);
+ psum=kvpb_block->psum1;
+ if((!mode && (kvpb_block->flags & KVPB_DESC_USE2ND))||(mode==2)) {
+ if(!(kvpb_block->flags&KVPB_DESC_DOUBLE))
+ return NULL;
+ p=kvpb_region_base(kvpb_block,1);
+ psum=kvpb_block->psum2;
+ }
+ do {
+ kvpb_size_t ksize=((KVPB_DPTRTYPE kvpb_key_t *)p)->size;
+ if(ksize==KVPB_EMPTY)
+ break;
+ if(((uint8_t*)psum-(uint8_t*)p)<ksize)
+ return NULL;
+ p+=kvpb_chunk_align(kvpb_block,ksize+sizeof(kvpb_key_t))+
+ (kvpb_block->flags&KVPB_DESC_CHUNKWO?kvpb_chunk_size(kvpb_block):0);
+ } while(1);
+ r=(KVPB_DPTRTYPE uint8_t*)p+size+sizeof(kvpb_key_t);
+ if(r<p)
+ return NULL;
+ if ((uint8_t*)kvpb_psum_align(kvpb_block,psum-1)<r) {
+ return NULL;
+ }
+ return (KVPB_DPTRTYPE kvpb_key_t*)p;
+}
+
+
+#ifndef KVPB_WITHOUT_HADLE
+/**
+ * kvpb_check - Check data consistency of the KVPB storage
+ * @kvpb_block: Pointer to the KVPB access information/state structure
+ * @mode: if mode is nonzero, try to restore valid state or erase all data
+ *
+ * Return Value: 0 .. all regions are correct, 1 .. the first region is valid, the second
+ * region is invalid or has been updated if @mode has been set, 2 .. the second region
+ * is valid, the first is invalid or has been updated if @mode has been set, 3 .. both
+ * regions has been erased and emptied, -1 .. the state is inconsistent and no valid
+ * region has been found and state has not be corrected
+ * File: keyvalpb.c
+ */
+int kvpb_check(kvpb_block_t *kvpb_block, uint8_t mode)
+#else
+int __kvpb_check(uint8_t mode)
+#endif
+{
+ KVPB_DPTRTYPE uint8_t *p;
+ KVPB_LOCALDATA int ret=-1;
+ KVPB_LOCALDATA kvpb_sum_t sum;
+
+ kvpb_block->flags&=~KVPB_DESC_USE2ND;
+
+ p=kvpb_region_base(kvpb_block,0);
+ kvpb_block->psum1=kvpb_get_psum(kvpb_block,p,kvpb_block->size);
+ if (kvpb_block->psum1) {
+ sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum1-p);
+ if(*kvpb_block->psum1==sum){
+ ret=1;
+ }
+ }
+
+ if(kvpb_block->flags&KVPB_DESC_DOUBLE){
+ p=kvpb_region_base(kvpb_block,1);
+ kvpb_block->psum2=kvpb_get_psum(kvpb_block,p,kvpb_block->size);
+ if (kvpb_block->psum2) {
+ sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum2-p);
+ if(*kvpb_block->psum2==sum) {
+ if(ret>=0){
+ ret=0;
+ } else {
+ ret=2;
+ kvpb_block->flags|=KVPB_DESC_USE2ND;
+ }
+ }
+ }
+ } else {
+ if(ret>=0)
+ ret=0;
+ }
+
+ if(ret){
+ if(!mode) {
+ kvpb_block->flags|=KVPB_DESC_RO;
+ } else {
+ /* correct for FLASH */
+ if(ret<0){
+ p=kvpb_region_base(kvpb_block,0);
+ kvpb_block_erase(kvpb_block,p,kvpb_block->size);
+ kvpb_block->psum1=kvpb_psum_align(kvpb_block,(KVPB_DPTRTYPE kvpb_sum_t*)(p+kvpb_block->size)-1);
+ sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum1-p);
+ kvpb_block_copy(kvpb_block,kvpb_block->psum1,&sum,sizeof(kvpb_sum_t));
+ if(kvpb_block->flags&KVPB_DESC_DOUBLE){
+ p=kvpb_region_base(kvpb_block,1);
+ kvpb_block_erase(kvpb_block,p,kvpb_block->size);
+ kvpb_block->psum2=kvpb_psum_align(kvpb_block,(KVPB_DPTRTYPE kvpb_sum_t*)(p+kvpb_block->size)-1);
+ sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum2-p);
+ kvpb_block_copy(kvpb_block,kvpb_block->psum2,&sum,sizeof(kvpb_sum_t));
+ }
+ ret=3;
+ }else{
+ if(ret==1){
+ kvpb_block_erase(kvpb_block,kvpb_region_base(kvpb_block,1),kvpb_block->size);
+ kvpb_block_copy(kvpb_block,kvpb_region_base(kvpb_block,1),
+ kvpb_region_base(kvpb_block,0),kvpb_block->size);
+
+ }else{
+ kvpb_block_erase(kvpb_block,kvpb_region_base(kvpb_block,0),kvpb_block->size);
+ kvpb_block_copy(kvpb_block,kvpb_region_base(kvpb_block,0),
+ kvpb_region_base(kvpb_block,1),kvpb_block->size);
+ }
+ }
+ kvpb_block->flags&=~KVPB_DESC_RO;
+ }
+ }
+ kvpb_block_flush(kvpb_block);
+ if(ret>=0) kvpb_block->flags|=KVPB_DESC_VALID;
+ return ret;
+}
+
+#ifndef KVPB_WITHOUT_HADLE
+/**
+ * kvpb_first - Get pointer to the first key-value pair in the KVPB storage
+ * @kvpb_block: Pointer to the KVPB access information/state structure
+ * @mode: 0 .. iterate over active/valid data region;
+ * 1 .. iterate over first copy/region, 2 .. iterate over second copy/region
+ *
+ * Return Value: Pointer to the first key-value pair
+ * or %NULL if no pair exist.
+ * File: keyvalpb.c
+ */
+KVPB_DPTRTYPE kvpb_key_t *kvpb_first(kvpb_block_t *kvpb_block, uint8_t mode)
+#else
+KVPB_DPTRTYPE kvpb_key_t *__kvpb_first(uint8_t mode)
+#endif
+{
+ KVPB_DPTRTYPE kvpb_key_t *key=(KVPB_DPTRTYPE kvpb_key_t *)kvpb_region_base(kvpb_block,0);
+ if((!mode && (kvpb_block->flags & KVPB_DESC_USE2ND))||(mode==2)) {
+ if(!(kvpb_block->flags&KVPB_DESC_DOUBLE))
+ return NULL;
+ key=(KVPB_DPTRTYPE kvpb_key_t *)kvpb_region_base(kvpb_block,1);
+ }
+ while(*kvpb_keyid_valid(kvpb_block,key)==KVPB_KEYID_INVALID) {
+ key=kvpb_next(kvpb_block,key);
+ if (!key)
+ return NULL;
+ }
+ return key->size!=KVPB_EMPTY?key:NULL;
+}
+
+#ifndef KVPB_WITHOUT_HADLE
+/**
+ * kvpb_next - Iterate to the next consecutive key-value pair
+ * @kvpb_block: Pointer to the KVPB access information/state structure
+ * @key: Pointer to the previous key-value pair
+ *
+ * Return Value: Pointer to the next key-value pair
+ * or %NULL if no/no-more pairs exist.
+ * File: keyvalpb.c
+ */
+KVPB_DPTRTYPE kvpb_key_t *kvpb_next(kvpb_block_t *kvpb_block, KVPB_DPTRTYPE kvpb_key_t *key)
+#else
+KVPB_DPTRTYPE kvpb_key_t *__kvpb_next(KVPB_DPTRTYPE kvpb_key_t *key)
+#endif
+{
+ do {
+ key=(KVPB_DPTRTYPE kvpb_key_t *)((KVPB_DPTRTYPE uint8_t *)key+
+ kvpb_chunk_align(kvpb_block,key->size+sizeof(kvpb_key_t))+
+ (kvpb_block->flags&KVPB_DESC_CHUNKWO?kvpb_chunk_size(kvpb_block):0));
+ if (key->size==KVPB_EMPTY) return NULL;
+ } while(*kvpb_keyid_valid(kvpb_block,key)==KVPB_KEYID_INVALID);
+ return key;
+}
+
+#ifndef KVPB_WITHOUT_HADLE
+/**
+ * kvpb_find - Find first of occurrence of given key ID
+ * @kvpb_block: Pointer to the KVPB access information/state structure
+ * @keyid: Ordinal value representing key ID
+ * @mode: iteration mode modifier: 0 .. search in the active/valid data region;
+ * 1 .. search in the first copy/region, 2 .. search in the second copy/region
+ * @key: Previous key occurrence pointer or %NULL value to find first key ID named key-value pair
+ *
+ * Return Value: Pointer to the first on subsequent occurrence of key-value pair addressed by given key ID
+ * or %NULL if no/no-more occurrences exists.
+ * File: keyvalpb.c
+ */
+KVPB_DPTRTYPE kvpb_key_t *kvpb_find(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, uint8_t mode, KVPB_DPTRTYPE kvpb_key_t *key)
+#else
+KVPB_DPTRTYPE kvpb_key_t *__kvpb_find(kvpb_keyid_t keyid, uint8_t mode, KVPB_DPTRTYPE kvpb_key_t *key)
+#endif
+{
+ if(!(kvpb_block->flags&KVPB_DESC_VALID))
+ return NULL;
+ if (key) {
+ key=kvpb_next(kvpb_block, key);
+ } else {
+ key=kvpb_first(kvpb_block, mode);
+ }
+ while(key) {
+ if((key->keyid==keyid) || (keyid==0))
+ return key;
+ key=kvpb_next(kvpb_block, key);
+ }
+ return key;
+}
+
+#ifndef KVPB_WITHOUT_HADLE
+/**
+ * kvpb_compact_region - Compact one KVPB data block/region
+ * @kvpb_block: Pointer to the KVPB access information/state structure
+ * @keyid: Key ID which should be omitted from compacted data
+ * @mode: 0 .. compact active/valid data region;
+ * 1 .. compact the first data copy, 2 .. compact the second copy
+ *
+ * Return Value: Operation cannot be finished.
+ * File: keyvalpb.c
+ */
+int kvpb_compact_region(kvpb_block_t *kvpb_block, uint8_t mode, kvpb_keyid_t keyid)
+#else
+int __kvpb_compact_region(uint8_t mode, kvpb_keyid_t keyid)
+#endif
+{
+ KVPB_DPTRTYPE uint8_t *p;
+ KVPB_DPTRTYPE kvpb_key_t *des,*src;
+
+ p=kvpb_region_base(kvpb_block,0);
+ des=(KVPB_DPTRTYPE kvpb_key_t*)p;
+ if(kvpb_block->flags&KVPB_DESC_DOUBLE)
+ src=(KVPB_DPTRTYPE kvpb_key_t*)kvpb_region_base(kvpb_block,1);
+ else
+ src=(KVPB_DPTRTYPE kvpb_key_t*)p;
+
+ if((!mode && (kvpb_block->flags & KVPB_DESC_USE2ND))||(mode==2)) {
+ if(!(kvpb_block->flags&KVPB_DESC_DOUBLE))
+ return -1;
+ des=src;
+ src=(KVPB_DPTRTYPE kvpb_key_t*)p;
+ p=(KVPB_DPTRTYPE uint8_t *)des;
+ kvpb_block->psum2=kvpb_psum_align(kvpb_block,
+ (KVPB_DPTRTYPE kvpb_sum_t*)(p+kvpb_block->size)-1);
+ } else {
+ kvpb_block->psum1=kvpb_psum_align(kvpb_block,
+ (KVPB_DPTRTYPE kvpb_sum_t*)(p+kvpb_block->size)-1);
+ }
+ kvpb_block_flush(kvpb_block);
+ kvpb_block_erase(kvpb_block,des,kvpb_block->size);
+ while(src) {
+ int s=kvpb_chunk_align(kvpb_block,src->size+sizeof(kvpb_key_t));
+ if((*kvpb_keyid_valid(kvpb_block,src)!=KVPB_KEYID_INVALID) && (src->keyid!=keyid)) {
+ if(src!=des)
+ kvpb_block_copy(kvpb_block,des,src,s);
+ if (kvpb_block->flags&KVPB_DESC_CHUNKWO) s+=kvpb_chunk_size(kvpb_block);
+ des=(KVPB_DPTRTYPE kvpb_key_t*)((uint8_t*)des+s);
+ }
+ src=kvpb_next(kvpb_block, src);
+ }
+ kvpb_block_flush(kvpb_block);
+ return 0;
+}
+
+#ifndef KVPB_WITHOUT_HADLE
+/**
+ * kvpb_get_key - Get value for given key ID
+ * @kvpb_block: Pointer to the KVPB access information/state structure
+ * @keyid: Ordinal value representing key ID
+ * @size: The size of the buffer provided to store data into
+ * @buf: Pointer to the buffer, where retrieved data should be copied
+ *
+ * Return Value: Number of retrieved value bytes if operation is successful
+ * or -1 if there is no such key ID or operation fails for other reason.
+ * File: keyvalpb.c
+ */
+int kvpb_get_key(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, kvpb_size_t size, void *buf)
+#else
+int __kvpb_get_key(kvpb_keyid_t keyid, kvpb_size_t size, void *buf)
+#endif
+{
+ KVPB_DPTRTYPE kvpb_key_t *key;
+ key=kvpb_find(kvpb_block,keyid,0,NULL);
+ if(!key) return -1;
+ if(size && buf){
+ if(key->size<size)
+ size=key->size;
+ memcpy(buf,key+1,size);
+ }
+ return key->size;
+}
+
+
+#ifndef KVPB_WITHOUT_HADLE
+/**
+ * kvpb_set_key - Set new value or define new key-value pair
+ * @kvpb_block: Pointer to the KVPB access information/state structure
+ * @keyid: Ordinal value representing key ID, if or-red with %KVPB_KEYID_DUPLIC,
+ * the key ID can be defined/inserted multiple times
+ * @size: Stored value size in bytes
+ * @buf: Pointer to the stored value data
+ *
+ * Return Value: Number of stored bytes (equal to @size) if operation is successful
+ * or -1 if operation fails.
+ * File: keyvalpb.c
+ */
+int kvpb_set_key(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, kvpb_size_t size, const void *buf)
+#else
+int __kvpb_set_key(kvpb_keyid_t keyid, kvpb_size_t size, const void *buf)
+#endif
+{
+ KVPB_LOCALDATA kvpb_sum_t sum;
+ KVPB_DPTRTYPE kvpb_sum_t *psum;
+ KVPB_DPTRTYPE kvpb_key_t *key;
+ KVPB_DPTRTYPE uint8_t *p;
+
+ if(!(kvpb_block->flags&KVPB_DESC_VALID))
+ return -1;
+ if(kvpb_block->flags&KVPB_DESC_RO)
+ return -1;
+
+ /*first region*/
+ psum=kvpb_psum_align(kvpb_block,kvpb_block->psum1);
+ sum=0;
+ kvpb_block_copy(kvpb_block,kvpb_psum_valid_loc(kvpb_block,psum),&sum,sizeof(kvpb_sum_t));
+ kvpb_block->psum1=kvpb_psum_align(kvpb_block,kvpb_block->psum1-1);
+ if (!(keyid&KVPB_KEYID_DUPLIC) || !buf) {
+ kvpb_each_from(kvpb_block,keyid,1,key) {
+ kvpb_keyid_t dkeyid=KVPB_KEYID_INVALID;
+ kvpb_block_copy(kvpb_block,kvpb_keyid_valid(kvpb_block,key),&dkeyid,sizeof(kvpb_keyid_t));
+ }
+ }
+ key=kvpb_get_cfk(kvpb_block,1,size);
+ if (!key) {
+ kvpb_compact_region(kvpb_block,1,(keyid&KVPB_KEYID_DUPLIC)?0:keyid);
+ key=kvpb_get_cfk(kvpb_block,1,size);
+ }
+ if (keyid && key && buf) {
+ kvpb_block_copy(kvpb_block,&key->size,&size,sizeof(kvpb_size_t));
+ kvpb_block_copy(kvpb_block,&key->keyid,&keyid,sizeof(kvpb_keyid_t));
+ kvpb_block_copy(kvpb_block,(uint8_t*)(key+1),buf,/*align???*/ size);
+ }
+ /* need flush data to count correct value of new check sum */
+ kvpb_block_flush(kvpb_block);
+
+ p=kvpb_region_base(kvpb_block,0);
+ sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum1-p);
+ kvpb_block_copy(kvpb_block,kvpb_block->psum1,&sum,sizeof(kvpb_sum_t));
+ kvpb_block_flush(kvpb_block);
+ if(!(kvpb_block->flags&KVPB_DESC_DOUBLE))
+ return key?size:-1;
+
+ /*Write in the first region failed, switching to backup region */
+ if(kvpb_block->flags&KVPB_DESC_RO){
+ kvpb_block->flags|=KVPB_DESC_USE2ND;
+ return -1;
+ }
+
+ /*second region*/
+ psum=kvpb_psum_align(kvpb_block,kvpb_block->psum2);
+ sum=0;
+ kvpb_block_copy(kvpb_block,kvpb_psum_valid_loc(kvpb_block,psum),&sum,sizeof(kvpb_sum_t));
+ kvpb_block->psum2=kvpb_psum_align(kvpb_block,kvpb_block->psum2-1);
+ if (!(keyid&KVPB_KEYID_DUPLIC) || !buf) {
+ kvpb_each_from(kvpb_block,keyid,2,key) {
+ kvpb_keyid_t dkeyid=KVPB_KEYID_INVALID;
+ kvpb_block_copy(kvpb_block,kvpb_keyid_valid(kvpb_block,key),&dkeyid,sizeof(kvpb_keyid_t));
+ }
+ }
+ key=kvpb_get_cfk(kvpb_block,2,size);
+ if (!key) {
+ kvpb_compact_region(kvpb_block,2,(keyid&KVPB_KEYID_DUPLIC)?0:keyid);
+ key=kvpb_get_cfk(kvpb_block,2,size);
+ }
+ if (keyid && key && buf) {
+ kvpb_block_copy(kvpb_block,&key->size,&size,sizeof(kvpb_size_t));
+ kvpb_block_copy(kvpb_block,&key->keyid,&keyid,sizeof(kvpb_keyid_t));
+ kvpb_block_copy(kvpb_block,(uint8_t*)(key+1),buf,/*align???*/ size);
+ }
+ kvpb_block_flush(kvpb_block);
+
+ p=kvpb_region_base(kvpb_block,1);
+ sum=kvpb_memsum(p,(KVPB_DPTRTYPE uint8_t*)kvpb_block->psum2-p);
+ kvpb_block_copy(kvpb_block,kvpb_block->psum2,&sum,sizeof(kvpb_sum_t));
+ kvpb_block_flush(kvpb_block);
+ /*Write in the second region failed, switching to the first region */
+ if(kvpb_block->flags&KVPB_DESC_RO){
+ kvpb_block->flags&=~KVPB_DESC_USE2ND;
+ return -1;
+ }
+
+ return key?size:-1;
+}
+
+#ifndef KVPB_MINIMALIZED
+/**
+ * kvpb_err_keys - Erase/delete key-value pair
+ * @kvpb_block: Pointer to the KVPB access information/state structure
+ * @keyid: Ordinal value representing key ID
+ *
+ * Return Value: Positive or zero value informs about successful operation,
+ * -1 if operation fails.
+ * File: keyvalpb.c
+ */
+int kvpb_err_keys(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid)
+{
+ return kvpb_set_key(kvpb_block,keyid,0,NULL);
+}
+#endif /*KVPB_MINIMALIZED*/
+
--- /dev/null
+/*******************************************************************
+ Key Value Persistent Storage
+
+ keyvalpb.h - key value parameters block
+
+ (C) Copyright 2003-2005 by Pavel Pisa - Originator
+ (C) Copyright 2004-2005 by Petr Smolik - Originator
+
+ The uLan utilities library can be used, copied and modified under
+ next licenses
+ - GPL - GNU General Public License
+ - LGPL - GNU Lesser General Public License
+ - MPL - Mozilla Public License
+ - and other licenses added by project originators
+ Code can be modified and re-distributed under any combination
+ of the above listed licenses. If contributor does not agree with
+ some of the licenses, he/she can delete appropriate line.
+ Warning, if you delete all lines, you are not allowed to
+ distribute source code and/or binaries utilizing code.
+
+ See files COPYING and README for details.
+
+ *******************************************************************/
+
+#ifndef _KEYVALPB_H_
+#define _KEYVALPB_H_
+
+//#include <inttypes.h>
+#include <types.h>
+#include <system_def.h>
+#include <cpu_def.h>
+
+#ifdef KVPB_MINIMALIZED
+#define KVPB_WITHOUT_HADLE
+#define KVPB_DPTRTYPE CODE
+#define KVPB_LOCALDATA DATA
+#endif /*KVPB_MINIMALIZED*/
+
+#ifndef KVPB_DPTRTYPE
+#define KVPB_DPTRTYPE
+#endif /*KVPB_DPTRTYPE*/
+
+#ifndef KVPB_LOCALDATA
+#define KVPB_LOCALDATA
+#endif /*KVPB_DPTRTYPE*/
+
+#ifndef KVPB_BLOCK_LOC
+#define KVPB_BLOCK_LOC
+#endif /*KVPB_BLOCK_LOC*/
+
+#define KVPB_EMPTY ((kvpb_size_t)~0)
+
+#define KVPB_KEYID_INVALID 0
+#define KVPB_KEYID_DUPLIC ((((kvpb_keyid_t)~0)>>1)+1)
+#define KBPB_KEYID_INVALID_BIT (KVPB_KEYID_DUPLIC>>1)
+
+#define KVPB_SUM_MASK (((kvpb_sum_t)~0)>>2)
+#define KVPB_SUM_OKVAL (KVPB_SUM_MASK+1)
+
+#define KVPB_DESC_DOUBLE 0x01
+#define KVPB_DESC_USE2ND 0x02
+#define KVPB_DESC_VALID 0x04
+#define KVPB_DESC_RO 0x08
+#define KVPB_DESC_CHUNKWO 0x10
+#define KVPB_DESC_ALIGN4 0x40
+#define KVPB_DESC_FLASH 0x80
+
+#ifdef KVPB_MINIMALIZED
+typedef uint16_t kvpb_sum_t;
+typedef uint16_t kvpb_size_t;
+typedef uint8_t kvpb_keyid_t;
+#else /*KVPB_MINIMALIZED*/
+typedef uint32_t kvpb_sum_t;
+typedef uint32_t kvpb_size_t;
+typedef uint32_t kvpb_keyid_t;
+#endif /*KVPB_MINIMALIZED*/
+
+/**
+ * struct kvpb_block - Key-value parameter block access information
+ * @base: Pointer to the start of physically mapped key-value block data
+ * @size: Size of one region (one data copy) of parameter block
+ * @flags: Block state flags:
+ * %KVPB_DESC_DOUBLE - the information is stored in two consecutive redundant copies/regions;
+ * %KVPB_DESC_USE2ND - data will be read from the second copy because first one is damaged;
+ * %KVPB_DESC_VALID - at least one region is valid;
+ * %KVPB_DESC_RO - because of some problems, only read access is allowed
+ * %KVPB_DESC_CHUNKWO - chunk can be written only once between erase operations
+ * %KVPB_DESC_ALIGN4 - data has to be aligned to four bytes
+ * %KVPB_DESC_FLASH - flash memory is used for data storage
+ * @psum1: Pointer to the control checksum of the first data region
+ * @psum2: Pointer to the control checksum of the second data region
+ * @erase: Function to erase some range of the storage region
+ * @copy: Function to copy data into or between storage regions
+ * @flush: Function to finish pending copy operations
+ * @chunk_size: Minimal store chunk size which can be independently modified
+ *
+ * File: keyvalpb.h
+ */
+typedef struct kvpb_block {
+ KVPB_DPTRTYPE uint8_t *base;
+ kvpb_size_t size;
+ short flags;
+ KVPB_DPTRTYPE kvpb_sum_t *psum1;
+ KVPB_DPTRTYPE kvpb_sum_t *psum2;
+ #ifndef KVPB_MINIMALIZED
+ int (*erase)(struct kvpb_block *store, void *base,int size);
+ int (*copy)(struct kvpb_block *store, void *des,const void *src,int len);
+ int (*flush)(struct kvpb_block *store);
+ unsigned chunk_size;
+ #endif /* KVPB_MINIMALIZED */
+} kvpb_block_t;
+
+
+#define kvpb_region_base(block,regidx) \
+ ((((KVPB_DPTRTYPE uint8_t *)(block)->base)+(regidx*(block)->size)))
+
+#ifndef KVPB_MINIMALIZED
+ #ifndef kvpb_chunk_size
+ #define kvpb_chunk_size(store) ((store)->chunk_size<4?4:(store)->chunk_size)
+ #endif /*kvpb_chunk_size*/
+ #define kvpb_chunk_size_mask(store) (kvpb_chunk_size(store)-1)
+
+/**
+ * kvpb_chunk_align - Round up KVPB size to minimal store chunk size multiple
+ * @store: Pointer to the KVPB access information/state structure
+ * @size: Unaligned size
+ *
+ * Return Value: Minimal aligned size to hold unaligned size.
+ * File: keyvalpb.h
+ */
+ static inline unsigned kvpb_chunk_align(struct kvpb_block *store, unsigned size)
+ {
+ return ((size)+kvpb_chunk_size_mask(store))&~kvpb_chunk_size_mask(store);
+ }
+
+/**
+ * kvpb_psum_align - Round up KVPB size to minimal store chunk size multiple
+ * @store: Pointer to the KVPB access information/state structure
+ * @psum: Pointer to proposed location of next check sum location
+ *
+ * Return Value: Pointer to next check sum location rounded down to next slot.
+ * File: keyvalpb.h
+ */
+ static inline kvpb_sum_t* kvpb_psum_align(struct kvpb_block *store, kvpb_sum_t *psum)
+ {
+ unsigned long mask=~kvpb_chunk_size_mask(store);
+ if(store->flags&KVPB_DESC_CHUNKWO)
+ mask<<=1;
+ return (kvpb_sum_t*)(((unsigned long)(psum))&mask);
+ }
+
+/**
+ * kvpb_psum_valid_loc - Return pointer to check sum validity info location
+ * @store: Pointer to the KVPB access information/state structure
+ * @psum: Pointer to corectly aligned check sum location
+ *
+ * Return Value: Pointer to location which indicates by zero value, that check sum
+ * is invalidated.
+ * File: keyvalpb.h
+ */
+ static inline kvpb_sum_t* kvpb_psum_valid_loc(struct kvpb_block *store, kvpb_sum_t *psum)
+ {
+ if(!(store->flags&KVPB_DESC_CHUNKWO))
+ return psum;
+ else
+ return (kvpb_sum_t*)(((char *)(psum))+kvpb_chunk_size(store));
+ }
+
+/**
+ * kvpb_block_erase - Wrapper function to call KVPB specific data erase function
+ * @store: Pointer to the KVPB access information/state structure
+ * @base: Base address of erased region inside parameter block data region
+ * @size: Number of bytes to erase
+ *
+ * The KVPB mechanism is intended for FLASH type memories and it expect
+ * that only whole data region can be erased at time. The expected erase state
+ * is all bits set to the ones.
+ *
+ * Return Value: Negative value indicates operation fault.
+ * File: keyvalpb.h
+ */
+ static inline int kvpb_block_erase(struct kvpb_block *store, void *base,int size)
+ {
+ return store->erase(store, base,size) ;
+ }
+
+/**
+ * kvpb_block_copy - Wrapper function to call KVPB specific data copy function
+ * @store: Pointer to the KVPB access information/state structure
+ * @des: Address of data destination pointing inside mapped parameter block data region
+ * @src: Address of data source pointing inside mapped parameter block data or RAM memory
+ * @len: Number of bytes to transfer
+ *
+ * Return Value: Negative value indicates operation fault.
+ * File: keyvalpb.h
+ */
+ static inline int kvpb_block_copy(struct kvpb_block *store, void *des,const void *src,int len)
+ {
+ return store->copy(store, des, src, len);
+ }
+
+/**
+ * kvpb_block_flush - Wrapper function to call KVPB specific flush function
+ * @store: Pointer to the KVPB access information/state structure
+ *
+ * Return Value: Negative value indicates operation fault.
+ * File: keyvalpb.h
+ */
+ static inline int kvpb_block_flush(struct kvpb_block *store)
+ {
+ if(!(store->flush)) return 0;
+ return store->flush(store);
+ }
+
+#else /* KVPB_MINIMALIZED */
+ #ifndef kvpb_chunk_size
+ #define kvpb_chunk_size(store) 1
+ #endif /*kvpb_chunk_size*/
+ #define kvpb_chunk_size_mask(store) (kvpb_chunk_size(store)-1)
+ #define kvpb_chunk_align(store,x) \
+ (((x)+kvpb_chunk_size_mask(store))&~kvpb_chunk_size_mask(store))
+ #define kvpb_psum_align(store,x) \
+ ((KVPB_DPTRTYPE kvpb_sum_t*)((unsigned)(x)&~kvpb_chunk_size_mask(store)))
+ #define kvpb_psum_valid_loc(store,x) \
+ ((kvpb_sum_t*)((char*)(x)+0*kvpb_chunk_size(store)))
+#ifndef kvpb_block_copy
+ #define kvpb_block_erase(store, base, size) flash_erase(base, size)
+ #define kvpb_block_copy(store, des, src, len) flash_copy(des, src, len)
+ #define kvpb_block_flush(store) flash_flush()
+
+ /* forward declarations for external procedures */
+ int flash_erase(void *base,int size);
+ int flash_copy(void *des,const void *src,int len);
+#ifndef flash_flush
+ int flash_flush(void);
+#endif /* flash_flush */
+#endif /* kvpb_block_copy */
+#endif /* KVPB_MINIMALIZED */
+
+/**
+ * struct kvpb_key - Header of stored key value pair and structure for iteration over KVPB
+ * @size: Non-aligned byte size of the stored value
+ * @keyid: Ordinal value representing stored data key
+ *
+ * The header structure is followed by @size data bytes in the KVPB storage block.
+ * Because only word aligned write accesses are possible on some architectures
+ * and memory types the whole size of space occupied by one key-value pair is
+ * sum of rounded-up data size kvpb_chunk_align(@size) and size of header sizeof(kvpb_key_t).
+ */
+typedef struct kvpb_key {
+ kvpb_size_t size;
+ kvpb_keyid_t keyid;
+} kvpb_key_t;
+
+#ifndef KVPB_WITHOUT_HADLE
+ static inline kvpb_keyid_t* kvpb_keyid_valid(struct kvpb_block *store, kvpb_key_t *key)
+ {
+ if(store->flags&KVPB_DESC_CHUNKWO)
+ return (kvpb_keyid_t*)((uint8_t*)key+(kvpb_chunk_align(store,key->size+sizeof(kvpb_key_t))));
+ return &(key->keyid);
+ }
+#else
+ #define kvpb_keyid_valid(store,key) (&((key)->keyid))
+#endif /*KVPB_WITHOUT_HADLE*/
+
+
+#ifndef KVPB_WITHOUT_HADLE
+KVPB_DPTRTYPE kvpb_key_t *kvpb_first(kvpb_block_t *block, uint8_t mode);
+KVPB_DPTRTYPE kvpb_key_t *kvpb_next(kvpb_block_t *block, KVPB_DPTRTYPE kvpb_key_t *key);
+KVPB_DPTRTYPE kvpb_key_t *kvpb_find(kvpb_block_t *block, kvpb_keyid_t keyid, uint8_t mode, KVPB_DPTRTYPE kvpb_key_t *key);
+int kvpb_get_key(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, kvpb_size_t size, void *buf);
+int kvpb_set_key(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid, kvpb_size_t size, const void *buf);
+int kvpb_err_keys(kvpb_block_t *kvpb_block, kvpb_keyid_t keyid);
+int kvpb_check(kvpb_block_t *kvpb_block, uint8_t mode);
+#else
+extern KVPB_BLOCK_LOC kvpb_block_t kvpb_block_global;
+#define kvpb_block (&kvpb_block_global)
+KVPB_DPTRTYPE kvpb_sum_t *__kvpb_get_psum(KVPB_DPTRTYPE uint8_t *base, kvpb_size_t size);
+KVPB_DPTRTYPE kvpb_key_t *__kvpb_first(uint8_t mode);
+KVPB_DPTRTYPE kvpb_key_t *__kvpb_next(KVPB_DPTRTYPE kvpb_key_t *key);
+KVPB_DPTRTYPE kvpb_key_t *__kvpb_find(kvpb_keyid_t keyid, uint8_t mode, KVPB_DPTRTYPE kvpb_key_t *key);
+int __kvpb_get_key(kvpb_keyid_t keyid, kvpb_size_t size, void *buf);
+int __kvpb_set_key(kvpb_keyid_t keyid, kvpb_size_t size, const void *buf);
+int __kvpb_check(uint8_t mode);
+#define kvpb_get_psum(block, base, size) __kvpb_get_psum(base, size)
+#define kvpb_first(block, mode) __kvpb_first(mode)
+#define kvpb_next(block, key) __kvpb_next(key)
+#define kvpb_find(block, keyid, mode, key) __kvpb_find(keyid, mode, key)
+#define kvpb_get_key(block, keyid, size, buf) __kvpb_get_key(keyid, size, buf)
+#define kvpb_set_key(block, keyid, size, buf) __kvpb_set_key(keyid, size, buf)
+#define kvpb_err_keys(block,keyid) kvpb_set_key(block,keyid,0,NULL)
+#define kvpb_check(block, mode) __kvpb_check(mode)
+#define kvpb_compact_region(block, mode, keyid) __kvpb_compact_region(mode, keyid)
+#define kvpb_get_cfk(block,mode,size) __kvpb_get_cfk(mode,size)
+#endif
+
+/**
+ * kvpb_for_each - Iterate over all key value pairs
+ * @root: Pointer to the KVPB access information/state structure
+ * @key: Iterator of kvpb_key_t* type
+ * @mode: iteration mode modifier: 0 .. iterate over active/valid data region;
+ * 1 .. iterate over first copy, 2 .. iterate over second copy
+ *
+ * File: keyvalpb.h
+ */
+#define kvpb_for_each(root, key,mode) \
+ for(key=kvpb_first(root,mode);key;\
+ key=kvpb_next(root, key))
+
+/**
+ * kvpb_for_each - Iterate over all key value pairs matching given key ID
+ * @root: Pointer to the KVPB access information/state structure
+ * @keyid: Ordinal value representing key ID
+ * @key: Iterator of kvpb_key_t* type
+ * @mode: iteration mode modifier: 0 .. iterate over active/valid data region;
+ * 1 .. iterate over first copy, 2 .. iterate over second copy
+ *
+ * File: keyvalpb.h
+ */
+#define kvpb_each_from(root, keyid, mode, key) \
+ for(key=kvpb_find(root,keyid,mode,NULL);key;\
+ key=kvpb_find(root,keyid,mode,key))
+
+#ifdef KVPB_MINIMALIZED
+#define kvpb_key2data(key) ((void*)(key+1))
+#else /*KVPB_MINIMALIZED*/
+static inline void* kvpb_key2data(kvpb_key_t *key) { return key+1; }
+#endif /*KVPB_MINIMALIZED*/
+
+#endif /* _KEYVALPB_H_ */
+