WinCE5.0 SMDK2410 BSP在GEC2410开发板上的移植(15)-CS8900 NDIS Miniport driver简析(1)

如何开发一个NDIS Miniport的网卡驱动,CS8900这个例子是个很好的参考.接下来我们就来分析下这个驱动,这样将来开发其他网卡驱动就知道怎么做了.
驱动共有4个文件:
cs8900.c:直接操作网卡的函数
interrupt.c:中断处理
miniport.c:NDIS miniport驱动接口实现
wince.c:驱动dll入口 

1.wince.c
我们先来看wince.c(应该改名为cs8900DriverEntry.c比较合适),其实这个文件就实现了DLL的入口函数DllEntry:
// // Standard Windows DLL entrypoint. // Since Windows CE NDIS miniports are implemented as DLLs, a DLL entrypoint is // needed. // BOOL __stdcall DllEntry( HANDLE hDLL, DWORD dwReason, LPVOID lpReserved ) { switch (dwReason) { case DLL_PROCESS_ATTACH: DEBUGREGISTER(hDLL); DEBUGMSG(1, (TEXT("CS8900: DLL_PROCESS_ATTACH/r/n"))); break; case DLL_PROCESS_DETACH: DEBUGMSG(1, (TEXT("CS8900: DLL_PROCESS_DETACH/r/n"))); break; } return TRUE; }
这就是在source文件定义DLLENTRY=DllEntry的原因.
这部分不需要做什么处理,真正驱动实现部分在其他3个文件里.

