linux-mips-fnet
[Top] [All Lists]

[PATCH] DECstation zs.c

To: linux-mips@fnet.fr
Subject: [PATCH] DECstation zs.c
From: "Gleb O. Raiko" <raiko@niisi.msk.ru>
Date: Tue, 13 Jul 1999 19:06:07 +0400
Organization: NIISI RAN
Hello,

The patch attached here fixes bugs, adds hooks (the low-level software
channels between the zs driver and the rest of the kernel), and adds
support for Baget. The hooks are intented for use by kgdb and keyboard
driver in Baget.

I'd like to hear opinions from DECstation mantainers, especially Michael
Engel who supports serial keyboard on zs. I think, serial keyboard in
DECstation might be implemented via hooks too and we can get rid of ugly
ifdefs in the zs driver.

Harald: this is the patch I've sent to you but against current cvs 2.2
branch, So, it should be applied cleanly.

Regards,
Gleb.
--- /ultra/vladimir/sgi/2.2/linux/drivers/tc/zs.c       Mon Jul 12 21:52:32 1999
+++ /home/vladimir/linux-2.2.1/drivers/tc/zs.c  Tue Jul 13 18:38:24 1999
@@ -31,6 +31,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 #ifdef CONFIG_SERIAL_CONSOLE
 #include <linux/console.h>
 #endif
@@ -42,17 +43,24 @@
 #include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
+#include <asm/wbflush.h>
+#include <asm/bootinfo.h>
+#ifdef CONFIG_DECSTATION
 #include <asm/dec/interrupts.h>
 #include <asm/dec/machtype.h>
 #include <asm/dec/tc.h>
 #include <asm/dec/ioasic_addrs.h>
+#endif
+#ifdef CONFIG_BAGET_MIPS
+#include <asm/baget/baget.h>
+unsigned long system_base;
+#endif
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
 
 #include "zs.h"
 
-
 /*
  * It would be nice to dynamically allocate everything that
  * depends on NUM_SERIAL, so we could support any number of
@@ -60,11 +68,60 @@
  */
 #define NUM_SERIAL     2               /* Max number of ZS chips supported */
 #define NUM_CHANNELS   (NUM_SERIAL * 2)        /* 2 channels per chip */
+#define CHANNEL_A_NR  (zs_parms->channel_a_offset > zs_parms->channel_b_offset)
+                                        /* Number of channel A in the chip */ 
+#define ZS_CHAN_IO_SIZE 8
+#define ZS_CLOCK        7372800        /* Z8530 RTxC input clock rate */
 
 #define RECOVERY_DELAY  udelay(2)
 
-struct dec_zschannel zs_channels[NUM_CHANNELS];
+struct zs_parms {
+       unsigned long scc0;
+       unsigned long scc1;
+       int channel_a_offset;
+       int channel_b_offset;
+       int irq;
+       int clock;
+};
 
+static struct zs_parms *zs_parms;
+
+#ifdef CONFIG_DECSTATION
+static struct zs_parms ds_parms = {
+       scc0 : SCC0,
+       scc1 : SCC1,
+       channel_a_offset : 1,
+       channel_b_offset : 9,
+       irq : SERIAL,
+       clock : ZS_CLOCK
+};
+#endif
+#ifdef CONFIG_BAGET_MIPS
+static struct zs_parms baget_parms = {
+       scc0 : UNI_SCC0,
+       scc1 : UNI_SCC1,
+       channel_a_offset : 9,
+       channel_b_offset : 1,
+       irq : BAGET_SCC_IRQ,
+       clock : 14745000
+};
+#endif
+
+#ifdef CONFIG_DECSTATION
+#define DS_BUS_PRESENT (IOASIC)
+#else
+#define DS_BUS_PRESENT 0
+#endif
+
+#ifdef CONFIG_BAGET_MIPS
+#define BAGET_BUS_PRESENT (mips_machtype == MACH_BAGET202)
+#else
+#define BAGET_BUS_PRESENT 0
+#endif
+
+#define BUS_PRESENT (DS_BUS_PRESENT || BAGET_BUS_PRESENT)
+
+struct dec_zschannel zs_channels[NUM_CHANNELS];
 struct dec_serial zs_soft[NUM_CHANNELS];
 int zs_channels_found;
 struct dec_serial *zs_chain;   /* list of all channels */
@@ -75,20 +132,6 @@
 static struct console sercons;
 #endif
 
-#ifdef CONFIG_KGDB
-struct dec_zschannel *zs_kgdbchan;
-static unsigned char scc_inittab[] = {
-       9,  0x80,       /* reset A side (CHRA) */
-       13, 0,          /* set baud rate divisor */
-       12, 1,
-       14, 1,          /* baud rate gen enable, src=rtxc (BRENABL) */
-       11, 0x50,       /* clocks = br gen (RCBR | TCBR) */
-       5,  0x6a,       /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
-       4,  0x44,       /* x16 clock, 1 stop (SB1 | X16CLK)*/
-       3,  0xc1,       /* rx enable, 8 bits (RxENABLE | Rx8)*/
-};
-#endif
-
 static unsigned char zs_init_regs[16] __initdata = {
        0,                           /* write 0 */
        0,                           /* write 1 */
@@ -105,8 +148,6 @@
        0                            /* write 15 */
 };
 
-#define ZS_CLOCK         7372800       /* Z8530 RTxC input clock rate */
-
 DECLARE_TASK_QUEUE(tq_zs_serial);
 
 struct tty_driver serial_driver, callout_driver;
@@ -128,6 +169,12 @@
 #undef SERIAL_DEBUG_THROTTLE
 #undef SERIAL_PARANOIA_CHECK
 
+#undef ZS_DEBUG_REGS
+
+#ifdef SERIAL_DEBUG_THROTTLE
+#define _tty_name(tty,buf) tty_name(tty,buf)
+#endif
+
 #define RS_STROBE_TIME 10
 #define RS_ISR_PASS_LIMIT 256
 
@@ -195,7 +242,7 @@
 
        if (reg != 0) {
                *channel->control = reg & 0xf;
-               RECOVERY_DELAY;
+               wbflush(); RECOVERY_DELAY;
        }
        retval = *channel->control;
        RECOVERY_DELAY;
@@ -207,10 +254,10 @@
 {
        if (reg != 0) {
                *channel->control = reg & 0xf;
-               RECOVERY_DELAY;
+               wbflush(); RECOVERY_DELAY;
        }
        *channel->control = value;
-       RECOVERY_DELAY;
+       wbflush(); RECOVERY_DELAY;
        return;
 }
 
@@ -227,7 +274,7 @@
                                unsigned char value)
 {
        *channel->data = value;
-       RECOVERY_DELAY;
+       wbflush(); RECOVERY_DELAY;
        return;
 }
 
@@ -255,16 +302,18 @@
 }
 
 /* Sets or clears DTR/RTS on the requested line */
-static inline void zs_rtsdtr(struct dec_serial *ss, int set)
+static inline void zs_rtsdtr(struct dec_serial *info, int set)
 {
-       if (ss->zs_channel != ss->zs_chan_a) {
-               if (set)
-                       ss->zs_chan_a->curregs[5] |= (RTS | DTR);
-               else
-                       ss->zs_chan_a->curregs[5] &= ~(RTS | DTR);
-               write_zsreg(ss->zs_chan_a, 5, ss->zs_chan_a->curregs[5]);
-       }
-       return;
+        unsigned long flags;
+
+        save_flags(flags); cli();
+        if(set) {
+                info->zs_channel->curregs[5] |= (RTS | DTR);
+        } else {
+                info->zs_channel->curregs[5] &= ~(RTS | DTR);
+        }
+       write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+        restore_flags(flags);
 }
 
 /* Utility routines for the Zilog */
@@ -280,7 +329,7 @@
         */
        brg = (read_zsreg(channel, 13) << 8);
        brg |= read_zsreg(channel, 12);
-       return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+       return BRG_TO_BPS(brg, (zs_parms->clock/(ss->clk_divisor)));
 }
 
 /* On receive, this clears errors and the receiver interrupts */
@@ -324,15 +373,11 @@
                stat = read_zsreg(info->zs_channel, R1);
                ch = read_zsdata(info->zs_channel);
 
-#ifdef CONFIG_KGDB
-               if (info->kgdb_channel) {
-                       if (ch == 0x03 || ch == '$')
-                               breakpoint();
-                       if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
-                               write_zsreg(info->zs_channel, 0, ERR_RES);
+               if (info->hook && info->hook->rx_char) {
+                       (*info->hook->rx_char)(info, ch, stat);
                        return;
                }
-#endif
+
                if (!tty)
                        continue;
 
@@ -361,7 +406,8 @@
                *tty->flip.flag_buf_ptr++ = flag;
                *tty->flip.char_buf_ptr++ = ch;
        }
-       tty_flip_buffer_push(tty);
+       if (tty)
+               tty_flip_buffer_push(tty);
 }
 
 static void transmit_chars(struct dec_serial *info)
@@ -458,7 +504,7 @@
                shift = 0;      /* Channel B */
 
        for (;;) {
-               zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift; 
+               zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
                if ((zs_intreg & CHAN_IRQMASK) == 0)
                        break;
 
@@ -472,7 +518,30 @@
                        status_handle(info);
                }
        }
+       
+       /* Why do we need this ? */
+       write_zsreg(info->zs_channel, 0, RES_H_IUS);
+}
+
+#ifdef ZS_DEBUG_REGS
+void zs_dump (void) {
+       int i, j;
+       for (i = 0; i < zs_channels_found; i++) {
+               struct dec_zschannel *ch = &zs_channels[i]; 
+               if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) {
+                       for (j = 0; j < 15; j++) {
+                               printk("W%d = 0x%x\t", 
+                                      j, (int)ch->curregs[j]);
+                       }
+                       for (j = 0; j < 15; j++) {
+                               printk("R%d = 0x%x\t", 
+                                      j, (int)read_zsreg(ch,j));
+                       }
+                       printk("\n\n");
+               }
+       }
 }
+#endif
 
 /*
  * -------------------------------------------------------------------
@@ -494,7 +563,7 @@
 
        if (serial_paranoia_check(info, tty->device, "rs_stop"))
                return;
-       
+
 #if 1
        save_flags(flags); cli();
        if (info->zs_channel->curregs[5] & TxENAB) {
@@ -545,7 +614,7 @@
 {
        struct dec_serial       *info = (struct dec_serial *) private_;
        struct tty_struct       *tty;
-       
+
        tty = info->tty;
        if (!tty)
                return;
@@ -667,8 +736,7 @@
        info->zs_channel->curregs[5] &= ~TxENAB;
        write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
        if (!info->tty || C_HUPCL(info->tty)) {
-               info->zs_chan_a->curregs[5] &= ~(DTR | RTS);
-               write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+               zs_rtsdtr(info, 0);
        }
 
        if (info->tty)
@@ -684,54 +752,65 @@
  */
 static void change_speed(struct dec_serial *info)
 {
-       unsigned short port;
        unsigned cflag;
        int     i;
-       int     brg;
+       int     brg, bits;
        unsigned long flags;
 
-       if (!info->tty || !info->tty->termios)
-               return;
-       cflag = info->tty->termios->c_cflag;
-       if (!(port = info->port))
-               return;
+       if (!info->hook) {
+               if (!info->tty || !info->tty->termios)
+                       return;
+               cflag = info->tty->termios->c_cflag;
+               if (!info->port)
+                       return;
+       } else {
+               cflag = info->hook->cflags;
+       }
        i = cflag & CBAUD;
-
        save_flags(flags); cli();
        info->zs_baud = baud_table[i];
        info->clk_divisor = 16;
-
-       switch (info->zs_baud) {
-       default:
+        if (info->zs_baud) {
                info->zs_channel->curregs[4] = X16CLK;
-               brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+               brg = BPS_TO_BRG(info->zs_baud, 
zs_parms->clock/info->clk_divisor);
                info->zs_channel->curregs[12] = (brg & 255);
                info->zs_channel->curregs[13] = ((brg >> 8) & 255);
-       }
+               zs_rtsdtr(info, 1); 
+       } else {
+                zs_rtsdtr(info, 0);
+                return;
+       }
 
        /* byte size and parity */
        info->zs_channel->curregs[3] &= ~RxNBITS_MASK;
        info->zs_channel->curregs[5] &= ~TxNBITS_MASK;
        switch (cflag & CSIZE) {
        case CS5:
+               bits = 7;
                info->zs_channel->curregs[3] |= Rx5;
                info->zs_channel->curregs[5] |= Tx5;
                break;
        case CS6:
+               bits = 8;
                info->zs_channel->curregs[3] |= Rx6;
                info->zs_channel->curregs[5] |= Tx6;
                break;
        case CS7:
+               bits = 9;
                info->zs_channel->curregs[3] |= Rx7;
                info->zs_channel->curregs[5] |= Tx7;
                break;
        case CS8:
        default: /* defaults to 8 bits */
+               bits = 10;
                info->zs_channel->curregs[3] |= Rx8;
                info->zs_channel->curregs[5] |= Tx8;
                break;
        }
 
+       info->timeout = ((info->xmit_fifo_size*HZ*bits) / info->zs_baud);
+        info->timeout += HZ/50;         /* Add .02 seconds of slop */
+
        info->zs_channel->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
        if (cflag & CSTOPB) {
                info->zs_channel->curregs[4] |= SB2;
@@ -854,7 +933,7 @@
 static void rs_flush_buffer(struct tty_struct *tty)
 {
        struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-                               
+       
        if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
                return;
        cli();
@@ -898,17 +977,7 @@
        }
 
        if (C_CRTSCTS(tty)) {
-               /*
-                * Here we want to turn off the RTS line.  On Macintoshes,
-                * we only get the DTR line, which goes to both DTR and
-                * RTS on the modem.  RTS doesn't go out to the serial
-                * port socket.  So you should make sure your modem is
-                * set to ignore DTR if you're using CRTSCTS.
-                */
-               save_flags(flags); cli();
-               info->zs_chan_a->curregs[5] &= ~(DTR | RTS);
-               write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
-               restore_flags(flags);
+               zs_rtsdtr(info, 0);
        }
 }
 
@@ -940,11 +1009,7 @@
        }
 
        if (C_CRTSCTS(tty)) {
-               /* Assert RTS and DTR lines */
-               save_flags(flags); cli();
-               info->zs_chan_a->curregs[5] |= DTR | RTS;
-               write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
-               restore_flags(flags);
+               zs_rtsdtr(info, 1);
        }
 }
 
@@ -1046,7 +1111,7 @@
        unsigned int result;
 
        cli();
-       control = info->zs_chan_a->curregs[5];
+       control = info->zs_channel->curregs[5];
        status = read_zsreg(info->zs_channel, 0);
        sti();
        result =  ((control & RTS) ? TIOCM_RTS: 0)
@@ -1071,19 +1136,20 @@
        cli();
        switch (cmd) {
        case TIOCMBIS:
-               info->zs_chan_a->curregs[5] |= bits;
+               info->zs_channel->curregs[5] |= bits;
                break;
        case TIOCMBIC:
-               info->zs_chan_a->curregs[5] &= ~bits;
+               info->zs_channel->curregs[5] &= ~bits;
                break;
        case TIOCMSET:
-               info->zs_chan_a->curregs[5] = (info->zs_chan_a->curregs[5] & 
~(DTR | RTS)) | bits;
+               info->zs_channel->curregs[5] = 
+                       (info->zs_channel->curregs[5] & ~(DTR | RTS)) | bits;
                break;
        default:
                sti();
                return -EINVAL;
        }
-       write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+       write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
        sti();
        return 0;
 }
@@ -1116,10 +1182,9 @@
        int error;
        struct dec_serial * info = (struct dec_serial *)tty->driver_data;
 
-#ifdef CONFIG_KGDB
-       if (info->kgdb_channel)
+       if (info->hook)
                return -ENODEV;
-#endif
+
        if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
                return -ENODEV;
 
@@ -1297,7 +1362,7 @@
 {
        struct dec_serial *info = (struct dec_serial *) tty->driver_data;
        unsigned long orig_jiffies, char_time;
-
+              
        if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
                return;
 
@@ -1313,7 +1378,7 @@
                char_time = 1;
        if (timeout)
                char_time = MIN(char_time, timeout);
-       while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
+       while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0) {
                current->state = TASK_INTERRUPTIBLE;
                current->counter = 0;   /* make us low-priority */
                schedule_timeout(char_time);
@@ -1491,10 +1556,9 @@
                return -ENODEV;
        info = zs_soft + line;
 
-#ifdef CONFIG_KGDB
-       if (info->kgdb_channel)
+       if (info->hook)
                return -ENODEV;
-#endif
+
        if (serial_paranoia_check(info, tty->device, "rs_open"))
                return -ENODEV;
 #ifdef SERIAL_DEBUG_OPEN
@@ -1576,12 +1640,11 @@
 {
        struct dec_serial **pp;
        int i, n, n_chips = 0, n_channels, chip, channel;
-       unsigned long flags;
 
        /*
         * did we get here by accident?
         */
-       if(!IOASIC) {
+       if(!BUS_PRESENT) {
                printk("Not on JUNKIO machine, skipping probe_sccs\n");
                return;
        }
@@ -1592,19 +1655,36 @@
         * system_base for this case :-(. HK
         */
        switch(mips_machtype) {
+#ifdef CONFIG_DECSTATION
        case MACH_DS5000_2X0:
                system_base = 0xbf800000;
                n_chips = 2;
+               zs_parms = &ds_parms;
                break;
        case MACH_DS5000_1XX:
                system_base = 0xbc000000;
                n_chips = 2;
+               zs_parms = &ds_parms;
                break;
        case MACH_DS5000_XX:
                system_base = 0xbc000000;
                n_chips = 1;
+               zs_parms = &ds_parms;
                break;
+#endif
+#ifdef CONFIG_BAGET_MIPS
+       case MACH_BAGET202:
+               system_base = UNI_IO_BASE;
+               n_chips = 2;
+               zs_parms = &baget_parms;
+               zs_init_regs[2] = 0x8;
+               break;
+#endif
+       default:
+               panic("zs: unsupported bus");
        }
+       if (!zs_parms)
+               panic("zs: uninitialized parms");
 
        pp = &zs_chain;
 
@@ -1615,16 +1695,38 @@
                        /*
                         * The sccs reside on the high byte of the 16 bit IOBUS
                         */
-                       zs_channels[n_channels].control = (volatile unsigned 
char *)
-                               system_base + (0 == chip ? SCC0 : SCC1) + (0 == 
channel ? 1 : 9);
-                       zs_channels[n_channels].data = 
zs_channels[n_channels].control + 4;
+                       zs_channels[n_channels].control = 
+                               (volatile unsigned char *)system_base + 
+                         (0 == chip ? zs_parms->scc0 : zs_parms->scc1) + 
+                         (0 == channel ? zs_parms->channel_a_offset : 
+                                         zs_parms->channel_b_offset);
+                       zs_channels[n_channels].data = 
+                               zs_channels[n_channels].control + 4;
+
+                       if (check_region((unsigned long)
+                                        zs_channels[n_channels].control,
+                                        ZS_CHAN_IO_SIZE) < 0)
+                               panic("SCC I/O region is not free");
+                       request_region((unsigned long)
+                                      zs_channels[n_channels].control,
+                                      ZS_CHAN_IO_SIZE, "SCC");
+
                        zs_soft[n_channels].zs_channel = 
&zs_channels[n_channels];
-                       zs_soft[n_channels].irq = SERIAL;
+                       zs_soft[n_channels].irq = zs_parms->irq;
 
-                       if (0 == channel)
-                               zs_soft[n_channels].zs_chan_a = 
&zs_channels[n_channels+1];
+                       /* 
+                        *  Identification of channel A. Location of channel A
+                         *  inside chip depends on mapping of internal address
+                        *  the chip decodes channels by.
+                        *  CHANNEL_A_NR returns either 0 (in case of 
+                        *  DECstations) or 1 (in case of Baget).
+                        */
+                       if (CHANNEL_A_NR == channel)
+                               zs_soft[n_channels].zs_chan_a = 
+                                   &zs_channels[n_channels+1-2*CHANNEL_A_NR];
                        else
-                               zs_soft[n_channels].zs_chan_a = 
&zs_channels[n_channels];
+                               zs_soft[n_channels].zs_chan_a = 
+                                   &zs_channels[n_channels];
 
                        *pp = &zs_soft[n_channels];
                        pp = &zs_soft[n_channels].zs_next;
@@ -1660,7 +1762,10 @@
        unsigned long flags;
        struct dec_serial *info;
 
-       if(!IOASIC)
+       if (zs_chain)
+               return 0;
+
+       if(!BUS_PRESENT)
                return -ENODEV;
 
        /* Setup base handler, and timer table. */
@@ -1729,18 +1834,19 @@
        save_flags(flags); cli();
 
        for (channel = 0; channel < zs_channels_found; ++channel) {
-#ifdef CONFIG_KGDB
-               if (zs_soft[channel].kgdb_channel) {
+               if (zs_soft[channel].hook && 
+                   zs_soft[channel].hook->init_channel) {
+                       
(*zs_soft[channel].hook->init_channel)(&zs_soft[channel]);
                        continue;
                }
-#endif
+
                zs_soft[channel].clk_divisor = 16;
                zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
 
-               if (request_irq(SERIAL, rs_interrupt, SA_SHIRQ,
+               if (request_irq(zs_parms->irq, rs_interrupt, SA_SHIRQ,
                                "SCC", &zs_soft[channel]))
                        printk(KERN_ERR "decserial: can't get irq %d\n",
-                              SERIAL);
+                              zs_parms->irq);
 
                /* If console serial line, then enable interrupts. */
 /*             if (zs_soft[channel].is_cons) {
@@ -1754,11 +1860,10 @@
 
        for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
        {
-#ifdef CONFIG_KGDB
-               if (info->kgdb_channel) {
+               if (info->hook && info->hook->init_info) {
+                       (*info->hook->init_info)(info);
                        continue;
                }
-#endif
                info->magic = SERIAL_MAGIC;
                info->port = (int) info->zs_channel->control;
                info->line = i;
@@ -1825,12 +1930,10 @@
                return;
 
        save_flags(flags); cli();
-
        while (!(*(info->zs_channel->control) & Tx_BUF_EMP) && --loops)
                RECOVERY_DELAY;
        *(info->zs_channel->data) = ch;
-       RECOVERY_DELAY;
-
+       wbflush(); RECOVERY_DELAY;
        restore_flags(flags);
 }
 
@@ -1839,32 +1942,13 @@
 {
        struct dec_serial *info;
        int i;
-       unsigned char nine;
 
        info = zs_soft + co->index;
-
-#if 0
-       /*
-        * disable master interrupt if necessary
-        */
-       nine = info->zs_channel->curregs[9];
-       if(nine & MIE)
-               write_zsreg(info->zs_channel, R9, nine & ~MIE);
-#endif
-       /*
-        * do it
-        */
        for (i = 0; i < count; i++, s++) {
                if(*s == '\n')
                        zs_console_putchar(info, '\r');
                zs_console_putchar(info, *s);
        }
-       /*
-        * restore master interrupt enable
-        */
-#if 0
-       write_zsreg(info->zs_channel, R9, nine);
-#endif
 }
 
 /*
@@ -1896,7 +1980,7 @@
        char    *s;
        unsigned long flags;
 
-       if(!IOASIC)
+       if(!BUS_PRESENT)
                return -ENODEV;
 
        info = zs_soft + co->index;
@@ -1971,7 +2055,7 @@
        /*
         * Turn on RTS and DTR.
         */
-       zs_rtsdtr(info, 1);
+        zs_rtsdtr(info, 1);
 
        /*
         * Finally, enable sequencing
@@ -2030,6 +2114,18 @@
 #endif /* ifdef CONFIG_SERIAL_CONSOLE */
 
 #ifdef CONFIG_KGDB
+struct dec_zschannel *zs_kgdbchan;
+static unsigned char scc_inittab[] = {
+       9,  0x80,       /* reset A side (CHRA) */
+       13, 0,          /* set baud rate divisor */
+       12, 1,
+       14, 1,          /* baud rate gen enable, src=rtxc (BRENABL) */
+       11, 0x50,       /* clocks = br gen (RCBR | TCBR) */
+       5,  0x6a,       /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
+       4,  0x44,       /* x16 clock, 1 stop (SB1 | X16CLK)*/
+       3,  0xc1,       /* rx enable, 8 bits (RxENABLE | Rx8)*/
+};
+
 /* These are for receiving and sending characters under the kgdb
  * source level kernel debugger.
  */
@@ -2064,6 +2160,24 @@
        write_zsreg(chan, 1, one);
        write_zsreg(chan, 9, nine);
 }
+
+static void kgdbhook_init_channel(struct dec_serial* info) 
+{
+}
+
+static void kgdbhook_init_info(struct dec_serial* info)
+{
+}
+
+static void kgdbhook_rx_char(struct dec_serial* info, 
+                            unsigned char ch, unsigned char stat)
+{
+       if (ch == 0x03 || ch == '$')
+               breakpoint();
+       if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
+               write_zsreg(info->zs_channel, 0, ERR_RES);
+}
+
 /* This sets up the serial port we're using, and turns on
  * interrupts for that channel, so kgdb is usable once we're done.
  */
@@ -2072,7 +2186,7 @@
        int brg;
        int i, x;
        volatile char *sccc = ms->control;
-       brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+       brg = BPS_TO_BRG(bps, zs_parms->clock/16);
        printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
        for (i = 20000; i != 0; --i) {
                x = *sccc; eieio();
@@ -2087,6 +2201,13 @@
  * for /dev/ttyb which is determined in setup_arch() from the
  * boot command line flags.
  */
+struct zs_hook zs_kgdbhook = {
+       init_channel : kgdbhook_init_channel,
+       init_info    : kgdbhook_init_info,
+       cflags       : B38400|CS8|CLOCAL,
+       rx_char      : kgdbhook_rx_char,
+}
+
 __initfunc(void zs_kgdb_hook(int tty_num))
 {
        /* Find out how many Z8530 SCCs we have */
@@ -2097,11 +2218,40 @@
        zs_soft[tty_num].change_needed = 0;
        zs_soft[tty_num].clk_divisor = 16;
        zs_soft[tty_num].zs_baud = 38400;
-       zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
-       zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
+       zs_soft[tty_num].hook = &zs_kgdbhook; /* This runs kgdb */
        /* Turn on transmitter/receiver at 8-bits/char */
         kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
        printk("KGDB: on channel %d initialized\n", tty_num);
        set_debug_traps(); /* init stub */
 }
 #endif /* ifdef CONFIG_KGDB */
+
+#ifdef CONFIG_BAGET_MIPS
+static void baget_kbd_rx_char(struct dec_serial *info, 
+                             unsigned char ch, unsigned char stat) 
+{
+       if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
+               write_zsreg(info->zs_channel, 0, ERR_RES);
+       else 
+               baget_kbd_put(ch);
+}
+
+struct zs_hook baget_kbdhook = {
+       init_channel : NULL,
+       init_info    : NULL,
+       cflags       : B9600|CS8|CSTOPB|CLOCAL,
+       rx_char      : baget_kbd_rx_char
+};
+
+__initfunc(void baget_kbd_hook(int tty_num))
+{
+       zs_init();
+       if (tty_num < 0 || tty_num > zs_channels_found) {
+               printk(KERN_ERR 
+                      "kbd: invalid tty number %d, keyboard disabled\n", 
tty_num);
+               return;
+       }
+       zs_soft[tty_num].hook = &baget_kbdhook;
+       startup(&zs_soft[tty_num]);
+}
+#endif /* ifdef CONFIG_BAGET_MIPS */
--- /ultra/vladimir/sgi/2.2/linux/drivers/tc/zs.h       Mon Jul 12 21:52:32 1999
+++ /home/vladimir/linux-2.2.1/drivers/tc/zs.h  Tue Jul 13 18:41:16 1999
@@ -89,6 +89,16 @@
        unsigned char curregs[NUM_ZSREGS];
 };
 
+struct dec_serial;
+
+struct zs_hook {
+       void (*init_channel)(struct dec_serial* info);
+       void (*init_info)(struct dec_serial* info);
+       unsigned cflags;
+       void (*rx_char)(struct dec_serial* info, 
+                       unsigned char ch, unsigned char stat);
+};
+
 struct dec_serial {
        struct dec_serial *zs_next;     /* For IRQ servicing chain */
        struct dec_zschannel *zs_channel; /* Channel registers */
@@ -97,7 +107,7 @@
 
        char soft_carrier;  /* Use soft carrier on this channel */
        char break_abort;   /* Is serial console in, so process brk/abrt */
-       char kgdb_channel;  /* Kgdb is running on this channel */
+       struct zs_hook *hook;  /* Hook on this channel */
        char is_cons;       /* Is this our console. */
        unsigned char tx_active; /* character is being xmitted */
        unsigned char tx_stopped; /* output is suspended */
<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH] DECstation zs.c, Gleb O. Raiko <=