历史上的今天

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

正在发生

2021年10月21日 | mini2440上dm9000驱动分析(三)

发布者:SHow111time 来源: eefocus关键字:mini2440  dm9000  驱动分析 手机看文章 扫描二维码
随时随地手机看文章

下面在重点分析几个dm9000收发包以及中断函数。


/*

 *  Hardware start transmission.

 *  Send a packet to media from the upper layer.

 */

static int

dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)

{

unsigned long flags;

board_info_t *db = netdev_priv(dev);

 

dm9000_dbg(db, 3, "%s:n", __func__);

 

if (db->tx_pkt_cnt > 1)

return NETDEV_TX_BUSY;

 

spin_lock_irqsave(&db->lock, flags);

 

/* Move data to DM9000 TX RAM */

writeb(DM9000_MWCMD, db->io_addr);

 

(db->outblk)(db->io_data, skb->data, skb->len);

dev->stats.tx_bytes += skb->len;

 

db->tx_pkt_cnt++;

/* TX control: First packet immediately send, second packet queue */

if (db->tx_pkt_cnt == 1) {

dm9000_send_packet(dev, skb->ip_summed, skb->len);

} else {

/* Second packet */

db->queue_pkt_len = skb->len;

db->queue_ip_summed = skb->ip_summed;

netif_stop_queue(dev);

}

 

spin_unlock_irqrestore(&db->lock, flags);

 

/* free this SKB */

dev_kfree_skb(skb);

 

return NETDEV_TX_OK;

}


首先将数据包内容用writeb写入网卡的发送buffer。如果tx_pkt_cnt =1,那么调用dm9000_send_packet直接发送。如果tx_pkt_cnt = 2,那么就要通过netif_stop_queue通知上层停止发送。然后等待第一个包发送完毕,在中断函数中发送第二包。


static void dm9000_send_packet(struct net_device *dev,

       int ip_summed,

       u16 pkt_len)

{

board_info_t *dm = to_dm9000_board(dev);

 

/* The DM9000 is not smart enough to leave fragmented packets alone. */

if (dm->ip_summed != ip_summed) {

if (ip_summed == CHECKSUM_NONE)

iow(dm, DM9000_TCCR, 0);

else

iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);

dm->ip_summed = ip_summed;

}

 

/* Set TX length to DM9000 */

iow(dm, DM9000_TXPLL, pkt_len);

iow(dm, DM9000_TXPLH, pkt_len >> 8);

 

/* Issue TX polling command */

iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */

}


上面的代码主要是 CPU向dm9000传递了发送这个命令。通过看数据手册,我们知道,发送时是先向dm9000写入包的长度,然后操作TCR寄存器,dm9000就开始发包。


下面是dm9000发送完毕后,被中断函数调用的一个发送完毕后的处理函数


/*

 * DM9000 interrupt handler

 * receive the packet to upper layer, free the transmitted packet

 */

 

static void dm9000_tx_done(struct net_device *dev, board_info_t *db)

{

 int tx_status = ior(db, DM9000_NSR); /* Got TX status */

 

 if (tx_status & (NSR_TX2END | NSR_TX1END)) {

  /* One packet sent complete */

  db->tx_pkt_cnt--;

  dev->stats.tx_packets++;

 

  if (netif_msg_tx_done(db))

   dev_dbg(db->dev, "tx done, NSR %02xn", tx_status);

 

  /* Queue packet check & send */

  if (db->tx_pkt_cnt > 0)

   dm9000_send_packet(dev, db->queue_ip_summed,

        db->queue_pkt_len);

  netif_wake_queue(dev);

 }

}

 

这里我们可以看到如果db->tx_pkt_cnt > 0,那么dm9000就会继续发送网卡里面的另一个包。


下面是收包函数,这个rx函数是在interrupt函数中调用的,它不属于struct net_device_ops dm9000_netdev_ops中的成员。


/*

 *  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 */

if (rxbyte & DM9000_PKT_ERR) {

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));

 

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);

}

 

/* rxhdr.RxStatus is identical to RSR register. */

if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |

      RSR_PLE | RSR_RWTO |

      RSR_LCS | RSR_RF)) {

GoodPacket = false;

if (rxhdr.RxStatus & RSR_FOE) {

if (netif_msg_rx_err(db))

dev_dbg(db->dev, "fifo errorn");

dev->stats.rx_fifo_errors++;

}

if (rxhdr.RxStatus & RSR_CE) {

if (netif_msg_rx_err(db))

dev_dbg(db->dev, "crc errorn");

dev->stats.rx_crc_errors++;

}

if (rxhdr.RxStatus & RSR_RF) {

if (netif_msg_rx_err(db))

dev_dbg(db->dev, "length errorn");

dev->stats.rx_length_errors++;

}

}

 

/* Move data from DM9000 */

if (GoodPacket

    && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {

skb_reserve(skb, 2);

rdptr = (u8 *) skb_put(skb, RxLen - 4);

 

/* Read received packet from RX SRAM */

 

(db->inblk)(db->io_data, rdptr, RxLen);

dev->stats.rx_bytes += RxLen;

 

/* Pass to upper layer */

skb->protocol = eth_type_trans(skb, dev);

if (db->rx_csum) {

if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)

skb->ip_summed = CHECKSUM_UNNECESSARY;

else

skb->ip_summed = CHECKSUM_NONE;

}

netif_rx(skb);

dev->stats.rx_packets++;

 

} else {

/* need to dump the packet's data */

 

(db->dumpblk)(db->io_data, RxLen);

}

} while (rxbyte & DM9000_PKT_RDY);

}


