历史上的今天
返回首页

历史上的今天

今天是:2024年11月10日(星期日)

正在发生

2021年11月10日 | mini2440 dm9000 网卡驱动详解 (三)

2021-11-10 来源:eefocus

*dm9000_get_drvinfo()


该函数去的设备的基本信息(设备名,版本,总线名)传给ethtool_drvinfo结构体变量。代码清单如下:


static void dm9000_get_drvinfo(struct net_device *dev,      

                   struct ethtool_drvinfo *info)      

{      

    board_info_t *dm = to_dm9000_board(dev); /*to_dm9000_board实际上就是调用了netdev_priv(dev)*/     

     

    strcpy(info->driver, CARDNAME);      

    strcpy(info->version, DRV_VERSION);      

    strcpy(info->bus_info, to_platform_device(dm->dev)->name);      

}    


   *dm9000_get_settings()


    该函数得到由参数cmd指定的设置信息。


   *dm9000_set_settings()


    该函数设置由参数cmd指定的信息。


   *dm9000_get_msglevel()


   *dm9000_set_msglevel()


这两个函数设置和取得messagelevel,实际是设置和取得board_info中的msg_enable信息。


   *dm9000_nway_reset()


    重启mii的自动协商


   *dm9000_get_link()


    该函数的到link状态。如果带外部PHY,则返回mii链接状态。 否则返回DM9000 NSR寄存器数值。


   *dm9000_get_eeprom_len()


     dm9000_get_eeprom()


     dm9000_set_eeprom()


这三个函数用来读写eeprom。


5. 与数据传输有关的函数。


上面已经分析了一个与数据传输有关的函数,那就是发送数据的函数dm9000_start_xmit()。这里再来分析数据的接收。再看具体代码之前还是来看看DM9000的数据接收的过程。


接收的数据存储在RX SRAM中,地址是0C00h~3FFFh。存储在RX_SRAM中的每个包都有4个字节的信息头。可以使用MRCMDX和MRCMD寄存器来得到这些信息。第一个字节用来检查数据包是否接收到了RX_SRAM中,如果这个字节是"01",意味着一个包已经接收。如果是"00",则还没有数据包被接收到RX_SRAM中。第二个字节保存接收到的数据包的信息,格式和RSR寄存器一样。根据这个格式,接收到的包能被校验是正确的还是错误的包。第三和第四字节保存了接收的数据包的长度。这四个字节以外的其他字节就是接收包的数据。看下图可以更好的理解这种格式。

根据包的结构可以知道接收一个包应该按照下面的步骤来进行:


第一步:判断包是否已经接收过来了。需要用到MRCMDX寄存器。MRCMDX寄存器是存储数据读命令寄存器(地址不增加)。这个寄存器只是用来读接收包标志位"01"。下面这段代码是一个例子,用来判断RX ready:


u8 RX_ready = ior( IOaddr, 0xF0 );         /* dummy read the packet ready flag */     

RX_ready = (u8) inp( IOaddr + 4 );         /* got the most updated data */     

if ( RX_ready == 1 ) {                     /* ready check: this byte must be 0 or 1 */     

       /* check the RX status and to get RX length (see datasheet ch.5.6.3) */     

       /* income RX a packet (see datasheet ch.5.6.4) */     

} else if ( RX_ready != 0 ) {              /* stop device and wait to reset device */     

       iow( IOaddr, 0xFF, 0x80 );          /* stop INT request */     

       iow( IOaddr, 0xFE, 0x0F );          /* clear ISR status */     

       iow( IOaddr, 0x05, 0x00 );          /* stop RX function */     

       u8 device_wait_reset = TRUE;        /* raise the reset flag */     

}    


第二步:检查包的状态和长度。需要用到MRCMD寄存器(存储数据读命令,读指针自动增加)。下面这段例子代码用来读RX状态和长度。


u8 io_mode = ior( IOaddr, 0xFE ) >> 6; /* ISR bit[7:6] keep I/O mode */     

outp( IOaddr, 0xF2 );                /* trigger MRCMD reg_F2h with read_ptr++ */     

/* int RX_status : the RX packet status, int RX_length : the RX packet length */     

if ( io_mode == 2 ) {                /* I/O byte mode */     

RX_status = inp( IOaddr + 4 ) + ( inp( IOaddr + 4 ) << 8 );      

RX_length = inp( IOaddr + 4 ) + ( inp( IOaddr + 4 ) << 8 );        }      

else if ( io_mode == 0 ) {           /* I/O word mode */     

RX_status = inpw( IOaddr + 4 );      

RX_length = inpw( IOaddr + 4 );             }      

else if ( io_mode == 1 ) {           /* I/O dword mode */     

(u32) status_tmp = inpl( IOaddr + 4 );           /* got the RX 32-bit dword data */     

RX_status = (u16)( status_tmp & 0xFFFF );      

RX_length = (u16)( ( status_tmp >> 16 ) & 0xFFFF );          }    


