From eee4e7bb27e0d8e6de071bbacfc6aacf6e5a640d Mon Sep 17 00:00:00 2001 From: Brett Gordon Date: Mon, 29 Jun 2015 08:59:13 -0400 Subject: [PATCH] fuzix: platform-coco3: better drivewire virtual serial port support * 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 | 40 +++++ Applications/dw/coco3.link | 9 + Applications/dw/dw.c | 63 +++++++ Kernel/platform-coco3/build | 5 + Kernel/platform-coco3/config.h | 8 +- Kernel/platform-coco3/devtty.c | 40 +++-- Kernel/platform-coco3/ttydw.c | 301 +++++++++++++++++++++++++++------ Kernel/platform-coco3/ttydw.h | 1 + 8 files changed, 407 insertions(+), 60 deletions(-) create mode 100644 Applications/dw/Makefile.6809 create mode 100644 Applications/dw/coco3.link create mode 100644 Applications/dw/dw.c diff --git a/Applications/dw/Makefile.6809 b/Applications/dw/Makefile.6809 new file mode 100644 index 00000000..00b3d4d7 --- /dev/null +++ b/Applications/dw/Makefile.6809 @@ -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 index 00000000..11740160 --- /dev/null +++ b/Applications/dw/coco3.link @@ -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 index 00000000..d5accc9d --- /dev/null +++ b/Applications/dw/dw.c @@ -0,0 +1,63 @@ +/* dw.c - Drivewire command + + */ +#include +#include +#include +#include +#include + + +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 ); + } + } +} diff --git a/Kernel/platform-coco3/build b/Kernel/platform-coco3/build index 1e4ad3a8..6a0d5e6b 100755 --- a/Kernel/platform-coco3/build +++ b/Kernel/platform-coco3/build @@ -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 diff --git a/Kernel/platform-coco3/config.h b/Kernel/platform-coco3/config.h index bca552c9..429547bf 100644 --- a/Kernel/platform-coco3/config.h +++ b/Kernel/platform-coco3/config.h @@ -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 */ + diff --git a/Kernel/platform-coco3/devtty.c b/Kernel/platform-coco3/devtty.c index eeaf7586..dcc249e9 100644 --- a/Kernel/platform-coco3/devtty.c +++ b/Kernel/platform-coco3/devtty.c @@ -15,15 +15,34 @@ 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; } diff --git a/Kernel/platform-coco3/ttydw.c b/Kernel/platform-coco3/ttydw.c index 47977f5c..19f10520 100644 --- a/Kernel/platform-coco3/ttydw.c +++ b/Kernel/platform-coco3/ttydw.c @@ -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 #include @@ -11,10 +83,26 @@ #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; iflags & 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 ); } diff --git a/Kernel/platform-coco3/ttydw.h b/Kernel/platform-coco3/ttydw.h index d1157d29..68e0e434 100644 --- a/Kernel/platform-coco3/ttydw.h +++ b/Kernel/platform-coco3/ttydw.h @@ -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 -- 2.34.1