收报时,数据包是分批从dm9000中读入的,先读入第一个byte,rxdata 看是否接收出错,然后在读入rxhdr,判断头部是否合格。这些都满足后,再读入完整的数据包。否则就调用dumpblk函数,让dm9000把错误的包丢弃。通过函数netif_rx 通知上层,对收到的包进行处理。在tx_done函数中,并不会直接通知上层发送完毕,只是调用了wakeup_queue函数,使上层可以继续发包。


网卡的学习和分析就到这里,


最后,网卡的carrier相关的部分,还有phy相关的部分,是我不明白的。。。希望以后有机会可以懂。

关键字:mini2440  dm9000  驱动分析 引用地址:mini2440上dm9000驱动分析(三)

上一篇:mini2440裸机编程-----IIC—读写AT24C08
下一篇:s3c2440上MMC/SD卡驱动的分析(一)

推荐阅读

Nordic Semiconductor演示nRF91系列SiP器件与蜂窝IoT的无缝网络连接,以配合挪威移动网络提供商Telenor在北欧最大的智慧城市展会中启动全国范围LTE-M / NB-IoT基础设施 挪威奥斯陆 – 2018年10月19日 – Nordic Semiconductor宣布已成功在Telenor Norway的公共蜂窝网络上演示nRF91®系列多模LTE-M / NB-IoT系统级封装(SiP)模块的LTE Cat M1...
无线通信技术凭借泛在、经济、灵活等综合优势,成为电力物联接入网的重要支撑。建设电力无线专网对解决“最后一公里”通信问题,推动我国电力企业成为世界一流企业、拓展新兴业务具有重要意义。我国电力企业可选择在230MHz、1.8GHz频段建设电力无线专网,随着5G技术的成熟,融合5G技术,构筑面向5G的电力无线专网并实现与5G公网融合,支撑安全可靠的电力...
电路保护、电源控制和感应技术的全球制造商Littelfuse, Inc. (NASDAQ: LFUS)宣布推出新的50 A单向瞬态抑制二极管阵列系列(SPA®二极管)。与市场上现有的解决方案相比, SP1250-01ETG 50单向瞬态抑制二极管阵列可凭借较低的钳位电压和低泄漏电流提供出色的保护,同时节省印刷电路板空间。 SP1250-01ETG瞬态抑制二极管阵列 SP1250-01ETG的典型市场和...
根据中国电子学会发布的《中国机器人产业发展报告(2021年)》显示,人机协作不断走向深入,协作型机器人成为工业机器人重要创新方向,安全的人机协作成为必然趋势。从专利角度看,根据智慧芽最新数据显示,全球在“协作机器人“领域,共有6400余件专利申请,其中发明专利5600余件。目前中国、日本、美国、德国四国在该领域的专利申请总量处于全球前列,分...

史海拾趣

问答坊 | AI 解惑

好资料“时钟参数shew和jitter介绍”!

这个资料不错,看看很有帮助的!…

查看全部问答∨

PCF8563在电子时钟设计中的应用

本帖最后由 paulhyde 于 2014-9-15 09:06 编辑 PCF8563在电子时钟设计中的应用  …

查看全部问答∨

原来,干电池就是这样制成的!

日前,笔者在松下中心东京(Panasonic Center Tokyo)亲身体验了干电池的制作。说是亲身体验,其实是参加了松下主办的干电池制作实践班,在旁边观看了孩子们制作电池的过程。虽为手工制作,但据说使用的部件与工厂实际使用的相同。此次制作的是锰干 ...…

查看全部问答∨

按键切换的动作,全部用串口进行通信???

“所有按键需要通过串口自发自收来调校各种功能” 本人太菜了,遇到了这个问题,虚心请教一下怎么样可以实现这种功能。 假如有4个以上的按键…

查看全部问答∨

是不是有个flable工具或框架

能用于wince上,做pushmail 一朋友说他听到过,问我,我也不知道,来问问大家 单词可能拼写错误.thanks!…

查看全部问答∨

_tmain 的参数问题

在wince6.0下,我传给_tmain函数的argv[1]的是一个字符串,怎么用%s打印出来只是此字符串的首字符? 有人遇到过这个问题吗?…

查看全部问答∨

请问如何调试CE驱动

1)我自己写了一个GPIO驱动,和一个应用,烧到板后,用应用打开驱动时,打开失败,不知道为什么,请教大家怎么样能调试驱动,那些打印信息DEBUGMSG()在串口怎么让他显示呢? 2)在自己定制的NK.B0烧到板上,启动的时候,DN ...…

查看全部问答∨

【芯币兑换】AVR学习板及USB编程器调试程序

以下是AVR学习板的调试程序,供大家收到学习板后进行测试   测试所用晶振为11.0592MHz。大家进行调试前,一定要确认自己板子上所接晶振的频率是否为11.0592MHz   1、流水灯 功能;短接跳线LED,8个流水灯一齐闪烁     ...…

查看全部问答∨

TM1722驱动段码式液晶显示屏的程序怎么写呀?

各位好:       我是新加入这个大家庭的一名成员,我是一名即将毕业的大四学生,现在正在做毕业设计,我的专业是电子信息工程。我的课题跟单片机有关,要用C语言编写程序,可是我这方面相当薄弱,希望大家能帮帮我。在此 ...…

查看全部问答∨

震荡电路咨询

做了下这个震荡电路,但是不起振,什么原因?急需帮忙 [ 本帖最后由 ssawee 于 2011-11-24 21:31 编辑 ]…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved