fuzix: platform-coco3: better drivewire virtual serial port support
authorBrett Gordon <beretta42@gmail.com>
Mon, 29 Jun 2015 12:59:13 +0000 (08:59 -0400)
committerAlan Cox <alan@linux.intel.com>
Tue, 30 Jun 2015 10:55:50 +0000 (11:55 +0100)
* Support for multiple virtual serial and "9server" windows
* Added 'dw' application for simple/testing Drivewire Command/Control API

--
Brett M. Gordon,
beretta42@gmail.com

Applications/dw/Makefile.6809 [new file with mode: 0644]
Applications/dw/coco3.link [new file with mode: 0644]
Applications/dw/dw.c [new file with mode: 0644]
Kernel/platform-coco3/build
Kernel/platform-coco3/config.h
Kernel/platform-coco3/devtty.c
Kernel/platform-coco3/ttydw.c
Kernel/platform-coco3/ttydw.h

diff --git a/Applications/dw/Makefile.6809 b/Applications/dw/Makefile.6809
new file mode 100644 (file)
index 0000000..00b3d4d
--- /dev/null
@@ -0,0 +1,40 @@
+PLATFORM = 6809
+CC = m6809-unknown-gcc
+# These are wrappers for lwasm and lwar
+ASM = m6809-unknown-as
+AR = m6809-unknown-ar
+LINKER = lwlink
+CFLAGS = -I../../Library/include -I../../Library/include/6502
+LINKER_OPT = --format=raw -L../../Library/libs -lc6809
+LIBGCCDIR = $(dir $(shell $(CC) -print-libgcc-file-name))
+LINKER_OPT += -L$(LIBGCCDIR) -lgcc
+LINKER_OPT += --script=$(TARGET).link
+ASM_OPT = -o
+CRT0 = ../../Library/libs/crt0_6809.o
+
+.SUFFIXES: .c .o
+
+
+SRCS  = dw.c
+
+OBJS = $(SRCS:.c=.o)
+
+APPS = $(OBJS:.o=)
+
+all: $(APPS) sizes
+
+$(OBJS): $(SRCS)
+
+$(APPS): $(CRT0)
+
+%: %.o
+       $(LINKER) -o $@ $(LINKER_OPT) $(CRT0) $<
+
+sizes: $(APPS)
+       ls -l $(APPS) > size.report
+
+clean:
+       rm -f $(OBJS) $(APPS) $(SRCS:.c=) core *~ *.asm *.lst *.sym *.map *.noi *.lk *.ihx *.tmp *.bin size.report
+
+rmbak:
+       rm -f *~ core
diff --git a/Applications/dw/coco3.link b/Applications/dw/coco3.link
new file mode 100644 (file)
index 0000000..1174016
--- /dev/null
@@ -0,0 +1,9 @@
+define basesympat __sectionbase_%s__
+define lensympat __sectionlen_%s__
+section .header load 0x0100
+section .text
+section .text.startup
+section .text.hot
+section .test.unlikely
+section .data
+section .bss
diff --git a/Applications/dw/dw.c b/Applications/dw/dw.c
new file mode 100644 (file)
index 0000000..d5accc9
--- /dev/null
@@ -0,0 +1,63 @@
+/* dw.c - Drivewire command
+
+ */
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <termios.h>
+
+
+char ibuf[128];
+char obuf[128];
+struct termios prior,new;
+
+
+
+void puterr( char *str ){
+       write(2, str, strlen(str));
+}
+
+void putstr( char *str ){
+       write(1, str, strlen(str));
+}
+
+int main( int argc, char *argv[]){
+       int fddw;
+       int len;
+
+       putstr( "DriveWire Terminal.  Type \"exit\" to quit.\n");
+
+       while(1){
+               putstr("dw> " );
+               len=read(0, ibuf, 127 );
+               ibuf[len]='\0';
+
+               if( ! strncmp("exit", ibuf,4 ) ) exit(0);
+
+               fddw=open("/dev/tty3", O_RDWR);
+
+               if( ! fddw ){
+                       puterr( "Cannot open device\n" );
+                       exit(-1);
+               }
+
+               tcgetattr( fddw, &prior );
+               tcgetattr( fddw, &new );
+               new.c_lflag = ~ECHO;
+               tcsetattr( fddw, TCSANOW, &new );
+       
+               write( fddw, "dw ", 3);
+               write( fddw, ibuf, len );
+
+               while(1){
+                       len=read( fddw, obuf, 128 );
+                       if( len<=0 ){
+                               tcsetattr( fddw, TCSANOW, &prior );
+                               close( fddw );
+                               break;
+                       }
+                       write( 1, obuf, len );
+               }
+       }
+}
index 1e4ad3a..6a0d5e6 100755 (executable)
@@ -32,6 +32,11 @@ cd ../../Applications/util
 make -f Makefile.6809 TARGET=coco3 clean
 make -f Makefile.6809 TARGET=coco3
 
+# build dw command
+cd ../dw
+make -f Makefile.6809 TARGET=coco3 clean
+make -f Makefile.6809 TARGET=coco3
+
 # build sh
 cd ../../Applications/V7/cmd/sh
 make -f Makefile.6809 TARGET=coco3 clean
index bca552c..429547b 100644 (file)
@@ -67,7 +67,7 @@ extern unsigned char vt_map( unsigned char c );
 #define CMDLINE        0x88      /* Location of root dev name */
 
 /* Device parameters */
-#define NUM_DEV_TTY 3
+#define NUM_DEV_TTY 10
 #define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
 #define NBUFS    6       /* Number of block buffers */
 #define NMOUNTS         2        /* Number of mounts at a time - nothing mountable! */
@@ -75,3 +75,9 @@ extern unsigned char vt_map( unsigned char c );
 #define CONFIG_COCO_KBD   /* Use CoCo key maps rather than Dragon */
 
 
+/* Drivewire Defines */
+
+#define DW_VSER_NUM 4     /* No of Virtual Serial Ports */
+#define DW_VWIN_NUM 4     /* No of Virtual Window Ports */
+#define DW_MIN_OFF  3     /* Minor number offset */
+
index eeaf758..dcc249e 100644 (file)
 uint8_t vtattr_cap;
 
 
-char tbuf1[TTYSIZ];
-char tbuf2[TTYSIZ];
-char tbuf3[TTYSIZ];
-
-struct s_queue ttyinq[NUM_DEV_TTY + 1] = {     /* ttyinq[0] is never used */
+char tbuf1[TTYSIZ];   /* console 0 */
+char tbuf2[TTYSIZ];   /* console 1 */
+char tbuf3[TTYSIZ];   /* drivewire VSER 0 */
+char tbuf4[TTYSIZ];   /* drivewire VSER 1 */
+char tbuf5[TTYSIZ];   /* drivewire VSER 2 */
+char tbuf6[TTYSIZ];   /* drivewire VSER 3 */
+char tbuf7[TTYSIZ];   /* drivewire VWIN 0 */
+char tbuf8[TTYSIZ];   /* drivewire VWIN 1 */
+char tbuf9[TTYSIZ];   /* drivewire VWIN 2 */
+char tbufa[TTYSIZ];   /* drivewire VWIN 3 */
+
+
+struct s_queue ttyinq[NUM_DEV_TTY + 1] = {     
+       /* ttyinq[0] is never used */
        {NULL, NULL, NULL, 0, 0, 0},
+       /* GIME Consoles */
        {tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ / 2},
        {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2},
-       {tbuf3, tbuf3, tbuf3, TTYSIZ, 0, TTYSIZ / 2}
+       /* Drivewire Virtual Serial Ports */
+       {tbuf3, tbuf3, tbuf3, TTYSIZ, 0, TTYSIZ / 2},
+       {tbuf4, tbuf4, tbuf4, TTYSIZ, 0, TTYSIZ / 2},
+       {tbuf5, tbuf5, tbuf5, TTYSIZ, 0, TTYSIZ / 2},
+       {tbuf6, tbuf6, tbuf6, TTYSIZ, 0, TTYSIZ / 2},
+       /* Drivewire Virtual Window Ports */
+       {tbuf7, tbuf7, tbuf7, TTYSIZ, 0, TTYSIZ / 2},
+       {tbuf8, tbuf8, tbuf8, TTYSIZ, 0, TTYSIZ / 2},
+       {tbuf9, tbuf9, tbuf9, TTYSIZ, 0, TTYSIZ / 2},
+       {tbufa, tbufa, tbufa, TTYSIZ, 0, TTYSIZ / 2},
 };
 
 
@@ -52,7 +71,7 @@ int curminor = 1;
 /* A wrapper for tty_close that closes the DW port properly */
 int my_tty_close(uint8_t minor)
 {
-       if (minor == 3 && ttydata[3].users == 0)
+       if (minor > 2 && ttydata[minor].users == 0)
                dw_vclose(minor);
        return (tty_close(minor));
 }
@@ -73,7 +92,7 @@ ttyready_t tty_writeready(uint8_t minor)
 
 void tty_putc(uint8_t minor, unsigned char c)
 {
-       if (minor == 3) {
+       if (minor > 2 ) {
                dw_putc(minor, c);
                return;
        }
@@ -95,15 +114,16 @@ void tty_sleeping(uint8_t minor)
 
 void tty_setup(uint8_t minor)
 {
-       if (minor == 3) {
+       if (minor > 2) {
                dw_vopen(minor);
                return;
        }
 }
 
-/* For the moment */
+
 int tty_carrier(uint8_t minor)
 {
+       if( minor > 2 ) return dw_carrier( minor );
        return 1;
 }
 
index 47977f5..19f1052 100644 (file)
@@ -1,7 +1,79 @@
-/* Drivewire tty
-        This module needs some help to make this cross-platform.
-       And, it only handles one virtual Window.
- */
+/* Drivewire TTY's
+   
+   config.h defines:
+
+   DW_VSER_NUM - number of virtual serial ports ( 0-14 )
+   DW_VWIN_NUM - number of virtual "9server" windows ( 0-14 )
+   DW_MIN_OFF  - tty device minor offset 
+   
+   example:
+
+   #define DW_VSER_NUM 4    
+   #define DW_VWIN_NUM 4     
+   #define DW_MIN_OFF  3    
+   #define NUM_DEV_TTY 10
+
+   then this module will map drivewire tty's to the following minors:
+
+   minor no    description
+   0-2         not mapped.
+   3-6         Drivewire Virtual Serial Ports 0-3
+   7-10        Drivewire Virtual Window Ports 0-3
+
+   Modify your platform's devtty.c to call the following external
+   functions: (don't forget to include ttydw.h)
+
+   Make sure to up your NUM_DEV_TTY define in your config.h to cover
+   all the added tty's !
+
+   External/Public Functions:
+
+   void dw_val( uint8_t minor );
+   void dw_putc( uint8_t minor, unsigned char c );
+   void dw_vopen( uint8_t minor );
+   void dw_vclose( uint8_t minor );
+   int dw_carrier( uint8_t minor );
+   void dw_vpoll( );
+
+   How you switch to these driver function/methods from your devtty.c
+   is up to you...
+
+   dw_vpoll should be called from the timer interrupt.  To conserve
+   cpu time, this fuction only actually polls the DW server every .25
+   seconds
+
+   Finally, you will have to provide a platform dependent
+   "dw_transaction" routine/function:
+
+   int16_t dw_transaction( char *send, uint16_t scnt,
+                            char *recv, uint16_t rcnt )
+
+   where "send" is a data buffer to send
+         "scnt" is the size of the send buffer
+         "recv" is a data buffer for the received reply
+        "rcnt" is the size of the recv buffer
+   returns:  0 on no error
+            -1 on DW reception framing error (too slow!!)
+            -2 on not all bytes received
+
+
+   Usage Notes:
+   
+   You cannot stick a "sh" or "getty" on Virtual Serial ports
+   directly, as these Drivewire ports speak a higher level, but
+   simple, API for do TCP, DW control, MIDI etc.  However, the Window
+   ports, are just that... you can "sh", "getty", or whatever them
+   directly. (stick 'em in your inittab)
+
+   Unfortunately, the current Drivewire server does not issue a close
+   port upon the closing of the actual window!  It will, however, open
+   them on you server's machine upon Fuzix's opening of the port.
+
+   A stock DriveWire4 installation sets up the Virtual Serial Ports like this:
+
+   ports 1-13 : generic ports
+   ports 14 : direct connection to DriveWire's General MIDI
+*/
 
 #include <kernel.h>
 #include <printf.h>
 #define DW_FASTWRITE 0x80
 #define DW_SETSTAT   0xC4
 #define DW_SERREAD   0x43
+#define DW_SERREADM  0x63
+#define DW_INIT      0x5a
 
 #define DW_VOPEN     0x29
 #define DW_VCLOSE    0x2A
 
+
+/* Internal Structure to represent state of DW ports */
+struct dw_in{
+       uint8_t flags;  /* flags for port */
+       /* outgoing buffer here! */
+};
+
+/* port flags */
+#define DW_FLG_OPEN 1     /* is port open? */
+
+
+/* and a table of the above structures */
+struct dw_in dwtab[ DW_VSER_NUM + DW_VWIN_NUM ];
+
 /* How many vsync ticks to wait until polling again, if
    DW reports no data is waiting. */
 #define MAX_WAIT     TICKSPERSEC / 4
@@ -25,62 +113,177 @@ int wait=MAX_WAIT;
    will not poll */
 int open_ports=0;
 
+
+/* buffer for receiving multiple bytes from vport channels */
+char tbuf[256];
+
+
+int mini( int a, int b ){
+       if( a < b ) return a;
+       return b;
+}
+
+
+/* Test a passed minor for validity and/or get index
+   returns: -1 on invalid, else ok. */
+int dw_val( uint8_t minor ){
+       minor-=DW_MIN_OFF;
+       if( minor < 0 ) return -1;
+       if( minor > (DW_VSER_NUM + DW_VWIN_NUM) ) return -1;
+       return minor;
+}
+
+
+/* Gets dw_tab entry for given minor */
+struct dw_in *dw_gettab( uint8_t minor ){
+       return &dwtab[ dw_val( minor ) ] ;
+}
+
+/* Translates a DW port no. to a proper minor no */
+int dw_minor( uint8_t port ){
+       if( port < 16 ) port -= 1 ;
+       else port = port - 64 + DW_VSER_NUM ;
+       return( port + DW_MIN_OFF );
+}
+
+
+/* Translates a Minor to a port no */
+int dw_port( uint8_t minor ){
+       minor -= DW_MIN_OFF;
+       /* fix next line? */
+       if( minor >= DW_VSER_NUM ) minor += 16 - DW_VSER_NUM ;
+       else minor++;
+       return minor;
+}
+
+
+
+/* Put a character to the DriveWire port */
 void dw_putc( uint8_t minor, unsigned char c ){
-  unsigned char buf[2];
-  buf[0]=DW_FASTWRITE | (16 + minor - 3) ;
-  buf[1]=c;
-  dw_transaction( buf, 2, NULL, 0 );
-  if( c == '\n' ){
-    c='\r';
-    dw_transaction( buf,2, NULL, 0 );
-  }
+       unsigned char buf[2];
+       buf[0]=DW_FASTWRITE | dw_port( minor ) ;
+       buf[1]=c;
+       dw_transaction( buf, 2, NULL, 0 );
+       if( c == '\n' ){
+               c='\r';
+               dw_transaction( buf,2, NULL, 0 );
+       }
 }
 
 
+
+/* Open a DriveWire port */
 void dw_vopen( uint8_t minor ){
-  unsigned char buf[3];
-  buf[0]=DW_SETSTAT;
-  buf[1]=minor-3+16;
-  buf[2]=DW_VOPEN;
-  dw_transaction( buf, 3, NULL, 0 );
-  open_ports++;
+       struct dw_in *p=dw_gettab( minor );
+       unsigned char buf[3];
+       buf[0]=DW_SETSTAT;
+       buf[1]=dw_port( minor );
+       buf[2]=DW_VOPEN;
+       if( ! ( p->flags & DW_FLG_OPEN ) ){
+               dw_transaction( buf, 3, NULL, 0 );
+               open_ports++;
+       }
+       p->flags |= DW_FLG_OPEN;
 }
 
-
+/* Close a DriveWire port */
 void dw_vclose( uint8_t minor){
-  unsigned char buf[3];
-  buf[0]=DW_SETSTAT;
-  buf[1]=minor-3+16;
-  buf[2]=DW_VCLOSE;
-  dw_transaction( buf, 3, NULL, 0 );
-  open_ports--;
+       struct dw_in *p=dw_gettab( minor );
+       unsigned char buf[3];
+       buf[0]=DW_SETSTAT;
+       buf[1]=dw_port( minor );
+       buf[2]=DW_VCLOSE;
+       dw_transaction( buf, 3, NULL, 0 );
+       open_ports--;
+       p->flags &= ~DW_FLG_OPEN ;
 }
 
+
+
+/* Return number of byte in tty's input queue */
+int qfree( uint8_t minor ){
+       queue_t *q = &ttyinq[minor];
+       return q->q_size - q->q_count;
+}
+
+
+
 /* Poll and add chars (if any) to input q
-   no multple char reads yet
  */
 void dw_vpoll( ){
-  unsigned char buf[2];
-  int i;
-  /* don't waste time polling of no port are open*/
-  if( ! open_ports ) return ;
-  /* check ticks */
-  if( --wait ) return;
-  for( i=0; i<4; i++){
-    buf[0]=DW_SERREAD;
-    dw_transaction( buf, 1, buf, 2 );
-    // nothing waiting ?
-    if( ! (buf[0] & 0x7e) ) {
-      wait=MAX_WAIT;
-      break;
-    }
-    // Window data?
-    if( buf[0] & 0x7e ){
-      int minor=buf[0]-64+3;
-      if( buf[1]== '\r' ) buf[1]='\n';
-      tty_inproc( minor, buf[1] );
-      continue;
-    }
-    kprintf("out of band data\n");
-  }
+       unsigned char buf[2];
+       int i;
+       /* don't waste time polling of no ports are open*/
+       if( ! open_ports ) return ;
+       /* check ticks - don't poll until our delay is done */
+       if( --wait ) return;
+       /* up to four transactions at a poll */
+       for( i=0; i<4; i++){
+               buf[0]=DW_SERREAD;
+               dw_transaction( buf, 1, buf, 2 );
+               /* nothing waiting ? */
+               if( ! (buf[0] & 0x7f) ) {
+                       wait=MAX_WAIT;
+                       break;
+               }
+               /* VSER Channel single datum */
+               if( buf[0]<16 ){
+                       int minor=dw_minor( buf[0] );
+                       if( buf[1]!= '\r' ) 
+                               tty_inproc( minor, buf[1] );
+                       continue;
+               }
+               /* VSER Channel closed? */
+               if( buf[0] == 16 ){
+                       int minor=dw_minor( buf[1] );
+                       struct dw_in *p=dw_gettab( buf[1]-1 );
+                       p->flags &= ~DW_FLG_OPEN ;
+                       dw_vclose( minor );
+                       tty_carrier_drop( minor );
+                       continue;
+               }
+               /* VSER channel multiple data */
+               if( buf[0] < 32 ){
+                       int i;
+                       char b[3];
+                       char c;
+                       int minor=dw_minor( buf[0]-17 );
+                       b[0]=DW_SERREADM;
+                       b[1]=buf[0]-17;
+                       b[2]=mini( buf[1], qfree( minor )-1 );
+                       dw_transaction( b,3,tbuf, b[2] );
+                       for( i=0; i<b[2]; i++){
+                               if( tbuf[i]!='\r') 
+                                       tty_inproc( minor, tbuf[i] );
+                       }
+                       wait=1;
+                       break;
+               }
+               /* VWIN channel single datum */
+               if( buf[0] < 144 ){
+                       int minor=dw_minor( buf[0] );
+                       tty_inproc( minor, buf[1] );
+                       continue;       
+               }
+               /* something we don't handle? */
+               kprintf("out of band data\n");
+       }
+}
+
+
+
+/* Tests DriveWire port for being open */
+/*   returns: 1 on open, 0 on closed */
+int dw_carrier( uint8_t minor ){
+       struct dw_in *p=dw_gettab( minor );
+       return p->flags & DW_FLG_OPEN ;
+}
+
+
+/* (re) Initializes DW */
+void dw_init( ){
+       char buf[2];
+       buf[0]=DW_INIT;
+       buf[1]=0x42;
+       dw_transaction( buf,2,buf,1 );
 }
index d1157d2..68e0e43 100644 (file)
@@ -4,5 +4,6 @@
 void dw_putc( uint8_t minor, unsigned char c );
 void dw_vopen( uint8_t minor );
 void dw_vclose( uint8_t minor );
+int dw_carrier( uint8_t minor );
 void dw_vpoll( );
 #endif