static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len) { struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int ret = 0; down(&lp->cmd_mutex); /* * My Turn */ lp->cmd_nonblocking=0; lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; memcpy((void *)lp->exec_box->data, data, len); barrier(); /* the memcpy forgot the volatile so be sure */ mc32_ready_poll(dev); outb(1<<6, ioaddr+HOST_CMD); wait_for_completion(&lp->execution_cmd); if(lp->exec_box->mbox&(1<<13)) ret = -1; up(&lp->cmd_mutex); /* * A multicast set got blocked - try it now */ if(lp->mc_reload_wait) { mc32_reset_multicast_list(dev); } return ret; }
static irqreturn_t mc32_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct mc32_local *lp; int ioaddr, status, boguscount = 0; int rx_event = 0; int tx_event = 0; ioaddr = dev->base_addr; lp = netdev_priv(dev); /* See whats cooking */ while((inb(ioaddr+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000) { status=inb(ioaddr+HOST_CMD); #ifdef DEBUG_IRQ printk("Status TX%d RX%d EX%d OV%d BC%d\n", (status&7), (status>>3)&7, (status>>6)&1, (status>>7)&1, boguscount); #endif switch(status&7) { case 0: break; case 6: /* TX fail */ case 2: /* TX ok */ tx_event = 1; break; case 3: /* Halt */ case 4: /* Abort */ complete(&lp->xceiver_cmd); break; default: printk("%s: strange tx ack %d\n", dev->name, status&7); } status>>=3; switch(status&7) { case 0: break; case 2: /* RX */ rx_event=1; break; case 3: /* Halt */ case 4: /* Abort */ complete(&lp->xceiver_cmd); break; case 6: /* Out of RX buffers stat */ /* Must restart rx */ dev->stats.rx_dropped++; mc32_rx_ring(dev); mc32_start_transceiver(dev); break; default: printk("%s: strange rx ack %d\n", dev->name, status&7); } status>>=3; if(status&1) { /* * No thread is waiting: we need to tidy * up ourself. */ if (lp->cmd_nonblocking) { up(&lp->cmd_mutex); if (lp->mc_reload_wait) mc32_reset_multicast_list(dev); } else complete(&lp->execution_cmd); } if(status&2) { /* * We get interrupted once per * counter that is about to overflow. */ mc32_update_stats(dev); } } /* * Process the transmit and receive rings */ if(tx_event) mc32_tx_ring(dev); if(rx_event) mc32_rx_ring(dev); return IRQ_HANDLED; }