完全可以,我刚写了一个代码,你先看看,最详细的代码见
http://blog.sina.com.cn/tymanium1.4.2 驱动程序架构和访问流程
l 体系结构和访问流程
在流式接口驱动程序中,驱动程序负责把外设抽象成一个文件,而应用程序则使用操作系统提供的文件API对外设进行访问。文件API被操作系统转发到FileSys.exe进程中;然后FileSys.exe发现是对设备的操作,就会把执行交给Device.exe处理;接着Device.exe根据具体的请求,调用流驱动接口函数;最终,驱动程序负责与硬件交互。
图7 流接口驱动体系结构
具体过程分析如下:
(1) 应用程序须使用该设备,首先调用CreateFile(TEXT(“IIC1”)…)打开设备。CreateFile函数是在FileSys.exe中实现的。但是FileSys.exe只作简单判断:如果发现打开的是设备驱动而不是一个文件,那么就重新把主动权交还给设备管理器。
(2) 设备管理器调用驱动程序中的IIC_Open()函数打开设备。在IIC_Open中,驱动程序可以对硬件进行一些额外的初始化工作,使硬件进入工作状态。
(3) IIC_Open()函数把打开设备的结果返回给设备管理器。
(4) 设备管理器把IIC_Open()返回的结果再传给应用程序中的CreateFile()函数调用。
(5) 设备已被成功打开,接下来可对设备进行读写和控制操作。以控制操作为例,CreateFile函数返回的句柄作为DeviceIoControl()的第1个参数,向设备发送控制请求。同样,DeviceIoControl()要FileSys.exe转发给设备管理器。
(6) 设备管理器调用驱动程序中的IIC_IOControl()函数,与硬件完成交互,读写设备的数据信息,然后返回给设备管理器,再返回给应用程序。
(7) 当应用程序不再使用该设备时,它可调用CloseHandle()将设备关闭。此时调用的是驱动程序中的IIC_Close()函数。
l 驱动目录组织
在AT24LC08读写驱动中,根据访问和交互的对象不同,将驱动程序目录组织如下:
Ø IICBus.c 用于和用户态程序的交互,提供流驱动接口函数;
Ø IIC2440.c 和S3C2440的硬件交互,完成寄存器的配置;
Ø 24LC08.c 对AT24LC08芯片操作,按照芯片的读写模式配置。
1.4.3 流驱动接口函数的实现
在本驱动中,定义前缀为“IIC”,IICBus.c文件中的流接口驱动函数都以该前缀命名,本驱动中流接口重点实现以下3个函数:
BOOL IIC_Init(DWORD dwcontext)
BOOL IIC_Deinit(DWORD hDeviceContext)
BOOL IIC_IOControl(DWORD hOpenContext, DWORD dwCode,
EEPROM_INFO *pBufIn, DWORD dwLenIn,
U8 *pBufOut, DWORD dwLenOut, PDWORD pdwActualOut)
IIC_Init()函数
该函数在设备加载时被调用,具体代码实现:
BOOL IIC_Init(DWORD dwcontext)
{
RETAILMSG(DBG_OUT,(TEXT("IIC_Init--- \r\n")));
Virtual_Alloc();
Setup_IIC();
return TRUE;
}
Setup_IIC()函数完成一些端口的初始化,以及IIC总线寄存器的初始化配置。
Setup_IIC()
{
RETAILMSG(DBG_OUT,(TEXT("IIC_INTR_Gpio_setting --- \r\n")));
s2440IOP->rGPEUP |= 0xc000; //Pull-up disable
s2440IOP->rGPECON=(s2440IOP->rGPECON&~(3<<30))|(2 << 30); //GPE15=IICSDA.
s2440IOP->rGPECON=(s2440IOP->rGPECON&~(3 << 28))|(2 << 28); //GPE14=IICSCL.
s2440IIC->rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf); //Tx clock = 0.195MHz
//[Bit7] = Enable ACK, [Bit6] = Prescaler IICCLK=PCLK/16, [Bit5] = Enable interrupt;
//[Bit3:0] = Transmit clock value Tx clock=IICCLK/16
s2440IIC->rIICSTAT = 0x10; //IIC bus data output enable(Rx/Tx)
s2440IIC->rIICADD = 0x10; //2440 slave address = [7:1]
s2440IIC->rIICLC = (1<<2)|(3); // Filter enable, 15 clocks SDA output delay
return TRUE;
}
IIC_Deinit()函数
该函数在设备卸载时被调用,释放加载时申请的虚拟地址空间,具体代码实现:
BOOL IIC_Deinit(DWORD hDeviceContext)
{
RETAILMSG(DBG_OUT, (TEXT("IIC_INTR_Deinit --- \r\n")));
VirtualFree((void*)s2440IOP, sizeof(IOPreg), MEM_RELEASE);
VirtualFree((void*)s2440IIC, sizeof(PWMreg), MEM_RELEASE);
return TRUE;
}
IIC_IOControl()函数
该函数用于处理应用程序发送过来的控制命令,控制指令dwCode有IOCTL_IIC_READ和IOCTL_IIC_WRITE两种。当收到读指令IOCTL_IIC_READ时,保存读操作的起始地址和读取字节数,然后调用E2P_Read()函数读取AT24LC08上的数据,将实际读取的字节数保存到*pdwActualOut。同样,当收到写指令IOCTL_IIC_WRITE时,保存写操作的起始地址和写字节数,然后调用E2P_PageWrite()函数往AT24LC08上写数据,将实际写入的字节数保存到*pdwActualOut。
BOOL IIC_IOControl(DWORD hOpenContext, DWORD dwCode,
EEPROM_INFO *pBufIn, DWORD dwLenIn,
U8 *pBufOut, DWORD dwLenOut, PDWORD pdwActualOut)
{
RETAILMSG(DBG_OUT,(TEXT("IIC: +IIC_IOControl (%d) \r\n"), dwCode));
switch(dwCode){
case IOCTL_IIC_READ:
{
U16 ReadAddress = pBufIn->start_address;
U8 ReadNum = (U8)dwLenOut; //ReadNum为要读取的字节数
*pdwActualOut = E2P_Read(ReadAddress, ReadNum, pBufOut);
return TRUE;
}
case IOCTL_IIC_WRITE:
{
U16 WriteAddress = pBufIn->start_address;
U8 WriteNum = (U8)dwLenIn;
*pdwActualOut = E2P_Write(WriteAddress, WriteNum, pBufIn->dwData);
return TRUE;
}
}
return TRUE;
}