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

📄 atp.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
	}    write_reg(ioaddr, CMR2, CMR2_IRQOUT);    write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);	/* Enable the interrupt line from the serial port. */	outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL);	/* Unmask the interesting interrupts. */    write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);    write_reg_high(ioaddr, IMR, ISRh_RxErr);	lp->tx_unit_busy = 0;    lp->pac_cnt_in_tx_buf = 0;	lp->saved_tx_size = 0;}static void trigger_send(long ioaddr, int length){	write_reg_byte(ioaddr, TxCNT0, length & 0xff);	write_reg(ioaddr, TxCNT1, length >> 8);	write_reg(ioaddr, CMR1, CMR1_Xmit);}static void write_packet(long ioaddr, int length, unsigned char *packet, int pad_len, int data_mode){    if (length & 1)    {    	length++;    	pad_len++;    }    outb(EOC+MAR, ioaddr + PAR_DATA);    if ((data_mode & 1) == 0) {		/* Write the packet out, starting with the write addr. */		outb(WrAddr+MAR, ioaddr + PAR_DATA);		do {			write_byte_mode0(ioaddr, *packet++);		} while (--length > pad_len) ;		do {			write_byte_mode0(ioaddr, 0);		} while (--length > 0) ;    } else {		/* Write the packet out in slow mode. */		unsigned char outbyte = *packet++;		outb(Ctrl_LNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL);		outb(WrAddr+MAR, ioaddr + PAR_DATA);		outb((outbyte & 0x0f)|0x40, ioaddr + PAR_DATA);		outb(outbyte & 0x0f, ioaddr + PAR_DATA);		outbyte >>= 4;		outb(outbyte & 0x0f, ioaddr + PAR_DATA);		outb(Ctrl_HNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL);		while (--length > pad_len)			write_byte_mode1(ioaddr, *packet++);		while (--length > 0)			write_byte_mode1(ioaddr, 0);    }    /* Terminate the Tx frame.  End of write: ECB. */    outb(0xff, ioaddr + PAR_DATA);    outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL);}static void tx_timeout(struct net_device *dev){	struct net_local *np = netdev_priv(dev);	long ioaddr = dev->base_addr;	printk(KERN_WARNING "%s: Transmit timed out, %s?\n", dev->name,		   inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem"		   :  "IRQ conflict");	np->stats.tx_errors++;	/* Try to restart the adapter. */	hardware_init(dev);	dev->trans_start = jiffies;	netif_wake_queue(dev);	np->stats.tx_errors++;}static int atp_send_packet(struct sk_buff *skb, struct net_device *dev){	struct net_local *lp = netdev_priv(dev);	long ioaddr = dev->base_addr;	int length;	unsigned long flags;	length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;	netif_stop_queue(dev);	/* Disable interrupts by writing 0x00 to the Interrupt Mask Register.	   This sequence must not be interrupted by an incoming packet. */	spin_lock_irqsave(&lp->lock, flags);	write_reg(ioaddr, IMR, 0);	write_reg_high(ioaddr, IMR, 0);	spin_unlock_irqrestore(&lp->lock, flags);	write_packet(ioaddr, length, skb->data, length-skb->len, dev->if_port);	lp->pac_cnt_in_tx_buf++;	if (lp->tx_unit_busy == 0) {		trigger_send(ioaddr, length);		lp->saved_tx_size = 0; 				/* Redundant */		lp->re_tx = 0;		lp->tx_unit_busy = 1;	} else		lp->saved_tx_size = length;	/* Re-enable the LPT interrupts. */	write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);	write_reg_high(ioaddr, IMR, ISRh_RxErr);	dev->trans_start = jiffies;	dev_kfree_skb (skb);	return 0;}/* The typical workload of the driver:   Handle the network interface interrupts. */static irqreturn_tatp_interrupt(int irq, void *dev_instance, struct pt_regs * regs){	struct net_device *dev = (struct net_device *)dev_instance;	struct net_local *lp;	long ioaddr;	static int num_tx_since_rx;	int boguscount = max_interrupt_work;	int handled = 0;	if (dev == NULL) {		printk(KERN_ERR "ATP_interrupt(): irq %d for unknown device.\n", irq);		return IRQ_NONE;	}	ioaddr = dev->base_addr;	lp = netdev_priv(dev);	spin_lock(&lp->lock);	/* Disable additional spurious interrupts. */	outb(Ctrl_SelData, ioaddr + PAR_CONTROL);	/* The adapter's output is currently the IRQ line, switch it to data. */	write_reg(ioaddr, CMR2, CMR2_NULL);	write_reg(ioaddr, IMR, 0);	if (net_debug > 5) printk(KERN_DEBUG "%s: In interrupt ", dev->name);    while (--boguscount > 0) {		int status = read_nibble(ioaddr, ISR);		if (net_debug > 5) printk("loop status %02x..", status);		if (status & (ISR_RxOK<<3)) {			handled = 1;			write_reg(ioaddr, ISR, ISR_RxOK); /* Clear the Rx interrupt. */			do {				int read_status = read_nibble(ioaddr, CMR1);				if (net_debug > 6)					printk("handling Rx packet %02x..", read_status);				/* We acknowledged the normal Rx interrupt, so if the interrupt				   is still outstanding we must have a Rx error. */				if (read_status & (CMR1_IRQ << 3)) { /* Overrun. */					lp->stats.rx_over_errors++;					/* Set to no-accept mode long enough to remove a packet. */					write_reg_high(ioaddr, CMR2, CMR2h_OFF);					net_rx(dev);					/* Clear the interrupt and return to normal Rx mode. */					write_reg_high(ioaddr, ISR, ISRh_RxErr);					write_reg_high(ioaddr, CMR2, lp->addr_mode);				} else if ((read_status & (CMR1_BufEnb << 3)) == 0) {					net_rx(dev);					num_tx_since_rx = 0;				} else					break;			} while (--boguscount > 0);		} else if (status & ((ISR_TxErr + ISR_TxOK)<<3)) {			handled = 1;			if (net_debug > 6)  printk("handling Tx done..");			/* Clear the Tx interrupt.  We should check for too many failures			   and reinitialize the adapter. */			write_reg(ioaddr, ISR, ISR_TxErr + ISR_TxOK);			if (status & (ISR_TxErr<<3)) {				lp->stats.collisions++;				if (++lp->re_tx > 15) {					lp->stats.tx_aborted_errors++;					hardware_init(dev);					break;				}				/* Attempt to retransmit. */				if (net_debug > 6)  printk("attempting to ReTx");				write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit);			} else {				/* Finish up the transmit. */				lp->stats.tx_packets++;				lp->pac_cnt_in_tx_buf--;				if ( lp->saved_tx_size) {					trigger_send(ioaddr, lp->saved_tx_size);					lp->saved_tx_size = 0;					lp->re_tx = 0;				} else					lp->tx_unit_busy = 0;				netif_wake_queue(dev);	/* Inform upper layers. */			}			num_tx_since_rx++;		} else if (num_tx_since_rx > 8				   && time_after(jiffies, dev->last_rx + HZ)) {			if (net_debug > 2)				printk(KERN_DEBUG "%s: Missed packet? No Rx after %d Tx and "					   "%ld jiffies status %02x  CMR1 %02x.\n", dev->name,					   num_tx_since_rx, jiffies - dev->last_rx, status,					   (read_nibble(ioaddr, CMR1) >> 3) & 15);			lp->stats.rx_missed_errors++;			hardware_init(dev);			num_tx_since_rx = 0;			break;		} else			break;    }	/* This following code fixes a rare (and very difficult to track down)	   problem where the adapter forgets its ethernet address. */	{		int i;		for (i = 0; i < 6; i++)			write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]);#if 0 && defined(TIMED_CHECKER)		mod_timer(&lp->timer, jiffies + TIMED_CHECKER);#endif	}	/* Tell the adapter that it can go back to using the output line as IRQ. */    write_reg(ioaddr, CMR2, CMR2_IRQOUT);	/* Enable the physical interrupt line, which is sure to be low until.. */	outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL);	/* .. we enable the interrupt sources. */	write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);	write_reg_high(ioaddr, IMR, ISRh_RxErr); 			/* Hmmm, really needed? */	spin_unlock(&lp->lock);	if (net_debug > 5) printk("exiting interrupt.\n");	return IRQ_RETVAL(handled);}#ifdef TIMED_CHECKER/* This following code fixes a rare (and very difficult to track down)   problem where the adapter forgets its ethernet address. */static void atp_timed_checker(unsigned long data){	struct net_device *dev = (struct net_device *)data;	long ioaddr = dev->base_addr;	struct net_local *lp = netdev_priv(dev);	int tickssofar = jiffies - lp->last_rx_time;	int i;	spin_lock(&lp->lock);	if (tickssofar > 2*HZ) {#if 1		for (i = 0; i < 6; i++)			write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]);		lp->last_rx_time = jiffies;#else		for (i = 0; i < 6; i++)			if (read_cmd_byte(ioaddr, PAR0 + i) != atp_timed_dev->dev_addr[i])				{			struct net_local *lp = netdev_priv(atp_timed_dev);			write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);			if (i == 2)			  lp->stats.tx_errors++;			else if (i == 3)			  lp->stats.tx_dropped++;			else if (i == 4)			  lp->stats.collisions++;			else			  lp->stats.rx_errors++;		  }#endif	}	spin_unlock(&lp->lock);	lp->timer.expires = jiffies + TIMED_CHECKER;	add_timer(&lp->timer);}#endif/* We have a good packet(s), get it/them out of the buffers. */static void net_rx(struct net_device *dev){	struct net_local *lp = netdev_priv(dev);	long ioaddr = dev->base_addr;	struct rx_header rx_head;	/* Process the received packet. */	outb(EOC+MAR, ioaddr + PAR_DATA);	read_block(ioaddr, 8, (unsigned char*)&rx_head, dev->if_port);	if (net_debug > 5)		printk(KERN_DEBUG " rx_count %04x %04x %04x %04x..", rx_head.pad,			   rx_head.rx_count, rx_head.rx_status, rx_head.cur_addr);	if ((rx_head.rx_status & 0x77) != 0x01) {		lp->stats.rx_errors++;		if (rx_head.rx_status & 0x0004) lp->stats.rx_frame_errors++;		else if (rx_head.rx_status & 0x0002) lp->stats.rx_crc_errors++;		if (net_debug > 3)			printk(KERN_DEBUG "%s: Unknown ATP Rx error %04x.\n",				   dev->name, rx_head.rx_status);		if  (rx_head.rx_status & 0x0020) {			lp->stats.rx_fifo_errors++;			write_reg_high(ioaddr, CMR1, CMR1h_TxENABLE);			write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);		} else if (rx_head.rx_status & 0x0050)			hardware_init(dev);		return;	} else {		/* Malloc up new buffer. The "-4" omits the FCS (CRC). */		int pkt_len = (rx_head.rx_count & 0x7ff) - 4;		struct sk_buff *skb;		skb = dev_alloc_skb(pkt_len + 2);		if (skb == NULL) {			printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n",				   dev->name);			lp->stats.rx_dropped++;			goto done;		}		skb->dev = dev;		skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */		read_block(ioaddr, pkt_len, skb_put(skb,pkt_len), dev->if_port);		skb->protocol = eth_type_trans(skb, dev);		netif_rx(skb);		dev->last_rx = jiffies;		lp->stats.rx_packets++;		lp->stats.rx_bytes += pkt_len;	} done:	write_reg(ioaddr, CMR1, CMR1_NextPkt);	lp->last_rx_time = jiffies;	return;}static void read_block(long ioaddr, int length, unsigned char *p, int data_mode){	if (data_mode <= 3) { /* Mode 0 or 1 */		outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL);		outb(length == 8  ?  RdAddr | HNib | MAR  :  RdAddr | MAR,			 ioaddr + PAR_DATA);		if (data_mode <= 1) { /* Mode 0 or 1 */			do  *p++ = read_byte_mode0(ioaddr);  while (--length > 0);		} else	/* Mode 2 or 3 */			do  *p++ = read_byte_mode2(ioaddr);  while (--length > 0);	} else if (data_mode <= 5)		do      *p++ = read_byte_mode4(ioaddr);  while (--length > 0);	else		do      *p++ = read_byte_mode6(ioaddr);  while (--length > 0);    outb(EOC+HNib+MAR, ioaddr + PAR_DATA);	outb(Ctrl_SelData, ioaddr + PAR_CONTROL);}/* The inverse routine to net_open(). */static intnet_close(struct net_device *dev){	struct net_local *lp = netdev_priv(dev);	long ioaddr = dev->base_addr;	netif_stop_queue(dev);	del_timer_sync(&lp->timer);	/* Flush the Tx and disable Rx here. */	lp->addr_mode = CMR2h_OFF;	write_reg_high(ioaddr, CMR2, CMR2h_OFF);	/* Free the IRQ line. */	outb(0x00, ioaddr + PAR_CONTROL);	free_irq(dev->irq, dev);	/* Reset the ethernet hardware and activate the printer pass-through. */	write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX);	return 0;}/* Get the current statistics.	This may be called with the card open or   closed. */static struct net_device_stats *net_get_stats(struct net_device *dev){	struct net_local *lp = netdev_priv(dev);	return &lp->stats;}/* *	Set or clear the multicast filter for this adapter. */static void set_rx_mode_8002(struct net_device *dev){	struct net_local *lp = netdev_priv(dev);	long ioaddr = dev->base_addr;	if ( dev->mc_count > 0 || (dev->flags & (IFF_ALLMULTI|IFF_PROMISC))) {		/* We must make the kernel realise we had to move		 *	into promisc mode or we start all out war on		 *	the cable. - AC		 */		dev->flags|=IFF_PROMISC;		lp->addr_mode = CMR2h_PROMISC;	} else		lp->addr_mode = CMR2h_Normal;	write_reg_high(ioaddr, CMR2, lp->addr_mode);}static void set_rx_mode_8012(struct net_device *dev){	struct net_local *lp = netdev_priv(dev);	long ioaddr = dev->base_addr;	unsigned char new_mode, mc_filter[8]; /* Multicast hash filter */	int i;	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		new_mode = CMR2h_PROMISC;	} else if ((dev->mc_count > 1000)  ||  (dev->flags & IFF_ALLMULTI)) {		/* Too many to filter perfectly -- accept all multicasts. */		memset(mc_filter, 0xff, sizeof(mc_filter));		new_mode = CMR2h_Normal;	} else {		struct dev_mc_list *mclist;		memset(mc_filter, 0, sizeof(mc_filter));		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;			 i++, mclist = mclist->next)		{			int filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f;			mc_filter[filterbit >> 5] |= cpu_to_le32(1 << (filterbit & 31));		}		new_mode = CMR2h_Normal;	}	lp->addr_mode = new_mode;    write_reg(ioaddr, CMR2, CMR2_IRQOUT | 0x04); /* Switch to page 1. */    for (i = 0; i < 8; i++)		write_reg_byte(ioaddr, i, mc_filter[i]);	if (net_debug > 2 || 1) {		lp->addr_mode = 1;		printk(KERN_DEBUG "%s: Mode %d, setting multicast filter to",			   dev->name, lp->addr_mode);		for (i = 0; i < 8; i++)			printk(" %2.2x", mc_filter[i]);		printk(".\n");	}	write_reg_high(ioaddr, CMR2, lp->addr_mode);    write_reg(ioaddr, CMR2, CMR2_IRQOUT); /* Switch back to page 0 */}static int __init atp_init_module(void) {	if (debug)					/* Emit version even if no cards detected. */		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);	return atp_init();}static void __exit atp_cleanup_module(void) {	struct net_device *next_dev;	while (root_atp_dev) {		next_dev = ((struct net_local *)root_atp_dev->priv)->next_module;		unregister_netdev(root_atp_dev);		/* No need to release_region(), since we never snarf it. */		free_netdev(root_atp_dev);		root_atp_dev = next_dev;	}}module_init(atp_init_module);module_exit(atp_cleanup_module);

⌨️ 快捷键说明

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