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

Patches for dz.c

To: linux-mips@fnet.fr
Subject: Patches for dz.c
From: Thomas Riemer <triemer@apt4g.a3nyc.com>
Date: Sun, 1 Nov 1998 15:07:26 -0500 (EST)
Following here, you'll find patches for the dc7085 serial driver.
These patches allow interrupt driven characters to cross the serial line.
It also includes console serial line routines that allow characters
to be sent across the serial line without conflicting with the interrupts.

It has a major flaw though - It does not handle characters received
from the serial line.  Despite all my efforts, I've been unable to
generate an interrupt upon receipt of a character.  I'm hoping someone
out on the list will take some time and see if they can solve that.

I'm a bit afraid of a hard disk crash - and so I'm preparing a patch -
this patch is based on 2.1.121-r3000_pre1.

I guess I'll try and work on the SII disk driver - as I seem to have
reached a brick wall with respects to the serial driver.  

-Tom Riemer

--------------------------------------------------------------------------
diff -rubN linux-2.1.121-r3000/drivers/char/dz.c 
linux-2.1.121-r3000_pl6/drivers/char/dz.c
--- linux-2.1.121-r3000/drivers/char/dz.c       Thu Oct  1 14:55:25 1998
+++ linux-2.1.121-r3000_pl6/drivers/char/dz.c   Sun Nov  1 14:30:58 1998
@@ -10,6 +10,27 @@
  * Changed IRQ to use Harald's dec internals interrupts.h
  * removed base_addr code - moving address assignment to setup.c
  * Changed name of dz_init to rs_init to be consistent with tc code
+
+ * WARNING - READ THIS CAREFULLY:
+ *   This code handles outgoing transmits only...
+ *   For some reason that apparently is beyond me at this point of
+ *   my learning curve - the receive of a character never generates
+ *   an interrupt!  I don't know why - docs indicate that there are 
+ *  two things that need to be done:  1. enable csr - RIE and 
+ *  and 2. enable lpr RXENAB - I've done both of these to no avail.
+ *  I know that characters are coming across the line...
+ *  If you comment out the body of dz_stop...
+ *  The kernel will go into an infinite loop calling dz_interrupt
+ *  At this point you should be able to type characters across the serial line
+ *  that will display on your monitor.  I've left in the code debug_console
+ *  to aid in the process.
+ *  Mind you - these are NOT really interrupts generated by the keys
+ *  coming in - they are actually interrupts generated from the line
+ *  being available to receive more characters. 
+ *  It simply shows that characters are getting across and that RDONE is
+ *  in fact being set on csr.  -triemer (triemer@apt4g.a3nyc.com)
+ *  Any kind soul that can see what I'm doing wrong - please fix it or 
+ *  tell me how to go about fixing it. 
  */
 
 #ifdef MODULE
@@ -29,12 +50,13 @@
 #include <linux/param.h>
 #include <linux/tqueue.h>
 #include <linux/interrupt.h>
-
+#include <asm-mips/wbflush.h>
 /* for definition of SERIAL */
 #include <asm/dec/interrupts.h>
 
 /* for definition of struct console */
 #ifdef CONFIG_SERIAL_CONSOLE
+#define CONSOLE_LINE (3)
 #include <linux/console.h>
 #endif /* ifdef CONFIG_SERIAL_CONSOLE */
 
@@ -47,14 +69,81 @@
 #include <asm/dec/machtype.h>
 #include <asm/dec/kn01.h>
 #include <asm/dec/kn02.h>
-
+#include <asm/bootinfo.h>
 #include "dz.h"
 
-#define DZ_INTR_DEBUG 1
+/* #define DZ_INTR_DEBUG  */
 
-DECLARE_TASK_QUEUE(tq_dz_serial);
+DECLARE_TASK_QUEUE(tq_serial);
+static struct dz_serial *lines[4];
 
 extern struct wait_queue *keypress_wait;
+/* TO FIX - its unclear what
+ the intention for tmp_buf is all about
+ but I'm just going to point tmp_buf at temp_buffer 
+ if tmp_buf is not defined
+*/
+
+unsigned char tmp_buffer[256];
+
+
+/* debugging code to send out chars via prom */
+static void debug_console( const char *s,int count)
+{
+    unsigned i;
+    
+    tag *atag;
+    static int (*prom_printf) (char *,...);
+    static int (*prom_getchar) (void);
+
+
+    atag = bi_TagFind(tag_prom_printf);
+    prom_printf =          (int (*)(char *,...)) *(int *) TAGVALPTR(atag);
+    atag = bi_TagFind(tag_prom_getchar);
+    prom_getchar = (int (*)(void)) *(int *) TAGVALPTR(atag);
+
+    /*
+     *    Now, do each character
+     */
+    /*    while (s[count] != '\0')
+      count++;
+    */
+
+    for (i = 0; i < count; i++) {
+       if (*s == 10)
+           prom_printf("%c", 13);
+       prom_printf("%c", *s++);
+    }
+}
+#ifdef DEBUG
+
+static void debug_int_console(unsigned short val, char *prn, int count)
+{
+  char bits[16];
+  int i;
+  for (i = 0; i < 16; i++)
+    if ((1<<i) & val)
+      bits[15-i] = '1';
+    else
+      bits[15-i] = '0';
+  debug_console(prn,count);
+  debug_console(bits,16);
+  debug_console("\n",1);
+}
+#endif
+
+static inline void outw (unsigned short val, unsigned port)
+{
+  volatile unsigned short *mem_port = (volatile unsigned short *)port;
+  *mem_port = val;
+}
+
+static inline unsigned short inw (unsigned port)
+{
+  volatile unsigned short *mem_port = (volatile unsigned short *)port;
+  return *mem_port;
+}
+
 
 /*
  * ------------------------------------------------------------
@@ -68,15 +157,15 @@
 static inline unsigned short dz_in (struct dz_serial *info, unsigned offset)
 {
   volatile unsigned short *addr = (volatile unsigned short *)(info->port + 
offset);
-
   return *addr;
 }
 
 static inline void dz_out (struct dz_serial *info, unsigned offset, unsigned 
short value)
 {
-  volatile unsigned short *addr = (volatile unsigned short *)(info->port + 
offset);
 
+    volatile unsigned short *addr = (volatile unsigned short *)(info->port + 
offset);
   *addr = value;
+
 }
 
 /*
@@ -94,13 +183,13 @@
   struct dz_serial *info = (struct dz_serial *)tty->driver_data;
   unsigned short mask, tmp;
 
+         
   mask = 1 << info->line;
   tmp = dz_in (info, DZ_TCR);       /* read the TX flag */
 
-  if (tmp & mask) {
+  wbflush();
     tmp &= ~mask;                   /* clear the TX flag */
     dz_out (info, DZ_TCR, tmp);
-  }
 }  
 
 static void dz_start (struct tty_struct *tty)
@@ -110,10 +199,10 @@
 
   mask = 1 << info->line;
   tmp = dz_in (info, DZ_TCR);      /* read the TX flag */
-  if (!(tmp & mask)) {
+
     tmp |= mask;                   /* set the TX flag */
     dz_out (info, DZ_TCR, tmp);
-  }
+
 }  
 
 /*
@@ -147,7 +236,7 @@
 static inline void dz_sched_event (struct dz_serial *info, int event)
 {
   info->event |= 1 << event;
-  queue_task (&info->tqueue, &tq_dz_serial);
+  queue_task (&info->tqueue, &tq_serial);
   mark_bh (SERIAL_BH);
 }
 
@@ -158,85 +247,26 @@
  * This routine deals with inputs from any lines.
  * ------------------------------------------------------------
  */
-static inline void receive_chars (struct dz_serial *info_in)
+static void receive_chars (struct dz_serial *info)
 {
-  struct dz_serial *info;
   struct tty_struct *tty;
   struct async_icount *icount;
   int ignore = 0;
   unsigned short status, tmp;
   unsigned char ch;
+  unsigned long flags;
 
-  do {
-    status = dz_in (info_in, DZ_RBUF); /* get the char in */
-    info = &multi[LINE(status)];       /* re-arrange info to point to the 
proper port */
-
-#ifdef DZ_INTR_DEBUG
-  printk ("line (%d)...", LINE(status));
-#endif
-
-    ch = UCHAR(status);                /* grab the char */
-
-#ifdef 0
-    if (info->is_console) {
-      if (ch == 0) return;            /* it's a break ... */
-
-      wake_up (&keypress_wait);       /* It is a 'keyboard interrupt' ;-) */
-    }
-#endif
-
-    tty = info->tty;                  /* now tty points to the proper dev */
-    icount = &info->icount;
-
-    if (!tty) break;
-
-    if (tty->flip.count >= TTY_FLIPBUF_SIZE) break;
-
-    *tty->flip.char_buf_ptr = ch;
-    *tty->flip.flag_buf_ptr = 0;
-    icount->rx++;
-
-    /* keep track of the statistics */
-    if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) {
-      if (status & DZ_PERR)                /* parity error */
-        icount->parity++;
-      else if (status & DZ_FERR)           /* frame error */
-        icount->frame++;
-      if (status & DZ_OERR)                /* overrun error */
-        icount->overrun++;
-      /* 
-        check to see if we should ignore the character
-        and mask off conditions that should be ignored
-      */
-      if (status & info->ignore_status_mask) {
-        if (++ignore > 100 ) break;
-        goto ignore_char;
-      }
-
-      /* mask off the error conditions we want to ignore */
-      tmp = status & info->read_status_mask;
-
-      if (tmp & DZ_PERR)
-        *tty->flip.flag_buf_ptr = TTY_PARITY;
-      else if (tmp & DZ_FERR)
-        *tty->flip.flag_buf_ptr = TTY_FRAME;
-      /* overrun might be special ?!? I don't know for the DZ chip so in doubt 
... */
-      if (tmp & DZ_OERR) { 
-       if (tty->flip.count < TTY_FLIPBUF_SIZE) {
-          tty->flip.count++;
-          tty->flip.flag_buf_ptr++;
-          tty->flip.char_buf_ptr++;
-          *tty->flip.flag_buf_ptr = TTY_OVERRUN;
-        }
-      }
-    }
-
-    tty->flip.flag_buf_ptr++;
-    tty->flip.char_buf_ptr++;
-    tty->flip.count++;
+  save_flags(flags);
+  cli();
+  do
+  {
+    status = dz_in (info, DZ_RBUF);
+    wbflush();
+    ch = UCHAR(status);
+    printk("char:%c\n", ch);
 
-  ignore_char:
   } while (status & DZ_DVAL);
+  restore_flags(flags);
 }
 
 /*
@@ -250,6 +280,7 @@
 {
   unsigned char tmp;
 
+
   if (info->x_char) {           /* XON/XOFF chars */
     dz_out (info, DZ_TDR, info->x_char);
     info->icount.tx++;
@@ -307,34 +338,17 @@
  */
 static void dz_interrupt (int irq, void *dev, struct pt_regs *regs)
 {
-  struct dz_serial *info = (struct dz_serial *)dev;
+  struct dz_serial *info;
   unsigned short status;
 
-#ifdef DZ_INTR_DEBUG
-  printk ("dz_interrupt_multi (%d)...", irq);
-#endif
-
-  status = dz_in (info, DZ_CSR);   /* get the reason why we just got an irq */
+  status = dz_in ((struct dz_serial *)dev, DZ_CSR); /* get the reason why we 
just got an irq */
+  info = lines[LINE(status)];     /* re-arrange info the proper port */
 
-  if (status & DZ_RDONE) {         /* RX interrupt */
-#ifdef DZ_INTR_DEBUG
-    printk (" RX ");
-#endif   
-    receive_chars (info);          /* the receive function will deal with the 
identification
-                                      of the line causing the irq */
-  }
+  if (status & DZ_RDONE) 
+      receive_chars (info);          /* the receive function */
 
-  if (status & DZ_TRDY) {          /* TX interrupt */ 
-#ifdef DZ_INTR_DEBUG
-  printk (" TX line (%d)...", LINE(status));
-#endif       
-    info = &multi[LINE(status)];   /* re-arrange info to point to the proper 
port */
+  if (status & DZ_TRDY) 
     transmit_chars (info);
-  }
-
-#ifdef DZ_INTR_DEBUG
-  printk ("end\n");
-#endif
 }
 
 /*
@@ -354,7 +368,7 @@
  */
 static void do_serial_bh (void)
 {
-        run_task_queue (&tq_dz_serial);
+        run_task_queue (&tq_serial);
 }
 
 static void do_softint (void *private_data)
@@ -401,7 +415,7 @@
 static int startup (struct dz_serial *info)
 {
   unsigned long page, flags;
-  unsigned short tmp;
+  unsigned short tmp,mask;
 
   if (info->is_initialized) return 0;
   
@@ -435,6 +449,12 @@
   /* set up the speed */
   change_speed (info);
 
+  /* clear the line transmitter buffer 
+     I can't figure out why I need to do this - but
+     its necessary - in order for the console portion
+     and the interrupt portion to live happily side by side.
+  */
+
   info->is_initialized = 1;
 
   restore_flags (flags);
@@ -461,6 +481,7 @@
 
   dz_stop (info->tty);
 
+
   info->cflags &= ~DZ_CREAD;          /* turn off receive enable flag */
   dz_out (info, DZ_LPR, info->cflags);
 
@@ -537,6 +558,7 @@
   default  :  info->cflags |= DZ_B9600; 
   }
 
+  info->cflags |= DZ_RXENAB;
   dz_out (info, DZ_LPR, info->cflags);
 
   /* setup accept flag */
@@ -616,12 +638,16 @@
 {
   struct dz_serial *info = (struct dz_serial *)tty->driver_data;
   unsigned long flags;
-
   int c, ret = 0;
 
-  if (!tty || !info->xmit_buf || !tmp_buf) return ret; 
+  if (!tty ) return ret;
+  if (!info->xmit_buf) return ret;
+  if (!tmp_buf) tmp_buf = tmp_buffer;
+
+
 
   if (from_user) {
+
     down (&tmp_buf_sem);
     while (1) {
       c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - 
info->xmit_head));
@@ -650,6 +676,8 @@
     
     up (&tmp_buf_sem);
   } else {
+
+
     while (1) {
       save_flags (flags);
       cli ();     
@@ -671,8 +699,17 @@
     }
   }
 
-  if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) dz_start 
(info->tty);
 
+  if (info->xmit_cnt)
+    {
+      if (!tty->stopped) 
+       {
+         if (!tty->hw_stopped)
+           {
+             dz_start (info->tty);
+           }
+       }
+    }
   return ret;
 }
 
@@ -695,7 +732,7 @@
 
 /* 
  * -------------------------------------------------------------------
- * dz_char_in_buffer ()
+ * dz_chars_in_buffer ()
  *
  * compute the amount of char left to be transmitted
  * ------------------------------------------------------------------- 
@@ -1194,6 +1231,7 @@
   int retval, line;
 
   line = MINOR(tty->device) - tty->driver.minor_start;
+
   /* The dz lines for the mouse/keyboard must be
    * opened using their respective drivers.
    */
@@ -1203,9 +1241,11 @@
   if ((line == DZ_KEYBOARD) || (line == DZ_MOUSE))
     return -ENODEV;
 
-  info = &multi[line];
+  /* force to console for now.*/
+  info = lines[line];
 
   info->count++;
+
   tty->driver_data = info;
   info->tty = tty;
 
@@ -1216,6 +1256,7 @@
   if (retval)
     return retval;
 
+
   retval = block_til_ready (tty, filp, info);
   if (retval)
     return retval;
@@ -1226,11 +1267,14 @@
     else 
       *tty->termios = info->callout_termios;
     change_speed (info);
+
   }
 
   info->session = current->session;
   info->pgrp = current->pgrp;
 
+
+
   return 0;
 }
 
@@ -1244,6 +1288,7 @@
 {
   int i, flags;
   struct dz_serial *info;
+  unsigned short tmp;
 
   /* Setup base handler, and timer table. */
   init_bh (SERIAL_BH, do_serial_bh);
@@ -1302,13 +1347,16 @@
   save_flags(flags); cli();
  
   i = 0;
-  for (info = &multi[i]; i < DZ_NB_PORT;  i++) {
+  for (info = &multi[i]; i < DZ_NB_PORT;  i++) 
+    {
+      lines[i] = info;
     info->magic = SERIAL_MAGIC;
-    if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) {
+
+      if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) 
       info->port = (unsigned long) KN01_DZ11_BASE;
-    } else {
+      else 
       info->port = (unsigned long) KN02_DZ11_BASE;
-    }
+
     info->line = i;
     info->tty = 0;
     info->close_delay = 50;
@@ -1334,15 +1382,54 @@
     printk("ttyS%02d at 0x%04x (irq = %d)\n", info->line, info->port, SERIAL);
   }
 
-  if (request_irq (SERIAL, dz_interrupt, (SA_INTERRUPT), "DZ", &multi[0]))
-    panic ("Unable to register DZ interrupt\n");
+  /* reset the chip */
+#ifndef CONFIG_SERIAL_CONSOLE
+  dz_out(info, DZ_CSR, DZ_CLR);
+  while ((tmp = dz_in(info,DZ_CSR)) & DZ_CLR) ;
+  wbflush();
   
+  /* enable scanning */
+   dz_out(info, DZ_CSR, DZ_MSE); 
+#endif
+  
+  /* order matters here... the trick is that flags
+     is updated... in request_irq - to immediatedly obliterate
+     it is unwise. */
   restore_flags(flags);
  
+
+  if (request_irq (SERIAL, dz_interrupt, SA_INTERRUPT, "DZ", lines[0]))
+    panic ("Unable to register DZ interrupt\n");
+ 
   return 0;
 }
 
 #ifdef CONFIG_SERIAL_CONSOLE
+static void dz_console_put_char (unsigned char ch)
+{
+  long flags;
+  int  loops = 1000;
+  unsigned short tmp = ch;
+  /* this code sends stuff out to serial device - spinning its
+      wheels and waiting. */
+
+  /* force the issue - point it at lines[3]*/
+
+  dz_console=&multi[CONSOLE_LINE];
+
+  save_flags(flags);
+  cli();
+  
+
+  /* spin our wheels */
+  while (((dz_in(dz_console,DZ_TCR) & DZ_TRDY) != DZ_TRDY) &&  loops--)
+    ;
+  
+  /* Actually transmit the character. */
+  dz_out (dz_console, DZ_TDR, tmp);
+
+  restore_flags(flags); 
+}
 /* 
  * -------------------------------------------------------------------
  * dz_console_print ()
@@ -1350,15 +1437,18 @@
  * dz_console_print is registered for printk.
  * ------------------------------------------------------------------- 
  */
