mini2440上dm9000驱动分析(三)

发布者:SHow111time最新更新时间:2021-10-21 来源: 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卡驱动的分析(一)

推荐阅读最新更新时间:2024-11-13 19:17

linux-2.6.32在mini2440开发板上移植 移植I2C-EEPROM 驱动
1 在内核中配置I2C 驱动 Linux-2.6.32.2 对S2C2440 的I2C 接口提供了完善的驱动,因此我们只需在内核中配置一下即可使用。 在内核源代码目录执行:make menuconfig,进入内核配置主菜单,依次选择进入如下子菜单: Device Drivers --- * I2C support --- I2C Hardware Bus support --- 如图,我们看到这里已经选择好了“ * S3C2410 I2C Driver”,这里的S3C2410 也可以适用于S3C2440,因为它们的I2C 端口及寄存器定义都是完全相同的。 以上配置所对
[单片机]
linux-2.6.32在<font color='red'>mini2440</font>开发板上移植 移植I2C-EEPROM <font color='red'>驱动</font>
Mini2440在Keil MDK下的裸机程序运行环境搭建
1)建立一个工程,选择芯片型号(S3C2440A),加入启动代码 2)打开S3C2440.S这个文件,点击configuration wizard,将里面的选项全部选中。 3)现在配置项中(alt+F7)做如下修改: 4)在output中勾选creat HEX file,在utilities中选择J-LINK/J-TRACE,点击setting做如下设置: S29GL016是我的开发板用的nor flash型号,至此,一个能用的环境就搭建好了。 不过上面的是把程序下载到NorFlash中去的,当需要上系统的时候,NorFlash里面是要放bootloader的,那个时候如果想要跑裸机程序,就得下载到SD
[单片机]
mini2440裸机试炼之--myled
/ //********************************************************** //*****************此函数为实现*************************** //**led1亮 led1灭 //** led1、led2亮 led1、led2灭 //** led1、led2、led3亮 ed1、led2、led3灭 //** led1、led2、led3、led4亮 Led1、led2、led3、led4灭 // // // #define rGPBCON (*(vol
[单片机]
<font color='red'>mini2440</font>裸机试炼之--myled
mini2440上安装u-boot
网上有很多关于如何移植u-boot到2440上的文章,我只是个新手没有接触过移植,所以在这里只是说一下如何安装在mini2440上安装u-boot的经验。希望大家多多指教。 1.买来的mini2440的nor flash中已经默认安装了supervivi,所以第一步就是通过supervivi将u-boot.bin下载到开发板。适合2440的u-boot的下载地址为http://blogold.chinaunix.net/u1/34474/showart.php?id=2217066,在这里要感谢Tekkaman为我们新手提供的方便。从nor flash启动开发板,在supervivi的界面中选择a)Absolute User
[单片机]
mini2440驱动分析之ADC
1 . ADC_DEV 结构 typedef struct { wait_queue_head_t wait; int channel; int prescale; }ADC_DEV; wait 等待队列,进程读取设备,如果没有转换数据,就会睡眠在此队列上 channel 转换通道,s3c2440有八通道的ad,但是只有四个通道AIN 可以使用,其他四个用于触摸屏 prescale 计算转换速率的时候使用 2 . 变量 OwnADC 表示是否拥有ADC信号量 ev_adc 使能ADC标志,用于等待队列的等待条件 adc_data 转换读出的数据 3 模块初始化,dev_init(
[单片机]
2016-2022车灯市场分析 LED驱动市值增长
据外媒报道,据市场研究公司Yole Développement透露,2016年车灯市场的总市值为257亿美元,预计到2022年将增至359亿美元,2016-2022的复合年增长率(CAGR)为5.7%。 Yole的分析师们预计,该增长是受到以下因素的驱动:LED成本侵蚀、LED模块标准化、性能优化驱动成本下降、车用LED应用加速。 自2007年引入首款全LED车头灯后,LED技术逐渐融入了车头灯设计中。LED技术使车辆照明设备成为一款特色产品,实现了多项创新功能,如:2013年引入的无眩光自适应高光束(glare free adaptive high beam)。 LED技术的使用仅限于高端车辆,该产品正与卤素灯及高强放电灯(H
[汽车电子]
关于mini2440触摸屏驱动设计
一.触摸屏的分类: 1、触摸屏种类、分别应用在哪里、屏和OS怎么配合使用?. 电容屏---静电感应;电阻屏---压力感应; 红外线式和感应电容式触摸屏能够支持多点触控。多点触控带来了更多的选择,抓取、拖曳、缩放、旋转。 屏要和系统搭配才能体现优势。IPHONE和android系统支持多点触控。Windows mobiles不支持多点触控。 2,触摸屏实现原理,功能实现出来(点一下触摸屏得到对应点的像素值)。总结实现原理。 触摸屏的坐标值和LCD的像素不是一比一的关系。且原点可能不是同一个角。 触摸屏校验2种方式:第一是4点式(2点式)。第二种三点式。 二.下面是SONY(320*240)的屏.
[单片机]
关于<font color='red'>mini2440</font>触摸屏<font color='red'>驱动</font>设计
三.mini2440按键控制LED
首先看原理图知道KEY的引脚: 那么我们知道了按键的引脚,根据上一篇的led的引脚,可以理清楚,按键按下会修改某寄存器的值,CPU检测到按键修改,则输出电平到LED数据寄存器,进而控制LED的亮灭。 那么来修改程序。 /*LED.c*/ #define GPBCON ((volatile unsigned int *)0x56000010)/*led控制引脚*/ #define GPBDAT ((volatile unsigned int *)0x56000014)/*led数据引脚*/ #define GPGCON ((volatile unsigned int *)0x56000060)/*key控制
[单片机]
三.<font color='red'>mini2440</font>按键控制LED
小广播
设计资源 培训 开发板 精华推荐

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

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

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

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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