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},
};
/* 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));
}
void tty_putc(uint8_t minor, unsigned char c)
{
- if (minor == 3) {
+ if (minor > 2 ) {
dw_putc(minor, c);
return;
}
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;
}
-/* 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
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 );
}