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

📄 scc.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		if (skb->len >= scc->stat.bufsize)	{#ifdef notdef		printk(KERN_DEBUG "z8530drv: oops, scc_rxint() received huge frame...\n");#endif		dev_kfree_skb_irq(skb);		scc->rx_buff = NULL;		Inb(scc->data);		or(scc, R3, ENT_HM);		return;	}	*(skb_put(skb, 1)) = Inb(scc->data);}/* Receive Special Condition interrupt handler */static inline void scc_spint(struct scc_channel *scc){	unsigned char status;	struct sk_buff *skb;	scc->stat.spints++;	status = InReg(scc->ctrl,R1);		/* read receiver status */		Inb(scc->data);				/* throw away Rx byte */	skb = scc->rx_buff;	if(status & Rx_OVR)			/* receiver overrun */	{		scc->stat.rx_over++;             /* count them */		or(scc,R3,ENT_HM);               /* enter hunt mode for next flag */				if (skb != NULL) 			dev_kfree_skb_irq(skb);		scc->rx_buff = skb = NULL;	}	if(status & END_FR && skb != NULL)	/* end of frame */	{		/* CRC okay, frame ends on 8 bit boundary and received something ? */				if (!(status & CRC_ERR) && (status & 0xe) == RES8 && skb->len > 0)		{			/* ignore last received byte (first of the CRC bytes) */			skb_trim(skb, skb->len-1);			scc_net_rx(scc, skb);			scc->rx_buff = NULL;			scc->stat.rxframes++;		} else {				/* a bad frame */			dev_kfree_skb_irq(skb);			scc->rx_buff = NULL;			scc->stat.rxerrs++;		}	} 	Outb(scc->ctrl,ERR_RES);}/* ----> interrupt service routine for the Z8530 <---- */static void scc_isr_dispatch(struct scc_channel *scc, int vector){	switch (vector & VECTOR_MASK)	{		case TXINT: scc_txint(scc); break;		case EXINT: scc_exint(scc); break;		case RXINT: scc_rxint(scc); break;		case SPINT: scc_spint(scc); break;	}}/* If the card has a latch for the interrupt vector (like the PA0HZP card)   use it to get the number of the chip that generated the int.   If not: poll all defined chips. */#define SCC_IRQTIMEOUT 30000static void scc_isr(int irq, void *dev_id, struct pt_regs *regs){	unsigned char vector;		struct scc_channel *scc;	struct scc_ctrl *ctrl;	int k;		if (Vector_Latch)	{	    	for(k=0; k < SCC_IRQTIMEOUT; k++)    		{			Outb(Vector_Latch, 0);      /* Generate INTACK */        			/* Read the vector */			if((vector=Inb(Vector_Latch)) >= 16 * Nchips) break; 			if (vector & 0x01) break;        	 		        scc=&SCC_Info[vector >> 3 ^ 0x01];			if (!scc->dev) break;			scc_isr_dispatch(scc, vector);			OutReg(scc->ctrl,R0,RES_H_IUS);              /* Reset Highest IUS */		}  		if (k == SCC_IRQTIMEOUT)			printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n");		return;	}	/* Find the SCC generating the interrupt by polling all attached SCCs	 * reading RR3A (the interrupt pending register)	 */	ctrl = SCC_ctrl;	while (ctrl->chan_A)	{		if (ctrl->irq != irq)		{			ctrl++;			continue;		}		scc = NULL;		for (k = 0; InReg(ctrl->chan_A,R3) && k < SCC_IRQTIMEOUT; k++)		{			vector=InReg(ctrl->chan_B,R2);	/* Read the vector */			if (vector & 0x01) break; 			scc = &SCC_Info[vector >> 3 ^ 0x01];		        if (!scc->dev) break;			scc_isr_dispatch(scc, vector);		}		if (k == SCC_IRQTIMEOUT)		{			printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?!\n");			break;		}		/* This looks weird and it is. At least the BayCom USCC doesn't		 * use the Interrupt Daisy Chain, thus we'll have to start		 * all over again to be sure not to miss an interrupt from 		 * (any of) the other chip(s)...		 * Honestly, the situation *is* braindamaged...		 */		if (scc != NULL)		{			OutReg(scc->ctrl,R0,RES_H_IUS);			ctrl = SCC_ctrl; 		} else			ctrl++;	}}/* ******************************************************************** *//* *			Init Channel					*//* ******************************************************************** *//* ----> set SCC channel speed <---- */static inline void set_brg(struct scc_channel *scc, unsigned int tc){	cl(scc,R14,BRENABL);		/* disable baudrate generator */	wr(scc,R12,tc & 255);		/* brg rate LOW */	wr(scc,R13,tc >> 8);   		/* brg rate HIGH */	or(scc,R14,BRENABL);		/* enable baudrate generator */}static inline void set_speed(struct scc_channel *scc){	disable_irq(scc->irq);	if (scc->modem.speed > 0)	/* paranoia... */		set_brg(scc, (unsigned) (scc->clock / (scc->modem.speed * 64)) - 2);	enable_irq(scc->irq);}/* ----> initialize a SCC channel <---- */static inline void init_brg(struct scc_channel *scc){	wr(scc, R14, BRSRC);				/* BRG source = PCLK */	OutReg(scc->ctrl, R14, SSBR|scc->wreg[R14]);	/* DPLL source = BRG */	OutReg(scc->ctrl, R14, SNRZI|scc->wreg[R14]);	/* DPLL NRZI mode */}/* * Initialization according to the Z8530 manual (SGS-Thomson's version): * * 1. Modes and constants * * WR9	11000000	chip reset * WR4	XXXXXXXX	Tx/Rx control, async or sync mode * WR1	0XX00X00	select W/REQ (optional) * WR2	XXXXXXXX	program interrupt vector * WR3	XXXXXXX0	select Rx control * WR5	XXXX0XXX	select Tx control * WR6	XXXXXXXX	sync character * WR7	XXXXXXXX	sync character * WR9	000X0XXX	select interrupt control * WR10	XXXXXXXX	miscellaneous control (optional) * WR11	XXXXXXXX	clock control * WR12	XXXXXXXX	time constant lower byte (optional) * WR13	XXXXXXXX	time constant upper byte (optional) * WR14	XXXXXXX0	miscellaneous control * WR14	XXXSSSSS	commands (optional) * * 2. Enables * * WR14	000SSSS1	baud rate enable * WR3	SSSSSSS1	Rx enable * WR5	SSSS1SSS	Tx enable * WR0	10000000	reset Tx CRG (optional) * WR1	XSS00S00	DMA enable (optional) * * 3. Interrupt status * * WR15	XXXXXXXX	enable external/status * WR0	00010000	reset external status * WR0	00010000	reset external status twice * WR1	SSSXXSXX	enable Rx, Tx and Ext/status * WR9	000SXSSS	enable master interrupt enable * * 1 = set to one, 0 = reset to zero * X = user defined, S = same as previous init * * * Note that the implementation differs in some points from above scheme. * */ static void init_channel(struct scc_channel *scc){	del_timer(&scc->tx_t);	del_timer(&scc->tx_wdog);	disable_irq(scc->irq);	wr(scc,R4,X1CLK|SDLC);		/* *1 clock, SDLC mode */	wr(scc,R1,0);			/* no W/REQ operation */	wr(scc,R3,Rx8|RxCRC_ENAB);	/* RX 8 bits/char, CRC, disabled */		wr(scc,R5,Tx8|DTR|TxCRC_ENAB);	/* TX 8 bits/char, disabled, DTR */	wr(scc,R6,0);			/* SDLC address zero (not used) */	wr(scc,R7,FLAG);		/* SDLC flag value */	wr(scc,R9,VIS);			/* vector includes status */	wr(scc,R10,(scc->modem.nrz? NRZ : NRZI)|CRCPS|ABUNDER); /* abort on underrun, preset CRC generator, NRZ(I) */	wr(scc,R14, 0);/* set clock sources:   CLK_DPLL: normal halfduplex operation   		RxClk: use DPLL		TxClk: use DPLL		TRxC mode DPLL output		   CLK_EXTERNAL: external clocking (G3RUH or DF9IC modem)     	        BayCom: 		others:  	          	        TxClk = pin RTxC	TxClk = pin TRxC  	        RxClk = pin TRxC 	RxClk = pin RTxC  	        CLK_DIVIDER:   		RxClk = use DPLL   		TxClk = pin RTxC   		   		BayCom:			others:   		pin TRxC = DPLL		pin TRxC = BRG   		(RxClk * 1)		(RxClk * 32)*/     			switch(scc->modem.clocksrc)	{		case CLK_DPLL:			wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP);			init_brg(scc);			break;		case CLK_DIVIDER:			wr(scc, R11, ((scc->brand & BAYCOM)? TRxCDP : TRxCBR) | RCDPLL|TCRTxCP|TRxCOI);			init_brg(scc);			break;		case CLK_EXTERNAL:			wr(scc, R11, (scc->brand & BAYCOM)? RCTRxCP|TCRTxCP : RCRTxCP|TCTRxCP);			OutReg(scc->ctrl, R14, DISDPLL);			break;	}		set_speed(scc);			/* set baudrate */		if(scc->enhanced)	{		or(scc,R15,SHDLCE|FIFOE);	/* enable FIFO, SDLC/HDLC Enhancements (From now R7 is R7') */		wr(scc,R7,AUTOEOM);	}	if(scc->kiss.softdcd || (InReg(scc->ctrl,R0) & DCD))						/* DCD is now ON */	{		start_hunt(scc);	}		/* enable ABORT, DCD & SYNC/HUNT interrupts */	wr(scc,R15, BRKIE|TxUIE|(scc->kiss.softdcd? SYNCIE:DCDIE));	Outb(scc->ctrl,RES_EXT_INT);	/* reset ext/status interrupts */	Outb(scc->ctrl,RES_EXT_INT);	/* must be done twice */	or(scc,R1,INT_ALL_Rx|TxINT_ENAB|EXT_INT_ENAB); /* enable interrupts */		scc->status = InReg(scc->ctrl,R0);	/* read initial status */		or(scc,R9,MIE);			/* master interrupt enable */		scc_init_timer(scc);				enable_irq(scc->irq);}/* ******************************************************************** *//* *			SCC timer functions			      * *//* ******************************************************************** *//* ----> scc_key_trx sets the time constant for the baudrate          generator and keys the transmitter		     <---- */static void scc_key_trx(struct scc_channel *scc, char tx){	unsigned int time_const;			if (scc->brand & PRIMUS)		Outb(scc->ctrl + 4, scc->option | (tx? 0x80 : 0));	if (scc->modem.speed < 300) 		scc->modem.speed = 1200;	time_const = (unsigned) (scc->clock / (scc->modem.speed * (tx? 2:64))) - 2;	disable_irq(scc->irq);	if (tx)	{		or(scc, R1, TxINT_ENAB);	/* t_maxkeyup may have reset these */		or(scc, R15, TxUIE);	}	if (scc->modem.clocksrc == CLK_DPLL)	{				/* force simplex operation */		if (tx)		{#ifdef CONFIG_SCC_TRXECHO			cl(scc, R3, RxENABLE|ENT_HM);	/* switch off receiver */			cl(scc, R15, DCDIE|SYNCIE);	/* No DCD changes, please */#endif			set_brg(scc, time_const);	/* reprogram baudrate generator */			/* DPLL -> Rx clk, BRG -> Tx CLK, TRxC mode output, TRxC = BRG */			wr(scc, R11, RCDPLL|TCBR|TRxCOI|TRxCBR);						/* By popular demand: tx_inhibit */			if (scc->kiss.tx_inhibit)			{				or(scc,R5, TxENAB);				scc->wreg[R5] |= RTS;			} else {				or(scc,R5,RTS|TxENAB);	/* set the RTS line and enable TX */			}		} else {			cl(scc,R5,RTS|TxENAB);						set_brg(scc, time_const);	/* reprogram baudrate generator */						/* DPLL -> Rx clk, DPLL -> Tx CLK, TRxC mode output, TRxC = DPLL */			wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP);#ifndef CONFIG_SCC_TRXECHO			if (scc->kiss.softdcd)#endif			{				or(scc,R15, scc->kiss.softdcd? SYNCIE:DCDIE);				start_hunt(scc);			}		}	} else {		if (tx)		{#ifdef CONFIG_SCC_TRXECHO			if (scc->kiss.fulldup == KISS_DUPLEX_HALF)			{				cl(scc, R3, RxENABLE);				cl(scc, R15, DCDIE|SYNCIE);			}#endif							if (scc->kiss.tx_inhibit)			{				or(scc,R5, TxENAB);				scc->wreg[R5] |= RTS;			} else {					or(scc,R5,RTS|TxENAB);	/* enable tx */			}		} else {			cl(scc,R5,RTS|TxENAB);		/* disable tx */			if ((scc->kiss.fulldup == KISS_DUPLEX_HALF) &&#ifndef CONFIG_SCC_TRXECHO			    scc->kiss.softdcd)#else			    1)#endif			{				or(scc, R15, scc->kiss.softdcd? SYNCIE:DCDIE);				start_hunt(scc);			}		}	}	enable_irq(scc->irq);}/* ----> SCC timer interrupt handler and friends. <---- */static void scc_start_tx_timer(struct scc_channel *scc, void (*handler)(unsigned long), unsigned long when){	unsigned long flags;			save_flags(flags);	cli();	del_timer(&scc->tx_t);	if (when == 0)	{		handler((unsigned long) scc);	} else 	if (when != TIMER_OFF)	{		scc->tx_t.data = (unsigned long) scc;		scc->tx_t.function = handler;		scc->tx_t.expires = jiffies + (when*HZ)/100;		add_timer(&scc->tx_t);	}		restore_flags(flags);}static void scc_start_defer(struct scc_channel *scc){	unsigned long flags;		save_flags(flags);	cli();	del_timer(&scc->tx_wdog);		if (scc->kiss.maxdefer != 0 && scc->kiss.maxdefer != TIMER_OFF)	{		scc->tx_wdog.data = (unsigned long) scc;		scc->tx_wdog.function = t_busy;		scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxdefer;		add_timer(&scc->tx_wdog);	}	restore_flags(flags);}static void scc_start_maxkeyup(struct scc_channel *scc){	unsigned long flags;		save_flags(flags);	cli();	del_timer(&scc->tx_wdog);		if (scc->kiss.maxkeyup != 0 && scc->kiss.maxkeyup != TIMER_OFF)	{		scc->tx_wdog.data = (unsigned long) scc;		scc->tx_wdog.function = t_maxkeyup;		scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup;		add_timer(&scc->tx_wdog);	}		restore_flags(flags);}/*  * This is called from scc_txint() when there are no more frames to send. * Not exactly a timer function, but it is a close friend of the family... */static void scc_tx_done(struct scc_channel *scc){	/* 	 * trx remains keyed in fulldup mode 2 until t_idle expires.	 */				 	switch (scc->kiss.fulldup)	{		case KISS_DUPLEX_LINK:			scc->stat.tx_state = TXS_IDLE2;			if (scc->kiss.idletime != TIMER_OFF)			scc_start_tx_timer(scc, t_idle, scc->kiss.idletime*100);			break;		case KISS_DUPLEX_OPTIMA:			scc_notify(scc, HWEV_ALL_SENT);			break;		default:			scc->stat.tx_state = TXS_BUSY;			scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime);	}	netif_wake_queue(scc->dev);}static unsigned char Rand = 17;static inline int is_grouped(struct scc_channel *scc){	int k;	struct scc_channel *scc2;	unsigned char grp1, grp2;

⌨️ 快捷键说明

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