hwcom.c
来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 1,737 行 · 第 1/4 页
C
1,737 行
/* Copyright (c) 1998 Motorola Inc. All rights reserved. */
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
hw.c
Abstract:
MPC821 hardware-specific functions for the NDIS 4.0 ETH8XX miniport
device driver.
Functions:
HW_Get_IMMR()
HW_Allocate_BDs()
HW_Allocate_Buffers()
HW_Internal_Setup_BDs()
HW_Setup_BD_List()
HW_Setup_Par_Ports()
HW_Setup_Serial_If()
HW_Setup_Common_Protocol_Area()
HW_Setup_Eth_Protocol_Area()
HW_Handshake_CPM_Init()
HW_Clear_Init_Events()
HW_Configure_Interrupts()
HW_Toggle_Eth_If()
HW_Initialize()
HW_Read_Eth_Address()
HW_Setup()
HW_Reset()
HW_Get_Interrupt_Status()
HW_Ack_Interrupt_Status()
HW_Block_Interrupts()
HW_Unblock_Interrupts()
HW_Copy_Down_Packet()
HW_Copy_Up_Packet()
HW_Start()
HW_Stop()
HW_Start_Xmit()
HW_Advance_Element()
HW_Fill_Multicast_Regs()
HW_Set_All_Multicast()
HW_Set_Promiscuous()
HW_Set_Broadcast()
Notes:
The routines in this file are used to support configuration and
initialization of the Ethernet interface (when called by routines
in eth8xx.c) and in handling Ethernet-related interrupts (when
called by routines in interrup.c). On the MPC821ADS platform, all
of the following components must be properly configured before
the Ethernet interface may be used:
1. the CPM SCC1 mode register (Ethernet must use SCC1)
2. the CPM common protocol RAM area
3. the CPM Ethernet-specific protocol RAM area
4. the Ethernet mode register
5. the Ethernet event/interrupt mask register
6. the send/receive buffer descriptors and data buffers
7. the parallel port pins used to pace Ethernet activity
8. the SIU interrupt registers
9. the BCSR1 register to enable the on-board External Ethernet
Serial Transceiver (EEST)
Only the MOTO_ADS definitions (for the MPC821ADS platform) have been
tested. The HELLCAT platform is not currently supported.
--*/
#include <ndis.h>
#include <excpt.h>
#define ADS_IMMR (Adapter->Immr) /* Use this to simplify access to
* the BCSR, CPM registers, and
* the Ethernet parameter RAM
*/
/* Declarations to enable use of #pragma NDIS_PAGEABLE_FUNCTION(). */
STATIC PDA *HW_Get_IMMR(VOID);
STATIC BOOLEAN HW_Allocate_BDs(IN PETH8XX_ADAPTER Adapter);
STATIC BOOLEAN HW_Allocate_Buffers(IN PETH8XX_ADAPTER Adapter);
STATIC VOID HW_Setup_BD_List(IN BD *pFirstBD,
IN BD *pLastBD,
IN UINT bd_status,
IN PUCHAR pFirstBuffer,
IN UINT bufferSize);
STATIC VOID HW_Setup_Par_Ports(IN PETH8XX_ADAPTER Adapter);
STATIC VOID HW_Setup_Serial_If(IN PETH8XX_ADAPTER Adapter);
STATIC VOID HW_Setup_Common_Protocol_Area(IN PETH8XX_ADAPTER Adapter);
STATIC VOID HW_Setup_Eth_Protocol_Area(IN PETH8XX_ADAPTER Adapter);
/*----------------------------------------------------------------------*/
#pragma NDIS_PAGEABLE_FUNCTION(HW_Get_IMMR)
PDA *HW_Get_IMMR(VOID)
/*++
Description:
Gets a copy of the CPM IMMR (internal memory map register).
This register is initialized during system boot and normally
remains unchanged after that. Note that access to the BCSR,
CPM registers, and the Ethernet parameter RAM are all relative
to the base memory pointer stored in the IMMR.
Arguments:
None
Return Value:
(PDA *)NULL if the IMMR could not be accessed
otherwise, the value of IMMR (usable as a virtual memory pointer)
--*/
{
ADDRESSES immr_addr; /* Ptr to physical/virtual address. */
PDA *immr = (PDA *)NULL; /* Return CPM internal memory map ptr. */
DWORD parm;
/* Messages for all possible error conditions. */
DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
(TEXT("+ETH8XX: HW_Get_IMMR\r\n")));
if (!KernelIoControl((DWORD)OEM_IOCTL_GET_IMMR, (LPVOID)&parm,
(DWORD)parm, (LPVOID)&immr_addr, (DWORD)parm, (LPDWORD)&parm))
{
ERRORMSG(1, (TEXT("HW_Get_IMMR: OEM_IOCTL_GET_IMMR failed, fatal\r\n"))); /* OEM_IOCTL_GET_IMMR failed */
} else {
/* OK, got IMMR as a physical address, now convert to equivalent
* virtual memory address with appropriate access priviledges.
* This may be done by the kernelIoControl services at some
* point in the future.
*/
immr = VirtualAlloc(0, sizeof(PDA), MEM_RESERVE,PAGE_NOACCESS);
if (immr == (PDA *)NULL)
{
ERRORMSG(1, (TEXT("HW_Get_IMMR: IMMR VirtualAlloc failed, fatal\r\n"))); /* VirtualAlloc failed */
} else if (!VirtualCopy(immr, immr_addr.VirtualAddress,
sizeof(PDA),
PAGE_READWRITE | PAGE_NOCACHE)) {
ERRORMSG(1, (TEXT("HW_Get_IMMR: IMMR VirtualCopy failed, fatal\r\n"))); /* VirtualCopy failed */
immr = (PDA *)NULL;
}
}
DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
(TEXT("-ETH8XX: HW_Get_IMMR\r\n")));
return(immr);
}
/*----------------------------------------------------------------------*/
#pragma NDIS_PAGEABLE_FUNCTION(HW_Allocate_BDs)
STATIC BOOLEAN HW_Allocate_BDs(IN PETH8XX_ADAPTER Adapter)
/*++
Description:
Allocates the necessary CPM buffer descriptors (for both Tx and
Rx buffers). All of the buffer descriptors are allocated from
the CPM dual-ported RAM. This is OK as long as we don't allocate
too many buffer descriptors (each one requires 8 bytes).
Arguments:
Adapter - pointer to the NDIS miniport adapter block
Return Value:
TRUE if successfully allocated memory for buffer descriptors
FALSE otherwise
--*/
{
OEM_IOCTL_INT_MEM_REQUEST alloc_info;
DWORD requested; /* Number of bytes required. */
DWORD allocated; /* Number of bytes allocated. */
BOOLEAN rc; /* KernelIOControl() return code. */
DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
(TEXT("+ETH8XX: HW_Allocate_BDs\r\n")));
/* Setup memory request to the HAL-layer. */
alloc_info.MemoryType = MEMORY_BD;
alloc_info.NumberOfBytes = sizeof(BD) * (Adapter->NbrRxBuffers
+ Adapter->NbrTxBuffers);
/* Save count of required number of bytes for later comparison. */
requested = alloc_info.NumberOfBytes;
/* Now call HAL-layer to request internal memory. */
rc = KernelIoControl((DWORD)OEM_IOCTL_ALLOC_MEM,
(LPVOID)&alloc_info, (DWORD) NOTUSED,
(LPVOID) &Adapter->BdStartArea,
(DWORD)NOTUSED, (LPDWORD)&allocated);
if ((rc == FALSE) || (allocated != requested))
{
/* Something went wrong. */
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("*ETH8XX: OEM_IOCTL_ALLOC_MEM failed\r\n")));
return (FALSE);
}
/* The BD Base returned is relative to the begining of the
* IMMR, so add the offset to get into the user defineable area.
*/
Adapter->BdStartArea = (BD *)(((ULONG)(Adapter->BdStartArea))
+ ((ULONG)ADS_IMMR));
DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
(TEXT("-ETH8XX: HW_Allocate_BDs\r\n")));
return(TRUE);
}
/*----------------------------------------------------------------------*/
#pragma NDIS_PAGEABLE_FUNCTION(HW_Allocate_Buffers)
STATIC BOOLEAN HW_Allocate_Buffers(IN PETH8XX_ADAPTER Adapter)
/*++
Description:
Allocates the memory for all Tx and Rx data buffers. The memory
is allocated from external RAM rather than the CPM dual-ported
RAM since each buffer can be quite large (currently 1520 bytes).
Arguments:
Adapter - pointer to the NDIS miniport adapter block
Return Value:
TRUE if successfully allocated memory for data buffers
FALSE otherwise
--*/
{
ULONG PoolSize; /* Size of the data buffer pool. */
ULONG debugBufferSize = 0;
DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
(TEXT("+ETH8XX: HW_Allocate_Buffers\r\n")));
/* The Rx. and Tx. buffers should be allocated from external
* memory as opposed to being allocated from the space-limited
* dual-ported RAM. Allocate and copy enough space for both
* Rx. and Tx buffers.
*/
PoolSize = (Adapter->NbrRxBuffers * Adapter->MaxRxBufferSize) +
(Adapter->NbrTxBuffers * Adapter->MaxTxBufferSize);
#if ETHDBG
/* Also allocate memory for debug buffer. */
debugBufferSize = ETH8XX_LOG_SIZE;
#endif
if (PoolSize + debugBufferSize > ALLOCATED_BUFFER_SPACE)
{
/* Insufficient memory for requested number of buffers. */
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("*ETH8XX: Requesting %d bytes for buffers\r\n"),
PoolSize + debugBufferSize));
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("*ETH8XX: Only reserved %d bytes in config.bib\r\n"),
ALLOCATED_BUFFER_SPACE));
return(FALSE);
}
/* First reserve the range of virtual addresses. */
Adapter->RamBase = (PUCHAR)VirtualAlloc(0, PoolSize + debugBufferSize,
MEM_RESERVE,
PAGE_NOACCESS);
if (!Adapter->RamBase)
{
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("*ETH8XX: Buffer allocation failed.\r\n")));
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("*ETH8XX: Requested %d bytes for buffers.\r\n"),
PoolSize + debugBufferSize));
return(FALSE);
}
DEBUGMSG(ZONE_INIT, (TEXT(" ETH8XX: Requested %d bytes for buffers.\r\n"),
PoolSize + debugBufferSize));
/* Now do the actual allocation, note that the address of the
* physical buffer must be reserved in the config.bib file and
* ETHERNET_RAM_ADDR defined appropriately in dma.h.
*/
if (!VirtualCopy(Adapter->RamBase, (LPVOID)ETHERNET_RAM_ADDR,
PoolSize, PAGE_READWRITE | PAGE_NOCACHE))
{
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("*ETH8XX: RX and Tx Buffer Copy Failed\r\n")));
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("*ETH8XX: Requested location was : 0x%X.\r\n"),
ETHERNET_RAM_ADDR));
return(FALSE);
}
/* Clear the area. */
memset(Adapter->RamBase, 0, PoolSize);
/* Setup the start of the receive buffer area. */
Adapter->RxStart = Adapter->RamBase;
/* The start of the transmit buffer area. */
Adapter->TxStart = Adapter->RamBase +
(Adapter->NbrRxBuffers * Adapter->MaxRxBufferSize);
#if ETHDBG
/* Also set up in-memory buffer for debug purposes. */
eth8xxLogBuffer = (PUCHAR)(Adapter->RamBase + PoolSize);
DEBUGMSG(ZONE_INIT, (TEXT(" ETH8XX: Debug buffer location: 0x%X (Physical).\r\n"),
((ETHERNET_RAM_ADDR + PoolSize) & SDB_PHYS_ADDR_MASK)));
DEBUGMSG(ZONE_INIT, (TEXT(" 0x%X (Virtual).\r\n"),
Adapter->RamBase + PoolSize));
DEBUGMSG(ZONE_INIT, (TEXT(" ETH8XX: Debug buffer size : %d bytes.\r\n"),
ETH8XX_LOG_SIZE));
#endif
DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
(TEXT("-ETH8XX: HW_Allocate_Buffers\r\n")));
return(TRUE);
}
/*----------------------------------------------------------------------*/
STATIC VOID HW_Internal_Setup_BDs(IN PETH8XX_ADAPTER Adapter)
/*++
Description:
Sets up the receive and transmit buffer descriptors in the CPM.
The Tx and Rx buffer descriptors must be configured as a circular
linked-list. Each buffer descriptor contains a physical address
pointer to its associated data buffer along with a number of status
fields. See the MPC821 User's Manual for complete details.
Note that the Windows CE 4GB virtual memory space is divided into 2
equal 2 GB portions with the upper 2 GB (8000 0000 - FFFF FFFF)
region being reserved for hardware access (i.e., write-through and
cache-inhibited). Hence, all of the RAM and flash memory is mapped
into a region beginning at 8000 0000. Therefore, to obtain, the
physical address of a data buffer, we must strip off the leading
bit. For additional details concerning the Windows CE memory layout,
see "Minimizing the Memory Footprint of Your Windows CE-based Program",
Douglas Boling, Microsoft Systems Journal, may 1998, vol. 13, no. 5,
pp.37-50.
Arguments:
Adapter - pointer to the NDIS miniport adapter block
Return Value:
None
--*/
{
PUCHAR pFirstRxBuffer = (PUCHAR)(ETHERNET_RAM_ADDR & SDB_PHYS_ADDR_MASK);
PUCHAR pFirstTxBuffer = pFirstRxBuffer
+ Adapter->NbrRxBuffers * Adapter->MaxRxBufferSize;
DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
(TEXT("+ETH8XX: HW_Internal_Setup_BDs\r\n")));
/* Note: it is required that all buffer descriptors be allocated
* contiguously, i.e. one starts every 8 bytes with no gaps. This
* greatly simplifies access to the buffer descriptors during
* initial setup and subsequent use. The list of buffer descriptors
* starts with all of the Rx BDs followed by all of the Tx BDs. A
* similar contiguous layout is also required for the data buffers.
*/
Adapter->FirstRxBD = Adapter->BdStartArea;
Adapter->LastRxBD = Adapter->FirstRxBD + Adapter->NbrRxBuffers - 1;
Adapter->FirstTxBD = Adapter->LastRxBD + 1;
Adapter->LastTxBD = Adapter->FirstTxBD + Adapter->NbrTxBuffers - 1;
/* Construct the cyclic Rx buffer descriptor list. */
HW_Setup_BD_List(Adapter->FirstRxBD, Adapter->LastRxBD,
ETH_RX_EMPT | ETH_RX_INTR,
pFirstRxBuffer,
Adapter->MaxRxBufferSize);
/* Construct the cyclic Tx buffer descriptor list. */
HW_Setup_BD_List(Adapter->FirstTxBD, Adapter->LastTxBD,
ETH_TX_PAD | ETH_TX_INTR | ETH_TX_CRC | ETH_TX_LAST,
pFirstTxBuffer,
Adapter->MaxTxBufferSize);
/* Reset the driver receive and transmit structures. */
Adapter->ActiveRx.pBufferDescriptor = Adapter->FirstRxBD;
Adapter->ActiveRx.pBuffer = Adapter->RxStart;
Adapter->FreeTx.pBufferDescriptor = Adapter->FirstTxBD;
Adapter->FreeTx.pBuffer = Adapter->TxStart;
Adapter->ActiveTx.pBufferDescriptor = NULL;
Adapter->ActiveTx.pBuffer = NULL;
Adapter->FirstPacket = NULL;
Adapter->LastPacket = NULL;
DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
(TEXT("-ETH8XX: HW_Internal_Setup_BDs\r\n")));
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?