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

📄 tms380tr.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Reads a number of bytes from adapter to system memory. */static void tms380tr_read_ram(struct net_device *dev, unsigned char *Data,				unsigned short Address, int Length){	int i;	unsigned short old_sifadx, old_sifadr, InWord;	/* Save the current values */	old_sifadx = SIFREADW(SIFADX);	old_sifadr = SIFREADW(SIFADR);	/* Page number of adapter memory */	SIFWRITEW(0x0001, SIFADX);	/* Address offset in adapter RAM */        SIFWRITEW(Address, SIFADR);	/* Copy len byte from adapter memory to system data area. */	i = 0;	for(;;)	{		InWord = SIFREADW(SIFINC);		*(Data + i) = HIBYTE(InWord);	/* Write first byte */		if(++i == Length)		/* All is done break */			break;		*(Data + i) = LOBYTE(InWord);	/* Write second byte */		if (++i == Length)		/* All is done break */			break;	}	/* Restore original values */	SIFWRITEW(old_sifadx, SIFADX);	SIFWRITEW(old_sifadr, SIFADR);	return;}/* * Cancel all queued packets in the transmission queue. */static void tms380tr_cancel_tx_queue(struct net_local* tp){	TPL *tpl;	struct sk_buff *skb;	/*	 * NOTE: There must not be an active TRANSMIT command pending, when	 * this function is called.	 */	if(tp->TransmitCommandActive)		return;	for(;;)	{		tpl = tp->TplBusy;		if(!tpl->BusyFlag)			break;		/* "Remove" TPL from busy list. */		tp->TplBusy = tpl->NextTPLPtr;		tms380tr_write_tpl_status(tpl, 0);	/* Clear VALID bit */		tpl->BusyFlag = 0;		/* "free" TPL */		printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl);		dev_kfree_skb(tpl->Skb);	}	for(;;)	{		skb = skb_dequeue(&tp->SendSkbQueue);		if(skb == NULL)			break;		tp->QueueSkb++;		dev_kfree_skb(skb);	}	return;}/* * This function is called whenever a transmit interrupt is generated by the * adapter. For a command complete interrupt, it is checked if we have to * issue a new transmit command or not. */static void tms380tr_tx_status_irq(struct net_device *dev){	struct net_local *tp = (struct net_local *)dev->priv;	unsigned char HighByte, HighAc, LowAc;	TPL *tpl;	/* NOTE: At this point the SSB from TRANSMIT STATUS is no longer	 * available, because the CLEAR SSB command has already been issued.	 *	 * Process all complete transmissions.	 */	for(;;)	{		tpl = tp->TplBusy;		if(!tpl->BusyFlag || (tpl->Status			& (TX_VALID | TX_FRAME_COMPLETE))			!= TX_FRAME_COMPLETE)		{			break;		}		/* "Remove" TPL from busy list. */		tp->TplBusy = tpl->NextTPLPtr ;		/* Check the transmit status field only for directed frames*/		if(DIRECTED_FRAME(tpl) && (tpl->Status & TX_ERROR) == 0)		{			HighByte = GET_TRANSMIT_STATUS_HIGH_BYTE(tpl->Status);			HighAc   = GET_FRAME_STATUS_HIGH_AC(HighByte);			LowAc    = GET_FRAME_STATUS_LOW_AC(HighByte);			if((HighAc != LowAc) || (HighAc == AC_NOT_RECOGNIZED))			{				printk(KERN_INFO "%s: (DA=%08lX not recognized)",					dev->name,					*(unsigned long *)&tpl->MData[2+2]);			}			else			{				if(tms380tr_debug > 3)					printk("%s: Directed frame tx'd\n", 						dev->name);			}		}		else		{			if(!DIRECTED_FRAME(tpl))			{				if(tms380tr_debug > 3)					printk("%s: Broadcast frame tx'd\n",						dev->name);			}		}		tp->MacStat.tx_packets++;		dev_kfree_skb(tpl->Skb);		tpl->BusyFlag = 0;	/* "free" TPL */	}	netif_wake_queue(dev);	if(tp->QueueSkb < MAX_TX_QUEUE)		tms380tr_hardware_send_packet(dev, tp);	return;}/* * Called if a frame receive interrupt is generated by the adapter. * Check if the frame is valid and indicate it to system. */static void tms380tr_rcv_status_irq(struct net_device *dev){	struct net_local *tp = (struct net_local *)dev->priv;	unsigned char *ReceiveDataPtr;	struct sk_buff *skb;	unsigned int Length, Length2;	RPL *rpl;	RPL *SaveHead;	/* NOTE: At this point the SSB from RECEIVE STATUS is no longer	 * available, because the CLEAR SSB command has already been issued.	 *	 * Process all complete receives.	 */	for(;;)	{		rpl = tp->RplHead;		if(rpl->Status & RX_VALID)			break;		/* RPL still in use by adapter */		/* Forward RPLHead pointer to next list. */		SaveHead = tp->RplHead;		tp->RplHead = rpl->NextRPLPtr;		/* Get the frame size (Byte swap for Intel).		 * Do this early (see workaround comment below)		 */		Length = be16_to_cpu((unsigned short)rpl->FrameSize);		/* Check if the Frame_Start, Frame_End and		 * Frame_Complete bits are set.		 */		if((rpl->Status & VALID_SINGLE_BUFFER_FRAME)			== VALID_SINGLE_BUFFER_FRAME)		{			ReceiveDataPtr = rpl->MData;			/* Workaround for delayed write of FrameSize on ISA			 * (FrameSize is false but valid-bit is reset)			 * Frame size is set to zero when the RPL is freed.			 * Length2 is there because there have also been			 * cases where the FrameSize was partially written			 */			Length2 = be16_to_cpu((unsigned short)rpl->FrameSize);			if(Length == 0 || Length != Length2)			{				tp->RplHead = SaveHead;				break;	/* Return to tms380tr_interrupt */			}#if 0  		/* This might happen for multicast or broadcast packets.		   The upper layers are expected to handle this, not here */			/* Drop frames sent by myself */			if(tms380tr_chk_frame(dev, rpl->MData))			{				printk(KERN_INFO "%s: Received my own frame\n",					dev->name);				if(rpl->Skb != NULL)					dev_kfree_skb(rpl->Skb);			}			else#endif			{			  tms380tr_update_rcv_stats(tp,ReceiveDataPtr,Length);			  			  if(tms380tr_debug > 3)			    printk("%s: Packet Length %04X (%d)\n",				   dev->name, Length, Length);			  				/* Indicate the received frame to system the				 * adapter does the Source-Routing padding for 				 * us. See: OpenOptions in tms380tr_init_opb()				 */				skb = rpl->Skb;				if(rpl->SkbStat == SKB_UNAVAILABLE)				{					/* Try again to allocate skb */					skb = dev_alloc_skb(tp->MaxPacketSize);					if(skb == NULL)					{						/* Update Stats ?? */					}					else					{						skb->dev	= dev;						skb_put(skb, tp->MaxPacketSize);						rpl->SkbStat 	= SKB_DATA_COPY;						ReceiveDataPtr 	= rpl->MData;					}				}				if(rpl->SkbStat == SKB_DATA_COPY					|| rpl->SkbStat == SKB_DMA_DIRECT)				{					if(rpl->SkbStat == SKB_DATA_COPY)						memmove(skb->data, ReceiveDataPtr, Length);					/* Deliver frame to system */					rpl->Skb = NULL;					skb_trim(skb,Length);					skb->protocol = tr_type_trans(skb,dev);					netif_rx(skb);				}			}		}		else	/* Invalid frame */		{			if(rpl->Skb != NULL)				dev_kfree_skb(rpl->Skb);			/* Skip list. */			if(rpl->Status & RX_START_FRAME)				/* Frame start bit is set -> overflow. */				tp->MacStat.rx_errors++;		}		/* Allocate new skb for rpl */		rpl->Skb = dev_alloc_skb(tp->MaxPacketSize);		/* skb == NULL ? then use local buffer */		if(rpl->Skb == NULL)		{			rpl->SkbStat = SKB_UNAVAILABLE;			rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex]));			rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex];		}		else	/* skb != NULL */		{			rpl->Skb->dev = dev;			skb_put(rpl->Skb, tp->MaxPacketSize);			/* Data unreachable for DMA ? then use local buffer */			if(tp->dmalimit && virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize > tp->dmalimit)			{				rpl->SkbStat = SKB_DATA_COPY;				rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex]));				rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex];			}			else			{				/* DMA directly in skb->data */				rpl->SkbStat = SKB_DMA_DIRECT;				rpl->FragList[0].DataAddr = htonl(virt_to_bus(rpl->Skb->data));				rpl->MData = rpl->Skb->data;			}		}		rpl->FragList[0].DataCount = cpu_to_be16((unsigned short)tp->MaxPacketSize);		rpl->FrameSize = 0;		/* Pass the last RPL back to the adapter */		tp->RplTail->FrameSize = 0;		/* Reset the CSTAT field in the list. */		tms380tr_write_rpl_status(tp->RplTail, RX_VALID | RX_FRAME_IRQ);		/* Current RPL becomes last one in list. */		tp->RplTail = tp->RplTail->NextRPLPtr;		/* Inform adapter about RPL valid. */		tms380tr_exec_sifcmd(dev, CMD_RX_VALID);	}	return;}/* * This function should be used whenever the status of any RPL must be * modified by the driver, because the compiler may otherwise change the * order of instructions such that writing the RPL status may be executed * at an undesireable time. When this function is used, the status is * always written when the function is called. */static void tms380tr_write_rpl_status(RPL *rpl, unsigned int Status){	rpl->Status = Status;	return;}/* * The function updates the statistic counters in mac->MacStat. * It differtiates between directed and broadcast/multicast ( ==functional) * frames. */static void tms380tr_update_rcv_stats(struct net_local *tp, unsigned char DataPtr[],					unsigned int Length){	tp->MacStat.rx_packets++;	tp->MacStat.rx_bytes += Length;		/* Test functional bit */	if(DataPtr[2] & GROUP_BIT)		tp->MacStat.multicast++;	return;}#if 0/* * Check if it is a frame of myself. Compare source address with my current * address in reverse direction, and mask out the TR_RII. */static unsigned char tms380tr_chk_frame(struct net_device *dev, unsigned char *Addr){	int i;	for(i = 5; i > 0; i--)	{		if(Addr[8 + i] != dev->dev_addr[i])			return (0);	}	/* Mask out RIF bit. */	if((Addr[8] & ~TR_RII) != (unsigned char)(dev->dev_addr[0]))		return (0);	return (1);  /* It is my frame. */}#endifstatic int tms380tr_set_mac_address(struct net_device *dev, void *addr){	struct net_local *tp = (struct net_local *)dev->priv;	struct sockaddr *saddr = addr;		if (tp->AdapterOpenFlag || tp->AdapterVirtOpenFlag) {		printk(KERN_WARNING "%s: Cannot set MAC/LAA address while card is open\n", dev->name);		return -EIO;	}	memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len);	return 0;}#if TMS380TR_DEBUG > 0/* * Dump Packet (data) */static void tms380tr_dump(unsigned char *Data, int length){	int i, j;	for (i = 0, j = 0; i < length / 8; i++, j += 8)	{		printk(KERN_DEBUG "%02x %02x %02x %02x %02x %02x %02x %02x\n",		       Data[j+0],Data[j+1],Data[j+2],Data[j+3],		       Data[j+4],Data[j+5],Data[j+6],Data[j+7]);	}	return;}#endifint tmsdev_init(struct net_device *dev){	if (dev->priv == NULL)	{		struct net_local *tms_local;				dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL | GFP_DMA);		if (dev->priv == NULL)			return -ENOMEM;		memset(dev->priv, 0, sizeof(struct net_local));		tms_local = (struct net_local *)dev->priv;		init_waitqueue_head(&tms_local->wait_for_tok_int);	}		/* These can be overridden by the card driver if needed */	dev->init		= tms380tr_init_card;	dev->open		= tms380tr_open;	dev->stop		= tms380tr_close;	dev->do_ioctl		= NULL; 	dev->hard_start_xmit	= tms380tr_send_packet;	dev->tx_timeout		= tms380tr_timeout;	dev->watchdog_timeo	= HZ;	dev->get_stats		= tms380tr_get_stats;	dev->set_multicast_list = &tms380tr_set_multicast_list;	dev->set_mac_address	= tms380tr_set_mac_address;	return 0;}#ifdef MODULEEXPORT_SYMBOL(tms380tr_open);EXPORT_SYMBOL(tms380tr_close);EXPORT_SYMBOL(tms380tr_interrupt);EXPORT_SYMBOL(tmsdev_init);EXPORT_SYMBOL(tms380tr_wait);struct module *TMS380_module = NULL;int init_module(void){	printk("%s", version);		TMS380_module = &__this_module;	return 0;}void cleanup_module(void){	TMS380_module = NULL;}#endif/* * Local variables: *  compile-command: "gcc -DMODVERSIONS  -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tms380tr.c" *  alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tms380tr.c" *  c-set-style "K&R" *  c-indent-level: 8 *  c-basic-offset: 8 *  tab-width: 8 * End: */

⌨️ 快捷键说明

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