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

📄 sktr.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Wait for interrupt from hardware. If interrupt does not come,	 * there will be a timeout from the timer.	 */	tp->Sleeping = 1;	interruptible_sleep_on(&tp->wait_for_tok_int);	del_timer(&tp->timer);	/* If AdapterVirtOpenFlag is 1, the adapter is now open for use */	if(tp->AdapterVirtOpenFlag == 0)	{		sktr_disable_interrupts(dev);		return (-1);	}	dev->start = 1;	tp->StartTime = jiffies;	/* Start function control timer */	tp->timer.expires	= jiffies + 2*HZ;	tp->timer.function	= sktr_timer_chk;	tp->timer.data		= (unsigned long)dev;	add_timer(&tp->timer);#ifdef MODULE	MOD_INC_USE_COUNT;#endif	return (0);}/* * Timeout function while waiting for event */static void sktr_timer_end_wait(unsigned long data){	struct device *dev = (struct device*)data;	struct net_local *tp = (struct net_local *)dev->priv;	if(tp->Sleeping)	{		tp->Sleeping = 0;		wake_up_interruptible(&tp->wait_for_tok_int);	}	return;}/* * Initialize the chipset */static int sktr_chipset_init(struct device *dev){	struct net_local *tp = (struct net_local *)dev->priv;	unsigned char PosReg, Tmp;	int i, err;	sktr_init_ipb(tp);	sktr_init_opb(tp);	sktr_init_net_local(dev);	/* Set pos register: selects irq and dma channel.	 * Only for ISA bus adapters.	 */	if(dev->dma > 0)	{		PosReg = 0;		for(i = 0; sktr_irqlist[i] != 0; i++)		{			if(sktr_irqlist[i] == dev->irq)				break;		}		/* Choose default cycle time, 500 nsec   */		PosReg |= CYCLE_TIME << 2;		PosReg |= i << 4;		i = dev->dma - 5;		PosReg |= i;		if(tp->DataRate == SPEED_4)			PosReg |= LINE_SPEED_BIT;		else			PosReg &= ~LINE_SPEED_BIT;		outb(PosReg, dev->base_addr + POSREG);		Tmp = inb(dev->base_addr + POSREG);		if((Tmp & ~CYCLE_TIME) != (PosReg & ~CYCLE_TIME))			printk(KERN_INFO "%s: POSREG error\n", dev->name);	}	err = sktr_reset_adapter(dev);	if(err < 0)		return (-1);	err = sktr_bringup_diags(dev);	if(err < 0)		return (-1);	err = sktr_init_adapter(dev);	if(err < 0)		return (-1);	return (0);}/* * Initializes the net_local structure. */static void sktr_init_net_local(struct device *dev){	struct net_local *tp = (struct net_local *)dev->priv;	int i;	tp->scb.CMD	= 0;	tp->scb.Parm[0] = 0;	tp->scb.Parm[1] = 0;	tp->ssb.STS	= 0;	tp->ssb.Parm[0] = 0;	tp->ssb.Parm[1] = 0;	tp->ssb.Parm[2] = 0;	tp->CMDqueue	= 0;	tp->AdapterOpenFlag	= 0;	tp->AdapterVirtOpenFlag = 0;	tp->ScbInUse		= 0;	tp->OpenCommandIssued	= 0;	tp->ReOpenInProgress	= 0;	tp->HaltInProgress	= 0;	tp->TransmitHaltScheduled = 0;	tp->LobeWireFaultLogged	= 0;	tp->LastOpenStatus	= 0;	tp->MaxPacketSize	= DEFAULT_PACKET_SIZE;	skb_queue_head_init(&tp->SendSkbQueue);	tp->QueueSkb = MAX_TX_QUEUE;	/* Create circular chain of transmit lists */	for (i = 0; i < TPL_NUM; i++)	{		tp->Tpl[i].NextTPLAddr = htonl((unsigned long) virt_to_bus(&tp->Tpl[(i+1) % TPL_NUM]));		tp->Tpl[i].Status	= 0;		tp->Tpl[i].FrameSize	= 0;		tp->Tpl[i].FragList[0].DataCount	= 0;		tp->Tpl[i].FragList[0].DataAddr		= 0;		tp->Tpl[i].NextTPLPtr	= &tp->Tpl[(i+1) % TPL_NUM];		tp->Tpl[i].MData	= NULL;		tp->Tpl[i].TPLIndex	= i;		tp->Tpl[i].BusyFlag	= 0;	}	tp->TplFree = tp->TplBusy = &tp->Tpl[0];	/* Create circular chain of receive lists */	for (i = 0; i < RPL_NUM; i++)	{		tp->Rpl[i].NextRPLAddr = htonl((unsigned long) virt_to_bus(&tp->Rpl[(i+1) % RPL_NUM]));		tp->Rpl[i].Status = (RX_VALID | RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);		tp->Rpl[i].FrameSize = 0;		tp->Rpl[i].FragList[0].DataCount = SWAPB(tp->MaxPacketSize);		/* Alloc skb and point adapter to data area */		tp->Rpl[i].Skb = dev_alloc_skb(tp->MaxPacketSize);		/* skb == NULL ? then use local buffer */		if(tp->Rpl[i].Skb == NULL)		{			tp->Rpl[i].SkbStat = SKB_UNAVAILABLE;			tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));			tp->Rpl[i].MData = tp->LocalRxBuffers[i];		}		else	/* SKB != NULL */		{			tp->Rpl[i].Skb->dev = dev;			skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize);			/* data unreachable for DMA ? then use local buffer */			if(virt_to_bus(tp->Rpl[i].Skb->data) + tp->MaxPacketSize > ISA_MAX_ADDRESS)			{				tp->Rpl[i].SkbStat = SKB_DATA_COPY;				tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));				tp->Rpl[i].MData = tp->LocalRxBuffers[i];			}			else	/* DMA directly in skb->data */			{				tp->Rpl[i].SkbStat = SKB_DMA_DIRECT;				tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->Rpl[i].Skb->data));				tp->Rpl[i].MData = tp->Rpl[i].Skb->data;			}		}		tp->Rpl[i].NextRPLPtr = &tp->Rpl[(i+1) % RPL_NUM];		tp->Rpl[i].RPLIndex = i;	}	tp->RplHead = &tp->Rpl[0];	tp->RplTail = &tp->Rpl[RPL_NUM-1];	tp->RplTail->Status = (RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);	return;}/* * Initializes the initialisation parameter block. */static void sktr_init_ipb(struct net_local *tp){	tp->ipb.Init_Options	= BURST_MODE;	tp->ipb.CMD_Status_IV	= 0;	tp->ipb.TX_IV		= 0;	tp->ipb.RX_IV		= 0;	tp->ipb.Ring_Status_IV	= 0;	tp->ipb.SCB_Clear_IV	= 0;	tp->ipb.Adapter_CHK_IV	= 0;	tp->ipb.RX_Burst_Size	= BURST_SIZE;	tp->ipb.TX_Burst_Size	= BURST_SIZE;	tp->ipb.DMA_Abort_Thrhld = DMA_RETRIES;	tp->ipb.SCB_Addr	= 0;	tp->ipb.SSB_Addr	= 0;	return;}/* * Initializes the open parameter block. */static void sktr_init_opb(struct net_local *tp){	unsigned long Addr;	unsigned short RplSize    = RPL_SIZE;	unsigned short TplSize    = TPL_SIZE;	unsigned short BufferSize = BUFFER_SIZE;	tp->ocpl.OPENOptions 	 = 0;	tp->ocpl.OPENOptions 	|= ENABLE_FULL_DUPLEX_SELECTION;	tp->ocpl.OPENOptions 	|= PAD_ROUTING_FIELD;	tp->ocpl.FullDuplex 	 = 0;	tp->ocpl.FullDuplex 	|= OPEN_FULL_DUPLEX_OFF;	/* Fixme: If mac address setable:	 * for (i=0; i<LENGTH_OF_ADDRESS; i++)	 *	mac->Vam->ocpl.NodeAddr[i] = mac->CurrentAddress[i];	 */	tp->ocpl.GroupAddr	 = 0;	tp->ocpl.FunctAddr	 = 0;	tp->ocpl.RxListSize	 = SWAPB(RplSize);	tp->ocpl.TxListSize	 = SWAPB(TplSize);	tp->ocpl.BufSize	 = SWAPB(BufferSize);	tp->ocpl.Reserved	 = 0;	tp->ocpl.TXBufMin	 = TX_BUF_MIN;	tp->ocpl.TXBufMax	 = TX_BUF_MAX;	Addr = htonl(virt_to_bus(tp->ProductID));	tp->ocpl.ProdIDAddr[0]	 = LOWORD(Addr);	tp->ocpl.ProdIDAddr[1]	 = HIWORD(Addr);	return;}/* * Send OPEN command to adapter */static void sktr_open_adapter(struct device *dev){	struct net_local *tp = (struct net_local *)dev->priv;	if(tp->OpenCommandIssued)		return;	tp->OpenCommandIssued = 1;	sktr_exec_cmd(dev, OC_OPEN);	return;}/* * Clear the adapter's interrupt flag. Clear system interrupt enable * (SINTEN): disable adapter to system interrupts. */static void sktr_disable_interrupts(struct device *dev){	outb(0, dev->base_addr + SIFACL);	return;}/* * Set the adapter's interrupt flag. Set system interrupt enable * (SINTEN): enable adapter to system interrupts. */static void sktr_enable_interrupts(struct device *dev){	outb(ACL_SINTEN, dev->base_addr + SIFACL);	return;}/* * Put command in command queue, try to execute it. */static void sktr_exec_cmd(struct device *dev, unsigned short Command){	struct net_local *tp = (struct net_local *)dev->priv;	tp->CMDqueue |= Command;	sktr_chk_outstanding_cmds(dev);	return;}/* * Linux always gives 18 byte of source routing information in the frame header. * But the length field can indicate shorter length. Then cut header * appropriate. */static unsigned char *sktr_fix_srouting(unsigned char *buf, short *FrameLen){	struct trh_hdr *trh = (struct trh_hdr *)buf;	int len;        	if(buf[8] & TR_RII)	{		trh->rcf &= ~SWAPB((unsigned short) TR_RCF_LONGEST_FRAME_MASK);		trh->rcf |= SWAPB((unsigned short) TR_RCF_FRAME4K);		len = (SWAPB(trh->rcf) & TR_RCF_LEN_MASK) >> 8;		if(len < 18)		{			memcpy(&buf[18-len],buf,sizeof(struct trh_hdr)-18+len);			*FrameLen -= (18 - len);		}		return (&buf[18-len]);	}	return (buf);}/* * Gets skb from system, queues it and checks if it can be sent */static int sktr_send_packet(struct sk_buff *skb, struct device *dev){	struct net_local *tp = (struct net_local *)dev->priv;	if(dev->tbusy)	{		/*		 * If we get here, some higher level has decided we are broken.		 * There should really be a "kick me" function call instead.		 *		 * Resetting the token ring adapter takes a long time so just		 * fake transmission time and go on trying. Our own timeout		 * routine is in sktr_timer_chk()		 */		dev->tbusy 	 = 0;		dev->trans_start = jiffies;		return (1);	}	/*	 * If some higher layer thinks we've missed an tx-done interrupt we	 * are passed NULL.	 */	if(skb == NULL)		return (0);	/*	 * Block a timer-based transmit from overlapping. This could better be	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.	 */	if(test_and_set_bit(0, (void*)&dev->tbusy) != 0)	{		printk("%s: Transmitter access conflict.\n", dev->name);		return (1);	}	if(tp->QueueSkb == 0)		return (1);	/* Return with tbusy set: queue full */	tp->QueueSkb--;	skb_queue_tail(&tp->SendSkbQueue, skb);	sktr_hardware_send_packet(dev, tp);	if(tp->QueueSkb > 0)		dev->tbusy = 0;	return (0);}/* * Move frames from internal skb queue into adapter tx queue */static void sktr_hardware_send_packet(struct device *dev, struct net_local* tp){	TPL *tpl;	short length;	unsigned char *buf, *newbuf;	struct sk_buff *skb;	int i;    	for(;;)	{		/* Try to get a free TPL from the chain.		 *		 * NOTE: We *must* always leave one unused TPL in the chain, 		 * because otherwise the adapter might send frames twice.		 */		if(tp->TplFree->NextTPLPtr->BusyFlag)	/* No free TPL */		{			printk(KERN_INFO "%s: No free TPL\n", dev->name);			return;		}		/* Send first buffer from queue */		skb = skb_dequeue(&tp->SendSkbQueue);		if(skb == NULL)			return;		tp->QueueSkb++;		/* Is buffer reachable for Busmaster-DMA? */		if(virt_to_bus((void*)(((long) skb->data) + skb->len))			> ISA_MAX_ADDRESS)		{			/* Copy frame to local buffer */			i 	= tp->TplFree->TPLIndex;			length 	= skb->len;			buf 	= tp->LocalTxBuffers[i];			memcpy(buf, skb->data, length);			newbuf 	= sktr_fix_srouting(buf, &length);		}		else		{			/* Send direct from skb->data */			length = skb->len;			newbuf = sktr_fix_srouting(skb->data, &length);		}		/* Source address in packet? */		sktr_chk_src_addr(newbuf, dev->dev_addr);		tp->LastSendTime	= jiffies;		tpl 			= tp->TplFree;	/* Get the "free" TPL */		tpl->BusyFlag 		= 1;		/* Mark TPL as busy */		tp->TplFree 		= tpl->NextTPLPtr;    		/* Save the skb for delayed return of skb to system */		tpl->Skb = skb;		tpl->FragList[0].DataCount = (unsigned short) SWAPB(length);		tpl->FragList[0].DataAddr  = htonl(virt_to_bus(newbuf));		/* Write the data length in the transmit list. */		tpl->FrameSize 	= (unsigned short) SWAPB(length);		tpl->MData 	= newbuf;		/* Transmit the frame and set the status values. */		sktr_write_tpl_status(tpl, TX_VALID | TX_START_FRAME					| TX_END_FRAME | TX_PASS_SRC_ADDR					| TX_FRAME_IRQ);		/* Let adapter send the frame. */		sktr_exec_sifcmd(dev, CMD_TX_VALID);	}	return;}/* * Write the given value to the 'Status' field of the specified TPL. * NOTE: This function should be used whenever the status of any TPL must be * modified by the driver, because the compiler may otherwise change the * order of instructions such that writing the TPL 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 sktr_write_tpl_status(TPL *tpl, unsigned int Status){	tpl->Status = Status;}static void sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr){	unsigned char SRBit;	if((((unsigned long)frame[8]) & ~0x80) != 0)	/* Compare 4 bytes */		return;	if((unsigned short)frame[12] != 0)		/* Compare 2 bytes */		return;	SRBit = frame[8] & 0x80;	memcpy(&frame[8], hw_addr, 6);	frame[8] |= SRBit;	return;}/* * The timer routine: Check if adapter still open and working, reopen if not.  */static void sktr_timer_chk(unsigned long data){	struct device *dev = (struct device*)data;	struct net_local *tp = (struct net_local*)dev->priv;	if(tp->HaltInProgress)		return;	sktr_chk_outstanding_cmds(dev);	if(time_before(tp->LastSendTime + SEND_TIMEOUT, jiffies)		&& (tp->QueueSkb < MAX_TX_QUEUE || tp->TplFree != tp->TplBusy))	{		/* Anything to send, but stalled to long */		tp->LastSendTime = jiffies;		sktr_exec_cmd(dev, OC_CLOSE);	/* Does reopen automatically */

⌨️ 快捷键说明

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