⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtk8189c.c

📁 ADTEK RTK8189C Linux 2.4.X Driver
💻 C
📖 第 1 页 / 共 4 页
字号:

	printk(KERN_INFO "%s: %s at 0x%lx, ",
		   dev->name, pci_id_tbl[chip_idx].name, ioaddr);

	for (i = 0; i < 3; i++)
	   ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i + 8));
	if (memcmp(dev->dev_addr, "\0\0\0\0\0", 6) == 0) {
		printk(" (MISSING EEPROM ADDRESS)");
		memcpy(dev->dev_addr, "\0Linux", 6);
	}
	for (i = 0; i < 5; i++)
		printk("%2.2x:", dev->dev_addr[i]);
	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);

#if ! defined(final_version) /* Dump the EEPROM contents during development. */
	if (debug > 4)
		for (i = 0; i < 0x40; i++)
			printk("%4.4x%s",
				   eeprom_read(ioaddr, i), i % 16 != 15 ? " " : "\n");
#endif

	/* Make certain elements e.g. descriptor lists are aligned. */
	priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
	/* Check for the very unlikely case of no memory. */
	if (priv_mem == NULL)
		return NULL;

	/* Do bogusness checks before this point.
	   We do a request_region() only to register /proc/ioports info. */
#ifdef USE_IO_OPS
	request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name);
#endif

	/* Reset the chip to erase previous misconfiguration. */
	writel(BCR_Reset, ioaddr + PCIBusCfg);

	dev->base_addr = ioaddr;
	dev->irq = irq;

	dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
	memset(np, 0, sizeof(*np));
	np->priv_addr = priv_mem;

	np->next_module = root_net_dev;
	root_net_dev = dev;

	np->pci_dev = pdev;
	np->chip_id = chip_idx;
	np->drv_flags = pci_id_tbl[chip_idx].drv_flags;

	if (dev->mem_start)
		option = dev->mem_start;

	/* The lower four bits are the media type. */
	if (option > 0) {
		if (option & 0x220)
			np->full_duplex = 1;
		np->default_port = option & 0x3ff;
		if (np->default_port)
			np->medialock = 1;
	}
	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
		np->full_duplex = 1;

	if (np->full_duplex) {
		printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
			   " disabled.\n", dev->name);
		np->duplex_lock = 1;
	}

	/* The chip-specific entries in the device structure. */
	dev->open = &netdev_open;
	dev->hard_start_xmit = &start_tx;
	dev->stop = &netdev_close;
	dev->get_stats = &get_stats;
	dev->set_multicast_list = &set_rx_mode;
	dev->do_ioctl = &mii_ioctl;

	if (mtu)
		dev->mtu = mtu;

	if (np->drv_flags & HasMIIXcvr) {
		int phy, phy_idx = 0;
		for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
			int mii_status = mdio_read(dev, phy, 1);
			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
				np->phys[phy_idx++] = phy;
				np->advertising = mdio_read(dev, phy, 4);
				printk(KERN_INFO "%s: MII PHY found at address %d, status "
					   "0x%4.4x advertising %4.4x.\n",
					   dev->name, phy, mii_status, np->advertising);
			}
		}
		np->mii_cnt = phy_idx;
	}
	if (np->drv_flags & HasChipXcvr) {
		np->phys[np->mii_cnt++] = 32;
		printk(KERN_INFO "%s: Internal PHY status 0x%4.4x"
			   " advertising %4.4x.\n",
			   dev->name, mdio_read(dev, 32, 1), mdio_read(dev, 32, 4));
	}
	if (np->default_port & 0x330) {
		np->medialock = 1;
		printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
			   (option & 0x300 ? 100 : 10),
			   (option & 0x220 ? "full" : "half"));
		if (np->mii_cnt)
			mdio_write(dev, np->phys[0], 0,
					   ((option & 0x300) ? 0x2000 : 0) |	/* 100mbps? */
					   ((option & 0x220) ? 0x0100 : 0)); /* Full duplex? */
	}

	return dev;
}


/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.  These are
   often serial bit streams generated by the host processor.
   The example below is for the common 93c46 EEPROM, 64 16 bit words. */

/* This "delay" forces out buffered PCI writes. */
#define eeprom_delay(ee_addr)	readl(ee_addr); udelay(2); readl(ee_addr)

enum EEPROM_Ctrl_Bits {
	EE_ShiftClk=0x04<<16, EE_ChipSelect=0x88<<16,
	EE_DataOut=0x02<<16, EE_DataIn=0x01<<16,
	EE_Write0=0x88<<16, EE_Write1=0x8a<<16,
};

/* The EEPROM commands always start with 01.. preamble bits.
   Commands are prepended to the variable-length address. */
enum EEPROM_Cmds { EE_WriteCmd=5, EE_ReadCmd=6, EE_EraseCmd=7, };


