基于S3C2440A的DM9000A的调试笔记

基于S3C2440ADM9000A的调试笔记

刘启明 2010-5-3

FL2440的开发板提供了DM9000A的驱动源码,在开发板上测试通过,能正常上网。将驱动移到公司的机器上,由于公司的硬件电路和FL2440上连接有一些差别,所以移起来并不是那么一帆风顺。

对比飞凌开发板和公司产品的硬件电路,区别如下:

一:飞凌开发板的DM9000A,中断脚即34脚连到了2440GPF7,而公司产品连到了GPF3.

二:FL2440DM9000A选择脚CS脚,即37脚连到了2440NGCS4,而公司产品连到了NGCS1.

三:FL2440DM9000ACMD脚,即第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了?如果这里设置错误,读取到的DM9000AID号会读成地址值,即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;

}

注意,如果DM9000AEECK脚悬空或是下拉,那么中断脚一定要设置为高电平触发中断,如果EECK脚上拉,那么中断脚一定要设置为低电平触发!

再打开E:/WINCE500/PLATFORM/SMDK2440A/Src/Common/Intrintr.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;          

}

查看S3C2440EINTMASK寄存器,发现EINT0EINT3是保留的,不知三星出于什么目的。如果三星规格书没有错,使用GPF3做中断脚时,EINTMASK应该可以不设置,即这个函数可以不作修改。

最后一步,在整个BSP包中搜索关于GPF3GPA12(nGCS1)的设置情况,如果发现有错误设置的,一定要屏掉,否则无法正常上网!在FL2440的包中,流水灯使用了GPF3OALinit.c中误设置了GPF3,更正过来后,编译common下的intr文件夹,编译kernelmake。到此为止,DM9000A驱动移植告一段落。

 

你可能感兴趣的:(基于S3C2440A的DM9000A的调试笔记)