下面在重点分析几个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裸机编程-----IIC—读写AT24C08
下一篇:s3c2440上MMC/SD卡驱动的分析(一)
推荐阅读
史海拾趣
在2005年的一个阳光明媚的春天,思博科技(Cybermax)公司在硅谷正式成立。创始人李明,一位经验丰富的电子工程师,看准了当时电子市场蓬勃发展的机遇,决定创办自己的公司。起初,公司只有几名员工,主要致力于研发和生产高性能的电子元器件。通过不懈的努力和优质的产品,思博科技逐渐在市场上崭露头角。
在快速发展的过程中,思博科技始终关注企业文化建设和社会责任。公司倡导“创新、协作、诚信、共赢”的价值观,为员工提供了良好的工作环境和发展机会。同时,思博科技还积极参与社会公益活动,回馈社会。这些举措不仅提升了公司的品牌形象和声誉,还增强了员工的归属感和凝聚力。
进入21世纪,随着电子医疗的兴起,DATEL Inc.看到了新的发展机遇。公司开始研发适用于医疗领域的数据采集产品,如医用传感器、生命体征监测仪等。通过与医疗机构紧密合作,DATEL Inc.成功推出了一系列高性能、高可靠性的医疗数据采集产品,为医疗行业的数字化转型做出了重要贡献。
为了保持市场竞争力,杰力不断投入研发资源,致力于技术创新和产品升级。公司成功研发出多款高性能、低功耗的功率组件和集成电路产品,并获得了多项专利。这些产品不仅满足了客户对高品质电子元件的需求,还推动了整个电子行业的发展。同时,杰力还密切关注市场动态和技术趋势,不断调整产品策略,以适应市场的变化。
日前,笔者在松下中心东京(Panasonic Center Tokyo)亲身体验了干电池的制作。说是亲身体验,其实是参加了松下主办的干电池制作实践班,在旁边观看了孩子们制作电池的过程。虽为手工制作,但据说使用的部件与工厂实际使用的相同。此次制作的是锰干 ...… 查看全部问答∨ |
|
1)我自己写了一个GPIO驱动,和一个应用,烧到板后,用应用打开驱动时,打开失败,不知道为什么,请教大家怎么样能调试驱动,那些打印信息DEBUGMSG()在串口怎么让他显示呢? 2)在自己定制的NK.B0烧到板上,启动的时候,DN ...… 查看全部问答∨ |
以下是AVR学习板的调试程序,供大家收到学习板后进行测试 测试所用晶振为11.0592MHz。大家进行调试前,一定要确认自己板子上所接晶振的频率是否为11.0592MHz 1、流水灯 功能;短接跳线LED,8个流水灯一齐闪烁 ...… 查看全部问答∨ |
各位好: 我是新加入这个大家庭的一名成员,我是一名即将毕业的大四学生,现在正在做毕业设计,我的专业是电子信息工程。我的课题跟单片机有关,要用C语言编写程序,可是我这方面相当薄弱,希望大家能帮帮我。在此 ...… 查看全部问答∨ |