static int eeprom_read(long addr, int location)
{
	int i;
	int retval = 0;
	long ee_addr = addr + EECtrl;
	int read_cmd = location | (EE_ReadCmd<<6);

	writel(EE_ChipSelect, ee_addr);

	/* Shift the read command bits out. */
	for (i = 10; i >= 0; i--) {
		int dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
		writel(dataval, ee_addr);
		eeprom_delay(ee_addr);
		writel(dataval | EE_ShiftClk, ee_addr);
		eeprom_delay(ee_addr);
	}
	writel(EE_ChipSelect, ee_addr);
	eeprom_delay(ee_addr);

	for (i = 16; i > 0; i--) {
		writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
		eeprom_delay(ee_addr);
		retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
		writel(EE_ChipSelect, ee_addr);
		eeprom_delay(ee_addr);
	}

	/* Terminate the EEPROM access. */
	writel(EE_ChipSelect, ee_addr);
	writel(0, ee_addr);
	return retval;
}

/*  MII transceiver control section.
	Read and write the MII registers using software-generated serial
	MDIO protocol.	See the MII specifications or DP83840A data sheet
	for details.

	The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
	met by back-to-back 33Mhz PCI cycles. */
#define mdio_delay(mdio_addr) readl(mdio_addr)

/* Set iff a MII transceiver on any interface requires mdio preamble.
   This only set with older tranceivers, so the extra
   code size of a per-interface flag is not worthwhile. */
static char mii_preamble_required = 0;

enum mii_reg_bits {
	MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,
};
#define MDIO_EnbIn  (0)
#define MDIO_WRITE0 (MDIO_EnbOutput)
#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput)

/* Generate the preamble required for initial synchronization and
   a few older transceivers. */
static void mdio_sync(long mdio_addr)
{
	int bits = 32;

	/* Establish sync by sending at least 32 logic ones. */
	while (--bits >= 0) {
		writel(MDIO_WRITE1, mdio_addr);
		mdio_delay(mdio_addr);
		writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
		mdio_delay(mdio_addr);
	}
}

static int mdio_read(struct net_device *dev, int phy_id, unsigned int location)
{
	long ioaddr = dev->base_addr;
	long mdio_addr = ioaddr + MIICtrl;
	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
	int i, retval = 0;

	if (location >= 32)
		return 0xffff;
	if (phy_id >= 32) {
		if (location < 6)
			return readw(ioaddr + PHYMgmt + location*2);
		else if (location == 16)
			return readw(ioaddr + PHYMgmt + 6*2);
		else if (location == 17)
			return readw(ioaddr + PHYMgmt + 7*2);
		else if (location == 18)
			return readw(ioaddr + PHYMgmt + 10*2);
		else
			return 0;
	}

	if (mii_preamble_required)
		mdio_sync(mdio_addr);

	/* Shift the read command bits out. */
	for (i = 15; i >= 0; i--) {
		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;

		writel(dataval, mdio_addr);
		mdio_delay(mdio_addr);
		writel(dataval | MDIO_ShiftClk, mdio_addr);
		mdio_delay(mdio_addr);
	}
	/* Read the two transition, 16 data, and wire-idle bits. */
	for (i = 19; i > 0; i--) {
		writel(MDIO_EnbIn, mdio_addr);
		mdio_delay(mdio_addr);
		retval = (retval << 1) | ((readl(mdio_addr) & MDIO_Data) ? 1 : 0);
		writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
		mdio_delay(mdio_addr);
	}
	return (retval>>1) & 0xffff;
}

static void mdio_write(struct net_device *dev, int phy_id,
					   unsigned int location, int value)
{
	struct netdev_private *np = (struct netdev_private *)dev->priv;
	long ioaddr = dev->base_addr;
	long mdio_addr = ioaddr + MIICtrl;
	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
	int i;

	if (location == 4  &&  phy_id == np->phys[0])
		np->advertising = value;
	else if (location >= 32)
		return;

	if (phy_id == 32) {
		if (location < 6)
			writew(value, ioaddr + PHYMgmt + location*2);
		else if (location == 16)
			writew(value, ioaddr + PHYMgmt + 6*2);
		else if (location == 17)
			writew(value, ioaddr + PHYMgmt + 7*2);
		return;
	}

	if (mii_preamble_required)
		mdio_sync(mdio_addr);

	/* Shift the command bits out. */
	for (i = 31; i >= 0; i--) {
		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;

		writel(dataval, mdio_addr);
		mdio_delay(mdio_addr);
		writel(dataval | MDIO_ShiftClk, mdio_addr);
		mdio_delay(mdio_addr);
	}
	/* Clear out extra bits. */
	for (i = 2; i > 0; i--) {
		writel(MDIO_EnbIn, mdio_addr);
		mdio_delay(mdio_addr);
		writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
		mdio_delay(mdio_addr);
	}
	return;
}


static int netdev_open(struct net_device *dev)
{
	struct netdev_private *np = (struct netdev_private *)dev->priv;
	long ioaddr = dev->base_addr;

	/* Some chips may need to be reset. */

	MOD_INC_USE_COUNT;

	writel(~0, ioaddr + IntrStatus);

	/* Note that both request_irq() and init_ring() call kmalloc(), which
	   break the global kernel lock protecting this routine. */
	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
		MOD_DEC_USE_COUNT;
		return -EAGAIN;
	}

	if (debug > 1)
		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
			   dev->name, dev->irq);

	init_ring(dev);

	writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
	writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);

	/* Address register must be written as words. */
	writel(cpu_to_le32(cpu_to_le32(get_unaligned((u32 *)dev->dev_addr))),
					   ioaddr + StationAddr);
	writel(cpu_to_le16(cpu_to_le16(get_unaligned((u16 *)(dev->dev_addr+4)))),
					   ioaddr + StationAddr + 4);
	/* Set the flow control address, 01:80:c2:00:00:01. */
//	writel(0x00c28001, ioaddr + FlowCtrlAddr);
//	writel(0x00000100, ioaddr + FlowCtrlAddr + 4);

	/* Initialize other registers. */
	/* Configure the PCI bus bursts and FIFO thresholds. */
//	writel(0x01f8, ioaddr + PCIBusCfg);
	writel(0x038, ioaddr + PCIBusCfg);

	if (dev->if_port == 0)
		dev->if_port = np->default_port;

//	np->txrx_config = TxEnable | RxEnable | RxFlowCtrl | 0x00600000;
	np->txrx_config = TxEnable | RxEnable | TxThreshold | 0x0f00;
	np->mcast_filter[0] = np->mcast_filter[1] = 0;
	set_rx_mode(dev);
	netif_start_tx_queue(dev);

	/* Enable interrupts by setting the interrupt mask. */
	writel(IntrRxDone | IntrRxErr | IntrRxEmpty | IntrTxDone | IntrTxEmpty
		   | StatsMax | RxOverflow | TxUnderrun | IntrPCIErr | NWayDone
		   | LinkChange,
		   ioaddr + IntrEnable);

	if (debug > 2)
		printk(KERN_DEBUG "%s: Done netdev_open(), PHY status: %x %x.\n",
			   dev->name, (int)readw(ioaddr + PHYMgmt),
			   (int)readw(ioaddr + PHYMgmt + 2));

	/* Set the timer to check for link beat. */
	init_timer(&np->timer);
	np->timer.expires = jiffies + 3*HZ;
	np->timer.data = (unsigned long)dev;
	np->timer.function = &netdev_timer;				/* timer handler */
	add_timer(&np->timer);

	return 0;
}

static void check_duplex(struct net_device *dev)
{
	struct netdev_private *np = (struct netdev_private *)dev->priv;
	long ioaddr = dev->base_addr;
	int new_tx_mode = np->txrx_config;

	if (np->medialock) {
	} else {
		int mii_reg5 = mdio_read(dev, np->phys[0], 5);
		int negotiated = mii_reg5 & np->advertising;
		int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
		if (np->duplex_lock  ||  mii_reg5 == 0xffff)
			return;
		if (duplex)
			new_tx_mode |= TxModeFDX;
		if (np->full_duplex != duplex) {
			np->full_duplex = duplex;
			if (debug)
				printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d"
					   " negotiated capability %4.4x.\n", dev->name,
					   duplex ? "full" : "half", np->phys[0], negotiated);
		}
	}
	if (np->txrx_config != new_tx_mode)
		writel(new_tx_mode, ioaddr + RxConfig);
}

static void resetnic(struct net_device *dev)
{
	struct netdev_private *np = (struct netdev_private *)dev->priv;
	int i;
	long ioaddr = dev->base_addr;
	struct sk_buff *skb;

	/* Perhaps we should reinitialize the hardware here. */
	dev->if_port = 0;

	/* Stop Tx and Rx */
	i=0;
	while (i<10)
	{
	    ++i;
	    writel(0, ioaddr + RxConfig);
	    if (readl(ioaddr + RxConfig)&TxEnable)
	      continue;
	    if (readl(ioaddr + RxConfig)&RxEnable)
	      continue;
	    break;
	}

	/* reset the nic */
	writel(1, ioaddr + PCIBusCfg);
	do
	{
	   if (!(readl(ioaddr + PCIBusCfg)&0x01))
	     break;
	} while (1);

	/* Initialize all Rx descriptors. */
	for (i = 0; i < RX_RING_SIZE; i++) {
		if (np->rx_ring[i].rxbuffer)
			np->rx_ring[i].status = cpu_to_le32(DescOwn);
	}

	/* Refill the Rx ring buffers. */
	while (np->lackrxcount) {
		skb = dev_alloc_skb(np->rx_buf_sz);
		if (skb == NULL)
		   break;	    /* Better luck next round. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -