Resent-Date: Sat, 20 Feb 1999 17:43:41 +0100 (MET)
Date: Sat, 20 Feb 1999 16:43:28 GMT
From: Jesper Skov <jskov@cygnus.co.uk>
To: linux-m68k@lists.linux-m68k.org, Jes.Sorensen@cern.ch
Subject: Amiga serial changes
Resent-From: linux-m68k@phil.uni-sb.de


Would anyone mind the below changes?

 o Added mb() for PPC support.
 o Added GDB support stuff.

Jesper

--- /home/jskov/kernel/dist/linux-2.2.1pre2/drivers/char/amiga_ser.c	Mon Jan 11 20:30:10 1999
+++ amiga_ser.c	Sat Feb 20 16:43:17 1999
@@ -7,6 +7,7 @@
  * Modifications by Matthias Welwarsky <Matthias.Welwarsky@ppp.th-darmstadt.de>
  * - fixed reentrancy problem in ser_tx_int()
  * 
+ * 20/02/99 - Jesper Skov: Added mb() calls and KGDB support.
  * 27/04/96 - Jes Soerensen: Upgraded for Linux-1.3.x.
  * 02/09/96 - Jes Soerensen: Moved the {request,free}_irq call for
  *            AMIGA_VERTB interrupts into the init/deinit funtions as
@@ -25,6 +26,7 @@
  * This file implements the driver for the Amiga built-in serial port.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/types.h>
@@ -202,34 +204,61 @@
      * set the appropriate directions for the modem control flags,
      * and clear RTS and DTR
      */
-    ciab.ddra |= (SER_DTR | SER_RTS);   /* outputs */
-    ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
-    
+    {
+	    unsigned short v = ciab.ddra;
+	    v |= (SER_DTR | SER_RTS);   /* outputs */
+	    v &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
+	    ciab.ddra = v;
+    }
+
     info->sw   = &amiga_ser_switch;
 
+#ifdef CONFIG_KGDB
+    /* turn Rx interrupts on for GDB */
+    custom.intena = IF_SETCLR | IF_RBF;
+    ser_RTSon();
+#endif
+
     return 0;
 }
 
 static void ser_rx_int(int irq, void *data, struct pt_regs *fp)
 {
-      struct m68k_async_struct *info = data;
-      int ch, err;
+      int ch;
 
       ch = custom.serdatr;
-
       custom.intreq = IF_RBF;
 
-      if ((ch & 0x1ff) == 0)
-	  err = TTY_BREAK;
-      else if (ch & SDR_OVRUN)
-	  err = TTY_OVERRUN;
-      else
-	  err = 0;
-      rs_receive_char(info, ch & 0xff, err);
+#ifdef CONFIG_KGDB
+      {
+	      extern void breakpoint (void);
+
+	      /* Break signal from GDB? */
+	      if (0x03 == (ch & 0xff)) {
+		      /* FIXME: This way of doing a breakpoint sucks
+                         big time. I will fix it later. */
+		      breakpoint ();
+	      }
+      }
+#else
+      {
+	      struct m68k_async_struct *info = data;
+	      int err;
+
+	      if ((ch & 0x1ff) == 0)
+		      err = TTY_BREAK;
+	      else if (ch & SDR_OVRUN)
+		      err = TTY_OVERRUN;
+	      else
+		      err = 0;
+	      rs_receive_char(info, ch & 0xff, err);
+      }
+#endif
 }
 
 static void ser_tx_int( int irq, void *data, struct pt_regs *fp)
 {
+#ifndef CONFIG_KGDB
       struct m68k_async_struct *info = data;
       int ch;
 
@@ -241,6 +270,7 @@
 	        /* disable tx interrupts */
 	        custom.intena = IF_TBE;
       }
+#endif
 }
 
 
@@ -254,6 +284,7 @@
 
 static void ser_init( struct m68k_async_struct *info )
 {	
+#ifndef CONFIG_KGDB
 	request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0,
 		    "serial status", amiga_info);
 
@@ -268,11 +299,13 @@
 	current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS);
 
 	MOD_INC_USE_COUNT;
+#endif
 }
 
 
 static void ser_enab_tx_int (struct m68k_async_struct *info, int enab_flag)
 {
+#ifndef CONFIG_KGDB
     if (enab_flag) {
         unsigned long flags;
 	save_flags(flags);
@@ -280,23 +313,26 @@
 	custom.intena = IF_SETCLR | IF_TBE;
 	/* set a pending Tx Interrupt, transmitter should restart now */
 	custom.intreq = IF_SETCLR | IF_TBE;
+	mb();			/* ensures interrupt on restore_flags */
 	restore_flags(flags);
     } else {
 	/* disable Tx interrupt and remove any pending interrupts */
         custom.intena = IF_TBE;
 	custom.intreq = IF_TBE;
     }
+#endif
 }
 
 
 static void ser_deinit( struct m68k_async_struct *info, int leave_dtr )
 {
+#ifndef CONFIG_KGDB
     /* disable Rx and Tx interrupt */
     custom.intena = IF_RBF | IF_TBE;
 
     /* wait for last byte to be completely shifted out */
     while( !(custom.serdatr & SDR_TSRE) )
-	;
+	    barrier();
 
     /* drop RTS and DTR if required */
     ser_RTSoff();
@@ -305,6 +341,7 @@
 
     free_irq(IRQ_AMIGA_VERTB, amiga_info);
     MOD_DEC_USE_COUNT;
+#endif
 }
 
 
@@ -319,10 +356,11 @@
 static void ser_change_speed( struct m68k_async_struct *info )
 
 {
+#ifndef CONFIG_KGDB
     unsigned	cflag, baud, chsize, stopb, parity, aflags;
     unsigned	div = 0;
     int realbaud;
-	
+
     if (!info->tty || !info->tty->termios) return;
 
     cflag  = info->tty->termios->c_cflag;
@@ -383,24 +421,29 @@
 
     /* setup the serial port period register */
     custom.serper = div;
+#endif /* !CONFIG_KGDB */
 }
 
 
 static void ser_throttle( struct m68k_async_struct *info, int status )
 {
+#ifndef CONFIG_KGDB
     if (status)
 	ser_RTSoff();
     else
 	ser_RTSon();
+#endif
 }
 
 
 static void ser_set_break( struct m68k_async_struct *info, int break_flag )
 {
+#ifndef CONFIG_KGDB
     if (break_flag)
 	custom.adkcon = AC_SETCLR | AC_UARTBRK;
     else
 	custom.adkcon = AC_UARTBRK;
+#endif
 }
 
 
@@ -430,6 +473,7 @@
 static int ser_set_modem_info( struct m68k_async_struct *info,
 			      int new_dtr, int new_rts )
 {
+#ifndef CONFIG_KGDB
     if (new_dtr == 0)
 	ser_DTRoff();
     else if (new_dtr == 1)
@@ -441,14 +485,17 @@
 	ser_RTSon();
 
     return( 0 );
+#endif
 }
 
 static void ser_stop_receive( struct m68k_async_struct *info )
 {
+#ifndef CONFIG_KGDB
 	/* disable receive interrupts */
 	custom.intena = IF_RBF;
 	/* clear any pending receive interrupt */
 	custom.intreq = IF_RBF;
+#endif
 }
 
 static int ser_trans_empty( struct m68k_async_struct *info )
@@ -458,42 +505,44 @@
 
 #ifdef CONFIG_KGDB
 int amiga_ser_out( unsigned char c )
-
 {
 	custom.serdat = c | 0x100;
+	mb();			/* don't allow prefetch */
 	while (!(custom.serdatr & 0x2000))
 		barrier();
 	return( 1 );
 }
 
 unsigned char amiga_ser_in( void )
-
 {
 	unsigned char c;
-	
+
 	/* XXX: is that ok?? derived from amiga_ser.c... */
 	while( !(custom.intreqr & IF_RBF) )
 		barrier();
-	c = custom.serdatr;
+
+	mb();			/* don't allow prefetch */
+	c = (unsigned char) (custom.serdatr & 0x00ff);
+
 	/* clear the interrupt, so that another character can be read */
 	custom.intreq = IF_RBF;
-	return( 0 );
+	return c;
 }
 #endif
 
 #ifdef MODULE
 int init_module(void)
 {
-return amiga_serinit();
+	return amiga_serinit();
 }
 
 void cleanup_module(void)
 {
-unregister_serial(line);
-custom.intena = IF_RBF | IF_TBE; /* forbid interrupts */
-custom.intreq = IF_RBF | IF_TBE; /* clear pending interrupts */
-free_irq(IRQ_AMIGA_TBE, amiga_info);
-free_irq(IRQ_AMIGA_RBF, amiga_info);
+	unregister_serial(line);
+	custom.intena = IF_RBF | IF_TBE; /* forbid interrupts */
+	custom.intreq = IF_RBF | IF_TBE; /* clear pending interrupts */
+	free_irq(IRQ_AMIGA_TBE, amiga_info);
+	free_irq(IRQ_AMIGA_RBF, amiga_info);
 }
 #endif
 

