dm9000驱动中一共包含两个中断
//这个中断函数主要做的事情是读dm9000寄存器NSR,WCR,根据读到的内容
//作出相应提示
static irqreturn_t dm9000_wol_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
board_info_t *db = netdev_priv(dev);
unsigned long flags;
unsigned nsr, wcr;
//关中断,获得自旋锁
spin_lock_irqsave(&db->lock, flags);
nsr = ior(db, DM9000_NSR);
wcr = ior(db, DM9000_WCR);
dev_dbg(db->dev, "%s: NSR=0x%02x, WCR=0x%02x\n", __func__, nsr, wcr);
if (nsr & NSR_WAKEST) {
/* clear, so we can avoid */
iow(db, DM9000_NSR, NSR_WAKEST);
if (wcr & WCR_LINKST)
dev_info(db->dev, "wake by link status change\n");
if (wcr & WCR_SAMPLEST)
dev_info(db->dev, "wake by sample packet\n");
if (wcr & WCR_MAGICST )
dev_info(db->dev, "wake by magic packet\n");
if (!(wcr & (WCR_LINKST | WCR_SAMPLEST | WCR_MAGICST)))
dev_err(db->dev, "wake signalled with no reason? "
"NSR=0x%02x, WSR=0x%02x\n", nsr, wcr);
}
//释放自旋锁,恢复本地中断
spin_unlock_irqrestore(&db->lock, flags);
return (nsr & NSR_WAKEST) ? IRQ_HANDLED : IRQ_NONE;
}
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__);
/* A real interrupt coming */
/* holders of db->lock must always block IRQs */
//获取自旋锁,关中断
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);
//通过读DM9000中断寄存器,判断是哪种类型中断,并作出相应处理
/* 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))
dev_dbg(db->dev, "interrupt status %02x\n", int_status);
/* Received the coming packet */
//如果是接收中断,读取接收的数据并存入skbuff,并提交协议上一层
if (int_status & ISR_PRS)
dm9000_rx(dev);
/* Trnasmit Interrupt check */
//发送中断,如果还有包未发完,继续发送。
if (int_status & ISR_PTS)
dm9000_tx_done(dev, db);
//如果是DM9000E系列的芯片,作特别处理。
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;
}