4106|7

854

帖子

0

TA的资源

五彩晶圆(中级)

楼主
 

wince dm9000驱动代码流程分析 [复制链接]

从dm9000.def文件中可以看到dm9000的驱动程序(dm9000.dll)exports的函数只有DriverEntry。从名字上也可以看出这是该dll文件入口。
     下面详细看下这个入口函数(在driver.cpp中实现):在这个函数中主要有一个NdisMInitializeWrapper(),这个函数的作用就是notifies NDIS that a new miniport is initializing。此函数在ndis.dll中提供,直接调用就可以。接下来就是给NDIS40_MINIPORT_CHARACTERISTICS这个结构体变量初始化,主要是设置一些回调函数(MiniportInitialize,MiniportReset,MiniportInterruptHandler,MiniportISRHandler,MiniportQueryInformation,MiniportSetInformation,MiniportSend),很明显这些函数有些要自己实现的。再下来就是NdisMRegisterMiniport()了,This function registers an NIC or intermediate driver's Miniport_* entry points and name with the NDIS library when the driver initializes。就是用刚才初始化的那个结构体注册。在public\common\oak\drivers\netsamp\passthru\miniport.c中微软提供了一系列Miniportxxxx函数的实现范例。help中对MiniportInitialize的解释是: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类的初始化,以及该类的EDriverInitialize函数调用,在此函数中全面展开了dm9000的所有初始化操作。主要是通过DeviceEntry()这个函数来实现(这个函数实现在dm9000.cpp文件中),在DeviceEntry这个函数中只做了一件事:new了一个C_DM9000类的实例并return。接下来就该C_DM9000的实例表演了(表演场地为上文提到的EDriverInitialize函数中):DeviceSetDefaultSettings();DeviceSetEepromFormat();DeviceRetriveConfigurations(hconfig);EDeviceValidateConfigurations()等等,一套非常漂亮的动作耍完之后又轮到NIC_DRIVER_OBJECT了,它只是个主持人,宣布下一个节目是DriverStart()(舞台在MiniportInitialize中),实际上表演人还是C_DM9000。其实C_DM9000的表演也很简单但是比较重要,它在此DeviceEnableInterrupt()启动了中断,接下来就是无休止的等待,接收,发送了。从此踏上了不归路.....

本文出自 “bluefish” 博客,请务必保留此出处http://bluefish.blog.51cto.com/214870/58106

点赞 关注
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460

回复
举报

854

帖子

0

TA的资源

五彩晶圆(中级)

沙发
 

一、项目硬件环境

S3C2442 + DM9000A + WINCE 5.0

其中DM9000采用EINT1,接到片选NGCS7(0X20000000)


二、驱动结构

DM9000和CS8900驱动不一样。

在EBOOT中,由于没有用到中断和协议,下载NK只是建立TFTP服务(EBOOT建立),然后通过DM9000收发数据。因此,在S3C的BSP包中,EBOOT调用的DM9000收发的函数在BSP\Src\common\Dm9000a\Dm9000a.c文件中。即,EBOOT完全与驱动分开。

驱动的结构。驱动主要包含三个文件:driver.cpp、device.cpp、dm9000.cpp。

可以把三个文件看成三层结构。最上面是driver.cpp,然后是device.cpp,最下面是dm9000.cpp。他们之间driver.cpp提供NDIS微端口函数,这些微端口函数调用device.cpp, device.cpp和dm9000.cpp通过类的继承相关联。dm9000.cpp则是完成收发的基本的驱动部分。


三、调试现象与问题描述(以时间为顺序)

最开始从EBOOT开始调试。首先遇到的问题是DM9000能读到ID号,但是通过PB下载时显示不出平台名字,通过抓包工具检测到DM9000不能发送和接受数据包,用示波器打INT脚的波形也看不到中断。后来发现是DM9000的RX没有打开,并且RX和TX的中断也没有打开。(由此可见,官方网站的BSP包不一定可靠。)

能够使用EBOOT下载NK镜像后至少证明DM9000和S3C2442能够通讯,即硬件上没有问题。(这个时候公司开始投PCB板量产)接下来的工作是DM9000驱动的调试。

直接采用官方的BSP包,修改INDEX和DATA的地址后编译。DM9000无中断产生。后来发现是中断GPIO的触发电平设置不正确。(这里的触发电平与DM9000的SSCK管脚的上下拉有关)。修改后中断能触发。系统异常,后来发现是DM9000的中断处理函数不正常。该中断处理程序由Dm9000a.c中的DeviceInterruptEventHandler函数完成相关工作。进一步跟踪发现,NSR寄存器的读操作并没有将其清零(DM9000A手册中写明读或写1至NSR会使其相应位清零),因此驱动将TXbuffer可用的消息发个上层NDIS时,NDIS检测实际上没有空间可用,于是产生异常。

另外,本平台未接EEPROM,因此,MAC地址需要自己设置。

至此,驱动调试完毕。

PS:驱动中有一个比较关键的函数完成注册驱动的功能(NdisMRegisterInterrupt)

    该函数的参数以及具体的用法参考网上资料。


四、修改的地方:

1.     OEM层的中断处理函数OEMInterruptHandler

    (该函数位于BSP\Src\common\Intr\Intr.c文件中)

在本次项目中网口中断使用EINT1,在原三星的BSP包中在OEM层未对该中断进行处理,一般来说,当中断触发后,首先执行OEMInterruptHandler,然后根据返回的系统中断号,转入相对应的IRQ程序。OEMInterruptHandler完成的工作包括:关中断,设SPEND、以及返回系统中断号(Sysintr由系统分配),分配代码如下:

        // First find if IRQ is claimed by chain

        sysIntr = NKCallIntChain((UCHAR)irq);

        if (sysIntr == SYSINTR_CHAIN || !NKIsSysIntrValid(sysIntr)) {

            // IRQ wasn't claimed, use static mapping

            sysIntr = OALIntrTranslateIrq(irq);}

(最初调试的时候因为此处未对中断进行处理,因此中断不断被触发,程序停止在这里)

2.     自己设置MAC地址

Device.cpp文件DeviceMacAddres函数中。

修改如下:

     PU8     NIC_DEVICE_OBJECT::DeviceMacAddress(

   PU8     ptrBuffer)

{

   if(!ptrBuffer) return ptrBuffer;

   PU16    pcurr=(PU16)&m_szEeprom[

       m_szEepromFormat[EID_MAC_ADDRESS]];

   //*(PU16)ptrBuffer = *pcurr++;

   //*(PU16)(ptrBuffer+2) = *pcurr++;

   //*(PU16)(ptrBuffer+4) = *pcurr++;

   *(PU16)ptrBuffer = MAC21;

   *(PU16)(ptrBuffer+2) = MAC43;

   *(PU16)(ptrBuffer+4) = MAC65;

   return ptrBuffer;

}

3.     驱动的中断处理函数

添加写1清除NSR语句

void C_DM9000::DeviceInterruptEventHandler(

  U32 uValue)

{

  // check RX activities

  if(uValue & 0x01) Dm9LookupRxBuffers();

  // return if not TX latch

  if(!(uValue & 0x02)) return;

  U32 nsr;

  nsr = DeviceReadPort(DM9_NSR);

  // check TX-END2

  if(nsr & 0x08)

  {

      m_nTxPendings--;

      DeviceSendCompleted(m_TQWaiting.Dequeue());

  }

  // check TX-END1

  if(nsr & 0x04)

  {

      m_nTxPendings--;

      DeviceSendCompleted(m_TQWaiting.Dequeue());

  }

  // report tx available now

  if( nsr & 0x0C )

      {

          NdisMSendResourcesAvailable(m_pUpper->GetNdisHandle());

      }

  DeviceWritePort(DM9_NSR,nsr);       //clear nsr by set 1

}

PS: DM9000A是一款应用相当广泛的成熟产品了,可是手册居然会犯这样的错误而网上也没有用户说明.实在是令人费解.如果读者用到该芯片,还请注意NSR.

 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 

回复

854

帖子

0

TA的资源

五彩晶圆(中级)

板凳
 
$(_COMMONSDKROOT)\lib\$(_CPUINDPATH)\ndis.lib     \
这个是关键。网卡驱动就这样子上去的。
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 
 

回复

854

帖子

0

TA的资源

五彩晶圆(中级)

4
 
/********************************************************************************************
*
* DriverEntry
*
********************************************************************************************/

extern "C" NTSTATUS DriverEntry(
        IN PDRIVER_OBJECT        pDriverObject,
        IN PUNICODE_STRING        pRegistryPath)
{
        NDIS_STATUS                status;
        NDIS_HANDLE                hwrapper;
        NDIS40_MINIPORT_CHARACTERISTICS        ndischar;


        //PUTS(("\r\n"));
          RETAILMSG(TRUE,(TEXT("\n")));

        NdisMInitializeWrapper(
                &hwrapper,
                pDriverObject,
                pRegistryPath,
                NULL);

        memset((void*)&ndischar,0,sizeof(ndischar));

    ndischar.Ndis30Chars.MajorNdisVersion = PRJ_NDIS_MAJOR_VERSION;
        ndischar.Ndis30Chars.MinorNdisVersion = PRJ_NDIS_MINOR_VERSION;

        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;


        if((status = NdisMRegisterMiniport(
                hwrapper,
                (PNDIS_MINIPORT_CHARACTERISTICS)&ndischar,
                sizeof(ndischar)) != NDIS_STATUS_SUCCESS))
        {
                NdisTerminateWrapper(hwrapper,NULL);
                return status;
        }


#ifndef        IMPL_DLL_ENTRY       
        INIT_EXCEPTION();
#endif

    return NDIS_STATUS_SUCCESS;

}
VOID        MiniportInterruptHandler(
        IN NDIS_HANDLE  MiniportContext)
{
        ((NIC_DRIVER_OBJECT*)MiniportContext)->DriverInterruptHandler();
}

