patch-1.3.11 linux/drivers/char/scc.c

Next file: linux/drivers/net/Makefile
Previous file: linux/drivers/block/sjcd.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.10/linux/drivers/char/scc.c linux/drivers/char/scc.c
@@ -1,9 +1,8 @@
 #include <linux/autoconf.h>	/* fastest method */
 #ifdef CONFIG_SCC
 
-#define RCS_ID "$Id: scc.c,v 1.17 1995/03/15 23:28:12 JReuter Exp JReuter $"
 
-#define BANNER "Z8530 SCC driver v1.8.dl1bke (beta) by dl1bke\n"
+#define BANNER "Z8530 SCC driver v1.8.17test.17.7.95 PE1AYX (c)\n"
 
 /* ******************************************************************** */
 /* *   SCC.C - Linux driver for Z8530 based HDLC cards for AX.25      *	*/ 
@@ -11,34 +10,45 @@
 
 /* ********************************************************************
 
-	(c) 1995 by Joerg Reuter DL1BKE
+	(c) Hans Alblas PE1AYX 1993,1994,1995
+	          Released for GNU
+	portions (c) 1995 by Joerg Reuter DL1BKE
+	         (c) 1993 Guido ten Dolle PE1NNZ
 
-	portions (c) 1994 Hans Alblas PE1AYX 
-	and      (c) 1993 Guido ten Dolle PE1NNZ
-
-	for the complete copyright notice see >> Copying.Z8530DRV <<
 
    ********************************************************************	*/   
 
 /*
 
-   940913	- started to rewrite the drive
-   950131	- changed copyright notice to GPL without limitations.
+
+   931100	- started with the projekt pe1ayx
+   9406??	- KISS-parameter setting and BayCom USCC support dl1bke
+   940613	- fixed memory leak ,main memory fragmentation problem,
+                  speeded up the interupt routines ,has now its own
+                  memory buffer pool and source cleanup. pe1ayx
+   940620	- bug fixed in line disipline change ,local ringbuf
+   		  reorganisation ,and some little bugfixes.
+   940715	- first release to the public (scc15b.tgz) pe1ayx		                
    950228	- (hopefully) fixed the reason for kernel panics in
-                  chk_rcv_queue() [stupid error]
-   950304       - fixed underrun/zcount handling
-   950305	- the driver registers port addresses now
-   950314	- fixed underrun interrupt handling again
+                  chk_rcv_queue() [stupid error] dl1bke
+   950229       - buffer timeout for vergotten buffer :-( pe1ayx                
+   950304       - fixed underrun/zcount handling dl1bke
+   950305	- the driver registers port addresses now dl1bke
+   950314	- fixed underrun interrupt handling again dl1bke
+   950514	- fixed slip tty wakeup (it wil now work again with kernel ax25)pe1ayx
+   950703	- rewrote the 8530 init/reset routines pe1ayx
+   950712	- rewrote the RXirq + buffering routines pe1ayx
+   950716	- It can now handle ax25 rx frame info > 256
+   O		- rewrite TX + buffering (there is a little mem leak ,but
+                  wil not be dangerous since my buffer timeout routine
+                  wil put back vergotten buffers in the queue pe1ayx
+   O		- change the tty i/o so that the tty wakeup is handled properly
+           	  pe1ayx
    
    Thanks to:
-   
+   DL1BKE Joerg - for some good ideas
    PE1CHL Rob	- for a lot of good ideas from his SCC driver for DOS
    PE1NNZ Guido - for his port of the original driver to Linux
-   KA9Q   Phil  - from whom we stole the mbuf-structure
-   PA3AYX Hans  - who rewrote the memory management and some minor,
-                  but nevertheless useful changes
-   DL8MBT Flori - for support
-   DG0FT  Rene  - for the BayCom USCC support
    PA3AOU Harry - for ESCC testing, information supply and support
    
    PE1KOX Rob, DG1RTF Thomas, ON5QK Roland, 
@@ -46,13 +56,7 @@
    and all who sent me bug reports and ideas... 
    
    
-   NB -- if you find errors, change something, please let me know
-      	 first before you distribute it... And please don't touch
-   	 the version number. Just replace my callsign in
-   	 "v1.8.dl1bke" with your own. Just to avoid confusion...
-   	  
-   Jörg Reuter DL1BKE
-   
+      
 */
 
 
@@ -110,8 +114,6 @@
 static void z8530_init(void);
 
 static void scc_change_speed(struct scc_channel *scc);
-static void kiss_encode(struct scc_channel *scc);
-
 static void init_channel(struct scc_channel *scc);
 static void scc_key_trx (struct scc_channel *scc, char tx);
 static void scc_txint(register struct scc_channel *scc);
@@ -124,6 +126,14 @@
 
 /* from serial.c */
 
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+static unsigned char *tmp_buf = 0;
+static struct semaphore tmp_buf_sem = MUTEX;
+static unsigned int start_controle;
+
 static int baud_table[] = {
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
 	9600, 19200, 38400, 57600, 115200, 0 };
@@ -142,6 +152,8 @@
 static struct sccbuf *sccfreelist[MAX_IBUFS] = {0};
 static int allocated_ibufs = 0;
 
+#define SERIAL_TYPE_NORMAL	1
+
 
 /* ******************************************************************** */
 /* *			Port Access Functions			      * */
@@ -197,10 +209,6 @@
 /* * 			Memory Buffer Management			*/
 /* ******************************************************************** */
 
-/* mbuf concept lent from KA9Q. Tnx PE1AYX for the buffer pool concept	*/
-/* (sorry, do you have any better ideas?) */
-
-
 /* allocate memory for the interrupt buffer pool */
 
 void scc_alloc_buffer_pool(void)
@@ -209,6 +217,8 @@
 	struct sccbuf *sccb;
 	struct mbuf   *bp;
 	
+	start_controle = 0;
+	
    	for (i = 0 ; i < MAX_IBUFS ; i++)
    	{
    		sccb = (struct sccbuf *)kmalloc(sizeof(struct sccbuf), GFP_ATOMIC);
@@ -286,6 +296,7 @@
 			sccfreelist[i]->bp->refcnt = 1;
 			sccfreelist[i]->bp->cnt = 0;
 			sccfreelist[i]->bp->in_use = 0;
+			sccfreelist[i]->bp->time_out = CURRENT_TIME + 300;
 		
 			restore_flags(flags);
 			return sccfreelist[i]->bp;
@@ -314,7 +325,33 @@
 		
 	save_flags(flags); cli();
 	bpnext = bp->next;
-	
+/*=========================================================================*/	
+/*==      THIS IS A LITTLE ROUTINE TO FIX THE TX MEM LEAK                ==*/
+/*==             UNTIL I HAVE REWRITE THE TX ROUTINES                    ==*/
+/*==                 PE1AYX@PI8HRL.AMPR.ORG                              ==*/
+/*=========================================================================*/
+
+	 start_controle++;
+	 if(start_controle > 100){
+	  if(bp->type == BT_TRANSMIT){
+	    start_controle = 0;
+	    for(i = 0 ; i < allocated_ibufs ; i++)
+	    {
+	       if(sccfreelist[i]->inuse == 1)
+	        if(sccfreelist[i]->bp->type == BT_TRANSMIT)
+	         if(sccfreelist[i]->bp->time_out < CURRENT_TIME)
+		    {
+			sccfreelist[i]->bp->cnt = 0;
+			sccfreelist[i]->bp->refcnt = 0;
+			sccfreelist[i]->inuse = 0;
+		    }
+ 	     }
+           } 
+	 }
+/*=========================================================================*/
+/*==                END OF THAT SILLY STUPID ROUTINE                     ==*/
+/*=========================================================================*/	 
+
 	if (bp->dup)
 	{
 		for(i = 0 ; i < allocated_ibufs ; i++)
@@ -481,13 +518,13 @@
 	
 	if (Vector_Latch)
 	{
-	    	while(1)			   /* forever...? */
+	    	while(1)
     		{ 
 			Outb(Vector_Latch, 0);      /* Generate INTACK */
         
 			/* Read the vector */
-			if((vector=Inb(Vector_Latch)) >= 16 * Nchips) break; 
-						/* ...not forever! */
+			if((vector=Inb(Vector_Latch)) >= 16 * Nchips)
+				break; 
           
 			/* Extract channel number and status from vector. */
 			/* Isolate channel nummer */
@@ -619,39 +656,20 @@
 /* Throw away received mbuf(s) when an error occurred */
 
 static inline void
-scc_toss_buffer(register struct scc_channel *scc)
-{
-	register struct mbuf *bp;
-	
-	if((bp = scc->rbp) != NULLBUF)
-	{
-		scc_free_chain(bp->next, BT_RECEIVE);
-		bp->next = NULLBUF;
-		scc->rbp1 = bp;         /* Don't throw this one away */
-		bp->cnt = 0;            /* Simply rewind it */
-		bp->in_use = 0;
-	}
-}
-
-static inline void
 flush_FIFO(register struct scc_channel *scc)
 {
 	register int k;
 	
 	for (k=0; k<3; k++)
 		Inb(scc->data);
-		
-	if(scc->rbp != NULLBUF)	/* did we receive something? */
+
+	if(scc->rxbufcnt > 0)
 	{
-		if(scc->rbp->next != NULLBUF || scc->rbp->cnt > 0)
-			scc->stat.rxerrs++;  /* then count it as an error */
-			
-		scc_toss_buffer(scc);         /* throw away buffer */
+		scc->stat.rxerrs++;
+		scc->rxbufcnt = 0;         /* throw away frame */
 	}
 }
 
-
-
 /* External/Status interrupt handler */
 static void
 scc_exint(register struct scc_channel *scc)
@@ -729,7 +747,7 @@
 static void
 scc_rxint(register struct scc_channel *scc)
 {
-	register struct mbuf *bp;
+	unsigned char ch;
 
 	scc->stat.rxints++;
 
@@ -740,32 +758,36 @@
 		return;
 	}
 
-	if ((bp = scc->rbp1) == NULLBUF || bp->cnt >= bp->size)	
-	{ 				/* no buffer available or buffer full */
-		if (scc->rbp == NULLBUF)
-		{
-			if ((bp = scc_get_buffer(BT_RECEIVE)) != NULLBUF)
-				scc->rbp = scc->rbp1 = bp;
-				
-		}
-		else if ((bp = scc_get_buffer(BT_RECEIVE)))
-		{
-			scc_append_to_chain(&scc->rbp, bp);
-			scc->rbp1 = bp;
-		}
-		
-		if (bp == NULLBUF)		/* no buffer available? */
-		{
-			Inb(scc->data);		/* discard character */
-			or(scc,R3,ENT_HM);      /* enter hunt mode */
-			scc_toss_buffer(scc);	/* throw away buffers */
-			scc->stat.nospace++;    /* and count this error */
-			return;
-		}
+	if (scc->rxbufcnt > 2044)		/* no buffer available? */
+	{
+		Inb(scc->data);		/* discard character */
+		or(scc,R3,ENT_HM);      /* enter hunt mode */
+		scc->rxbufcnt = 0;	/* throw away frame */
+		scc->stat.nospace++;    /* and count this error */
+		return;
+	}
+
+	if(scc->rxbufcnt == 0) /* make begin of kissframe */
+	{
+		scc->rxbuf[scc->rxbufcnt++] = FEND;
+		if (scc->kiss.not_slip)
+			scc->rxbuf[scc->rxbufcnt++] = 0;
+	}
+
+	switch( ch = Inb(scc->data) )
+	{
+		case FEND:
+			scc->rxbuf[scc->rxbufcnt++] = FESC;
+			scc->rxbuf[scc->rxbufcnt++] = TFEND;
+			break;
+		case FESC:
+			scc->rxbuf[scc->rxbufcnt++] = FESC;
+			scc->rxbuf[scc->rxbufcnt++] = TFESC;
+			break;
+		default:
+			scc->rxbuf[scc->rxbufcnt++] = ch;
 	}
 
-	/* now, we have a buffer. read character and store it */
-	bp->data[bp->cnt++] = Inb(scc->data);
 }
 
 
@@ -774,42 +796,82 @@
 scc_spint(register struct scc_channel *scc)
 {
 	register unsigned char status;
-	register struct mbuf *bp;
+	int i;
+	unsigned char	*cp;
+	char		*fp;
+	int		count;
+
 
 	scc->stat.spints++;
 
-	status = InReg(scc->ctrl,R1);		/* read receiver status */
+	status = InReg(scc->ctrl,R1);		/* read Special Receive Condition status */
 	
-	Inb(scc->data);				/* throw away Rx byte */
+	Inb(scc->data);				/* read byte */
 
-	if(status & Rx_OVR)			/* receiver overrun */
+	if(status & Rx_OVR)			/* RX_OVerRrun? */
 	{
-		scc->stat.rx_over++;                /* count them */
-		or(scc,R3,ENT_HM);              /* enter hunt mode for next flag */
-		scc_toss_buffer(scc);                 /* rewind the buffer and toss */
+		scc->stat.rx_over++;
+		or(scc,R3,ENT_HM);              /* enter hunt mode */
+		scc->rxbufcnt = 0;              /* rewind the buffer */
 	}
 	
-	if(status & END_FR && scc->rbp != NULLBUF)	/* end of frame */
+	if(status & END_FR && scc->rxbufcnt != 0)	/* END of FRame */
 	{
-		/* CRC okay, frame ends on 8 bit boundary and received something ? */
-		
-		if (!(status & CRC_ERR) && (status & 0xe) == RES8 && scc->rbp->cnt)
+		if (!(status & CRC_ERR) && (status & 0xe) == RES8 && scc->rxbufcnt > 0)
 		{
-			/* ignore last received byte (first of the CRC bytes) */
+		   scc->rxbufcnt--;	/*strip the CRC */
+  		   scc->rxbuf[scc->rxbufcnt++] = FEND;
+
+		   for(i = 0 ; i < scc->rxbufcnt ; i++)
+			{
+			if((scc->tty->flip.count + 1) < TTY_FLIPBUF_SIZE)
+				tty_insert_flip_char(scc->tty, scc->rxbuf[i], 0);
+			else    {
+				if (scc->tty->flip.buf_num) {
+					cp = scc->tty->flip.char_buf + TTY_FLIPBUF_SIZE;
+					fp = scc->tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
+					scc->tty->flip.buf_num = 0;
+					scc->tty->flip.char_buf_ptr = scc->tty->flip.char_buf;
+					scc->tty->flip.flag_buf_ptr = scc->tty->flip.flag_buf;
+				} else {
+					cp = scc->tty->flip.char_buf;
+					fp = scc->tty->flip.flag_buf;
+					scc->tty->flip.buf_num = 1;
+					scc->tty->flip.char_buf_ptr = scc->tty->flip.char_buf + TTY_FLIPBUF_SIZE;
+					scc->tty->flip.flag_buf_ptr = scc->tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
+					}
+				count = scc->tty->flip.count;
+				scc->tty->flip.count = 0;
+				scc->tty->ldisc.receive_buf(scc->tty, cp, fp, count);
+				tty_insert_flip_char(scc->tty, scc->rxbuf[i], 0);
+				}
+			}
+
+		if (scc->tty->flip.buf_num) {
+			cp = scc->tty->flip.char_buf + TTY_FLIPBUF_SIZE;
+			fp = scc->tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
+			scc->tty->flip.buf_num = 0;
+			scc->tty->flip.char_buf_ptr = scc->tty->flip.char_buf;
+			scc->tty->flip.flag_buf_ptr = scc->tty->flip.flag_buf;
+		} else {
+			cp = scc->tty->flip.char_buf;
+			fp = scc->tty->flip.flag_buf;
+			scc->tty->flip.buf_num = 1;
+			scc->tty->flip.char_buf_ptr = scc->tty->flip.char_buf + TTY_FLIPBUF_SIZE;
+			scc->tty->flip.flag_buf_ptr = scc->tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
+			}
+		count = scc->tty->flip.count;
+		scc->tty->flip.count = 0;
+		scc->tty->ldisc.receive_buf(scc->tty, cp, fp, count);
+		scc->stat.rxframes++;
+
+		scc->rxbufcnt = 0;
 			
-			for (bp = scc->rbp; bp->next != NULLBUF; bp = bp->next) ;
-				bp->cnt--;              /* last byte is first CRC byte */
-				
-			scc_enqueue(&scc->rcvq,scc->rbp);
-			scc->rbp = scc->rbp1 = NULLBUF;
-			scc->stat.rxframes++;
-			scc->stat.rx_queued++;
-		} else {				/* a bad frame */
-			scc_toss_buffer(scc);		/* throw away frame */
+		} else {
+			scc->rxbufcnt = 0;		/* frame is not good */
 			scc->stat.rxerrs++;
-		}
+	  		}		
 	}
-	
 	Outb(scc->ctrl,ERR_RES);
 }
 
@@ -934,7 +996,7 @@
 	Outb(scc->ctrl,RES_EXT_INT);	/* must be done twice */
 	
 	scc->status = InReg(scc->ctrl,R0);	/* read initial status */
-
+	scc->rxbufcnt = 0;
 	or(scc,R1,INT_ALL_Rx|TxINT_ENAB|EXT_INT_ENAB); /* enable interrupts */
 	or(scc,R9,MIE);			/* master interrupt enable */
 			
@@ -1142,42 +1204,13 @@
 	scc->t_tail = scc->kiss.tailtime;
 }
 
-static inline void check_rcv_queue(register struct scc_channel *scc)
-{
-	register struct mbuf *bp;
-	
-	if (scc->stat.rx_queued > QUEUE_THRES)
-	{
-		if (scc->rcvq == NULLBUF)
-		{
-			printk("z8530drv: Warning - scc->stat.rx_queued shows overflow"
-			       " (%d) but queue is empty\n", scc->stat.rx_queued);
-			       
-			scc->stat.rx_queued = 0;	/* correct it */
-			scc->stat.nospace = 12345;	/* draw attention to it */
-			return;
-		}
-			
-		bp = scc->rcvq->anext;	/* don't use the one we currently use */
-		
-		while (bp && (scc->stat.rx_queued > QUEUE_HYST))
-		{
-			bp = scc_free_chain(bp, BT_RECEIVE);
-			scc->stat.rx_queued--;
-			scc->stat.nospace++;
-		}
-		
-		scc->rcvq->anext = bp;
-	}
-}
-
 static void
 scc_timer(void)
 {
 	register struct scc_channel *scc;
 	register int chan;
 	unsigned long flags;
-		
+
 	save_flags(flags); cli();
 	
 	for (chan = 0; chan < (Nchips * 2); chan++)
@@ -1186,11 +1219,7 @@
 		
 		if (scc->tty && scc->init)
 		{
-			kiss_encode(scc);
-			check_rcv_queue(scc);
-			
 			/* KISS-TNC emulation */
-			
 			if (Expired(t_dwait)) dw_slot_timeout(scc)	; else
 			if (Expired(t_slot))  dw_slot_timeout(scc)	; else
 			if (Expired(t_txdel)) txdel_timeout(scc)   	; else
@@ -1201,8 +1230,10 @@
 			if (Expired(t_mbusy)) busy_timeout(scc);
 			if (Expired(t_maxk))  maxk_idle_timeout(scc);
 			if (Expired(t_idle))  maxk_idle_timeout(scc);
+
 		}
 	}
+
 	
 	timer_table[SCC_TIMER].fn = scc_timer;
 	timer_table[SCC_TIMER].expires = jiffies + HZ/TPS;
@@ -1259,7 +1290,7 @@
 	case PARAM_TXTAIL:
 		scc->kiss.tailtime = VAL; break;
 	case PARAM_FULLDUP:
-		scc->kiss.fulldup = val; break;
+		scc->kiss.fulldup = val; break; 
 	case PARAM_WAIT:
 		scc->kiss.waittime = VAL; break;
 	case PARAM_MAXKEY:
@@ -1423,97 +1454,6 @@
 	
 }
 
-/* ----> Encode received data and write it to the flip-buffer  <---- */
-
-/* receive raw frame from SCC. used for AX.25 */
-static void
-kiss_encode(register struct scc_channel *scc)
-{
-	struct mbuf *bp,*bp2;
-	struct tty_struct * tty = scc->tty;
-	unsigned long flags; 
-	unsigned char ch;
-
-	if(!scc->rcvq)
-	{
-		scc->stat.rx_kiss_state = KISS_IDLE;
-		return;
-	}
-	
-	/* worst case: FEND 0 FESC TFEND -> 4 bytes */
-	
-	while(tty->flip.count < TTY_FLIPBUF_SIZE-3)
-	{ 
-		if (scc->rcvq->cnt)
-		{
-			bp = scc->rcvq;
-			
-			if (scc->stat.rx_kiss_state == KISS_IDLE)
-			{
-				tty_insert_flip_char(tty, FEND, 0);
-				
-				if (scc->kiss.not_slip)
-					tty_insert_flip_char(tty, 0, 0);
-					
-				scc->stat.rx_kiss_state = KISS_RXFRAME;
-			}
-				
-			switch(ch = bp->data[bp->in_use++])
-			{
-				case FEND:
-					tty_insert_flip_char(tty, FESC, 0);
-					tty_insert_flip_char(tty, TFEND, 0);
-					break;
-				case FESC:
-					tty_insert_flip_char(tty, FESC, 0);
-					tty_insert_flip_char(tty, TFESC, 0);
-					break;
-				default:
-					tty_insert_flip_char(tty, ch, 0);
-			}
-			
-			bp->cnt--;
-			
- 		} else {
-			save_flags(flags); cli();
-			
-			while (!scc->rcvq->cnt)
-	 		{				 /* buffer empty? */
-				bp  = scc->rcvq->next;  /* next buffer */
-				bp2 = scc->rcvq->anext; /* next packet */
-				
-				
-				scc_return_buffer(scc->rcvq, BT_RECEIVE);
-				
-				if (!bp)	/* end of frame ? */
-				{
-					scc->rcvq = bp2;
-					
-					if (--scc->stat.rx_queued < 0)
-						scc->stat.rx_queued = 0;
-					
-					if (scc->stat.rx_kiss_state == KISS_RXFRAME)	/* new packet? */
-					{
-						tty_insert_flip_char(tty, FEND, 0); /* send FEND for old frame */
-						scc->stat.rx_kiss_state = KISS_IDLE; /* generate FEND for new frame */
-					}
-					
-					restore_flags(flags);
-					queue_task(&tty->flip.tqueue, &tq_timer);
-					return;
-					
-				} else scc->rcvq = bp; /* next buffer */
-			}
-			
-			restore_flags(flags);
-		}						
-		
-	}
-	
- 	queue_task(&tty->flip.tqueue, &tq_timer); /* kick it... */
-}
-
-
 /* ******************************************************************* */
 /* *		Init channel structures, special HW, etc...	     * */
 /* ******************************************************************* */
@@ -1523,11 +1463,10 @@
 z8530_init(void)
 {
 	struct scc_channel *scc;
-	int chip,chan;
+	int chip;
 	unsigned long flags;
-    	int k;
 
-	/* reset and pre-init all chips in the system */
+	/* reset all scc chips */
 	for (chip = 0; chip < Nchips; chip++)
 	{
 		/* Special SCC cards */
@@ -1538,30 +1477,25 @@
 		if(Board & (PC100 | PRIMUS))		/* this is a PC100/EAGLE card */
 			Outb(Special_Port,Option);	/* set the MODEM mode (22H normally) */
 			
-		/* Init SCC */
-		
 		scc=&SCC_Info[2*chip];
 		if (!scc->ctrl) continue;
 		
 		save_flags(flags); cli();
 		
-		Outb(scc->ctrl, 0);
-		OutReg(scc->ctrl,R9,FHWRES);		/* force hardware reset */
-		for (k=1; k < 1000; k++) ;
-		
-		for (chan = 0; chan < 2; chan++)
-		{
-			scc=&SCC_Info[2*chip+chan];
-			
-			wr(scc,R1, 0);
-			wr(scc,R2, chip*16);		/* No of chip is vector */
-			wr(scc,R9,VIS);			/* vector includes status */
-		}
+		OutReg(scc->ctrl,R9,FHWRES);	/* force hardware reset */
+		OutReg(scc->ctrl,R9,0);		/* end hardware reset */
+		OutReg(scc->ctrl,R9,CHRA);	/* reset channel A */
+		OutReg(scc->ctrl,R9,CHRB);	/* reset channel B */
+		OutReg(scc->ctrl,R1, 0);	/* No Rx irq from channel A */
+		scc=&SCC_Info[2*chip+1];
+		OutReg(scc->ctrl,R1, 0);	/* No Rx irq from channel B */
+		scc=&SCC_Info[2*chip];
+		OutReg(scc->ctrl,R2, chip*16);	/* Set Interrupt vector */
  
         	restore_flags(flags);
         }
 
-	if (Ivec == 2) Ivec = 9;			/* this f... IBM AT-design! */
+	if (Ivec == 2) Ivec = 9;
 	request_irq(Ivec, scc_isr,   SA_INTERRUPT, "AX.25 SCC");
  
 	Driver_Initialized = 1;
@@ -1613,6 +1547,9 @@
  	scc = &SCC_Info[chan];
  	
 	tty->driver_data = scc;
+        tty->termios->c_iflag = IGNBRK | IGNPAR;
+        tty->termios->c_cflag = B9600 | CS8 | CLOCAL;
+
  	tty->termios->c_cflag &= ~CBAUD; 
  	
 	if (!Driver_Initialized)
@@ -1643,7 +1580,28 @@
 	timer_table[SCC_TIMER].fn = scc_timer;
 	timer_table[SCC_TIMER].expires = 0;	/* now! */
 	timer_active |= 1 << SCC_TIMER;
-	
+
+/*====================new pe1ayx====================
+planed for the new TX routines
+
+	if (!scc->xmit_buf) {
+		scc->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+		if (!scc->xmit_buf)
+			return -ENOMEM;
+	}
+
+	scc->xmit_cnt = scc->xmit_head = scc->xmit_tail = 0;
+
+
+====================new pe1ayx end================*/
+
+	if (!tmp_buf) {
+		tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+		if (!tmp_buf)
+			return -ENOMEM;
+	}
+
+
 	return 0;
 }
 
@@ -1796,7 +1754,7 @@
 				scc->kiss.softdcd = 0;		   /* hardware dcd */
 			}
 			
-			scc->init = 1;			
+			scc->init = 1;
 			
 			return 0;
 		}
@@ -1821,7 +1779,7 @@
 		
 		restore_flags(flags);
 			
-		put_user(result,(unsigned int *) arg);
+		put_fs_long(result,(unsigned long *) arg);
 		return 0;
 	case TIOCMBIS:
 	case TIOCMBIC:
@@ -1836,7 +1794,7 @@
 			scc->wreg[R5] &= ~RTS;
 			break;
 		case TIOCMSET:
-			value = get_user((unsigned int *) arg);
+			value = get_fs_long((unsigned long *) arg);
 			
 			if(value & TIOCM_DTR)
 				scc->wreg[R5] |= DTR;
@@ -2022,6 +1980,7 @@
 		
 		scc->sndq1->anext = bp;
 	}
+	
 }
 
 
@@ -2031,12 +1990,14 @@
 /* send raw frame to SCC. used for AX.25 */
 int scc_write(struct tty_struct *tty, int from_user, unsigned char *buf, int count)
 {
+	unsigned long flags;
+	static unsigned char *p;
 	struct scc_channel * scc = tty->driver_data;
-	unsigned char tbuf[BUFSIZE], *p;
 	int cnt, cnt2;
-	
-	if (!tty) return count;
-	
+
+	if (!tty || !tmp_buf)
+		return 0;
+		
 	if (scc_paranoia_check(scc, tty->device, "scc_write"))
 		return 0;
 
@@ -2044,31 +2005,43 @@
 	
 	check_tx_queue(scc);
 
+	save_flags(flags);
+
 	cnt2 = count;
 	
 	while (cnt2)
 	{
-		cnt   = cnt2 > BUFSIZE? BUFSIZE:cnt2;
+		cli();
+		cnt   = cnt2 > SERIAL_XMIT_SIZE? SERIAL_XMIT_SIZE:cnt2;
 		cnt2 -= cnt;
 		
-		if (from_user)
-			memcpy_fromfs(tbuf, buf, cnt);
+		if (from_user){
+			down(&tmp_buf_sem);
+			memcpy_fromfs(tmp_buf, buf, cnt);
+			up(&tmp_buf_sem);
+			}
 		else
-			memcpy(tbuf, buf, cnt);
+			memcpy(tmp_buf, buf, cnt);
 		
 		buf += cnt;
 			
-		p=tbuf;
+		p=tmp_buf;
 		
 		while(cnt--) 
 		  if (kiss_decode(scc, *p++))
 		  {
 		  	scc->stat.nospace++;
+		  	restore_flags(flags);
 		  	return 0;
 		  }
 		  	
 	} /* while cnt2 */
-	
+		
+	if ((scc->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) 
+	     && scc->tty->ldisc.write_wakeup)
+		(scc->tty->ldisc.write_wakeup)(scc->tty);
+
+	restore_flags(flags);
 	return count;
 }
 				
