Windows CE驱动N枪拍案惊奇系列之
基于Wince5.0的DM9000A的驱动分析和移植步骤
华清远见非著名讲师 O(∩_∩)O 牛牛猛
首先要找到驱动程的入口点,从dm9000.def文件中可以看到dm9000的驱动程序(dm9000.dll)exports的函数只有DriverEntry。可以确定这里便是DM9000 驱动入口函数。
详细查看这个位于driver.cpp文件中的入口函数会发现这个函数中主要有一个函数NdisMInitializeWrapper(
&hwrapper,
pDriverObject,
pRegistryPath,
NULL);
查看微软的帮助文档可知这个函数作用是This function notifies NDIS that a new miniport is initializing,翻译一下,函数的功能是通知NDIS这个函数是一个初始化函数,NDIS(网络驱动器标准接口),NdisMInitializeWrapper()函数是内核提供给我们的,可以直接调用。
接下来就是给
NDIS30_MINIPORT_CHARACTERISTICS这个结构体变量初始化,主要是设置一些回调函数,这是Windows程序的常见风格:
ndischar.Ndis30Chars.InitializeHandler = MiniportInitialize; ndischar.Ndis30Chars.ResetHandler = MiniportReset; ndischar.Ndis30Chars.CheckForHangHandler = MiniportCheckForHang; ndischar.Ndis30Chars.HaltHandler = MiniportHalt; ndischar.Ndis30Chars.HandleInterruptHandler = MiniportInterruptHandler; ndischar.Ndis30Chars.ISRHandler = MiniportISRHandler; ndischar.Ndis30Chars.QueryInformationHandler=MiniportQueryInformation; ndischar.Ndis30Chars.SetInformationHandler = MiniportSetInformation; ndischar.Ndis30Chars.SendHandler = MiniportSend; |
很明显上面提到的通常要自己实现的。再下来就是NdisMRegisterMiniport()函数了,【F1】查看帮助文档,
This function registers an NIC or intermediate driver's Miniport_* entry points and name with the NDIS library when the driver initializes。
顾名思义这是一个注册函数,想wince内核注册驱动程序,注册刚才初始化的结构体就是用刚才初始化的那个结构体NDIS30_MINIPORT_CHARACTERISTICS注册。搞过Linux驱动的兄弟一定对这种思路一定不陌生。
函数中只有一个函数NdisTerminateWrapper,接着查看帮助文档,
This function releases system resources allocated when the NIC driver called the NdisMInitializeWrapper function,意思是说函数调用后获得系统资源。
帮助文档里有这样的描述:A miniport calls this function during initialization if it cannot find an NIC that it supports in the current platform or if it cannot successfully initialize at least one NIC or virtual NIC.那么后面将是从成功注册的结构体的第一个函数执行了即:NDIS_STATUS
MiniportInitialize( OUT PNDIS_STATUS OpenErrorStatus, OUT PUINT SelectedMediaIndex, IN PNDIS_MEDIUM MediaArray, IN UINT MediaArraySize, IN NDIS_HANDLE MiniportHandle, IN NDIS_HANDLE WrapperConfigHandle) |
This function is a required function that sets up a network adapter, or virtual network adapter, for network I/O operations, claims all hardware resources necessary to the network adapter in the registry, and allocates resources the driver needs to carry out network I/O operations 。
意思是说,开启所有网口资源。我们看看MiniportInitialize函数中做了那些工作。
NIC_DRIVER_OBJECT *pnic;意思是实例化NIC_DRIVER_OBJECT类
其中有NIC_DRIVER_OBJECT类的初始化,以及该类的EDriverInitialize函数调用,在此函数中全面展开了dm9000的所有初始化操作。
pnic->EDriverInitialize( OpenErrorStatus, SelectedMediaIndex, MediaArray, MediaArraySize);
pnic->DriverStart();
|
我们跟踪到EDriverInitialize中,发现这样一句话:
m_pLower = DeviceEntry(this,NULL);
主要是通过DeviceEntry()这个函数来实现(这个函数实现在dm9isa.cpp文件中),
extern "C" NIC_DEVICE_OBJECT *DeviceEntry( NIC_DRIVER_OBJECT *pDriverObject, PVOID pVoid) {
return new C_DM9000(pDriverObject,pVoid); } |
在DeviceEntry这个函数中只做了一件事:new了一个C_DM9000类的实例并return。
接下来就该C_DM9000的实例了,真正进入DM9000的初始化阶段
m_pLower->DeviceSetDefaultSettings(); m_pLower->DeviceSetEepromFormat(); m_pLower->DeviceRetriveConfigurations(hconfig); m_pLower->EDeviceValidateConfigurations(); |
完成若干初始化工作后, NIC_DRIVER_OBJECT又出现了,
pnic->DriverStart();函数将被调用,
驱动程序进入DriverStart()函数,
函数很简单但是比较重要,它在此DeviceEnableInterrupt()启动了中断,至此正常的话可以看到DM9:--MiniportInitialize的提示。
DriverStart函数中有个EDeviceValidateConfigurations函数会获得g_szDm9ConfigParams结构体中的中断号和片选地址:
{ CID_IO_BASE_ADDRESS, 0x20000000, NDIS_STRING_CONST("IoAddress")},
{ CID_IRQ_NUMBER, 16, NDIS_STRING_CONST("IrqNumber")},
Step-by-step移植:
1、获得dm9000的基于wince的驱动包,复制
到%_winceroot%/ PLATFORM/SMDK2440A/Src/Drivers/目录下;
2、打开在driver目录下dirs文件,在该文件里将dm9000加入到dirs中;
3、打开driver/dm9000目录,在该目录下将dirs、source等文件改了
4、中断和片选参考上面的提示即可。
附上我的注册表信息供大家参考哦!
IF BSP_DM9000 !
[HKEY_LOCAL_MACHINE/Comm/DM9CE]
"DisplayName"="DM9000A/9010 ISA Fast Ethernet Adapter"
"Group"="NDIS"
"ImagePath"="dm9isa.dll"
[HKEY_LOCAL_MACHINE/Comm/DM9CE/Linkage]
"Route"=multi_sz:"dm9ce1"
[HKEY_LOCAL_MACHINE/Comm/DM9CE1]
"DisplayName"="DM9000A/9010 ISA Fast Ethernet Adapter"
"Group"="NDIS"
"ImagePath"="dm9isa.dll"
[HKEY_LOCAL_MACHINE/Comm/Tcpip/Linkage]
"Bind"="dm9ce1"
[HKEY_LOCAL_MACHINE/Comm/DM9CE1/Parms]
"BusNumber"=dword:0
"BusType"=dword:0
"XmitBuffer"=dword:20
"RecvBuffer"=dword:20
"IrqNumber"=dword:10
"MACAddress" =hex:00,0A,EB,FD,7A,00
[HKEY_LOCAL_MACHINE/Comm/DM9CE1/Parms/TcpIp]
"EnableDHCP"=dword:0
"UseZeroBroadcast"=dword:0
"DefaultGateway"="192.168.4.1"
"IpAddress"="192.168.4.215"
"Subnetmask"="255.255.255.0"
"DNS"="202.106.0.20"
ENDIF BSP_DM9000 !
本文参考:
“bluefish” 博客,出处http://bluefish.blog.51cto.com/214870/58106,
感谢bluefish的分享。