2.miniport.c
(1)DriverEntry
NDIS driver调用的第一个函数,该函数用来初始化NDIS Wrapper和注册miniport driver.
NDIS Wrapper是用来开发miniport driver和protocol driver的库,抽象了向OS提供的接口并提供一些支持函数.在CE中就是Network Driver Architecture (NDIS)组件提供的库.而另一个组件NDIS User-mode I/O Driver实际上就是实现了一个protocol driver,可以通过ReadFile和WriteFile来读写以太网帧.这些都是比较上层的实现,CE中都已经有组件实现好了.我们要实现的就是底层的部分.
DriverEntry函数首先声明了NDIS51_MINIPORT_CHARACTERISTICS(NDIS_MINIPORT_CHARACTERISTICS结构加上一些5.1下新的成员,实际用到的还是前者的成员)结构的变量CS8900Char, 原型在ndis.h中:
typedef struct _NDIS_MINIPORT_CHARACTERISTICS {         UCHAR MajorNdisVersion;         UCHAR MinorNdisVersion;         UINT Reserved;         W_CHECK_FOR_HANG_HANDLER CheckForHangHandler;         W_DISABLE_INTERRUPT_HANDLER DisableInterruptHandler;         W_ENABLE_INTERRUPT_HANDLER EnableInterruptHandler;         W_HALT_HANDLER HaltHandler;         W_HANDLE_INTERRUPT_HANDLER HandleInterruptHandler;         W_INITIALIZE_HANDLER InitializeHandler;         W_ISR_HANDLER ISRHandler;         W_QUERY_INFORMATION_HANDLER QueryInformationHandler;         W_RECONFIGURE_HANDLER ReconfigureHandler;         W_RESET_HANDLER ResetHandler;         W_SEND_HANDLER SendHandler;         W_SET_INFORMATION_HANDLER SetInformationHandler;         W_TRANSFER_DATA_HANDLER TransferDataHandler;         W_RETURN_PACKET_HANDLER ReturnPacketHandler;         W_SEND_PACKETS_HANDLER SendPacketsHandler;         W_ALLOCATE_COMPLETE_HANDLER AllocateCompleteHandler;         W_CANCEL_SEND_PACKETS_HANDLER CancelSendPacketsHandler;         W_MINIPORT_SHUTDOWN_HANDLER AdapterShutdownHandler;} NDIS_MINIPORT_CHARACTERISTICS, *PNDIS_MINIPORT_CHARACTERISTICS;
这个结构定义了NDIS的版本号,以及要导出Minioprt的相应的接口函数的函数指针。该结构会在DriverEntry函数中被设置,并进行注册.
DriverEntry函数首先调用NdisMInitializeWrapper通知NDIS一个新的miniport driver正在初始化,并获得一个NDIS wrapper的句柄.
初始化好CS8900Char函数指针后,调用NdisMRegisterMiniport注册一个网卡实例.
如果返回值不为NDIS_STATUS_SUCCESS,就调用NdisTerminateWrapper释放由NdisMInitializeWrapper分配的系统资源.
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This is the primary initialization routine for the CS8900 driver. It is simply responsible for the intializing the wrapper and registering the Miniport driver. It then calls a system and architecture specific routine that will initialize and register each adapter. Arguments: DriverObject - Pointer to driver object created by the system. RegistryPath - Path to the parameters for this driver in the registry. Return Value: The status of the operation. --*/ { // // Receives the status of the NdisMRegisterMiniport operation. // NDIS_STATUS Status; // // Characteristics table for this driver. // // NDIS_MINIPORT_CHARACTERISTICS CS8900Char; NDIS51_MINIPORT_CHARACTERISTICS CS8900Char; // // Pointer to the global information for this driver // PDRIVER_BLOCK NewDriver = &CS8900MiniportBlock; // // Handle for referring to the wrapper about this driver. // NDIS_HANDLE NdisWrapperHandle; DEBUGMSG(1, (TEXT("+CS8900:DriverEntry/r/n"))); RETAILMSG(1, (TEXT("+CS8900:DriverEntry/r/n"))); // // Initialize the wrapper. // NdisMInitializeWrapper( &NdisWrapperHandle, DriverObject, RegistryPath, NULL ); // // Save the global information about this driver. // NewDriver->NdisWrapperHandle = NdisWrapperHandle; NewDriver->AdapterQueue = (PCS8900_ADAPTER)NULL; // // Initialize the Miniport characteristics for the call to // NdisMRegisterMiniport. // memset(&CS8900Char,0,sizeof(CS8900Char)); CS8900Char.MajorNdisVersion = CS8900_NDIS_MAJOR_VERSION; CS8900Char.MinorNdisVersion = CS8900_NDIS_MINOR_VERSION; CS8900Char.CheckForHangHandler = NULL; CS8900Char.DisableInterruptHandler = NULL; CS8900Char.EnableInterruptHandler = NULL; CS8900Char.HaltHandler = CS8900Halt; CS8900Char.HandleInterruptHandler = CS8900HandleInterrupt; CS8900Char.InitializeHandler = MiniportInitialize; CS8900Char.ISRHandler = CS8900Isr; CS8900Char.QueryInformationHandler = CS8900QueryInformation; CS8900Char.ReconfigureHandler = NULL; CS8900Char.ResetHandler = CS8900Reset; CS8900Char.SendHandler = CS8900Send; CS8900Char.SetInformationHandler = CS8900SetInformation; CS8900Char.TransferDataHandler = CS8900TransferData; CS8900Char.ReturnPacketHandler = NULL; CS8900Char.SendPacketsHandler = NULL; CS8900Char.AllocateCompleteHandler = NULL; CS8900Char.CancelSendPacketsHandler = CS8900CancelSendPackets; CS8900Char.AdapterShutdownHandler = CS8900AdapterShutdown; CS8900Char.PnPEventNotifyHandler = CS8900DevicePnPEvent; DEBUGMSG(1, (TEXT("CS8900: -> NdisMRegisterMiniport/r/n"))); Status = NdisMRegisterMiniport( NdisWrapperHandle, &CS8900Char, sizeof(CS8900Char) ); if (Status == NDIS_STATUS_SUCCESS) { DEBUGMSG(1, (TEXT("-CS8900:DriverEntry: Success!/r/n"))); return STATUS_SUCCESS; } // Terminate the wrapper. NdisTerminateWrapper (CS8900MiniportBlock.NdisWrapperHandle, NULL); CS8900MiniportBlock.NdisWrapperHandle = NULL; DEBUGMSG(1, (TEXT("-CS8900:DriverEntry: Fail!/r/n"))); return STATUS_UNSUCCESSFUL; }
2.MiniportInitialize
这个函数在DriverEntry中被赋值给NDIS51_MINIPORT_CHARACTERISTICS结构(CS8900Char.InitializeHandler = MiniportInitialize;)用来设置网卡,分配硬件资源(根据注册表信息),分配IO操作所需的资源.
主要通过调用NdisOpenConfiguration,NdisReadConfiguration,NdisReadNetworkAddress获得注册表中网卡的配置信息,如网卡类型,中断号,IO基址等.
获得的信息都保存到PCS8900_ADAPTER这样一个结构体,供其他函数使用.其原型如下:
typedef struct _CS8900_ADAPTER { // This is the handle given by the wrapper for calling ndis // functions. NDIS_HANDLE MiniportAdapterHandle; // Interrupt object. NDIS_MINIPORT_INTERRUPT Interrupt; // used by DriverBlock->AdapterQueue struct _CS8900_ADAPTER * NextAdapter; // This is a count of the number of receives that have been // indicated in a row. This is used to limit the number // of sequential receives so that one can periodically check // for transmit complete interrupts. ULONG ReceivePacketCount; // Configuration information // Physical address of the IoBaseAddress PVOID IoBaseAddr; // Interrupt number this adapter is using. CHAR InterruptNumber; // Number of multicast addresses that this adapter is to support. UINT MulticastListMax; // The type of bus that this adapter is running on. Either ISA or // MCA. UCHAR BusType; // InterruptType is the next interrupt that should be serviced. UCHAR InterruptType; // Type of CS8900 card. UINT CardType; // Address of the memory window. ULONG AttributeMemoryAddress; ULONG AttributeMemorySize; // Operational information. // Mapped address of the base io port. ULONG IoPAddr; // InterruptStatus tracks interrupt sources that still need to be serviced, // it is the logical OR of all card interrupts that have been received and not // processed and cleared. (see also INTERRUPT_TYPE definition in cs8900.h) UCHAR InterruptStatus; // The ethernet address currently in use. UCHAR StationAddress[CS8900_LENGTH_OF_ADDRESS]; // The ethernet address that is burned into the adapter. UCHAR PermanentAddress[CS8900_LENGTH_OF_ADDRESS]; // The current packet filter in use. ULONG PacketFilter; // Flag that is set when we are shutting down the interface BOOLEAN ShuttingDown; // Statistics used by Set/QueryInformation. ULONG FramesXmitGood; // Good Frames Transmitted ULONG FramesRcvGood; // Good Frames Received ULONG FramesXmitBad; // Bad Frames Transmitted ULONG FramesXmitOneCollision; // Frames Transmitted with one collision ULONG FramesXmitManyCollisions; // Frames Transmitted with > 1 collision ULONG FrameAlignmentErrors; // FAE errors counted ULONG CrcErrors; // CRC errors counted ULONG MissedPackets; // missed packet counted // Reset information. UCHAR NicMulticastRegs[8]; // contents of card multicast registers UCHAR NicReceiveConfig; // contents of NIC RCR UCHAR NicInterruptMask; // contents of NIC IMR // The lookahead buffer size in use. ULONG MaxLookAhead; // CS8900 address of the beginning of the packet. PUCHAR PacketHeaderLoc; // Lookahead buffer UCHAR Lookahead[CS8900_MAX_LOOKAHEAD + CS8900_HEADER_SIZE]; // List of multicast addresses in use. CHAR Addresses[DEFAULT_MULTICASTLISTMAX][CS8900_LENGTH_OF_ADDRESS]; } CS8900_ADAPTER, * PCS8900_ADAPTER;
最后调用CS8900RegisterAdapter来注册网卡实例.
以下是MiniportInitialize的源代码:
#pragma NDIS_PAGEABLE_FUNCTION(MiniportInitialize) extern NDIS_STATUS MiniportInitialize( OUT PNDIS_STATUS OpenErrorStatus, OUT PUINT SelectedMediumIndex, IN PNDIS_MEDIUM MediumArray, IN UINT MediumArraySize, IN NDIS_HANDLE MiniportAdapterHandle, IN NDIS_HANDLE ConfigurationHandle ) /*++ Routine Description: CS8900Initialize starts an adapter and registers resources with the wrapper. Arguments: OpenErrorStatus - Extra status bytes for opening token ring adapters. SelectedMediumIndex - Index of the media type chosen by the driver. MediumArray - Array of media types for the driver to chose from. MediumArraySize - Number of entries in the array. MiniportAdapterHandle - Handle for passing to the wrapper when referring to this adapter. ConfigurationHandle - A handle to pass to NdisOpenConfiguration. Return Value: NDIS_STATUS_SUCCESS NDIS_STATUS_PENDING --*/ { // // Pointer to our newly allocated adapter. // PCS8900_ADAPTER Adapter; // // The handle for reading from the registry. // NDIS_HANDLE ConfigHandle; // // The value read from the registry. // PNDIS_CONFIGURATION_PARAMETER ReturnedValue; // // String names of all the parameters that will be read. // NDIS_STRING IOAddressStr = IOADDRESS; NDIS_STRING InterruptStr = INTERRUPT; NDIS_STRING MaxMulticastListStr = MAX_MULTICAST_LIST; NDIS_STRING NetworkAddressStr = NETWORK_ADDRESS; NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType"); NDIS_STRING CardTypeStr = NDIS_STRING_CONST("CardType"); // // TRUE if there is a configuration error. // BOOLEAN ConfigError = FALSE; // // A special value to log concerning the error. // ULONG ConfigErrorValue = 0; // // The slot number the adapter is located in, used for // Microchannel adapters. // UINT SlotNumber = 0; // // TRUE if it is unnecessary to read the Io Base Address // and Interrupt from the registry. Used for Microchannel // adapters, which get this information from the slot // information. // BOOLEAN SkipIobaseAndInterrupt = FALSE; // // The network address the adapter should use instead of the // the default burned in address. // PVOID NetAddress; // // The number of bytes in the address. It should be // CS8900_LENGTH_OF_ADDRESS // ULONG Length; // // These are used when calling CS8900RegisterAdapter. // // // The physical address of the base I/O port. // PVOID IoBaseAddr; // // The interrupt number to use. // CCHAR InterruptNumber; // // The number of multicast address to be supported. // UINT MaxMulticastList; // // Temporary looping variable. // ULONG i; // // Status of Ndis calls. // NDIS_STATUS Status; // NDIS_MCA_POS_DATA McaData; DEBUGMSG(1, (TEXT("+CS8900:CS8900Initialize/r/n"))); // // Search for the medium type (802.3) in the given array. // for (i = 0; i < MediumArraySize; i++) { if (MediumArray[i] == NdisMedium802_3) { break; } } if (i == MediumArraySize) { DEBUGMSG(1, (TEXT("CS8900: No Supported Media!/r/n"))); return( NDIS_STATUS_UNSUPPORTED_MEDIA ); } *SelectedMediumIndex = i; // // Set default values. // IoBaseAddr = DEFAULT_IOBASEADDR; InterruptNumber = DEFAULT_INTERRUPTNUMBER; MaxMulticastList = DEFAULT_MULTICASTLISTMAX; // // Allocate memory for the adapter block now. // Status = NdisAllocateMemory( (PVOID *)&Adapter, sizeof(CS8900_ADAPTER), 0, HighestAcceptableMax ); if (Status != NDIS_STATUS_SUCCESS) { DEBUGMSG(1, (TEXT("CS8900: NdisAllocateMemory(CS8900_ADAPTER) Fail!/r/n"))); return Status; } // // Clear out the adapter block, which sets all default values to FALSE, // or NULL. // NdisZeroMemory (Adapter, sizeof(CS8900_ADAPTER)); // // Open the configuration space. // NdisOpenConfiguration( &Status, &ConfigHandle, ConfigurationHandle ); if (Status != NDIS_STATUS_SUCCESS) { NdisFreeMemory(Adapter, sizeof(CS8900_ADAPTER), 0); DEBUGMSG(1, (TEXT("CS8900: NdisOpenconfiguration Fail! - 0x%x/n"), Status)); return Status; } // // Read in the card type. // NdisReadConfiguration( &Status, &ReturnedValue, ConfigHandle, &CardTypeStr, NdisParameterHexInteger ); if (Status == NDIS_STATUS_SUCCESS) Adapter->CardType = (UINT)ReturnedValue->ParameterData.IntegerData; // // Read net address // NdisReadNetworkAddress( &Status, &NetAddress, &Length, ConfigHandle ); if ((Length == CS8900_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) { // // Save the address that should be used. // NdisMoveMemory( Adapter->StationAddress, NetAddress, CS8900_LENGTH_OF_ADDRESS ); } // // Read Bus Type (for NE2/AE2 support) // NdisReadConfiguration( &Status, &ReturnedValue, ConfigHandle, &BusTypeStr, NdisParameterHexInteger ); if (Status == NDIS_STATUS_SUCCESS) { Adapter->BusType = (UCHAR)ReturnedValue->ParameterData.IntegerData; } if (!SkipIobaseAndInterrupt) { // // Read I/O Address // NdisReadConfiguration( &Status, &ReturnedValue, ConfigHandle, &IOAddressStr, NdisParameterHexInteger ); if (Status == NDIS_STATUS_SUCCESS) { IoBaseAddr = (PVOID)(ReturnedValue->ParameterData.IntegerData); } // // Read interrupt number // NdisReadConfiguration( &Status, &ReturnedValue, ConfigHandle, &InterruptStr, NdisParameterInteger ); if (Status == NDIS_STATUS_SUCCESS) { InterruptNumber = (CCHAR)(ReturnedValue->ParameterData.IntegerData); } } // // Read MaxMulticastList // NdisReadConfiguration( &Status, &ReturnedValue, ConfigHandle, &MaxMulticastListStr, NdisParameterInteger ); if (Status == NDIS_STATUS_SUCCESS) { MaxMulticastList = ReturnedValue->ParameterData.IntegerData; if (ReturnedValue->ParameterData.IntegerData <= DEFAULT_MULTICASTLISTMAX) MaxMulticastList = ReturnedValue->ParameterData.IntegerData; } // RegisterAdapter: // // Now to use this information and register with the wrapper // and initialize the adapter. // // // First close the configuration space. // NdisCloseConfiguration(ConfigHandle); DEBUGMSG(1, (TEXT("CS8900:Card type: 0x%x/r/n"), Adapter->CardType)); DEBUGMSG(1, (TEXT("CS8900:I/O base addr 0x%lx/r/n"), IoBaseAddr)); DEBUGMSG(1, (TEXT("CS8900:interrupt number %ld/r/n"), InterruptNumber)); DEBUGMSG(1, (TEXT("CS8900:max multicast %ld/r/n"), DEFAULT_MULTICASTLISTMAX)); DEBUGMSG(1, (TEXT("CS8900:attribute memory address 0x%X/r/n"), Adapter->AttributeMemoryAddress)); DEBUGMSG(1, (TEXT("CS8900:attribute memory size 0x%X/r/n"), Adapter->AttributeMemorySize)); DEBUGMSG(1, (TEXT("CS8900:Bus type: %d/r/n"), Adapter->BusType)); // // Set up the parameters. // Adapter->IoBaseAddr = IoBaseAddr; Adapter->InterruptNumber = InterruptNumber; Adapter->MulticastListMax = MaxMulticastList; Adapter->MiniportAdapterHandle = MiniportAdapterHandle; Adapter->MaxLookAhead = CS8900_MAX_LOOKAHEAD; // // Now do the work. // if (CS8900RegisterAdapter(Adapter, ConfigurationHandle, ConfigError, ConfigErrorValue ) != NDIS_STATUS_SUCCESS) { // // CS8900RegisterAdapter failed. // NdisFreeMemory(Adapter, sizeof(CS8900_ADAPTER), 0); return NDIS_STATUS_FAILURE; } DEBUGMSG(1, (TEXT("-CS8900:CS8900Initialize Success!/r/n"))); return NDIS_STATUS_SUCCESS; }
(3).CS8900RegisterAdapter
在MiniportInitialize最后调用了CS8900RegisterAdapter来注册网卡实例.
该函数首先调用NdisMSetAttributes来通知NDIS Library网卡的主要特性.然后调用NdisMRegisterInterrupt和NdisMRegisterAdapterShutdownHandler来注册中断和shutdown处理.
NdisMRegisterInterrupt:映射NIC驱动由NdisMRegisterMiniport注册注册的MiniportISR和MiniportHandleInterrupt函数,并设置相应的中断向量
NdisMRegisterAdapterShutdownHandler:注册NIC驱动提供的MiniportShutdown函数,当系统关闭时被调用
#pragma NDIS_PAGEABLE_FUNCTION(CS8900RegisterAdapter) NDIS_STATUS CS8900RegisterAdapter( IN PCS8900_ADAPTER Adapter, IN NDIS_HANDLE ConfigurationHandle, IN BOOLEAN ConfigError, IN ULONG ConfigErrorValue ) /*++ Routine Description: Called when a new adapter should be registered. It allocates space for the adapter, initializes the adapter's block, registers resources with the wrapper and initializes the physical adapter. Arguments: Adapter - The adapter structure. ConfigurationHandle - Handle passed to CS8900Initialize. ConfigError - Was there an error during configuration reading. ConfigErrorValue - Value to log if there is an error. Return Value: Indicates the success or failure of the registration. --*/ { // // Temporary looping variable. // unsigned char *m_pCS8900IoPort; // // General purpose return from NDIS calls // NDIS_STATUS status; DEBUGMSG(1, (TEXT("+CS8900:CS8900RegisterAdapter/r/n"))); // // Check for a configuration error // if (ConfigError) { // // Log Error and exit. // NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, 1, ConfigErrorValue ); DEBUGMSG(1, (TEXT("CS8900:RegisterAdapter: CS8900Initialize had a config error %d/r/n"), ConfigErrorValue)); return(NDIS_STATUS_FAILURE); } // // Inform the wrapper of the physical attributes of this adapter. // DEBUGMSG(1, (TEXT("CS8900: -> NdisMSetAttributes/r/n"))); NdisMSetAttributes( Adapter->MiniportAdapterHandle, (NDIS_HANDLE)Adapter, FALSE, Adapter->BusType ); m_pCS8900IoPort = VirtualAlloc(0, 0x1000, MEM_RESERVE, PAGE_NOACCESS); DEBUGMSG(1, (TEXT("[CS8900] VirtualAlloc of m_pCS8900IoPort returns %x/r/n"), m_pCS8900IoPort)); if (!VirtualCopy(m_pCS8900IoPort, (LPVOID)((IO_PACKET_PAGE_BASE_ADDR) & 0xFFFFF000), 0x1000, PAGE_READWRITE|PAGE_NOCACHE) ) DEBUGMSG(1, (TEXT("[CS8900] m_pCS8900IoPort Virtual Copy failed/r/n"))); else DEBUGMSG(1, (TEXT("[CS8900] m_pCS8900IoPort Virtual Copy OK!/r/n"))); ioPacketPage = (volatile unsigned char *)(m_pCS8900IoPort + (IO_PACKET_PAGE_BASE_ADDR - ((IO_PACKET_PAGE_BASE_ADDR) & 0xFFFFF000)) ); Adapter->IoPAddr = (unsigned long)ioPacketPage; DEBUGMSG(1, (TEXT("[CS8900] m_pCS8900IoPort= %x/r/n"), Adapter->IoPAddr)); if (Adapter->IoPAddr == 0) { DEBUGMSG(1, (TEXT("CS8900:Invalid IoPAddr!/r/n"))); return NDIS_STATUS_FAILURE; } // // Initialize the card. // DEBUGMSG(1, (TEXT("+CS8900:CS8900Initialize/r/n"))); if (!CS8900Initialize(Adapter)) { DEBUGMSG(1, (TEXT("-CS8900:CS8900Initialize - Fail!/r/n"))); NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_ADAPTER_NOT_FOUND, 0 ); status = NDIS_STATUS_ADAPTER_NOT_FOUND; goto fail2; } DEBUGMSG(1, (TEXT("-CS8900:CS8900Initialize - Success!/r/n"))); // // Read the Ethernet address off of the PROM. // if (!CS8900ReadEthernetAddress(Adapter)) { DEBUGMSG(1, (TEXT("CS8900:RegisterAdapter Could not read the ethernet address/n"))); NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_ADAPTER_NOT_FOUND, 0 ); status = NDIS_STATUS_ADAPTER_NOT_FOUND; goto fail2; } // /* Initialize The Interrupt */ DEBUGMSG(1, (TEXT("CS8900RegisterAdapter:Initialize the Interrupt!/r/n"))); status = NdisMRegisterInterrupt( &Adapter->Interrupt, Adapter->MiniportAdapterHandle, (UINT)Adapter->InterruptNumber, (UINT)Adapter->InterruptNumber, (BYTE)TRUE, (BYTE)FALSE, (NDIS_INTERRUPT_MODE)NdisInterruptLatched ); if (status != NDIS_STATUS_SUCCESS) { DEBUGMSG(1, (TEXT("CS8900:RegisterAdapter -> NdisMRegisterInterrupt failed 0x%x/r/n"), status)); NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_INTERRUPT_CONNECT, 0 ); goto fail3; } DEBUGMSG(1, (TEXT("CS8900:RegisterAdapter Interrupt Connected/r/n"))); // register a shutdown handler for this card NdisMRegisterAdapterShutdownHandler( Adapter->MiniportAdapterHandle, // miniport handle. Adapter, // shutdown context. CS8900Shutdown // shutdown handler. ); /* Initialize The Interrupt */ DEBUGMSG(1, (TEXT("CS8900RegisterAdapter:Initialize the Interrupt!/r/n"))); // // Initialization completed successfully. // DEBUGMSG(1, (TEXT("CS8900:RegisterAdapter OK/r/n"))); return(NDIS_STATUS_SUCCESS); // // Code to unwind what has already been set up when a part of // initialization fails, which is jumped into at various // points based on where the failure occured. Jumping to // a higher-numbered failure point will execute the code // for that block and all lower-numbered ones. // fail3: // // Take us out of the AdapterQueue. // if (CS8900MiniportBlock.AdapterQueue == Adapter) { CS8900MiniportBlock.AdapterQueue = Adapter->NextAdapter; } else { PCS8900_ADAPTER TmpAdapter = CS8900MiniportBlock.AdapterQueue; while (TmpAdapter->NextAdapter != Adapter) { TmpAdapter = TmpAdapter->NextAdapter; } TmpAdapter->NextAdapter = TmpAdapter->NextAdapter->NextAdapter; } fail2: NdisMDeregisterIoPortRange( Adapter->MiniportAdapterHandle, (ULONG)Adapter->IoBaseAddr, 0x20, (PVOID)Adapter->IoPAddr ); return(status); }
还调用了CS8900Initialize进行了网卡硬件的初始化,设置了外部总线控制器,物理中断号和中断模式等;调用CS8900ReadEthernetAddress设置网卡MAC地址.这两个函数都实现在cs8900.c中,涉及硬件的代码我们之后再来分析.
最后调用NdisMRegisterAdapterShutdownHandler时注册了一个ShutdownHandler,仅仅设置一个标志,并没有具体处理.
extern VOID CS8900Shutdown( IN NDIS_HANDLE MiniportAdapterContext ) /*++ Routine Description: CS8900Shutdown is called to shut down the adapter. We need to unblock any threads which may be called in, and terminate any loops. This function is called by the WinCE NDIS.DLL when a PCMCIA card removal is detected. At that point, any access to the CS8900 registers may return random data, as the bus is floating. Arguments: MiniportAdapterContext - The context value that the Miniport returned from CS8900Initialize; actually as pointer to an CS8900_ADAPTER. Return Value: None. --*/ { PCS8900_ADAPTER Adapter; Adapter = PCS8900_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); Adapter->ShuttingDown = TRUE; DEBUGMSG(1, (TEXT("+CS8900:CS8900Shutdown - Not Implemented!/r/n"))); }
下一篇我们来介绍其他几个在NDIS51_MINIPORT_CHARACTERISTICS结构注册的Handler

你可能感兴趣的:(WinCE5.0 SMDK2410 BSP在GEC2410开发板上的移植(15)-CS8900 NDIS Miniport driver简析(1))