void        NIC_DRIVER_OBJECT::DriverInterruptHandler(void)
{
       
       
        m_pLower->DeviceInterruptEventHandler(m_uRecentInterruptStatus);

        m_pLower->DeviceEnableInterrupt();
       
}




void C_DM9000::DeviceInterruptEventHandler(
        U32        uValue)
{
        // check RX activities
        if(uValue & 0x01) Dm9LookupRxBuffers();

        // return if not TX latch
        if(!(uValue & 0x02)) return;

        U32        nsr;

        nsr = DeviceReadPort(DM9_NSR);
       
        // check TX-END2
        if(nsr & 0x08)
        {
                m_nTxPendings--;
                DeviceSendCompleted(m_TQWaiting.Dequeue());
        }

        // check TX-END1
        if(nsr & 0x04)
        {
                m_nTxPendings--;
                DeviceSendCompleted(m_TQWaiting.Dequeue());
        }
       
        // report tx available now
        if( nsr & 0x0C )
                NdisMSendResourcesAvailable(m_pUpper->GetNdisHandle());

}
不过我还是有点不明白,这个网卡的物理中断是如何和这个网卡的中断处理函数绑定上的?

难道这个名字是约定的?
来看个究竟!
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 
 

回复

854

帖子

0

TA的资源

五彩晶圆(中级)

5
 
//------------------------------------------------
        OALIntrStaticTranslate(SYSINTR_ETH, IRQ_EINT0);        // for DM9000A
虽然申请了静态中断,但是,这个静态中断还是要绑定网卡的线程的啊。不然会根本触发不了读写网卡的线程。

点评

原帖由 Wince.Android 于 2013-11-9 14:33 发表 https://bbs.eeworld.com.cn/images/common/back.gif //------------------------------------------------ OALIntrStaticTranslate(SYSINTR_ETH, IRQ_EINT  详情 回复 发表于 2013-11-9 14:58
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 
 

回复

854

帖子

0

TA的资源

五彩晶圆(中级)

6
 
总线的设置要加上去,否则也是麻烦的。嘿嘿。
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 
 

回复

854

帖子

0

TA的资源

五彩晶圆(中级)

7
 
原帖由 Wince.Android 于 2013-11-9 14:33 发表
//------------------------------------------------
        OALIntrStaticTranslate(SYSINTR_ETH, IRQ_EINT0);        // for DM9000A
虽然申请了静态中断,但是,这个静态中断还是要绑定网卡的线程的啊。不然会根本触 ...


找到了,在这里

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, 0x88000000, NDIS_STRING_CONST("IoAddress")},
        { CID_IO_RANGE, 0x10, NDIS_STRING_CONST("IoRange")},
        { CID_IRQ_NUMBER, 0x23, NDIS_STRING_CONST("IrqNumber")},
        { -1,-1,NULL}
};

0x23=35= SYSINTR_ETH   =       (SYSINTR_FIRMWARE+19) =16+19  // for DM9000A

再看看怎么联系起来的
PCONFIG_PARAMETER        C_DM9000::DeviceConfigureParameters(void)
{
        return (PCONFIG_PARAMETER)&g_szDm9ConfigParams[0];
}



void        NIC_DEVICE_OBJECT::DeviceRetriveConfigurations(
        NDIS_HANDLE                hConfig)
{
        NDIS_STATUS        status;

        PCONFIG_PARAMETER        pconfig;
       
        PNDIS_CONFIGURATION_PARAMETER        param;

        for(pconfig=DeviceConfigureParameters();
                (pconfig->uId != (U32)-1);
                pconfig++)
        {
                NdisReadConfiguration(
                        &status,
                        ¶m,
                        hConfig,
                        &(pconfig->szName),
                        NdisParameterHexInteger);
                if(status == NDIS_STATUS_SUCCESS)
                        m_szConfigures[pconfig->uId] =
                                param->ParameterData.IntegerData;
                else
                        m_szConfigures[pconfig->uId] = pconfig->uDefValue;
        }


        // read mac addr
        {
            NDIS_STATUS         Status;  // Status of Ndis calls.
            PVOID    NetAddress;
            UINT     Length;

            NdisReadNetworkAddress(&Status,&NetAddress,&Length,hConfig);
            if ((Length        == ETH_ADDRESS_LENGTH) &&        (Status        == NDIS_STATUS_SUCCESS))
            {
                        // Save        the address that should        be used.
                        NdisMoveMemory(        &m_szEeprom[        m_szEepromFormat[EID_MAC_ADDRESS]],NetAddress,ETH_ADDRESS_LENGTH);
                   }
        }
//--------------------------------------------------------
}


 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 
 

回复

854

帖子

0

TA的资源

五彩晶圆(中级)

8
 
有源码看就是好,一下子就找到问题点了。今晚回去整一下
Sate210+DM9000 +iNand 我相信必然会跑的嘎嘎叫了。
 
个人签名如果对linux,Android,wince 等嵌入式底层有兴趣的,请加这个QQ群吧,群号:27100460
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表