网卡驱动DM9000(2)

从中断函数入手:
static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
{
    struct net_device *dev = dev_id;
    board_info_t *db = netdev_priv(dev);
    int int_status;
    unsigned long flags;
    u8 reg_save;

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

    spin_lock_irqsave(&db->lock, flags);	//加锁同时禁止本地中断

    /*有中断,控制网卡做必要的处理,取出中断信息*/
    /* Save previous register address */
    reg_save = readb(db->io_addr);
    /* Disable all interrupts */
    iow(db, DM9000_IMR, IMR_PAR);
    /* Got DM9000 interrupt status */
    int_status = ior(db, DM9000_ISR);   /* Got ISR */
    iow(db, DM9000_ISR, int_status);    /* Clear ISR status */

    if (netif_msg_intr(db))	//((p)->msg_enable & NETIF_MSG_INTR)
        dev_dbg(db->dev, "interrupt status %02x\n", int_status);

    /*判断网卡此次中断类型*/
    if (int_status & ISR_PRS)
        dm9000_rx(dev);		//==>接收
    if (int_status & ISR_PTS)
        dm9000_tx_done(dev, db);//==>发送

    if (db->type != TYPE_DM9000E) {
        if (int_status & ISR_LNKCHNG) {
            /* fire a link-change request */
            schedule_delayed_work(&db->phy_poll, 1);
        }
    }

    /* Re-enable interrupt mask */
    iow(db, DM9000_IMR, db->imr_all);

    /* Restore previous register address */
    writeb(reg_save, db->io_addr);

    spin_unlock_irqrestore(&db->lock, flags);

    return IRQ_HANDLED;
}

    

  判断中断的类型(接收触发,发送触发),对数据包进行处理。先看接收数据包:dm9000_rx

struct dm9000_rxhdr {    //以太网MAC帧头信息
u8 RxPktReady;
u8 RxStatus;
__le16 RxLen;
} __packed;
//占32位



/* Received a packet and pass to upper layer */
staticvoid 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: %d\n", 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));//读到32位的数据包头信息

RxLen
= le16_to_cpu(rxhdr.RxLen);

if (netif_msg_rx_status(db))
dev_dbg(db
->dev, "RX: status %02x, length %04x\n",
rxhdr.RxStatus, RxLen);

/* Packet Status check */
if (RxLen <0x40) { //包长不能小于64字节,mac帧格式要求
GoodPacket =false;
if (netif_msg_rx_err(db))
dev_dbg(db
->dev, "RX: Bad Packet (runt)\n");
}

if (RxLen > DM9000_PKT_MAX) { //mac帧第三字段:长度/类型,大于1536表示类型
dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);
}

/* 包校验相关*/
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 error\n");
dev
->stats.rx_fifo_errors++;
}
if (rxhdr.RxStatus & RSR_CE) {
if (netif_msg_rx_err(db))
dev_dbg(db
->dev, "crc error\n");
dev
->stats.rx_crc_errors++;
}
if (rxhdr.RxStatus & RSR_RF) {
if (netif_msg_rx_err(db))
dev_dbg(db
->dev, "length error\n");
dev
->stats.rx_length_errors++;
}
}

/* 包没问题了就可以正式处理了 */
if (GoodPacket && ((skb = dev_alloc_skb(RxLen +4)) != NULL)) {
skb_reserve(skb,
2); //data,tail向后移2
rdptr = (u8 *) skb_put(skb, RxLen -4);
/*skb_put:刷新缓冲区内的数据末尾指针,返回新创建数据区指针*/

(db
->inblk)(db->io_data, rdptr, RxLen); //接收包头后的数据部分

/*
例:16位接收模式

db->inblk = dm9000_inblk_16bit;

static void dm9000_inblk_16bit(void __iomem *reg, void *data, int count)
{
readsw(reg, data, (count+1) >> 1); //汇编实现
}

*/
/*数据已到位*/
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_checksum_none_assert(skb);
}
netif_rx(skb);
//通知上层有新的skb收到nn
dev->stats.rx_packets++;//数据包个数增加

}
else {
/* need to dump the packet's data */

(db
->dumpblk)(db->io_data, RxLen);
}
}
while (rxbyte & DM9000_PKT_RDY);
}

 

分为两部分,dev_alloc_skb之前,要保证数据包是个“好包”;之后则是LDD中提及的模板。

驱动这东西,宋宝华的《设备驱动开发详解》中驱动模板编写de思想基本上影响了一批人,但终归是受LDD的影响,上面驱代码中dev_alloc_skb之后的部分,基本就是ldd的小小扩充。

网络驱动编写基本也就是这么个模板:

dev_alloc_skb 分配 sk_buf
skb_put 找到sk_buf中的data指针
inblk 给sk_buf填数据包

然后便是相应长度,包的个数的统计变量增加。再通知上层,“包来啦!”就这么个过程……

  

发送: dm9000_tx_done
staticvoid 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 %02x\n", 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);
}
}

发送相对容易,dm9000_send_packet,本质上就是将数据一点点的发给dm9000的dataio,over...

 

看来,dm9000真是个傻瓜化的网卡,现在的芯片集成性越来越强,驱动越来越模块,将来,真不知道内核驱动还有什么可做……

posted @ 2011-07-22 16:18  郝壹贰叁  阅读(404)  评论(0编辑  收藏  举报