第三步:读包的数据。也需要MRCMD寄存器。例子代码如下:


/* u8 RX_data[] : the data of the received packet */     

if ( io_mode == 2 ) {                 /* I/O byte mode */     

for ( i = 0 ; i < RX_length ; i++ ) /* loop to read a byte data from RX SRAM */     

  RX_data[ i ] = (u8) inp( IOaddr + 4 );          }      

else if ( io_mode == 0 ) {            /* I/O word mode */     

int length_tmp = ( RX_length + 1 ) / 2;      

for ( i = 0 ; i < length_tmp ; i++ ) /* loop to read a word data from RX SRAM */     

 ( (u16 *)RX_data)[ i ] = inpw( IOaddr + 4 );           }      

else if ( io_mode == 1 ) {            /* I/O dword mode */     

int length_tmp = ( RX_length + 3 ) / 4;      

for ( i = 0 ; i < length_tmp ; i++ ) /* loop to read a dword data from RX SRAM */     

 ( (u32 *)RX_data)[ i ] = inpl( IOaddr + 4 ); }         /* inpl() is inport 32-bit I/O */    


下面的dm9000_rx()函数实际上是按照上面这三个步骤来实现的,具体实现并不一定是要参照例子代码。注意这里按照DM9000接收包的格式定义了一个结构体dm9000_rxhdr用来表示头部的四个字节。代码清单如下:


struct dm9000_rxhdr {      

    u8  RxPktReady;      

    u8  RxStatus;      

    __le16  RxLen;      

} __attribute__((__packed__));    


接收函数代码如下:


/*    

 *  Received a packet and pass to upper layer    

 */     

static void     

dm9000_rx(struct net_device *dev)      