@@ -2092,7 +2065,7 @@
 	struct scc_channel *scc = tty->driver_data;
 	
 	scc_paranoia_check(scc, tty->device, "scc_flush_chars"); /* just to annoy the user... */
-	
+
 	return;	/* no flush needed */
 }
 
@@ -2101,7 +2074,7 @@
 static int scc_write_room(struct tty_struct *tty)
 {
 	struct scc_channel *scc = tty->driver_data;
-	
+
 	if (scc_paranoia_check(scc, tty->device, "scc_write_room"))
 		return 0;
 	
@@ -2117,7 +2090,7 @@
 static int scc_chars_in_buffer(struct tty_struct *tty)
 {
 	struct scc_channel *scc = tty->driver_data;
-	
+
 	if (scc && scc->sndq2)
 		return scc->sndq2->cnt;
 	else
@@ -2127,37 +2100,35 @@
 static void scc_flush_buffer(struct tty_struct *tty)
 {
 	struct scc_channel *scc = tty->driver_data;
-	
+
 	if (scc_paranoia_check(scc, tty->device, "scc_flush_buffer"))
 		return;
 		
 	scc->stat.tx_kiss_state = KISS_IDLE;
-	
-	wake_up_interruptible(&tty->write_wait);
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
+
 }
 
 static void scc_throttle(struct tty_struct *tty)
 {
 	struct scc_channel *scc = tty->driver_data;
-	
+
 	if (scc_paranoia_check(scc, tty->device, "scc_throttle"))
 		return;
 		
 		
 	/* dummy */
+	
 }
 
 static void scc_unthrottle(struct tty_struct *tty)
 {
 	struct scc_channel *scc = tty->driver_data;
-	
+
 	if (scc_paranoia_check(scc, tty->device, "scc_unthrottle"))
 		return;
 		
 	/* dummy */
+	
 }
 
 static void scc_start(struct tty_struct *tty)
@@ -2181,6 +2152,14 @@
 	/* dummy */
 }
 
+void scc_hangup(struct tty_struct *tty)
+{
+	struct scc_channel *scc = tty->driver_data;
+	
+	if (scc_paranoia_check(scc, tty->device, "scc_hangup"))
+		return;
+}
+
 
 /* ******************************************************************** */
 /* * 			Init SCC driver 			      * */
@@ -2188,7 +2167,11 @@
 
 long scc_init (long kmem_start)
 {
-	int chip, chan;
+
+	int chip;
+#ifdef VERBOSE_BOOTMSG
+	int chan;
+#endif	
 	register io_port ctrl;
 	long flags;
 	
@@ -2200,31 +2183,31 @@
         scc_driver.minor_start = 96;
         scc_driver.num = Nchips*2;
         scc_driver.type = TTY_DRIVER_TYPE_SERIAL;
-        scc_driver.subtype = 0;			/* not needed */
+        scc_driver.subtype = SERIAL_TYPE_NORMAL;			/* not needed */
         scc_driver.init_termios = tty_std_termios;
-        scc_driver.init_termios.c_cflag = B9600	| CS8 | CREAD | HUPCL | CLOCAL;
+        scc_driver.init_termios.c_iflag = IGNBRK | IGNPAR;
+        scc_driver.init_termios.c_cflag = B9600	| CS8 | CLOCAL;
         scc_driver.flags = TTY_DRIVER_REAL_RAW;
         scc_driver.refcount = &scc_refcount;	/* not needed yet */
         scc_driver.table = scc_table;
         scc_driver.termios = (struct termios **) scc_termios;
         scc_driver.termios_locked = (struct termios **) scc_termios_locked;
+
         scc_driver.open = scc_open;
         scc_driver.close = scc_close;
         scc_driver.write = scc_write;
-        scc_driver.start = scc_start;
-        scc_driver.stop = scc_stop;
-        
         scc_driver.put_char = scc_put_char;
         scc_driver.flush_chars = scc_flush_chars;        
 	scc_driver.write_room = scc_write_room;
 	scc_driver.chars_in_buffer = scc_chars_in_buffer;
 	scc_driver.flush_buffer = scc_flush_buffer;
-	
+        scc_driver.ioctl = scc_ioctl;
 	scc_driver.throttle = scc_throttle;
 	scc_driver.unthrottle = scc_unthrottle;
-        
-        scc_driver.ioctl = scc_ioctl;
         scc_driver.set_termios = scc_set_termios;
+        scc_driver.stop = scc_stop;
+        scc_driver.start = scc_start;
+        scc_driver.hangup = scc_hangup;
         
         if (tty_register_driver(&scc_driver))
            panic("Couldn't register Z8530 SCC driver\n");

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this