1999-04-16 01:33:56 +00:00
/* Remote serial interface using Hitachi E7000 PC ISA card in a PC
Copyright 1994 , 1999 Free Software Foundation , Inc .
This file is part of GDB .
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA . */
# if defined __GO32__ || defined _WIN32
# include "defs.h"
# include "serial.h"
# include "gdb_string.h"
/* MSVC uses strnicmp instead of strncasecmp */
# ifdef _MSC_VER
# define strncasecmp strnicmp
# define WIN32_LEAN_AND_MEAN
# endif
# ifdef _WIN32
# include <windows.h>
# endif
# ifdef __GO32__
# include <sys/dos.h>
# endif
static int e7000pc_open PARAMS ( ( serial_t scb , const char * name ) ) ;
static void e7000pc_raw PARAMS ( ( serial_t scb ) ) ;
static int e7000pc_readchar PARAMS ( ( serial_t scb , int timeout ) ) ;
static int e7000pc_setbaudrate PARAMS ( ( serial_t scb , int rate ) ) ;
static int e7000pc_write PARAMS ( ( serial_t scb , const char * str , int len ) ) ;
static void e7000pc_close PARAMS ( ( serial_t scb ) ) ;
static serial_ttystate e7000pc_get_tty_state PARAMS ( ( serial_t scb ) ) ;
static int e7000pc_set_tty_state PARAMS ( ( serial_t scb , serial_ttystate state ) ) ;
# define OFF_DPD 0x0000
# define OFF_DDP 0x1000
# define OFF_CPD 0x2000
# define OFF_CDP 0x2400
# define OFF_FA 0x3000
# define OFF_FB 0x3002
# define OFF_FC 0x3004
# define OFF_IRQTOD 0x3008
# define OFF_IRQTOP 0x300a
# define OFF_READY 0x300c
# define OFF_PON 0x300e
# define IDLE 0x0000
# define CMD_CI 0x4349
# define CMD_CO 0x434f
# define CMD_LO 0x4c4f
# define CMD_LS 0x4c53
# define CMD_SV 0x5356
# define CMD_SS 0x5353
# define CMD_OK 0x4f4b
# define CMD_ER 0x4552
# define CMD_NF 0x4e46
# define CMD_AB 0x4142
# define CMD_ED 0x4544
# define CMD_CE 0x4345
static unsigned long fa ;
static unsigned long irqtod ;
static unsigned long ready ;
static unsigned long fb ;
static unsigned long cpd ;
static unsigned long cdp ;
static unsigned long ready ;
static unsigned long pon ;
static unsigned long irqtop ;
static unsigned long board_at ;
# ifdef __GO32__
# define SET_BYTE(x,y) { char _buf = y;dosmemput(&_buf,1, x);}
# define SET_WORD(x,y) { short _buf = y;dosmemput(&_buf,2, x);}
# define GET_BYTE(x) ( dosmemget(x,1,&bb), bb)
# define GET_WORD(x) ( dosmemget(x,2,&sb), sb)
static unsigned char bb ;
static unsigned short sb ;
# else /* win32 */
# define SET_BYTE(x,y) *(volatile unsigned char *)(x) = (y)
# define SET_WORD(x,y) *(volatile unsigned short *)(x) = (y)
# define GET_BYTE(x) (*(volatile unsigned char *)(x))
# define GET_WORD(x) (*(volatile unsigned short *)(x))
# define dosmemget(FROM, LEN, TO) memcpy ((void *)(TO), (void *)(FROM), (LEN))
# define dosmemput(FROM, LEN, TO) memcpy ((void *)(TO), (void *)(FROM), (LEN))
# endif
static struct sw
{
int sw ;
int addr ;
} sigs [ ] = {
{ 0x14 , 0xd0000 } ,
{ 0x15 , 0xd4000 } ,
{ 0x16 , 0xd8000 } ,
{ 0x17 , 0xdc000 } ,
0 } ;
# ifdef _MSC_VER
/* Get the base of the data segment. This is needed to calculate the offset
between data segment addresses and the base of linear memory , which is where
device registers reside . Note that this is really only necessary for
Win32s , since Win95 and NT keep the data segment at linear 0. */
static unsigned long
get_ds_base ( void )
{
unsigned short dsval ;
LDT_ENTRY ldt ;
unsigned long dsbase ;
__asm
{
mov dsval , ds
}
dsbase = 0 ;
GetThreadSelectorEntry ( GetCurrentThread ( ) , dsval , & ldt ) ;
dsbase = ldt . HighWord . Bits . BaseHi < < 24 | ldt . HighWord . Bits . BaseMid < < 16
| ldt . BaseLow ;
return dsbase ;
}
# else /* !_MSC_VER */
# define get_ds_base() 0
# endif /* _MSC_VER */
static int
e7000pc_init ( )
{
int try ;
unsigned long dsbase ;
dsbase = get_ds_base ( ) ;
/* Look around in memory for the board's signature */
for ( try = 0 ; sigs [ try ] . sw ; try + + )
{
int val ;
board_at = sigs [ try ] . addr - dsbase ;
fa = board_at + OFF_FA ;
fb = board_at + OFF_FB ;
cpd = board_at + OFF_CPD ;
cdp = board_at + OFF_CDP ;
ready = board_at + OFF_READY ;
pon = board_at + OFF_PON ;
irqtop = board_at + OFF_IRQTOP ;
irqtod = board_at + OFF_IRQTOD ;
val = GET_WORD ( ready ) ;
if ( val = = ( 0xaaa0 | sigs [ try ] . sw ) )
{
if ( GET_WORD ( pon ) & 0xf )
{
SET_WORD ( fa , 0 ) ;
SET_WORD ( fb , 0 ) ;
SET_WORD ( irqtop , 1 ) ; /* Disable interrupts from e7000 */
SET_WORD ( ready , 1 ) ;
printf_filtered ( " \n Connected to the E7000PC at address 0x%x \n " ,
sigs [ try ] . addr ) ;
return 1 ;
}
error ( " The E7000 PC board is working, but the E7000 is turned off. \n " ) ;
return 0 ;
}
}
error ( " GDB cannot connect to the E7000 PC board, check that it is installed \n \
and that the switch settings are correct . Some other DOS programs can \ n \
stop the board from working . Try starting from a very minimal boot , \ n \
perhaps you need to disable EMM386 over the region where the board has \ n \
its I / O space , remove other unneeded cards , etc etc \ n " );
return 0 ;
}
static int pbuf_size ;
static int pbuf_index ;
/* Return next byte from cdp. If no more, then return -1. */
static int
e7000_get ( void )
{
static char pbuf [ 1000 ] ;
char tmp [ 1000 ] ;
int x ;
if ( pbuf_index < pbuf_size )
{
x = pbuf [ pbuf_index + + ] ;
}
else if ( ( GET_WORD ( fb ) & 1 ) )
{
int i ;
pbuf_size = GET_WORD ( cdp + 2 ) ;
dosmemget ( cdp + 8 , pbuf_size + 1 , tmp ) ;
/* Tell the E7000 we've eaten */
SET_WORD ( fb , 0 ) ;
/* Swap it around */
for ( i = 0 ; i < pbuf_size ; i + + )
{
pbuf [ i ] = tmp [ i ^ 1 ] ;
}
pbuf_index = 0 ;
x = pbuf [ pbuf_index + + ] ;
}
else
{
x = - 1 ;
}
return x ;
}
/* Works just like read(), except that it takes a TIMEOUT in seconds. Note
that TIMEOUT = = 0 is a poll , and TIMEOUT = = - 1 means wait forever . */
static int
dosasync_read ( fd , buf , len , timeout )
int fd ;
char * buf ;
int len ;
int timeout ;
{
long now ;
long then ;
int i = 0 ;
/* Then look for some more if we're still hungry */
time ( & now ) ;
then = now + timeout ;
while ( i < len )
{
int ch = e7000_get ( ) ;
/* While there's room in the buffer, and we've already
read the stuff in , suck it over */
if ( ch ! = - 1 )
{
buf [ i + + ] = ch ;
while ( i < len & & pbuf_index < pbuf_size )
{
ch = e7000_get ( ) ;
if ( ch = = - 1 )
break ;
buf [ i + + ] = ch ;
}
}
time ( & now ) ;
if ( timeout = = 0 )
return i ;
if ( now > = then & & timeout > 0 )
{
return i ;
}
}
return len ;
}
static int
dosasync_write ( fd , buf , len )
int fd ;
const char * buf ;
int len ;
{
int i ;
char dummy [ 1000 ] ;
/* Construct copy locally */
( ( short * ) dummy ) [ 0 ] = CMD_CI ;
( ( short * ) dummy ) [ 1 ] = len ;
( ( short * ) dummy ) [ 2 ] = 0 ;
( ( short * ) dummy ) [ 3 ] = 0 ;
for ( i = 0 ; i < len ; i + + )
{
1999-04-26 18:23:13 +00:00
dummy [ ( 8 + i ) ^ 1 ] = buf [ i ] ;
1999-04-16 01:33:56 +00:00
}
/* Wait for the card to get ready */
while ( GET_WORD ( fa ) & 1 ) ;
/* Blast onto the ISA card */
dosmemput ( dummy , 8 + len + 1 , cpd ) ;
SET_WORD ( fa , 1 ) ;
SET_WORD ( irqtod , 1 ) ; /* Interrupt the E7000 */
return len ;
}
static int
e7000pc_open ( scb , name )
serial_t scb ;
const char * name ;
{
if ( strncasecmp ( name , " pc " , 2 ) ! = 0 )
{
errno = ENOENT ;
return - 1 ;
}
scb - > fd = e7000pc_init ( ) ;
if ( ! scb - > fd )
return - 1 ;
return 0 ;
}
static int
e7000pc_noop ( scb )
serial_t scb ;
{
return 0 ;
}
static void
e7000pc_raw ( scb )
serial_t scb ;
{
/* Always in raw mode */
}
static int
e7000pc_readchar ( scb , timeout )
serial_t scb ;
int timeout ;
{
char buf ;
top :
if ( dosasync_read ( scb - > fd , & buf , 1 , timeout ) )
{
if ( buf = = 0 ) goto top ;
return buf ;
}
else
return SERIAL_TIMEOUT ;
}
struct e7000pc_ttystate {
int dummy ;
} ;
/* e7000pc_{get set}_tty_state() are both dummys to fill out the function
vector . Someday , they may do something real . . . */
static serial_ttystate
e7000pc_get_tty_state ( scb )
serial_t scb ;
{
struct e7000pc_ttystate * state ;
state = ( struct e7000pc_ttystate * ) xmalloc ( sizeof * state ) ;
return ( serial_ttystate ) state ;
}
static int
e7000pc_set_tty_state ( scb , ttystate )
serial_t scb ;
serial_ttystate ttystate ;
{
return 0 ;
}
static int
e7000pc_noflush_set_tty_state ( scb , new_ttystate , old_ttystate )
serial_t scb ;
serial_ttystate new_ttystate ;
serial_ttystate old_ttystate ;
{
return 0 ;
}
static void
e7000pc_print_tty_state ( scb , ttystate )
serial_t scb ;
serial_ttystate ttystate ;
{
/* Nothing to print. */
return ;
}
static int
e7000pc_setbaudrate ( scb , rate )
serial_t scb ;
int rate ;
{
return 0 ;
}
static int
e7000pc_write ( scb , str , len )
serial_t scb ;
const char * str ;
int len ;
{
dosasync_write ( scb - > fd , str , len ) ;
return 0 ;
}
static void
e7000pc_close ( scb )
serial_t scb ;
{
}
static struct serial_ops e7000pc_ops =
{
" pc " ,
0 ,
e7000pc_open ,
e7000pc_close ,
e7000pc_readchar ,
e7000pc_write ,
e7000pc_noop , /* flush output */
e7000pc_noop , /* flush input */
e7000pc_noop , /* send break -- currently used only for nindy */
e7000pc_raw ,
e7000pc_get_tty_state ,
e7000pc_set_tty_state ,
e7000pc_print_tty_state ,
e7000pc_noflush_set_tty_state ,
e7000pc_setbaudrate ,
e7000pc_noop , /* wait for output to drain */
} ;
void
_initialize_ser_e7000pc ( )
{
serial_add_interface ( & e7000pc_ops ) ;
}
# else
void
_initialize_ser_e7000pc ( )
{
}
# endif