+
 static void dz_console_print (struct console *cons, const char *str, unsigned 
int count)
 {
-  while (count--) {
+
+  /* turn off interrupts */
+ 
+  while (count--) 
+    {
     if (*str == '\n')
-      dz_put_char (dz_console->tty, '\r');
-    dz_put_char (dz_console->tty, *str++);
+         dz_console_put_char('\r');
+      dz_console_put_char(*str++);
   }
-
-  dz_start (dz_console->tty);
 }
 
 static int dz_console_wait_key(struct console *co)
@@ -1378,6 +1468,7 @@
        int     parity = 'n';
        int     cflag = CREAD | HUPCL | CLOCAL;
        char    *s;
+       unsigned short mask,tmp;
 
        if (options) {
                baud = simple_strtoul(options, NULL, 10);
@@ -1427,6 +1518,34 @@
        }
        co->cflag = cflag;
 
+       /* TOFIX: force to console line */
+       dz_console = &multi[CONSOLE_LINE];
+       dz_console->port = KN01_DZ11_BASE;
+       dz_console->line = CONSOLE_LINE;
+
+       dz_out(dz_console, DZ_CSR, DZ_CLR);
+       while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR)
+         ;
+
+       /* enable scanning */
+       dz_out(dz_console, DZ_CSR, DZ_MSE); 
+
+        /*  Set up flags... */
+       dz_console->cflags = 0;
+       dz_console->cflags |= DZ_B9600;
+       dz_console->cflags |= DZ_CS8;
+       dz_console->cflags |= DZ_PARENB;
+       dz_out (dz_console, DZ_LPR, dz_console->cflags);
+
+
+       mask = 1 << dz_console->line;
+       tmp = dz_in (dz_console, DZ_TCR);       /* read the TX flag */
+       if (!(tmp & mask)) {
+         tmp |= mask;                   /* set the TX flag */
+         dz_out (dz_console, DZ_TCR, tmp); 
+       }
+       
+
        return 0;
 }
 
@@ -1438,8 +1557,8 @@
        dz_console_wait_key,
        NULL,
        dz_console_setup,
-       CON_PRINTBUFFER,
-       -1,
+       CON_CONSDEV | CON_PRINTBUFFER,
+       CONSOLE_LINE,
        0,
        NULL
 };
@@ -1447,6 +1566,7 @@
 __initfunc (long dz_serial_console_init(long kmem_start, long kmem_end))
 {
        register_console(&dz_sercons);
+
        return kmem_start;
 }
 
diff -rubN linux-2.1.121-r3000/drivers/char/dz.h 
linux-2.1.121-r3000_pl6/drivers/char/dz.h
--- linux-2.1.121-r3000/drivers/char/dz.h       Thu Oct  1 14:55:25 1998
+++ linux-2.1.121-r3000_pl6/drivers/char/dz.h   Sat Oct 31 23:11:02 1998
@@ -94,7 +94,7 @@
 #define DZ_B9600         0x0E00
 
 #define DZ_CREAD         0x1000               /* Enable receiver */
-
+#define DZ_RXENAB        0x1000               /* enable receive char */
 /*
  * Addresses for the DZ registers
  */
@@ -208,7 +208,6 @@
 static void do_softint (void *);
 static void do_serial_hangup (void *);
 static void change_speed (struct dz_serial *);
-static void dz_put_char (struct tty_struct *, unsigned char);
 static void dz_flush_chars (struct tty_struct *);
 static void dz_console_print (struct console *, const char *, unsigned int);
 static void dz_flush_buffer (struct tty_struct *);
diff -rubN linux-2.1.121-r3000/drivers/net/declance.c 
linux-2.1.121-r3000_pl6/drivers/net/declance.c
--- linux-2.1.121-r3000/drivers/net/declance.c  Thu Oct  1 14:55:26 1998
+++ linux-2.1.121-r3000_pl6/drivers/net/declance.c      Sat Oct 31 23:11:02 1998
@@ -963,6 +963,7 @@
        return 0;
 }
 
+#ifdef CONFIG_TC
 static int tc_probe(struct device *dev, unsigned char *esar_base)
 {
        extern slot_info tc_bus[MAX_SLOT];
@@ -984,6 +985,7 @@
        }
        return 0;
 }
+#endif
 
 /* Find all the lance cards on the system and initialize them */
 __initfunc(int dec_lance_probe (struct device *dev))


<Prev in Thread] Current Thread [Next in Thread>
  • Patches for dz.c, Thomas Riemer <=