📄 eepro.c
字号:
eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */ if (request_irq (*irqp, NULL, IRQF_SHARED, "bogus", dev) != EBUSY) { unsigned long irq_mask; /* Twinkle the interrupt, and check if it's seen */ irq_mask = probe_irq_on(); eepro_diag(ioaddr); /* RESET the 82595 */ mdelay(20); if (*irqp == probe_irq_off(irq_mask)) /* It's a good IRQ line */ break; /* clear all interrupts */ eepro_clear_int(ioaddr); } } while (*++irqp); eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */ /* Disable the physical interrupt line. */ eepro_dis_intline(ioaddr); eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */ /* Mask all the interrupts. */ eepro_dis_int(ioaddr); /* clear all interrupts */ eepro_clear_int(ioaddr); return dev->irq;}static int eepro_open(struct net_device *dev){ unsigned short temp_reg, old8, old9; int irqMask; int i, ioaddr = dev->base_addr; struct eepro_local *lp = netdev_priv(dev); if (net_debug > 3) printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name); irqMask = lp->word[7]; if (lp->eepro == LAN595FX_10ISA) { if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n"); } else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */ { lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */ if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n"); } else if ((dev->dev_addr[0] == SA_ADDR0 && dev->dev_addr[1] == SA_ADDR1 && dev->dev_addr[2] == SA_ADDR2)) { lp->eepro = 1; if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n"); } /* Yes, an Intel EtherExpress Pro/10 */ else lp->eepro = 0; /* No, it is a generic 82585 lan card */ /* Get the interrupt vector for the 82595 */ if (dev->irq < 2 && eepro_grab_irq(dev) == 0) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } if (request_irq(dev->irq , &eepro_interrupt, 0, dev->name, dev)) { printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } /* Initialize the 82595. */ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ temp_reg = inb(ioaddr + lp->eeprom_reg); lp->stepping = temp_reg >> 5; /* Get the stepping number of the 595 */ if (net_debug > 3) printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping); if (temp_reg & 0x10) /* Check the TurnOff Enable bit */ outb(temp_reg & 0xef, ioaddr + lp->eeprom_reg); for (i=0; i < 6; i++) outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i); temp_reg = inb(ioaddr + REG1); /* Setup Transmit Chaining */ outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */ | RCV_Discard_BadFrame, ioaddr + REG1); temp_reg = inb(ioaddr + REG2); /* Match broadcast */ outb(temp_reg | 0x14, ioaddr + REG2); temp_reg = inb(ioaddr + REG3); outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */ /* Set the receiving mode */ eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */ /* Set the interrupt vector */ temp_reg = inb(ioaddr + INT_NO_REG); if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA) outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG); else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); temp_reg = inb(ioaddr + INT_NO_REG); if (lp->eepro == LAN595FX || lp->eepro == LAN595FX_10ISA) outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG); else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); if (net_debug > 3) printk(KERN_DEBUG "eepro_open: content of INT Reg is %x\n", temp_reg); /* Initialize the RCV and XMT upper and lower limits */ outb(lp->rcv_lower_limit >> 8, ioaddr + RCV_LOWER_LIMIT_REG); outb(lp->rcv_upper_limit >> 8, ioaddr + RCV_UPPER_LIMIT_REG); outb(lp->xmt_lower_limit >> 8, ioaddr + lp->xmt_lower_limit_reg); outb(lp->xmt_upper_limit >> 8, ioaddr + lp->xmt_upper_limit_reg); /* Enable the interrupt line. */ eepro_en_intline(ioaddr); /* Switch back to Bank 0 */ eepro_sw2bank0(ioaddr); /* Let RX and TX events to interrupt */ eepro_en_int(ioaddr); /* clear all interrupts */ eepro_clear_int(ioaddr); /* Initialize RCV */ outw(lp->rcv_lower_limit, ioaddr + RCV_BAR); lp->rx_start = lp->rcv_lower_limit; outw(lp->rcv_upper_limit | 0xfe, ioaddr + RCV_STOP); /* Initialize XMT */ outw(lp->xmt_lower_limit, ioaddr + lp->xmt_bar); lp->tx_start = lp->tx_end = lp->xmt_lower_limit; lp->tx_last = 0; /* Check for the i82595TX and i82595FX */ old8 = inb(ioaddr + 8); outb(~old8, ioaddr + 8); if ((temp_reg = inb(ioaddr + 8)) == old8) { if (net_debug > 3) printk(KERN_DEBUG "i82595 detected!\n"); lp->version = LAN595; } else { lp->version = LAN595TX; outb(old8, ioaddr + 8); old9 = inb(ioaddr + 9); if (irqMask==ee_FX_INT2IRQ) { if (net_debug > 3) { printk(KERN_DEBUG "IrqMask: %#x\n",irqMask); printk(KERN_DEBUG "i82595FX detected!\n"); } lp->version = LAN595FX; outb(old9, ioaddr + 9); if (dev->if_port != TPE) { /* Hopefully, this will fix the problem of using Pentiums and pro/10 w/ BNC. */ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ temp_reg = inb(ioaddr + REG13); /* disable the full duplex mode since it is not applicable with the 10Base2 cable. */ outb(temp_reg & ~(FDX | A_N_ENABLE), REG13); eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */ } } else if (net_debug > 3) { printk(KERN_DEBUG "temp_reg: %#x ~old9: %#x\n",temp_reg,((~old9)&0xff)); printk(KERN_DEBUG "i82595TX detected!\n"); } } eepro_sel_reset(ioaddr); netif_start_queue(dev); if (net_debug > 3) printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name); /* enabling rx */ eepro_en_rx(ioaddr); return 0;}static void eepro_tx_timeout (struct net_device *dev){ struct eepro_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* if (net_debug > 1) */ printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name, "network cable problem"); /* This is not a duplicate. One message for the console, one for the log file */ printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name, "network cable problem"); eepro_complete_selreset(ioaddr);}static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev){ struct eepro_local *lp = netdev_priv(dev); unsigned long flags; int ioaddr = dev->base_addr; short length = skb->len; if (net_debug > 5) printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name); if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) return 0; length = ETH_ZLEN; } netif_stop_queue (dev); eepro_dis_int(ioaddr); spin_lock_irqsave(&lp->lock, flags); { unsigned char *buf = skb->data; if (hardware_send_packet(dev, buf, length)) /* we won't wake queue here because we're out of space */ dev->stats.tx_dropped++; else { dev->stats.tx_bytes+=skb->len; dev->trans_start = jiffies; netif_wake_queue(dev); } } dev_kfree_skb (skb); /* You might need to clean up and record Tx statistics here. */ /* dev->stats.tx_aborted_errors++; */ if (net_debug > 5) printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name); eepro_en_int(ioaddr); spin_unlock_irqrestore(&lp->lock, flags); return 0;}/* The typical workload of the driver: Handle the network interface interrupts. */static irqreturn_teepro_interrupt(int irq, void *dev_id){ struct net_device *dev = dev_id; struct eepro_local *lp; int ioaddr, status, boguscount = 20; int handled = 0; lp = netdev_priv(dev); spin_lock(&lp->lock); if (net_debug > 5) printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name); ioaddr = dev->base_addr; while (((status = inb(ioaddr + STATUS_REG)) & (RX_INT|TX_INT)) && (boguscount--)) { handled = 1; if (status & RX_INT) { if (net_debug > 4) printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name); eepro_dis_int(ioaddr); /* Get the received packets */ eepro_ack_rx(ioaddr); eepro_rx(dev); eepro_en_int(ioaddr); } if (status & TX_INT) { if (net_debug > 4) printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name); eepro_dis_int(ioaddr); /* Process the status of transmitted packets */ eepro_ack_tx(ioaddr); eepro_transmit_interrupt(dev); eepro_en_int(ioaddr); } } if (net_debug > 5) printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name); spin_unlock(&lp->lock); return IRQ_RETVAL(handled);}static int eepro_close(struct net_device *dev){ struct eepro_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; short temp_reg; netif_stop_queue(dev); eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */ /* Disable the physical interrupt line. */ temp_reg = inb(ioaddr + REG1); outb(temp_reg & 0x7f, ioaddr + REG1); eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */ /* Flush the Tx and disable Rx. */ outb(STOP_RCV_CMD, ioaddr); lp->tx_start = lp->tx_end = lp->xmt_lower_limit; lp->tx_last = 0; /* Mask all the interrupts. */ eepro_dis_int(ioaddr); /* clear all interrupts */ eepro_clear_int(ioaddr); /* Reset the 82595 */ eepro_reset(ioaddr); /* release the interrupt */ free_irq(dev->irq, dev); /* Update the statistics here. What statistics? */ return 0;}/* Set or clear the multicast filter for this adaptor. */static voidset_multicast_list(struct net_device *dev){ struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; unsigned short mode; struct dev_mc_list *dmi=dev->mc_list; if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || dev->mc_count > 63) { /* * We must make the kernel realise we had to move * into promisc mode or we start all out war on * the cable. If it was a promisc request the * flag is already set. If not we assert it. */ dev->flags|=IFF_PROMISC; eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); outb(mode | PRMSC_Mode, ioaddr + REG2); mode = inb(ioaddr + REG3); outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ } else if (dev->mc_count==0 ) { eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */ mode = inb(ioaddr + REG3); outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ } else { unsigned short status, *eaddrs; int i, boguscount = 0; /* Disable RX and TX interrupts. Necessary to avoid corruption of the HOST_ADDRESS_REG by interrupt service routines. */ eepro_dis_int(ioaddr); eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); outb(mode | Multi_IA, ioaddr + REG2); mode = inb(ioaddr + REG3); outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG); outw(MC_SETUP, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); outw(6*(dev->mc_count + 1), ioaddr + IO_PORT); for (i = 0; i < dev->mc_count; i++) { eaddrs=(unsigned short *)dmi->dmi_addr; dmi=dmi->next; outw(*eaddrs++, ioaddr + IO_PORT); outw(*eaddrs++, ioaddr + IO_PORT); outw(*eaddrs++, ioaddr + IO_PORT); } eaddrs = (unsigned short *) dev->dev_addr; outw(eaddrs[0], ioaddr + IO_PORT); outw(eaddrs[1], ioaddr + IO_PORT); outw(eaddrs[2], ioaddr + IO_PORT); outw(lp->tx_end, ioaddr + lp->xmt_bar); outb(MC_SETUP, ioaddr); /* Update the transmit queue */ i = lp->tx_end + XMT_HEADER + 6*(dev->mc_count + 1); if (lp->tx_start != lp->tx_end) { /* update the next address and the chain bit in the last packet */ outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG); outw(i, ioaddr + IO_PORT); outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG); status = inw(ioaddr + IO_PORT); outw(status | CHAIN_BIT, ioaddr + IO_PORT); lp->tx_end = i ; } else { lp->tx_start = lp->tx_end = i ; } /* Acknowledge that the MC setup is done */ do { /* We should be doing this in the eepro_interrupt()! */ SLOW_DOWN; SLOW_DOWN;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -