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

📄 3c574_cs.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
	} else {		EL3WINDOW(0);		for (i = 0; i < 3; i++)			phys_addr[i] = htons(read_eeprom(ioaddr, i + 10));		if (phys_addr[0] == 0x6060) {			printk(KERN_NOTICE "3c574_cs: IO port conflict at 0x%03lx"				   "-0x%03lx\n", dev->base_addr, dev->base_addr+15);			goto failed;		}	}	tuple.DesiredTuple = CISTPL_VERS_1;	if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS &&		pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS &&		pcmcia_parse_tuple(handle, &tuple, &parse) == CS_SUCCESS) {		cardname = parse.version_1.str + parse.version_1.ofs[1];	} else		cardname = "3Com 3c574";	{		u_char mcr;		outw(2<<11, ioaddr + RunnerRdCtrl);		mcr = inb(ioaddr + 2);		outw(0<<11, ioaddr + RunnerRdCtrl);		printk(KERN_INFO "  ASIC rev %d,", mcr>>3);		EL3WINDOW(3);		config.i = inl(ioaddr + Wn3_Config);		lp->default_media = config.u.xcvr;		lp->autoselect = config.u.autoselect;	}	init_timer(&lp->media);	{		int phy;				/* Roadrunner only: Turn on the MII transceiver */		outw(0x8040, ioaddr + Wn3_Options);		mdelay(1);		outw(0xc040, ioaddr + Wn3_Options);		tc574_wait_for_completion(dev, TxReset);		tc574_wait_for_completion(dev, RxReset);		mdelay(1);		outw(0x8040, ioaddr + Wn3_Options);				EL3WINDOW(4);		for (phy = 1; phy <= 32; phy++) {			int mii_status;			mdio_sync(ioaddr, 32);			mii_status = mdio_read(ioaddr, phy & 0x1f, 1);			if (mii_status != 0xffff) {				lp->phys = phy & 0x1f;				DEBUG(0, "  MII transceiver at index %d, status %x.\n",					  phy, mii_status);				if ((mii_status & 0x0040) == 0)					mii_preamble_required = 1;				break;			}		}		if (phy > 32) {			printk(KERN_NOTICE "  No MII transceivers found!\n");			goto failed;		}		i = mdio_read(ioaddr, lp->phys, 16) | 0x40;		mdio_write(ioaddr, lp->phys, 16, i);		lp->advertising = mdio_read(ioaddr, lp->phys, 4);		if (full_duplex) {			/* Only advertise the FD media types. */			lp->advertising &= ~0x02a0;			mdio_write(ioaddr, lp->phys, 4, lp->advertising);		}	}	link->state &= ~DEV_CONFIG_PENDING;	link->dev = &lp->node;	SET_NETDEV_DEV(dev, &handle_to_dev(handle));	if (register_netdev(dev) != 0) {		printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");		link->dev = NULL;		goto failed;	}	strcpy(lp->node.dev_name, dev->name);	printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ",		   dev->name, cardname, dev->base_addr, dev->irq);	for (i = 0; i < 6; i++)		printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n"));	printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",		   8 << config.u.ram_size, ram_split[config.u.ram_split],		   config.u.autoselect ? "autoselect " : "");	return;cs_failed:	cs_error(link->handle, last_fn, last_ret);failed:	tc574_release(link);	return;} /* tc574_config *//*	After a card is removed, tc574_release() will unregister the net	device, and release the PCMCIA configuration.  If the device is	still open, this will be postponed until it is closed.*/static void tc574_release(dev_link_t *link){	DEBUG(0, "3c574_release(0x%p)\n", link);	pcmcia_release_configuration(link->handle);	pcmcia_release_io(link->handle, &link->io);	pcmcia_release_irq(link->handle, &link->irq);	link->state &= ~DEV_CONFIG;}/*	The card status event handler.  Mostly, this schedules other	stuff to run after an event is received.  A CARD_REMOVAL event	also sets some flags to discourage the net drivers from trying	to talk to the card any more.*/static int tc574_event(event_t event, int priority,					   event_callback_args_t *args){	dev_link_t *link = args->client_data;	struct net_device *dev = link->priv;	DEBUG(1, "3c574_event(0x%06x)\n", event);	switch (event) {	case CS_EVENT_CARD_REMOVAL:		link->state &= ~DEV_PRESENT;		if (link->state & DEV_CONFIG)			netif_device_detach(dev);		break;	case CS_EVENT_CARD_INSERTION:		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;		tc574_config(link);		break;	case CS_EVENT_PM_SUSPEND:		link->state |= DEV_SUSPEND;		/* Fall through... */	case CS_EVENT_RESET_PHYSICAL:		if (link->state & DEV_CONFIG) {			if (link->open)				netif_device_detach(dev);			pcmcia_release_configuration(link->handle);		}		break;	case CS_EVENT_PM_RESUME:		link->state &= ~DEV_SUSPEND;		/* Fall through... */	case CS_EVENT_CARD_RESET:		if (link->state & DEV_CONFIG) {			pcmcia_request_configuration(link->handle, &link->conf);			if (link->open) {				tc574_reset(dev);				netif_device_attach(dev);			}		}		break;	}	return 0;} /* tc574_event */static void dump_status(struct net_device *dev){	kio_addr_t ioaddr = dev->base_addr;	EL3WINDOW(1);	printk(KERN_INFO "  irq status %04x, rx status %04x, tx status "		   "%02x, tx free %04x\n", inw(ioaddr+EL3_STATUS),		   inw(ioaddr+RxStatus), inb(ioaddr+TxStatus),		   inw(ioaddr+TxFree));	EL3WINDOW(4);	printk(KERN_INFO "  diagnostics: fifo %04x net %04x ethernet %04x"		   " media %04x\n", inw(ioaddr+0x04), inw(ioaddr+0x06),		   inw(ioaddr+0x08), inw(ioaddr+0x0a));	EL3WINDOW(1);}/*  Use this for commands that may take time to finish*/static void tc574_wait_for_completion(struct net_device *dev, int cmd){	int i = 1500;	outw(cmd, dev->base_addr + EL3_CMD);	while (--i > 0)		if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;	if (i == 0)		printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n", dev->name, cmd);}/* Read a word from the EEPROM using the regular EEPROM access register.   Assume that we are in register window zero. */static unsigned short read_eeprom(kio_addr_t ioaddr, int index){	int timer;	outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd);	/* Pause for at least 162 usec for the read to take place. */	for (timer = 1620; timer >= 0; timer--) {		if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)			break;	}	return inw(ioaddr + Wn0EepromData);}/* 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 maxium data clock rate is 2.5 Mhz.  The timing is easily met by the   slow PC card interface. */#define MDIO_SHIFT_CLK	0x01#define MDIO_DIR_WRITE	0x04#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)#define MDIO_DATA_READ	0x02#define MDIO_ENB_IN		0x00/* Generate the preamble required for initial synchronization and   a few older transceivers. */static void mdio_sync(kio_addr_t ioaddr, int bits){	kio_addr_t mdio_addr = ioaddr + Wn4_PhysicalMgmt;	/* Establish sync by sending at least 32 logic ones. */	while (-- bits >= 0) {		outw(MDIO_DATA_WRITE1, mdio_addr);		outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);	}}static int mdio_read(kio_addr_t ioaddr, int phy_id, int location){	int i;	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;	unsigned int retval = 0;	kio_addr_t mdio_addr = ioaddr + Wn4_PhysicalMgmt;	if (mii_preamble_required)		mdio_sync(ioaddr, 32);	/* Shift the read command bits out. */	for (i = 14; i >= 0; i--) {		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;		outw(dataval, mdio_addr);		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);	}	/* Read the two transition, 16 data, and wire-idle bits. */	for (i = 19; i > 0; i--) {		outw(MDIO_ENB_IN, mdio_addr);		retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);	}	return (retval>>1) & 0xffff;}static void mdio_write(kio_addr_t ioaddr, int phy_id, int location, int value){	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;	kio_addr_t mdio_addr = ioaddr + Wn4_PhysicalMgmt;	int i;	if (mii_preamble_required)		mdio_sync(ioaddr, 32);	/* Shift the command bits out. */	for (i = 31; i >= 0; i--) {		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;		outw(dataval, mdio_addr);		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);	}	/* Leave the interface idle. */	for (i = 1; i >= 0; i--) {		outw(MDIO_ENB_IN, mdio_addr);		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);	}	return;}/* Reset and restore all of the 3c574 registers. */static void tc574_reset(struct net_device *dev){	struct el3_private *lp = netdev_priv(dev);	int i;	kio_addr_t ioaddr = dev->base_addr;	unsigned long flags;	tc574_wait_for_completion(dev, TotalReset|0x10);	spin_lock_irqsave(&lp->window_lock, flags);	/* Clear any transactions in progress. */	outw(0, ioaddr + RunnerWrCtrl);	outw(0, ioaddr + RunnerRdCtrl);	/* Set the station address and mask. */	EL3WINDOW(2);	for (i = 0; i < 6; i++)		outb(dev->dev_addr[i], ioaddr + i);	for (; i < 12; i+=2)		outw(0, ioaddr + i);	/* Reset config options */	EL3WINDOW(3);	outb((dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);	outl((lp->autoselect ? 0x01000000 : 0) | 0x0062001b,		 ioaddr + Wn3_Config);	/* Roadrunner only: Turn on the MII transceiver. */	outw(0x8040, ioaddr + Wn3_Options);	mdelay(1);	outw(0xc040, ioaddr + Wn3_Options);	EL3WINDOW(1);	spin_unlock_irqrestore(&lp->window_lock, flags);		tc574_wait_for_completion(dev, TxReset);	tc574_wait_for_completion(dev, RxReset);	mdelay(1);	spin_lock_irqsave(&lp->window_lock, flags);	EL3WINDOW(3);	outw(0x8040, ioaddr + Wn3_Options);	/* Switch to the stats window, and clear all stats by reading. */	outw(StatsDisable, ioaddr + EL3_CMD);	EL3WINDOW(6);	for (i = 0; i < 10; i++)		inb(ioaddr + i);	inw(ioaddr + 10);	inw(ioaddr + 12);	EL3WINDOW(4);	inb(ioaddr + 12);	inb(ioaddr + 13);	/* .. enable any extra statistics bits.. */	outw(0x0040, ioaddr + Wn4_NetDiag);		EL3WINDOW(1);	spin_unlock_irqrestore(&lp->window_lock, flags);		/* .. re-sync MII and re-fill what NWay is advertising. */	mdio_sync(ioaddr, 32);	mdio_write(ioaddr, lp->phys, 4, lp->advertising);	if (!auto_polarity) {		/* works for TDK 78Q2120 series MII's */		int i = mdio_read(ioaddr, lp->phys, 16) | 0x20;		mdio_write(ioaddr, lp->phys, 16, i);	}	spin_lock_irqsave(&lp->window_lock, flags);	/* Switch to register set 1 for normal use, just for TxFree. */	set_rx_mode(dev);	spin_unlock_irqrestore(&lp->window_lock, flags);	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */	/* Allow status bits to be seen. */	outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);	/* Ack all pending events, and set active indicator mask. */	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,		 ioaddr + EL3_CMD);	outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull		 | AdapterFailure | RxEarly, ioaddr + EL3_CMD);}static int el3_open(struct net_device *dev){	struct el3_private *lp = netdev_priv(dev);	dev_link_t *link = &lp->link;	if (!DEV_OK(link))		return -ENODEV;		link->open++;	netif_start_queue(dev);		tc574_reset(dev);	lp->media.function = &media_check;	lp->media.data = (unsigned long) dev;	lp->media.expires = jiffies + HZ;	add_timer(&lp->media);		DEBUG(2, "%s: opened, status %4.4x.\n",		  dev->name, inw(dev->base_addr + EL3_STATUS));		return 0;}static void el3_tx_timeout(struct net_device *dev){	struct el3_private *lp = netdev_priv(dev);	kio_addr_t ioaddr = dev->base_addr;		printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);	dump_status(dev);	lp->stats.tx_errors++;	dev->trans_start = jiffies;	/* Issue TX_RESET and TX_START commands. */	tc574_wait_for_completion(dev, TxReset);	outw(TxEnable, ioaddr + EL3_CMD);	netif_wake_queue(dev);}static void pop_tx_status(struct net_device *dev){	struct el3_private *lp = netdev_priv(dev);	kio_addr_t ioaddr = dev->base_addr;	int i;    	/* Clear the Tx status stack. */	for (i = 32; i > 0; i--) {		u_char tx_status = inb(ioaddr + TxStatus);		if (!(tx_status & 0x84))			break;		/* reset transmitter on jabber error or underrun */		if (tx_status & 0x30)			tc574_wait_for_completion(dev, TxReset);		if (tx_status & 0x38) {			DEBUG(1, "%s: transmit error: status 0x%02x\n",				  dev->name, tx_status);			outw(TxEnable, ioaddr + EL3_CMD);			lp->stats.tx_aborted_errors++;		}		outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */	}}static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev){

⌨️ 快捷键说明

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