📄 rtl8139.c
字号:
tp->stats.rx_errors++; if (rx_status & (RxBadSymbol|RxBadAlign)) tp->stats.rx_frame_errors++; if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++; if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++; /* Reset the receiver, based on RealTek recommendation. (Bug?) */ tp->cur_rx = 0; outb(CmdTxEnb, ioaddr + ChipCmd); /* A.C.: Reset the multicast list. */ set_rx_mode(dev); outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); } else { /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ struct sk_buff *skb; int pkt_size = rx_size - 4; skb = dev_alloc_skb(pkt_size + 2); if (skb == NULL) { printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n", dev->name); /* We should check that some rx space is free. If not, free one and mark stats->rx_dropped++. */ tp->stats.rx_dropped++; break; } skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP fields. */ if (ring_offset + rx_size > tp->rx_buf_len) { int semi_count = tp->rx_buf_len - ring_offset - 4; /* This could presumably use two calls to copy_and_sum()? */ memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4], semi_count); memcpy(skb_put(skb, pkt_size-semi_count), rx_ring, pkt_size-semi_count); if (debug > 4) { int i; printk(KERN_DEBUG"%s: Frame wrap @%d", dev->name, semi_count); for (i = 0; i < 16; i++) printk(" %2.2x", rx_ring[i]); printk(".\n"); memset(rx_ring, 0xcc, 16); } } else { eth_copy_and_sum(skb, &rx_ring[ring_offset + 4], pkt_size, 0); skb_put(skb, pkt_size); } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb);#if LINUX_VERSION_CODE > 0x20119 tp->stats.rx_bytes += pkt_size;#endif tp->stats.rx_packets++; } cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; outw(cur_rx - 16, ioaddr + RxBufPtr); } if (debug > 4) printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, inw(ioaddr + RxBufAddr), inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd)); tp->cur_rx = cur_rx; return 0;}static intrtl8129_close(struct net_device *dev){ long ioaddr = dev->base_addr; struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; int i; netif_stop_tx_queue(dev); if (debug > 1) printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, inw(ioaddr + IntrStatus)); /* Disable interrupts by clearing the interrupt mask. */ outw(0x0000, ioaddr + IntrMask); /* Stop the chip's Tx and Rx DMA processes. */ outb(0x00, ioaddr + ChipCmd); /* Update the error counts. */ tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); outl(0, ioaddr + RxMissed); del_timer(&tp->timer); free_irq(dev->irq, dev); for (i = 0; i < NUM_TX_DESC; i++) { if (tp->tx_skbuff[i]) dev_free_skb(tp->tx_skbuff[i]); tp->tx_skbuff[i] = 0; } kfree(tp->rx_ring); tp->rx_ring = 0; /* Green! Put the chip in low-power mode. */ outb(0xC0, ioaddr + Cfg9346); outb(0x03, ioaddr + Config1); outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */ MOD_DEC_USE_COUNT; return 0;}static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct rtl8129_private *np = (struct rtl8129_private *)dev->priv; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { case SIOCGMIIPHY: /* Get the address of the PHY in use. */ data[0] = np->phys[0] & 0x3f; /* Fall Through */ case SIOCGMIIREG: /* Read the specified MII register. */ data[3] = mdio_read(dev, data[0], data[1] & 0x1f); return 0; case SIOCSMIIREG: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; if (data[0] == np->phys[0]) { u16 value = data[2]; switch (data[1]) { case 0: /* Check for autonegotiation on or reset. */ np->medialock = (value & 0x9000) ? 0 : 1; if (np->medialock) np->full_duplex = (value & 0x0100) ? 1 : 0; break; case 4: np->advertising = value; break; } } mdio_write(dev, data[0], data[1] & 0x1f, data[2]); return 0; default: return -EOPNOTSUPP; }}static struct net_device_stats *rtl8129_get_stats(struct net_device *dev){ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; if (netif_running(dev)) { tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); outl(0, ioaddr + RxMissed); } return &tp->stats;}/* Set or clear the multicast filter for this adaptor. This routine is not state sensitive and need not be SMP locked. */static unsigned const ethernet_polynomial = 0x04c11db7U;static inline u32 ether_crc(int length, unsigned char *data){ int crc = -1; while (--length >= 0) { unsigned char current_octet = *data++; int bit; for (bit = 0; bit < 8; bit++, current_octet >>= 1) crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); } return crc;}/* Bits in RxConfig. */enum rx_mode_bits { AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08, AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,};static void set_rx_mode(struct net_device *dev){ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; if (debug > 3) printk(KERN_DEBUG"%s: set_rx_mode(%4.4x) done -- Rx config %8.8x.\n", dev->name, dev->flags, inl(ioaddr + RxConfig)); /* Note: do not reorder, GCC is clever about common statements. */ if (dev->flags & IFF_PROMISC) { /* Unconditionally log net taps. */ printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name); rx_mode = AcceptBroadcast|AcceptMulticast|AcceptMyPhys|AcceptAllPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; } else if ((dev->mc_count > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; } else { struct dev_mc_list *mclist; rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0; for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); } /* We can safely update without stopping the chip. */ outl(tp->rx_config | rx_mode, ioaddr + RxConfig); outl(mc_filter[0], ioaddr + MAR0 + 0); outl(mc_filter[1], ioaddr + MAR0 + 4); return;}static int rtl_pwr_event(void *dev_instance, int event){ struct net_device *dev = dev_instance; struct rtl8129_private *np = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; if (debug > 1) printk("%s: Handling power event %d.\n", dev->name, event); switch(event) { case DRV_ATTACH: MOD_INC_USE_COUNT; break; case DRV_SUSPEND: netif_device_detach(dev); /* Disable interrupts, stop Tx and Rx. */ outw(0x0000, ioaddr + IntrMask); outb(0x00, ioaddr + ChipCmd); /* Update the error counts. */ np->stats.rx_missed_errors += inl(ioaddr + RxMissed); outl(0, ioaddr + RxMissed); break; case DRV_RESUME: netif_device_attach(dev); rtl_hw_start(dev); break; case DRV_DETACH: { struct net_device **devp, **next; if (dev->flags & IFF_UP) { dev_close(dev); dev->flags &= ~(IFF_UP|IFF_RUNNING); } unregister_netdev(dev); release_region(dev->base_addr, pci_tbl[np->chip_id].io_size);#ifndef USE_IO_OPS iounmap((char *)dev->base_addr);#endif for (devp = &root_rtl8129_dev; *devp; devp = next) { next = &((struct rtl8129_private *)(*devp)->priv)->next_module; if (*devp == dev) { *devp = *next; break; } } if (np->priv_addr) kfree(np->priv_addr); kfree(dev); MOD_DEC_USE_COUNT; break; } } return 0;}#ifdef CARDBUS#include <pcmcia/driver_ops.h>static dev_node_t *rtl8139_attach(dev_locator_t *loc){ struct net_device *dev; u16 dev_id; u32 pciaddr; u8 bus, devfn, irq; long hostaddr; /* Note: the chip index should match the 8139B pci_tbl[] entry. */ int chip_idx = 2; if (loc->bus != LOC_PCI) return NULL; bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; printk(KERN_DEBUG "rtl8139_attach(bus %d, function %d)\n", bus, devfn);#ifdef USE_IO_OPS pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &pciaddr); hostaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK;#else pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &pciaddr); hostaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK, pci_tbl[chip_idx].io_size);#endif pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq); pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id); if (hostaddr == 0 || irq == 0) { printk(KERN_ERR "The %s interface at %d/%d was not assigned an %s.\n" KERN_ERR " It will not be activated.\n", pci_tbl[chip_idx].name, bus, devfn, hostaddr == 0 ? "address" : "IRQ"); return NULL; } dev = rtl8139_probe1(pci_find_slot(bus, devfn), NULL, hostaddr, irq, chip_idx, 0); if (dev) { dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); strcpy(node->dev_name, dev->name); node->major = node->minor = 0; node->next = NULL; MOD_INC_USE_COUNT; return node; } return NULL;}static void rtl8139_detach(dev_node_t *node){ struct net_device **devp, **next; printk(KERN_INFO "rtl8139_detach(%s)\n", node->dev_name); for (devp = &root_rtl8129_dev; *devp; devp = next) { next = &((struct rtl8129_private *)(*devp)->priv)->next_module; if (strcmp((*devp)->name, node->dev_name) == 0) break; } if (*devp) { struct rtl8129_private *np = (struct rtl8129_private *)(*devp)->priv; unregister_netdev(*devp); release_region((*devp)->base_addr, pci_tbl[np->chip_id].io_size);#ifndef USE_IO_OPS iounmap((char *)(*devp)->base_addr);#endif kfree(*devp); if (np->priv_addr) kfree(np->priv_addr); *devp = *next; kfree(node); MOD_DEC_USE_COUNT; }}struct driver_operations realtek_ops = { "realtek_cb", rtl8139_attach, /*rtl8139_suspend*/0, /*rtl8139_resume*/0, rtl8139_detach};#endif /* Cardbus support */int rtl8139_init_module(void){ if (debug) /* Emit version even if no cards detected. */ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);#ifdef CARDBUS register_driver(&realtek_ops); return 0;#else return pci_drv_register(&rtl8139_drv_id, NULL);#endif}void rtl8139_cleanup_module(void){ struct net_device *next_dev;#ifdef CARDBUS unregister_driver(&realtek_ops);#else pci_drv_unregister(&rtl8139_drv_id);#endif while (root_rtl8129_dev) { struct rtl8129_private *np = (void *)(root_rtl8129_dev->priv); unregister_netdev(root_rtl8129_dev); release_region(root_rtl8129_dev->base_addr, pci_tbl[np->chip_id].io_size);#ifndef USE_IO_OPS iounmap((char *)(root_rtl8129_dev->base_addr));#endif next_dev = np->next_module; if (np->priv_addr) kfree(np->priv_addr); kfree(root_rtl8129_dev); root_rtl8129_dev = next_dev; }}module_init(rtl8139_init_module);module_exit(rtl8139_cleanup_module);/* * Local variables: * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c rtl8139.c" * cardbus-compile-command: "gcc -DCARDBUS -DMODULE -Wall -Wstrict-prototypes -O6 -c rtl8139.c -o realtek_cb.o -I/usr/src/pcmcia/include/" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -