在WINCE下能够直接访问的都是虚拟地址,不能直接访问GPIO端口,因此首先需要使用VirtualAlloc和VirtualCopy这两个函数将GPIO口的物理地址映射到虚拟地址上来。
函数原型分别是:
LPVOID VirtualAlloc( LPVOID lpAddress, DWORD dwSize, DWORD flAllocationType, DWORD flProtect );
BOOL VirtualCopy( LPVOID lpvDest, LPVOID lpvSrc, DWORD cbSize, DWORD fdwProtect );
如果这两个函数执行成功,VirtualAlloc将返回一个指针。使用这个指针就可以直接访问GPIO,通过读写相关地址寄存器,来控制GPIO端口! v_pIOPregs = (volatile IOPreg *)VirtualAlloc(0, sizeof(IOPreg), MEM_RESERVE, PAGE_NOACCESS);
if (v_pIOPregs == NULL){
RetValue = FALSE;
}
else {
if (!VirtualCopy((PVOID)v_pIOPregs, (PVOID)(IOP_BASE), sizeof(IOPreg), PAGE_READWRITE | PAGE_NOCACHE)) {
RetValue = FALSE;
}
}
if (!RetValue){
//PIO_InitializeAddresses - Failed !!
if (v_pIOPregs){
VirtualFree((PVOID) v_pIOPregs, 0, MEM_RELEASE);
}
v_pIOPregs = NULL;
}
//else RETAILMSG (1, (TEXT("::: PBT_InitializeAddresses - Success\r\n") ));
return(RetValue);
v_pIOPregs是一个IOPreg结构,在s2410.h中定义,
// Registers : I/O port
#define IOP_BASE 0xB1600000 // 0x56000000
typedef struct {
unsigned int rGPACON; // 00
unsigned int rGPADAT;
unsigned int rPAD1[2];
unsigned int rGPBCON; // 10
unsigned int rGPBDAT;
unsigned int rGPBUP;
unsigned int rPAD2;
unsigned int rGPCCON; // 20
unsigned int rGPCDAT;
unsigned int rGPCUP;
unsigned int rPAD3;
unsigned int rGPDCON; // 30
unsigned int rGPDDAT;
unsigned int rGPDUP;
unsigned int rPAD4;
unsigned int rGPECON; // 40
unsigned int rGPEDAT;
unsigned int rGPEUP;
unsigned int rPAD5;
unsigned int rGPFCON; // 50
unsigned int rGPFDAT;
unsigned int rGPFUP;
unsigned int rPAD6;
unsigned int rGPGCON; // 60
unsigned int rGPGDAT;
unsigned int rGPGUP;
unsigned int rPAD7;
unsigned int rGPHCON; // 70
unsigned int rGPHDAT;
unsigned int rGPHUP;
unsigned int rPAD8;
unsigned int rMISCCR; // 80
unsigned int rDCKCON;
unsigned int rEXTINT0;
unsigned int rEXTINT1;
unsigned int rEXTINT2; // 90
unsigned int rEINTFLT0;
unsigned int rEINTFLT1;
unsigned int rEINTFLT2;
unsigned int rEINTFLT3; // A0
unsigned int rEINTMASK;
unsigned int rEINTPEND;
unsigned int rGSTATUS0;
unsigned int rGSTATUS1; // B0
}IOPreg;
4.2BSP按键驱动的例子:
/* IO Register Allocation */
v_pIOPregs = (volatile IOPreg *)VirtualAlloc(0, sizeof(IOPreg), MEM_RESERVE, PAGE_NOACCESS);
if (v_pIOPregs == NULL)
{
ERRORMSG(1,(TEXT("For IOPregs : VirtualAlloc failed!\r\n")));
RetValue = FALSE;
}
else
{
if (!VirtualCopy((PVOID)v_pIOPregs, (PVOID)(IOP_BASE), sizeof(IOPreg), PAGE_READWRITE | PAGE_NOCACHE))
{
ERRORMSG(1,(TEXT("For IOPregs: VirtualCopy failed!\r\n")));
RetValue = FALSE;
}
}
在VirtualCopy的IOP_BASE是个虚拟地址
#define IOP_BASE 0xB1600000 // 0x56000000
但是在5.0BSP却不一样
v_pIOPregs = (volatile S3C2440A_IOPORT_REG *)VirtualAlloc(0, sizeof(S3C2440A_IOPORT_REG), MEM_RESERVE, PAGE_NOACCESS);
VirtualCopy((PVOID)v_pIOPregs, (PVOID)(S3C2440A_BASE_REG_PA_IOPORT >> 8), sizeof(S3C2440A_IOPORT_REG), PAGE_PHYSICAL|PAGE_READWRITE|PAGE_NOCACHE );
S3C2440A_BASE_REG_PA_IOPORT 是个物理地址
#define S3C2440A_BASE_REG_PA_IOPORT (0x56000000)
This function dynamically maps a virtual address to a physical address by creating a new page-table entry. Terminate the mapping by calling .
BOOL VirtualCopy(
LPVOID ,
LPVOID ,
DWORD ,
DWORD
);
Parameters
-
lpvDest
- [in] Pointer to the destination memory, which must be reserved. lpvSrc
- [in] Pointer to committed memory. cbSize
- [in] Size, in bytes, of the region. The allocated pages include all pages containing one or more bytes in the range from lpAddress to lpAddress+cbSize. This means that a 2-byte range straddling a page boundary causes both pages to be included in the allocated region.
Value | Description |
---|---|
PAGE_READONLY | Enables read access to the committed region of pages. An attempt to write to the committed region results in an access violation. If the system differentiates between read-only access and execute access, an attempt to execute code in the committed region results in an access violation. |
PAGE_READWRITE | Enables both read and write access to the committed region of pages. |
PAGE_EXECUTE | Enables execution access to the committed region of pages. An attempt to read or write to the committed region results in an access violation. |
PAGE_EXECUTE_READ | Enables execute and read access to the committed region of pages. An attempt to write to the committed region results in an access violation. |
PAGE_EXECUTE_READWRITE | Enables execute, read, and write access to the committed region of pages. |
PAGE_GUARD | Pages in the region become guard pages. Any attempt to read from or write to a guard page causes the operating system to raise the STATUS_GUARD_PAGE exception and turn off the guard page status. Guard pages thus act as a one-shot access alarm. The PAGE_GUARD flag is a page protection modifier. An application uses it with one of the other page protection flags, with one exception: it cannot be used with PAGE_NOACCESS. When an access attempt leads the operating system to turn off guard page status, the underlying page protection takes over. If a guard page exception occurs during a system service, the service typically returns a failure status indicator. |
PAGE_NOACCESS | Disables all access to the committed region of pages. An attempt to read from, write to, or execute in the committed region results in an access violation exception, called a general protection (GP) fault. |
PAGE_NOCACHE | Allows no caching of the committed regions of pages. The hardware attributes for the physical memory should be specified as no cache. It is useful for device drivers; when, for example, mapping a video frame buffer with no caching. This flag is a page protection modifier and is valid only when used with one of the page protections other than PAGE_NOACCESS. |
PAGE_PHYSICAL | Used to map a physical memory region. When using this flag, divide the physical address — that is, lpvSrc — by 256. Memory mapped with PAGE_PHYSICAL is not freed until the device is rebooted. Calling VirtualFree will not free this mapped physical memory. PAGE_PHYSICAL is intended for use with dedicated hardware buffers, so it cannot be freed after being mapped. |
PAGE_PHYSICAL这个参数决定了要右移八位(除以256)。不过还有一点就是使用了PAGE_PHYSICAL之后就不要使用VirtualFree .
VirtualAlloc
This function reserves or commits a region of pages in the virtual address space of the calling process.
Memory allocated by VirtualAlloc is initialized to zero.
LPVOID VirtualAlloc(
LPVOID ,
DWORD ,
DWORD ,
DWORD
);
Parameters
-
lpAddress
-
[in] Long pointer to the specified starting address of the region to be allocated.
If the memory is being reserved, the specified address is rounded down to the next 64-KB boundary.
If the memory is reserved and is being committed, the address is rounded down to the next page boundary.
To determine the size of a page on the host computer, use the function.
If this parameter is NULL, the system determines where to allocate the region.
dwSize
-
[in] Specifies the size, in bytes, of the region. It is an error to set this parameter to 0.
If the lpAddress parameter is NULL, this value is rounded up to the next page boundary.
Otherwise, the allocated pages include all pages containing one or more bytes in the range from lpAddress to lpAddress+dwSize. This means that a 2-byte range straddling a page boundary causes both pages to be included in the allocated region.
flAllocationType
- [in] Specifies the type of allocation.