{      

    board_info_t *db = netdev_priv(dev);      

    struct dm9000_rxhdr rxhdr;      

    struct sk_buff *skb;      

    u8 rxbyte, *rdptr;      

    bool GoodPacket;      

    int RxLen;      

     

    /* Check packet ready or not */     

    do {      

        ior(db, DM9000_MRCMDX); /* Dummy read */     

     

        /* Get most updated data */     

                /*读一下最新数据的第一个字节*/     

        rxbyte = readb(db->io_data);      

     

        /* Status check: this byte must be 0 or 1 */     

                /*DM9000_PKT_RDY定义是0x01,如果第一个字节大于0x01,则不是正确的状态。因为第一个字节只能是01h或00h*/     

        if (rxbyte > DM9000_PKT_RDY) {      

            dev_warn(db->dev, "status check fail: %dn", rxbyte);      

            iow(db, DM9000_RCR, 0x00);  /* Stop Device */     

            iow(db, DM9000_ISR, IMR_PAR);   /* Stop INT request */     

            return;      

        }      

     

        if (rxbyte != DM9000_PKT_RDY)      

            return;      

     

        /* A packet ready now  & Get status/length */     

        GoodPacket = true;      

        writeb(DM9000_MRCMD, db->io_addr);      

     

        (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));/*一次性读入四个字节的内容到rxhdr变量*/     

     

        RxLen = le16_to_cpu(rxhdr.RxLen);      

     

        if (netif_msg_rx_status(db))      

            dev_dbg(db->dev, "RX: status %02x, length %04xn",      

                rxhdr.RxStatus, RxLen);      

     

        /* Packet Status check */     

        if (RxLen < 0x40) {      

            GoodPacket = false;      

            if (netif_msg_rx_err(db))      

                dev_dbg(db->dev, "RX: Bad Packet (runt)n");      

        }      

     

        if (RxLen > DM9000_PKT_MAX) {      

            dev_dbg(db->dev, "RST: RX Len:%xn", RxLen);      

        }      

     

推荐阅读

史海拾趣

Force Technologies Ltd公司的发展小趣事

背景:在电子行业竞争日益激烈的背景下,Force Technologies Ltd意识到通过并购整合可以迅速扩大规模、提升竞争力。

发展:公司精心挑选了几家在特定领域具有优势的企业作为并购目标,并成功完成了多起并购案。这些并购不仅为公司带来了先进的技术和人才资源,还极大地丰富了产品线和市场布局。通过并购整合,Force Technologies Ltd在多个细分领域均占据了领先地位。

Frolyt Condensers & Elements GmbH公司的发展小趣事

随着业务规模的扩大,Frolyt Condensers & Elements GmbH意识到全球化布局的重要性。2010年,公司制定了全球化战略,首先在亚洲设立了生产基地,以利用当地丰富的资源和低廉的劳动力成本。随后几年间,Frolyt还通过一系列并购活动,收购了多家在特定市场具有影响力的电容器制造商,进一步巩固了其在全球市场的地位。这些并购不仅扩大了Frolyt的产品线,还增强了其技术研发能力和市场服务能力。

益升华(Essentra)公司的发展小趣事

在电子产品的保护领域,益升华(Essentra)公司一直走在行业前列。多年前,公司研发团队发现市场上缺乏一种既轻便又耐用的塑料保护盖。于是,他们投入大量资源进行研发,经过数百次的试验和改进,最终成功开发出一种新型的塑料保护盖,它不仅具备优异的抗冲击性和耐磨损性,还能有效隔绝外界环境中的静电和尘埃。这一创新产品迅速获得市场的认可,为益升华(Essentra)公司带来了可观的收益。

ANOVA公司的发展小趣事

ANOVA公司的全球扩张步伐迅速而稳健。在成功创立之后不久,ANOVA便通过收购ISA,进一步增强了其在全球市场的竞争力。这次收购不仅使ANOVA在全球超过70个国家拥有了监控超过70万台设备的能力,更在北美、南美、欧洲和亚太等关键地区设立了办公室,为公司的全球化战略打下了坚实的基础。ANOVA始终坚持本地化服务,无论客户身处何地,都能享受到最高级别的服务和支持。

Cal Crystal Lab Inc / Comclok Inc公司的发展小趣事

随着电子行业的快速发展,技术创新和合作成为了企业发展的重要驱动力。Cal Crystal Lab Inc深知这一点,积极寻求与其他企业的技术合作。通过与国内外知名高校和研究机构的深入合作,公司不断引进新技术、新工艺,提升了产品的技术含量和附加值。同时,Cal Crystal Lab Inc还与其他企业建立了战略合作关系,共同开发新产品、拓展新市场,实现了共赢发展。

Barry Industries Inc公司的发展小趣事

随着电子行业的快速发展,Barry Industries Inc意识到只有不断创新才能在市场中立足。公司加大了对研发的投入,引进了一批高素质的研发人才,并建立了完善的研发体系。经过多年的努力,Barry成功突破了微波半导体封装技术的多项关键技术,推出了多款性能卓越、具有创新性的产品。这些产品不仅广泛应用于军事、航天、通信等领域,还为公司赢得了市场的广泛认可。

问答坊 | AI 解惑

Windows CE驱动程序开发.pdf

Windows CE驱动程序开发.pdf…

查看全部问答>

S3C2410管脚复用超级基础问题

新手提问,请勿取笑,呵呵。 S3C2410在管脚复用的时候有这样一段代码: //set GPG1 as EINT9 for CS8900A value = INREG32(&pOalPortRegs->GPGCON); OUTREG32(&pOalPortRegs->GPGCON,(value & ~(3…

查看全部问答>

有个产品使用了一段时间后无法启动了,帮分析分析

产品最初正常工作,内核和应用程序都好的。过了一段时间后启动异常。 步骤是开机Bootloader启动,启动时加载了LOGO界面填充了液晶的显示缓冲区,后来就停在这里了。 我可以按照原来的方式烧内核,更换了画面也可以显示。 重烧了BOOTLOADER后也没 ...…

查看全部问答>

在应用程序里如何查询某个USB连在哪一个USB controller上

在具有多个USB controller和多个USB设备的情况下, 如何查询这些USB设备连接在哪个USB controller上。 设备管理器中,如果选择“依连接排序设备”,就可以看到所 有设备的Device Tree,VC里有什么API或者什么方法可以获得 类似的信息吗? 请高 ...…

查看全部问答>

昨天收到开发板,今天做了第一块STM32的板子

看看有没有问题,第一次玩STM32,没有什么经验,硬件是按照st-link制作的,做了一些修改(st-link本来也是一块开发板)。准备自己做JTAG下载工具或者调试工具,呵呵,如果搞的定的话。PCB还没铺地,其他都OK了。发现一个错误,应该BOOT1接地,BO ...…

查看全部问答>

μC/OS-II实时性能测试指标

μC/OS-II实时性能测试指标   衡量嵌入式实时操作系统的好坏一般主要参考以下主要性能指标参数: 任务切换时间、中断响应时间、任务响应时间、任务创建/删除时间、交替信号量时间、取得/释放信号量时间、交替消息队列传输时间等。本文仅对前2个 ...…

查看全部问答>

51单片机实践群179146897

欢迎51单片机初学者加入…

查看全部问答>

lpc2366电源电压过高

最近调试LPC2366发现,该芯片再电源电压为3.5V时,可以下载程序但是不能正常工作;…

查看全部问答>

ispLEVER 软件问题,菜鸟求救

我写的一个程序,是Abel编写的,编译没用任何错误,怎么没用生成熔丝图文件啊。我用的是GAL16V8D…

查看全部问答>