📄 pci-skeleton.c
字号:
static int read_eeprom (void *ioaddr, int location, int addr_len);static int netdrv_open (struct net_device *dev);static int mdio_read (struct net_device *dev, int phy_id, int location);static void mdio_write (struct net_device *dev, int phy_id, int location, int val);static void netdrv_timer (unsigned long data);static void netdrv_tx_timeout (struct net_device *dev);static void netdrv_init_ring (struct net_device *dev);static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev);static irqreturn_t netdrv_interrupt (int irq, void *dev_instance, struct pt_regs *regs);static int netdrv_close (struct net_device *dev);static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);static struct net_device_stats *netdrv_get_stats (struct net_device *dev);static void netdrv_set_rx_mode (struct net_device *dev);static void netdrv_hw_start (struct net_device *dev);#ifdef USE_IO_OPS#define NETDRV_R8(reg) inb (((unsigned long)ioaddr) + (reg))#define NETDRV_R16(reg) inw (((unsigned long)ioaddr) + (reg))#define NETDRV_R32(reg) ((unsigned long) inl (((unsigned long)ioaddr) + (reg)))#define NETDRV_W8(reg, val8) outb ((val8), ((unsigned long)ioaddr) + (reg))#define NETDRV_W16(reg, val16) outw ((val16), ((unsigned long)ioaddr) + (reg))#define NETDRV_W32(reg, val32) outl ((val32), ((unsigned long)ioaddr) + (reg))#define NETDRV_W8_F NETDRV_W8#define NETDRV_W16_F NETDRV_W16#define NETDRV_W32_F NETDRV_W32#undef readb#undef readw#undef readl#undef writeb#undef writew#undef writel#define readb(addr) inb((unsigned long)(addr))#define readw(addr) inw((unsigned long)(addr))#define readl(addr) inl((unsigned long)(addr))#define writeb(val,addr) outb((val),(unsigned long)(addr))#define writew(val,addr) outw((val),(unsigned long)(addr))#define writel(val,addr) outl((val),(unsigned long)(addr))#else/* write MMIO register, with flush *//* Flush avoids rtl8139 bug w/ posted MMIO writes */#define NETDRV_W8_F(reg, val8) do { writeb ((val8), ioaddr + (reg)); readb (ioaddr + (reg)); } while (0)#define NETDRV_W16_F(reg, val16) do { writew ((val16), ioaddr + (reg)); readw (ioaddr + (reg)); } while (0)#define NETDRV_W32_F(reg, val32) do { writel ((val32), ioaddr + (reg)); readl (ioaddr + (reg)); } while (0)#if MMIO_FLUSH_AUDIT_COMPLETE/* write MMIO register */#define NETDRV_W8(reg, val8) writeb ((val8), ioaddr + (reg))#define NETDRV_W16(reg, val16) writew ((val16), ioaddr + (reg))#define NETDRV_W32(reg, val32) writel ((val32), ioaddr + (reg))#else/* write MMIO register, then flush */#define NETDRV_W8 NETDRV_W8_F#define NETDRV_W16 NETDRV_W16_F#define NETDRV_W32 NETDRV_W32_F#endif /* MMIO_FLUSH_AUDIT_COMPLETE *//* read MMIO register */#define NETDRV_R8(reg) readb (ioaddr + (reg))#define NETDRV_R16(reg) readw (ioaddr + (reg))#define NETDRV_R32(reg) ((unsigned long) readl (ioaddr + (reg)))#endif /* USE_IO_OPS */static const u16 netdrv_intr_mask = PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;static const unsigned int netdrv_rx_config = RxCfgEarlyRxNone | RxCfgRcv32K | RxNoWrap | (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);static int __devinit netdrv_init_board (struct pci_dev *pdev, struct net_device **dev_out, void **ioaddr_out){ void *ioaddr = NULL; struct net_device *dev; struct netdrv_private *tp; int rc, i; u32 pio_start, pio_end, pio_flags, pio_len; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; u32 tmp; DPRINTK ("ENTER\n"); assert (pdev != NULL); assert (ioaddr_out != NULL); *ioaddr_out = NULL; *dev_out = NULL; /* dev zeroed in alloc_etherdev */ dev = alloc_etherdev (sizeof (*tp)); if (dev == NULL) { printk (KERN_ERR PFX "unable to alloc new ethernet\n"); DPRINTK ("EXIT, returning -ENOMEM\n"); return -ENOMEM; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); tp = dev->priv; /* enable device (incl. PCI PM wakeup), and bus-mastering */ rc = pci_enable_device (pdev); if (rc) goto err_out; pio_start = pci_resource_start (pdev, 0); pio_end = pci_resource_end (pdev, 0); pio_flags = pci_resource_flags (pdev, 0); pio_len = pci_resource_len (pdev, 0); mmio_start = pci_resource_start (pdev, 1); mmio_end = pci_resource_end (pdev, 1); mmio_flags = pci_resource_flags (pdev, 1); mmio_len = pci_resource_len (pdev, 1); /* set this immediately, we need to know before * we talk to the chip directly */ DPRINTK("PIO region size == 0x%02X\n", pio_len); DPRINTK("MMIO region size == 0x%02lX\n", mmio_len); /* make sure PCI base addr 0 is PIO */ if (!(pio_flags & IORESOURCE_IO)) { printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n"); rc = -ENODEV; goto err_out; } /* make sure PCI base addr 1 is MMIO */ if (!(mmio_flags & IORESOURCE_MEM)) { printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); rc = -ENODEV; goto err_out; } /* check for weird/broken PCI region reporting */ if ((pio_len < NETDRV_MIN_IO_SIZE) || (mmio_len < NETDRV_MIN_IO_SIZE)) { printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); rc = -ENODEV; goto err_out; } rc = pci_request_regions (pdev, "pci-skeleton"); if (rc) goto err_out; pci_set_master (pdev);#ifdef USE_IO_OPS ioaddr = (void *) pio_start;#else /* ioremap MMIO region */ ioaddr = ioremap (mmio_start, mmio_len); if (ioaddr == NULL) { printk (KERN_ERR PFX "cannot remap MMIO, aborting\n"); rc = -EIO; goto err_out_free_res; }#endif /* USE_IO_OPS */ /* Soft reset the chip. */ NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear) | CmdReset); /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) if ((NETDRV_R8 (ChipCmd) & CmdReset) == 0) break; else udelay (10); /* Bring the chip out of low-power mode. */ /* <insert device-specific code here> */#ifndef USE_IO_OPS /* sanity checks -- ensure PIO and MMIO registers agree */ assert (inb (pio_start+Config0) == readb (ioaddr+Config0)); assert (inb (pio_start+Config1) == readb (ioaddr+Config1)); assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig)); assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig));#endif /* !USE_IO_OPS */ /* identify chip attached to board */ tmp = NETDRV_R8 (ChipVersion); for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--) if (tmp == rtl_chip_info[i].version) { tp->chipset = i; goto match; } /* if unknown chip, assume array element #0, original RTL-8139 in this case */ printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8139\n", pci_name(pdev)); printk (KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", pci_name(pdev), NETDRV_R32 (TxConfig)); tp->chipset = 0;match: DPRINTK ("chipset id (%d) == index %d, '%s'\n", tmp, tp->chipset, rtl_chip_info[tp->chipset].name); i = register_netdev (dev); if (i) goto err_out_unmap; DPRINTK ("EXIT, returning 0\n"); *ioaddr_out = ioaddr; *dev_out = dev; return 0;err_out_unmap:#ifndef USE_IO_OPS iounmap(ioaddr);err_out_free_res:#endif pci_release_regions (pdev);err_out: free_netdev (dev); DPRINTK ("EXIT, returning %d\n", rc); return rc;}static int __devinit netdrv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent){ struct net_device *dev = NULL; struct netdrv_private *tp; int i, addr_len, option; void *ioaddr = NULL; static int board_idx = -1;/* when built into the kernel, we only print version if device is found */#ifndef MODULE static int printed_version; if (!printed_version++) printk(version);#endif DPRINTK ("ENTER\n"); assert (pdev != NULL); assert (ent != NULL); board_idx++; i = netdrv_init_board (pdev, &dev, &ioaddr); if (i < 0) { DPRINTK ("EXIT, returning %d\n", i); return i; } tp = dev->priv; assert (ioaddr != NULL); assert (dev != NULL); assert (tp != NULL); addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) ((u16 *) (dev->dev_addr))[i] = le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len)); /* The Rtl8139-specific entries in the device structure. */ dev->open = netdrv_open; dev->hard_start_xmit = netdrv_start_xmit; dev->stop = netdrv_close; dev->get_stats = netdrv_get_stats; dev->set_multicast_list = netdrv_set_rx_mode; dev->do_ioctl = netdrv_ioctl; dev->tx_timeout = netdrv_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; /* dev->priv/tp zeroed and aligned in alloc_etherdev */ tp = dev->priv; /* note: tp->chipset set in netdrv_init_board */ tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | NETDRV_CAPS; tp->pci_dev = pdev; tp->board = ent->driver_data; tp->mmio_addr = ioaddr; spin_lock_init(&tp->lock); pci_set_drvdata(pdev, dev); tp->phys[0] = 32; printk (KERN_INFO "%s: %s at 0x%lx, " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " "IRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], dev->irq); printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", dev->name, rtl_chip_info[tp->chipset].name); /* Put the chip into low-power mode. */ NETDRV_W8_F (Cfg9346, Cfg9346_Unlock); /* The lower four bits are the media type. */ option = (board_idx > 7) ? 0 : media[board_idx]; if (option > 0) { tp->full_duplex = (option & 0x200) ? 1 : 0; tp->default_port = option & 15; if (tp->default_port) tp->medialock = 1; } if (tp->full_duplex) { printk (KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); mdio_write (dev, tp->phys[0], MII_ADVERTISE, ADVERTISE_FULL); tp->duplex_lock = 1; } DPRINTK ("EXIT - returning 0\n"); return 0;}static void __devexit netdrv_remove_one (struct pci_dev *pdev){ struct net_device *dev = pci_get_drvdata (pdev); struct netdrv_private *np; DPRINTK ("ENTER\n"); assert (dev != NULL); np = dev->priv; assert (np != NULL); unregister_netdev (dev);#ifndef USE_IO_OPS iounmap (np->mmio_addr);#endif /* !USE_IO_OPS */ pci_release_regions (pdev); free_netdev (dev); pci_set_drvdata (pdev, NULL); pci_disable_device (pdev); DPRINTK ("EXIT\n");}/* Serial EEPROM section. *//* EEPROM_Ctrl bits. */#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */#define EE_CS 0x08 /* EEPROM chip select. */#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */#define EE_WRITE_0 0x00#define EE_WRITE_1 0x02#define EE_DATA_READ 0x01 /* EEPROM chip data out. */#define EE_ENB (0x80 | EE_CS)/* Delay between EEPROM clock transitions. No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. */#define eeprom_delay() readl(ee_addr)/* The EEPROM commands include the alway-set leading bit. */#define EE_WRITE_CMD (5)#define EE_READ_CMD (6)#define EE_ERASE_CMD (7)static int __devinit read_eeprom (void *ioaddr, int location, int addr_len){ int i; unsigned retval = 0; void *ee_addr = ioaddr + Cfg9346; int read_cmd = location | (EE_READ_CMD << addr_len); DPRINTK ("ENTER\n"); writeb (EE_ENB & ~EE_CS, ee_addr); writeb (EE_ENB, ee_addr); eeprom_delay (); /* Shift the read command bits out. */ for (i = 4 + addr_len; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; writeb (EE_ENB | dataval, ee_addr); eeprom_delay (); writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay (); } writeb (EE_ENB, ee_addr); eeprom_delay (); for (i = 16; i > 0; i--) { writeb (EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay (); retval = (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 : 0); writeb (EE_ENB, ee_addr); eeprom_delay (); } /* Terminate the EEPROM access. */ writeb (~EE_CS, ee_addr); eeprom_delay (); DPRINTK ("EXIT - returning %d\n", retval); return retval;}/* MII serial management: mostly bogus for now. *//* Read and write the MII management registers using software-generated serial MDIO protocol. The maximum data clock rate is 2.5 Mhz. The minimum timing is usually met by back-to-back PCI I/O cycles, but we insert a delay to avoid "overclocking" issues. */#define MDIO_DIR 0x80#define MDIO_DATA_OUT 0x04#define MDIO_DATA_IN 0x02#define MDIO_CLK 0x01#define MDIO_WRITE0 (MDIO_DIR)#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)#define mdio_delay() readb(mdio_addr)static char mii_2_8139_map[8] = { BasicModeCtrl, BasicModeStatus, 0, 0, NWayAdvert, NWayLPAR, NWayExpansion, 0};/* Syncronize the MII management interface by shifting 32 one bits out. */static void mdio_sync (void *mdio_addr){ int i; DPRINTK ("ENTER\n"); for (i = 32; i >= 0; i--) { writeb (MDIO_WRITE1, mdio_addr); mdio_delay (); writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr); mdio_delay (); } DPRINTK ("EXIT\n");}static int mdio_read (struct net_device *dev, int phy_id, int location){ struct netdrv_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -