寄存器的使用:
1、wince内部对物理地址的访问:
可以有3个途径。
1:直接使用g_oalAddressTable(oemaddrtab_cfg.inc)的已经定义好的,物理地址对应的虚拟地址。
如:
DCD 0x80000000, 0x30000000, 128 ;
访问虚拟地址0x80000000实际就是访问物理地址0x30000000。
2:在OAL层,使用OALPAtoVA函数。
如:
volatile S3C2410X_IOPORT_REG *pIOCTR;
pIOCTR = (volatile S3C2410X_IOPORT_REG *)OALPAtoVA(S3C2410X_BASE_REG_PA_IOPORT, FALSE);
那么在访问pIOCTR指向的首地址,实际就是访问被映射后S3C2410X_BASE_REG_PA_IOPORT定义的物理地址。
VOID* OALPAtoVA(
UINT32 pa, 参数1:需要映射的物理地址
BOOL cached 参数2:是否使用cache(驱动中要使用uncached)
)
3:在kernel里,使用MmMapIoSpace函数。
如:pBaseAddress = (PUCHAR)MmMapIoSpace(ioPhysicalBase, Size, FALSE);
同上,访问pBaseAddress的指向地址,就为访问被映射后ioPhysicalBase定义的物理地址。
PVOID MmMapIoSpace(
PHYSICAL_ADDRESS PhysicalAddress, 参数1:需要映射的物理地址
ULONG NumberOfBytes, 参数2:映射的地址长度
BOOLEAN CacheEnable 参数3:是否使用cache(驱动中要使用uncached)
);
与OALPAtoVA不同,在使用MmMapIoSpace后,必须使用MmUnmapIoSpace。
VOID MmUnmapIoSpace(
PVOID BaseAddress, 参数1:被映射后的虚拟地址
ULONG NumberOfBytes 参数2:映射的地址长度
);
在一般的NK驱动编写中,为了规范编程风格,请勿直接使用g_oalAddressTable中的虚拟地址。统一使用MmMapIoSpace、MmUnmapIoSpace函数。
2、wince标准的寄存器访问
定义一个结构体。此结构包含某功能模块的寄存器地址。
如:
typedef struct {
UINT32 GPACON; // Port A - offset 0
UINT32 GPADAT; // Data
UINT32 PAD1[2];
……
……
UINT32 GSTATUS0; // external pin status
UINT32 GSTATUS1; // chip ID
UINT32 GSTATUS2; // reset status
UINT32 GSTATUS3; // inform register
UINT32 GSTATUS4; // inform register
} S3C2410X_IOPORT_REG, *PS3C2410X_IOPORT_REG;
volatile S3C2410X_IOPORT_REG *pIOCTR;
pIOCTR = (volatile S3C2410X_IOPORT_REG *)OALPAtoVA(S3C2410X_BASE_REG_PA_IOPORT, FALSE);
这样,访问pIOCTR的各个成员,就为访问被映射后S3C2410X_BASE_REG_PA_IOPORT定义的物理偏移地址。
为了统一、兼容平台的驱动代码,我们加入了寄存器操作宏(oal_io.h):
#define REG8(_register_) (*(volatile unsigned char *)(_register_))
#define REG16(_register_) (*(volatile unsigned short *)(_register_))
#define REG32(_register_) (*(volatile unsigned long *)(_register_))
访问模块中的功能寄存器,使用加上偏移地址的方式。
#define USB_REG_FADDR_OFFSET (0x0000)
#define USB_REG_POWER_OFFSET (0x0001)
例子:
要编写某个模块的驱动,首先使用MmMapIoSpace或OALPAtoVA建立物理地址映射关系。
volatile BYTE *pUSBCtrlAddr;
pUSBCtrlAddr= (volatile BYTE *)OALPAtoVA(AK3224_BASE_REG_PA_USB, FALSE);
这样,usb模块的首地址就为pUSBCtrlAddr的指向地址。然后,使用REGXX的宏来访问各个功能寄存器。
REG8(pUSBCtrlAddr + USB_REG_POWER_OFFSET) = USB_POWER_ENSUSPEND;
ucIntStatusR = REG16(pUSBCtrlAddr + USB_REG_INTRRX1_OFFSET);
REG32(pUSBCtrlAddr + USB_DMA_COUNT_1_OFFSET) = 256;
在驱动编写中,请统一使用REGXX的宏操作。