刘启明 2010-5-3
FL2440的开发板提供了DM9000A的驱动源码,在开发板上测试通过,能正常上网。将驱动移到公司的机器上,由于公司的硬件电路和FL2440上连接有一些差别,所以移起来并不是那么一帆风顺。
对比飞凌开发板和公司产品的硬件电路,区别如下:
一:飞凌开发板的DM9000A,中断脚即34脚连到了2440的GPF7,而公司产品连到了GPF3.
二:FL2440的DM9000A选择脚CS脚,即37脚连到了2440的NGCS4,而公司产品连到了NGCS1.
三:FL2440的DM9000A的CMD脚,即第32脚连到了2440地址总线的ADDR2,而公司产品却连到了ADDR11.
四:网口,FL2440用的HR911105A,而公司产品为了省钱,这么昂贵的东西舍不得啊,不过对编程这个没有影响。
这里我们只关心前面三点,第一点,中断脚。在整个DM9000A的源码中,找不到中断脚的任何配置,首先这个就难住了一片人。我们仔细分析,发现在Dm9isa.cpp的开头处,有这么一个结构数组:
CONFIG_PARAMETER g_szDm9ConfigParams[] =
{
{ CID_CONNECTION_TYPE, -1, NDIS_STRING_CONST("ConnectionType") },
{ CID_SLOT_NUMBER, -1, NDIS_STRING_CONST("SlotNumber")},
{ CID_BUFFER_PHYSICAL_ADDRESS, 0, NDIS_STRING_CONST("BufferPhysicalAddress")},
{ CID_TXBUFFER_NUMBER, 0x20, NDIS_STRING_CONST("XmitBuffer")},
{ CID_RXBUFFER_NUMBER, 0x10, NDIS_STRING_CONST("RecvBuffer")},
{ CID_ADAPTER_NUMBER, 0, NDIS_STRING_CONST("AdapterNumber")},
{ CID_IO_BASE_ADDRESS, 0x08300000/*0x08000300*/, NDIS_STRING_CONST("IoAddress")},// 这样应该就改成nGCS1了吧!!!
//{ CID_IO_BASE_ADDRESS, 0x20300000, NDIS_STRING_CONST("IoAddress")},
{ CID_IO_RANGE, 0x10, NDIS_STRING_CONST("IoRange")},
//{ CID_IRQ_NUMBER, 0X23, NDIS_STRING_CONST("IrqNumber")},
{ CID_IRQ_NUMBER, 0x3, NDIS_STRING_CONST("IrqNumber")},// 这里是物理中断号.K390硬件接GPF3.lqm:10-04-30
{ -1,-1,NULL}
};
这里CID_IRQ_NUMBER表示DM9000A所连接的物理中断号,FL2440默认为0x23,转化为十进制为35,在s3c2440a_intr.h里面,不然发现,原来35表示IRQ_EINT7,其定义如下:
#define IRQ_EINT7 35
这就是定义DM9000A的中断所在!由于公司产品使用的是GPF3,同样看s3c2440a_intr.h里面的定义,发现IRQ_EINT3=3,于是我们顺理成章的将0x23改成了0x3。
上面数组中还有一个数字很重要,0x20300000。打开三星的内存映射表,具体如下:
可以看到,上面的地址在bank4的范围内,而bank4是通过nGCS4选择的!这一点与FL2440的硬件连接不谋而合,这也正是为什么飞凌DM9000A驱动使用这个地址的原因所在!由于公司产品使用的nGCS1,于是我将地址改成了0x80000300。
也许你认为两处差异,一下子就在这里解决了,其实事情远没有这么简单!难道中断,就只用在一个数组里面定义就OK了吗?仔细看驱动源代码,不然发现程序是通过读取注册表的键值来决定中断,IP地址等的。打开注册表,platform.reg,相关代码如下:
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:23
"IrqNumber"=dword:3 ;lqm changed for K390.
"MACAddress" =hex:00,0A,EB,FD,7A,00
[HKEY_LOCAL_MACHINE/Comm/DM9CE1/Parms/TcpIp]
"EnableDHCP"=dword:0
"UseZeroBroadcast"=dword:0
"DefaultGateway"="192.168.1.1"
"IpAddress"="192.168.1.227"
"Subnetmask"="255.255.255.0"
"DNS"="202.96.134.133"
ENDIF BSP_DM9000 !
将上面的IrqNumber值改成0x3,将IP地址,子网掩码,DNS等全照你电脑上的设置(通过ipconfig /all命令查看)。
再看第三点,CMD。该管脚为高电平时,表示访问数据端口,为低电平时,表示访问INDEX端口。在Dm9isa.h的最前面,有如下定义:
#define DM9000_ADDR_OFFSET 0x00//(SMSC_ETHERNET_BASE_U_VIRTUAL+0x300)
//#define DM9000_DATA_OFFSET 0x04
#define DM9000_DATA_OFFSET 0x800 //lqm changed for K390
飞凌的板CMD接到了ADDR2上,拿起指甲数数,是不是0x04?再看公司接的是ADDR11上,再数下,是不是0x800了?如果这里设置错误,读取到的DM9000A的ID号会读成地址值,即0x28292a2b。
理论上,到此,程序已经改完了。但是还有一点我们绝对不能忽视,那就是中断的实现机制。在E:/WINCE500/PLATFORM/SMDK2440A/Src/Kernel/Oal中目录下,打开intr.c文件,将默认的GPF7中断全改为GPF3,包括EXTINT0寄存器。具体更改后的代码如下:
BOOL BSPIntrInit()
{
S3C2440A_IOPORT_REG *pOalPortRegs;
ULONG value;
OALMSG(OAL_INTR&&OAL_FUNC, (L"+BSPIntrInit/r/n"));
// Then get virtual address for IO port
pOalPortRegs = OALPAtoVA(S3C2440A_BASE_REG_PA_IOPORT, FALSE);
// Set GPF7 as EINT7
value = INREG32(&pOalPortRegs->GPFCON);
//OUTREG32(&pOalPortRegs->GPFCON, (value & ~(3 << 14))|(2 << 14));
OUTREG32(&pOalPortRegs->GPFCON, (value & ~(3 << 6))|(2 << 6));// lqm changed to GPF3 for K390.
// Disable pullup
value = INREG32(&pOalPortRegs->GPFUP);
//OUTREG32(&pOalPortRegs->GPFUP, value | (1 << 7));
OUTREG32(&pOalPortRegs->GPFUP, value | (1 << 3));// lqm changed to GPF3 for K390.
// High level interrupt
value = INREG32(&pOalPortRegs->EXTINT0);
//OUTREG32(&pOalPortRegs->EXTINT0, (value & ~(0xf << 28))|(0x1 << 28));
OUTREG32(&pOalPortRegs->EXTINT0, (value & ~(0xf << 12))|(0x1 << 12));// lqm changed to GPF3 for K390.
// Set GPG1 as EINT9
value = INREG32(&pOalPortRegs->GPGCON);
OUTREG32(&pOalPortRegs->GPGCON, (value & ~(3 << 2))|(2 << 2));
// Disable pullup
value = INREG32(&pOalPortRegs->GPGUP);
OUTREG32(&pOalPortRegs->GPGUP, value | (1 << 1));
// High level interrupt
value = INREG32(&pOalPortRegs->EXTINT1);
OUTREG32(&pOalPortRegs->EXTINT1, (value & ~(0xf << 4))|(0x4 << 4));
// Add static mapping for Built-In OHCI
OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBH);
// OALIntrStaticTranslate(SYSINTR_USBFN, IRQ_USBFN);
OALMSG(OAL_INTR&&OAL_FUNC, (L"-BSPIntrInit(rc = 1)/r/n"));
return TRUE;
}
注意,如果DM9000A的EECK脚悬空或是下拉,那么中断脚一定要设置为高电平触发中断,如果EECK脚上拉,那么中断脚一定要设置为低电平触发!
再打开E:/WINCE500/PLATFORM/SMDK2440A/Src/Common/Intr的intr.c文件,仔细查看里面的每一个函数的实现,如果没有对GPF3设置,需要修改!这里我对OALIntrEnableIrqs函数做了如下修改:
BOOL OALIntrEnableIrqs(UINT32 count, const UINT32 *pIrqs)
{
BOOL rc = TRUE;
UINT32 i, mask, irq;
OALMSG(OAL_INTR&&OAL_FUNC, (L"+OALIntrEnableIrqs(%d, 0x%08x)/r/n", count, pIrqs));
for (i = 0; i < count; i++) {
#ifndef OAL_BSP_CALLBACKS
irq = pIrqs[i];
#else
// Give BSP chance to enable irq on subordinate interrupt controller
irq = BSPIntrEnableIrq(pIrqs[i]);
#endif
if (irq == OAL_INTR_IRQ_UNDEFINED)
continue;
// Depending on IRQ number use internal or external mask register
if(irq <= IRQ_EINT3)// lqm added for K390 DM9000.10-05-03
{
// Use external mask register
CLRREG32(&g_pIntrRegs->INTMSK, 1 << irq);
CLRREG32(&g_pPortRegs->EINTMASK, 1 << irq);// EINTMASK[3:0] is reserved!!!lqm...................
}
// lqm changed for K390.10-05-03
//if (irq <= IRQ_ADC)
else if (irq <= IRQ_ADC)
{
// Use interrupt mask register
CLRREG32(&g_pIntrRegs->INTMSK, 1 << irq);
}
else if (irq <= IRQ_EINT7)
{
// Use external mask register
CLRREG32(&g_pIntrRegs->INTMSK, 1 << IRQ_EINT4_7);
CLRREG32(&g_pPortRegs->EINTMASK, 1 << (irq - IRQ_EINT4 + 4));
}
else if (irq <= IRQ_EINT23)
{
// Use external mask register
mask = 1 << (irq - IRQ_EINT4 + 4);
OUTREG32(&g_pPortRegs->EINTPEND, mask);
CLRREG32(&g_pPortRegs->EINTMASK, mask);
mask = 1 << IRQ_EINT8_23;
if ((INREG32(&g_pIntrRegs->INTPND) & mask) != 0) {
OUTREG32(&g_pIntrRegs->INTPND, mask);
}
CLRREG32( &g_pIntrRegs->INTMSK, 1 << IRQ_EINT8_23);
}
else
{
rc = FALSE;
}
}
OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALIntrEnableIrqs(rc = %d)/r/n", rc));
return rc;
}
查看S3C2440的EINTMASK寄存器,发现EINT0到EINT3是保留的,不知三星出于什么目的。如果三星规格书没有错,使用GPF3做中断脚时,EINTMASK应该可以不设置,即这个函数可以不作修改。
最后一步,在整个BSP包中搜索关于GPF3,GPA12(即nGCS1)的设置情况,如果发现有错误设置的,一定要屏掉,否则无法正常上网!在FL2440的包中,流水灯使用了GPF3,OAL的init.c中误设置了GPF3,更正过来后,编译common下的intr文件夹,编译kernel,make。到此为止,DM9000A驱动移植告一段落。