summaryrefslogtreecommitdiffstats
path: root/protocols/software_registers.c
blob: ab5d31d07e846bb7c473e3912b297d349c719c47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <string.h>
#include <sys/file.h>
#include <unistd.h>

#include "model.h"
#include "error.h"
#include "kmem.h"
#include "pcilib.h"
#include "pci.h"

#include <stdio.h>

/**
 * pcilib_software_registers_open
 * this function initializes the kernel space memory and stores in it the default values of the registers of the given bank index, if it was not initialized by a concurrent process, and return a bank context containing the adress of this kernel space. It the kernel space memory was already initialized by a concurrent process, then this function just return the bank context with the adress of this kernel space already used
 *@param[in] ctx the pcilib_t structure running
 * @param[in] bank the bank index that will permits to get the bank we want registers from
 * @param[in] model not used
 * @param[in] args not used
 *@return a bank context with the adress of the kernel space memory related to it
 */
pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pcilib_register_bank_t bank,const char* model, const void *args){
	pcilib_register_bank_context_t* bank_ctx;
	pcilib_kmem_handle_t *handle;
	int j;
	/* the protocol thing is here to make sure to avoid segfault in write_registers_internal, but is not useful as it is now*/
	pcilib_register_protocol_t protocol;
	protocol = pcilib_find_register_protocol_by_addr(ctx, ctx->banks[bank].protocol);
	
	bank_ctx=calloc(1,sizeof(pcilib_register_bank_context_t));
	bank_ctx->bank=ctx->banks + bank;
	bank_ctx->ctx=ctx;
	bank_ctx->api=ctx->protocols[protocol].api;
	ctx->bank_ctx[bank]=bank_ctx;

	handle=pcilib_alloc_kernel_memory(ctx, PCILIB_KMEM_TYPE_PAGE, 1, 0, 1,PCILIB_KMEM_USE_STANDARD,PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT);

	if (!handle)pcilib_error("allocation of kernel memory for registers has failed");
	
	bank_ctx->kmem_base_address=handle;

	if(pcilib_kmem_is_reused(ctx,handle)!= PCILIB_KMEM_REUSE_ALLOCATED){
		j=0;
		while(ctx->model_info.registers[j].name!=NULL){
		  if(ctx->model_info.registers[j].bank==(ctx->banks+bank)->addr){
		/* !!!!!warning!!!!! 
		hey suren,
		you may check here too  :the programm seems to always go this path, so pcilib_write_register_by_id always write the original value, kmem_is_reused working?
		*/
		pcilib_write_register_by_id(ctx,j,ctx->model_info.registers[j].defvalue);
			
			}	
			j++;
		}		
	}

	return bank_ctx;
}


/**
 * pcilib_software_registers_close
 * this function clear the kernel memory space that could have been allocated for software registers
 * @param[in] bank_ctx the bank context running that we get from the initialisation function
 */	
void pcilib_software_registers_close(pcilib_register_bank_context_t *bank_ctx){
	/*!!!!! to check!!!!
	
	ps: i am using uint32_t to calculate registers adress, may it change in the future? should we define some #define?	
	*/
	pcilib_free_kernel_memory(bank_ctx->ctx,bank_ctx->kmem_base_address, 0);
}

/**
 * pcilib_software_registers_read
 * this function read the value of a said register in the kernel space
 * @param[in] ctx the pcilib_t structure runnning
 * @param[in] bank_ctx the bank context that was returned by the initialisation function
 * @param[in] addr the adress of the register we want to read
 *@param[out] value the value of the register
 * @return 0 in case of success
 */
int pcilib_software_registers_read(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx,pcilib_register_addr_t addr, pcilib_register_value_t *value){
	int i;
	void* base_addr;
	
	base_addr=pcilib_kmem_get_block_ua(ctx,bank_ctx->kmem_base_address,0);
	for(i=0;ctx->registers[i].name!=NULL;i++){
		if(ctx->registers[i].addr==addr) break;
	}
	*value=*(pcilib_register_value_t*)(base_addr+i*sizeof(uint32_t));
	return 0;
}

/**
 * pcilib_software_registers_write
 * this function write the said value to a said register in the kernel space
 * @param[in] ctx the pcilib_t structure runnning
 * @param[in] bank_ctx the bank context that was returned by the initialisation function
 * @param[in] addr the adress of the register we want to write in
 *@param[out] value the value we want to write in the register
 * @return 0 in case of success
 */
int pcilib_software_registers_write(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx, pcilib_register_addr_t addr, pcilib_register_value_t value){
	int i;
	void* base_addr;
	
	base_addr=pcilib_kmem_get_block_ua(ctx,bank_ctx->kmem_base_address,0);
	for(i=0;ctx->registers[i].name!=NULL;i++){
		if(ctx->registers[i].addr==addr) break;
	}
	*(pcilib_register_value_t*)(base_addr+i*sizeof(uint32_t))=value;
	return 0;
}