网卡驱动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真是个傻瓜化的网卡,现在的芯片集成性越来越强,驱动越来越模块,将来,真不知道内核驱动还有什么可做……