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

📄 z85230.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	"Z85C30",	"Z85230"};/** *	z8530_describe - Uniformly describe a Z8530 port *	@dev: Z8530 device to describe *	@mapping: string holding mapping type (eg "I/O" or "Mem") *	@io: the port value in question * *	Describe a Z8530 in a standard format. We must pass the I/O as *	the port offset isnt predictable. The main reason for this function *	is to try and get a common format of report. */void z8530_describe(struct z8530_dev *dev, char *mapping, unsigned long io){	printk(KERN_INFO "%s: %s found at %s 0x%lX, IRQ %d.\n",		dev->name, 		z8530_type_name[dev->type],		mapping,		Z8530_PORT_OF(io),		dev->irq);}EXPORT_SYMBOL(z8530_describe);/* *	Locked operation part of the z8530 init code */ static inline int do_z8530_init(struct z8530_dev *dev){	/* NOP the interrupt handlers first - we might get a	   floating IRQ transition when we reset the chip */	dev->chanA.irqs=&z8530_nop;	dev->chanB.irqs=&z8530_nop;	dev->chanA.dcdcheck=DCD;	dev->chanB.dcdcheck=DCD;	/* Reset the chip */	write_zsreg(&dev->chanA, R9, 0xC0);	udelay(200);	/* Now check its valid */	write_zsreg(&dev->chanA, R12, 0xAA);	if(read_zsreg(&dev->chanA, R12)!=0xAA)		return -ENODEV;	write_zsreg(&dev->chanA, R12, 0x55);	if(read_zsreg(&dev->chanA, R12)!=0x55)		return -ENODEV;			dev->type=Z8530;		/*	 *	See the application note.	 */	 	write_zsreg(&dev->chanA, R15, 0x01);		/*	 *	If we can set the low bit of R15 then	 *	the chip is enhanced.	 */	 	if(read_zsreg(&dev->chanA, R15)==0x01)	{		/* This C30 versus 230 detect is from Klaus Kudielka's dmascc */		/* Put a char in the fifo */		write_zsreg(&dev->chanA, R8, 0);		if(read_zsreg(&dev->chanA, R0)&Tx_BUF_EMP)			dev->type = Z85230;	/* Has a FIFO */		else			dev->type = Z85C30;	/* Z85C30, 1 byte FIFO */	}			/*	 *	The code assumes R7' and friends are	 *	off. Use write_zsext() for these and keep	 *	this bit clear.	 */	 	write_zsreg(&dev->chanA, R15, 0);			/*	 *	At this point it looks like the chip is behaving	 */	 	memcpy(dev->chanA.regs, reg_init, 16);	memcpy(dev->chanB.regs, reg_init ,16);		return 0;}/** *	z8530_init - Initialise a Z8530 device *	@dev: Z8530 device to initialise. * *	Configure up a Z8530/Z85C30 or Z85230 chip. We check the device *	is present, identify the type and then program it to hopefully *	keep quite and behave. This matters a lot, a Z8530 in the wrong *	state will sometimes get into stupid modes generating 10Khz *	interrupt streams and the like. * *	We set the interrupt handler up to discard any events, in case *	we get them during reset or setp. * *	Return 0 for success, or a negative value indicating the problem *	in errno form. */int z8530_init(struct z8530_dev *dev){	unsigned long flags;	int ret;	/* Set up the chip level lock */	spin_lock_init(&dev->lock);	dev->chanA.lock = &dev->lock;	dev->chanB.lock = &dev->lock;	spin_lock_irqsave(&dev->lock, flags);	ret = do_z8530_init(dev);	spin_unlock_irqrestore(&dev->lock, flags);	return ret;}EXPORT_SYMBOL(z8530_init);/** *	z8530_shutdown - Shutdown a Z8530 device *	@dev: The Z8530 chip to shutdown * *	We set the interrupt handlers to silence any interrupts. We then  *	reset the chip and wait 100uS to be sure the reset completed. Just *	in case the caller then tries to do stuff. * *	This is called without the lock held */ int z8530_shutdown(struct z8530_dev *dev){	unsigned long flags;	/* Reset the chip */	spin_lock_irqsave(&dev->lock, flags);	dev->chanA.irqs=&z8530_nop;	dev->chanB.irqs=&z8530_nop;	write_zsreg(&dev->chanA, R9, 0xC0);	/* We must lock the udelay, the chip is offlimits here */	udelay(100);	spin_unlock_irqrestore(&dev->lock, flags);	return 0;}EXPORT_SYMBOL(z8530_shutdown);/** *	z8530_channel_load - Load channel data *	@c: Z8530 channel to configure *	@rtable: table of register, value pairs *	FIXME: ioctl to allow user uploaded tables * *	Load a Z8530 channel up from the system data. We use +16 to  *	indicate the "prime" registers. The value 255 terminates the *	table. */int z8530_channel_load(struct z8530_channel *c, u8 *rtable){	unsigned long flags;	spin_lock_irqsave(c->lock, flags);	while(*rtable!=255)	{		int reg=*rtable++;		if(reg>0x0F)			write_zsreg(c, R15, c->regs[15]|1);		write_zsreg(c, reg&0x0F, *rtable);		if(reg>0x0F)			write_zsreg(c, R15, c->regs[15]&~1);		c->regs[reg]=*rtable++;	}	c->rx_function=z8530_null_rx;	c->skb=NULL;	c->tx_skb=NULL;	c->tx_next_skb=NULL;	c->mtu=1500;	c->max=0;	c->count=0;	c->status=read_zsreg(c, R0);	c->sync=1;	write_zsreg(c, R3, c->regs[R3]|RxENABLE);	spin_unlock_irqrestore(c->lock, flags);	return 0;}EXPORT_SYMBOL(z8530_channel_load);/** *	z8530_tx_begin - Begin packet transmission *	@c: The Z8530 channel to kick * *	This is the speed sensitive side of transmission. If we are called *	and no buffer is being transmitted we commence the next buffer. If *	nothing is queued we idle the sync.  * *	Note: We are handling this code path in the interrupt path, keep it *	fast or bad things will happen. * *	Called with the lock held. */static void z8530_tx_begin(struct z8530_channel *c){	unsigned long flags;	if(c->tx_skb)		return;			c->tx_skb=c->tx_next_skb;	c->tx_next_skb=NULL;	c->tx_ptr=c->tx_next_ptr;		if(c->tx_skb==NULL)	{		/* Idle on */		if(c->dma_tx)		{			flags=claim_dma_lock();			disable_dma(c->txdma);			/*			 *	Check if we crapped out.			 */			if(get_dma_residue(c->txdma))			{				c->stats.tx_dropped++;				c->stats.tx_fifo_errors++;			}			release_dma_lock(flags);		}		c->txcount=0;	}	else	{		c->txcount=c->tx_skb->len;						if(c->dma_tx)		{			/*			 *	FIXME. DMA is broken for the original 8530,			 *	on the older parts we need to set a flag and			 *	wait for a further TX interrupt to fire this			 *	stage off				 */			 			flags=claim_dma_lock();			disable_dma(c->txdma);			/*			 *	These two are needed by the 8530/85C30			 *	and must be issued when idling.			 */			 			if(c->dev->type!=Z85230)			{				write_zsctrl(c, RES_Tx_CRC);				write_zsctrl(c, RES_EOM_L);			}				write_zsreg(c, R10, c->regs[10]&~ABUNDER);			clear_dma_ff(c->txdma);			set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr));			set_dma_count(c->txdma, c->txcount);			enable_dma(c->txdma);			release_dma_lock(flags);			write_zsctrl(c, RES_EOM_L);			write_zsreg(c, R5, c->regs[R5]|TxENAB);		}		else		{			/* ABUNDER off */			write_zsreg(c, R10, c->regs[10]);			write_zsctrl(c, RES_Tx_CRC);				while(c->txcount && (read_zsreg(c,R0)&Tx_BUF_EMP))			{						write_zsreg(c, R8, *c->tx_ptr++);				c->txcount--;			}		}	}	/*	 *	Since we emptied tx_skb we can ask for more	 */	netif_wake_queue(c->netdevice);}/** *	z8530_tx_done - TX complete callback *	@c: The channel that completed a transmit. * *	This is called when we complete a packet send. We wake the queue, *	start the next packet going and then free the buffer of the existing *	packet. This code is fairly timing sensitive. * *	Called with the register lock held. */  static void z8530_tx_done(struct z8530_channel *c){	struct sk_buff *skb;	/* Actually this can happen.*/	if(c->tx_skb==NULL)		return;	skb=c->tx_skb;	c->tx_skb=NULL;	z8530_tx_begin(c);	c->stats.tx_packets++;	c->stats.tx_bytes+=skb->len;	dev_kfree_skb_irq(skb);}/** *	z8530_null_rx - Discard a packet *	@c: The channel the packet arrived on *	@skb: The buffer * *	We point the receive handler at this function when idle. Instead *	of syncppp processing the frames we get to throw them away. */ void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb){	dev_kfree_skb_any(skb);}EXPORT_SYMBOL(z8530_null_rx);/** *	z8530_rx_done - Receive completion callback *	@c: The channel that completed a receive * *	A new packet is complete. Our goal here is to get back into receive *	mode as fast as possible. On the Z85230 we could change to using *	ESCC mode, but on the older chips we have no choice. We flip to the *	new buffer immediately in DMA mode so that the DMA of the next *	frame can occur while we are copying the previous buffer to an sk_buff * *	Called with the lock held */ static void z8530_rx_done(struct z8530_channel *c){	struct sk_buff *skb;	int ct;		/*	 *	Is our receive engine in DMA mode	 */	 	if(c->rxdma_on)	{		/*		 *	Save the ready state and the buffer currently		 *	being used as the DMA target		 */		 		int ready=c->dma_ready;		unsigned char *rxb=c->rx_buf[c->dma_num];		unsigned long flags;				/*		 *	Complete this DMA. Neccessary to find the length		 */				 		flags=claim_dma_lock();				disable_dma(c->rxdma);		clear_dma_ff(c->rxdma);		c->rxdma_on=0;		ct=c->mtu-get_dma_residue(c->rxdma);		if(ct<0)			ct=2;	/* Shit happens.. */		c->dma_ready=0;				/*		 *	Normal case: the other slot is free, start the next DMA		 *	into it immediately.		 */		 		if(ready)		{			c->dma_num^=1;			set_dma_mode(c->rxdma, DMA_MODE_READ|0x10);			set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num]));			set_dma_count(c->rxdma, c->mtu);			c->rxdma_on = 1;			enable_dma(c->rxdma);			/* Stop any frames that we missed the head of 			   from passing */			write_zsreg(c, R0, RES_Rx_CRC);		}		else			/* Can't occur as we dont reenable the DMA irq until			   after the flip is done */			printk(KERN_WARNING "%s: DMA flip overrun!\n", c->netdevice->name);					release_dma_lock(flags);				/*		 *	Shove the old buffer into an sk_buff. We can't DMA		 *	directly into one on a PC - it might be above the 16Mb		 *	boundary. Optimisation - we could check to see if we		 *	can avoid the copy. Optimisation 2 - make the memcpy		 *	a copychecksum.		 */		 		skb=dev_alloc_skb(ct);		if(skb==NULL)		{			c->stats.rx_dropped++;			printk(KERN_WARNING "%s: Memory squeeze.\n", c->netdevice->name);		}		else		{			skb_put(skb, ct);			memcpy(skb->data, rxb, ct);			c->stats.rx_packets++;			c->stats.rx_bytes+=ct;		}		c->dma_ready=1;	}	else	{		RT_LOCK;			skb=c->skb;				/*		 *	The game we play for non DMA is similar. We want to		 *	get the controller set up for the next packet as fast		 *	as possible. We potentially only have one byte + the		 *	fifo length for this. Thus we want to flip to the new		 *	buffer and then mess around copying and allocating		 *	things. For the current case it doesn't matter but		 *	if you build a system where the sync irq isnt blocked		 *	by the kernel IRQ disable then you need only block the		 *	sync IRQ for the RT_LOCK area.		 *			 */		ct=c->count;				c->skb = c->skb2;		c->count = 0;		c->max = c->mtu;		if(c->skb)		{			c->dptr = c->skb->data;			c->max = c->mtu;		}		else		{			c->count= 0;			c->max = 0;		}		RT_UNLOCK;		c->skb2 = dev_alloc_skb(c->mtu);		if(c->skb2==NULL)			printk(KERN_WARNING "%s: memory squeeze.\n",				c->netdevice->name);		else		{			skb_put(c->skb2,c->mtu);		}		c->stats.rx_packets++;		c->stats.rx_bytes+=ct;			}	/*	 *	If we received a frame we must now process it.	 */	if(skb)	{		skb_trim(skb, ct);		c->rx_function(c,skb);	}	else	{		c->stats.rx_dropped++;		printk(KERN_ERR "%s: Lost a frame\n", c->netdevice->name);	}}/** *	spans_boundary - Check a packet can be ISA DMA'd *	@skb: The buffer to check * *	Returns true if the buffer cross a DMA boundary on a PC. The poor *	thing can only DMA within a 64K block not across the edges of it. */ static inline int spans_boundary(struct sk_buff *skb){	unsigned long a=(unsigned long)skb->data;	a^=(a+skb->len);	if(a&0x00010000)	/* If the 64K bit is different.. */		return 1;	return 0;}/** *	z8530_queue_xmit - Queue a packet *	@c: The channel to use *	@skb: The packet to kick down the channel * *	Queue a packet for transmission. Because we have rather *	hard to hit interrupt latencies for the Z85230 per packet  *	even in DMA mode we do the flip to DMA buffer if needed here *	not in the IRQ. * *	Called from the network code. The lock is not held at this  *	point. */int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb){	unsigned long flags;		netif_stop_queue(c->netdevice);	if(c->tx_next_skb)	{		return 1;	}		/* PC SPECIFIC - DMA limits */		/*	 *	If we will DMA the transmit and its gone over the ISA bus	 *	limit, then copy to the flip buffer	 */	 	if(c->dma_tx && ((unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024 || spans_boundary(skb)))	{		/* 		 *	Send the flip buffer, and flip the flippy bit.		 *	We don't care which is used when just so long as		 *	we never use the same buffer twice in a row. Since		 *	only one buffer can be going out at a time the other		 *	has to be safe.		 */		c->tx_next_ptr=c->tx_dma_buf[c->tx_dma_used];		c->tx_dma_used^=1;	/* Flip temp buffer */		memcpy(c->tx_next_ptr, skb->data, skb->len);	}	else		c->tx_next_ptr=skb->data;		RT_LOCK;	c->tx_next_skb=skb;	RT_UNLOCK;		spin_lock_irqsave(c->lock, flags);	z8530_tx_begin(c);	spin_unlock_irqrestore(c->lock, flags);		return 0;}EXPORT_SYMBOL(z8530_queue_xmit);/** *	z8530_get_stats - Get network statistics *	@c: The channel to use * *	Get the statistics block. We keep the statistics in software as *	the chip doesn't do it for us. * *	Locking is ignored here - we could lock for a copy but its *	not likely to be that big an issue */ struct net_device_stats *z8530_get_stats(struct z8530_channel *c){	return &c->stats;}EXPORT_SYMBOL(z8530_get_stats);/* *	Module support */static char banner[] __initdata = KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n";static int __init z85230_init_driver(void){	printk(banner);	return 0;}module_init(z85230_init_driver);static void __exit z85230_cleanup_driver(void){}module_exit(z85230_cleanup_driver);MODULE_AUTHOR("Red Hat Inc.");MODULE_DESCRIPTION("Z85x30 synchronous driver core");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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