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
- Lines: 943
- Date:
Mon Jul 17 14:49:30 1995
- Orig file:
v1.3.10/linux/drivers/char/scc.c
- Orig date:
Tue Jun 27 14:11:34 1995
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