388 lines
9.9 KiB
C
388 lines
9.9 KiB
C
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
|
|
#include "emulator.h"
|
|
#include "emulator_inner.h"
|
|
#include "config.h"
|
|
|
|
static int wire_fd;
|
|
static int ir_fd;
|
|
static int ttyp;
|
|
|
|
char* wire_name = ( char* )0;
|
|
char* ir_name = ( char* )0;
|
|
|
|
void update_connection_display( void )
|
|
{
|
|
if ( wire_fd == -1 ) {
|
|
if ( wire_name )
|
|
free( wire_name );
|
|
wire_name = ( char* )0;
|
|
}
|
|
if ( ir_fd == -1 ) {
|
|
if ( ir_name )
|
|
free( ir_name );
|
|
ir_name = ( char* )0;
|
|
}
|
|
}
|
|
|
|
int init_serial( void )
|
|
{
|
|
int c;
|
|
int n;
|
|
char tty_dev_name[ 128 ];
|
|
struct termios ttybuf;
|
|
|
|
wire_fd = -1;
|
|
ttyp = -1;
|
|
if ( config.useTerminal ) {
|
|
/* Unix98 PTY (Preferred) */
|
|
if ( ( wire_fd = open( "/dev/ptmx", O_RDWR | O_NONBLOCK, 0666 ) ) >= 0 ) {
|
|
grantpt( wire_fd );
|
|
unlockpt( wire_fd );
|
|
if ( ptsname_r( wire_fd, tty_dev_name, 128 ) ) {
|
|
perror( "Could not get the name of the wire device." );
|
|
exit( -1 );
|
|
}
|
|
if ( ( ttyp = open( tty_dev_name, O_RDWR | O_NDELAY, 0666 ) ) >= 0 ) {
|
|
if ( config.verbose )
|
|
printf( "wire connection on %s\n", tty_dev_name );
|
|
wire_name = strdup( tty_dev_name );
|
|
}
|
|
}
|
|
/* BSD PTY (Legacy) */
|
|
else {
|
|
c = 'p';
|
|
do {
|
|
for ( n = 0; n < 16; n++ ) {
|
|
sprintf( tty_dev_name, "/dev/pty%c%x", c, n );
|
|
if ( ( wire_fd = open( tty_dev_name, O_RDWR | O_EXCL | O_NDELAY, 0666 ) ) >= 0 ) {
|
|
ttyp = wire_fd;
|
|
sprintf( tty_dev_name, "/dev/tty%c%x", c, n );
|
|
if ( config.verbose )
|
|
printf( "wire connection on %s\n", tty_dev_name );
|
|
wire_name = strdup( tty_dev_name );
|
|
break;
|
|
}
|
|
}
|
|
c++;
|
|
} while ( ( wire_fd < 0 ) && ( errno != ENOENT ) );
|
|
}
|
|
}
|
|
|
|
if ( ttyp >= 0 ) {
|
|
#if defined( TCSANOW )
|
|
if ( tcgetattr( ttyp, &ttybuf ) < 0 )
|
|
#else
|
|
if ( ioctl( ttyp, TCGETS, ( char* )&ttybuf ) < 0 )
|
|
#endif
|
|
{
|
|
if ( config.verbose )
|
|
fprintf( stderr, "ioctl(wire, TCGETS) failed, errno = %d\n", errno );
|
|
wire_fd = -1;
|
|
ttyp = -1;
|
|
}
|
|
}
|
|
|
|
ttybuf.c_lflag = 0;
|
|
ttybuf.c_iflag = 0;
|
|
ttybuf.c_oflag = 0;
|
|
ttybuf.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
|
|
for ( n = 0; n < NCCS; n++ )
|
|
ttybuf.c_cc[ n ] = 0;
|
|
ttybuf.c_cc[ VTIME ] = 0;
|
|
ttybuf.c_cc[ VMIN ] = 1;
|
|
|
|
if ( ttyp >= 0 ) {
|
|
#if defined( TCSANOW )
|
|
if ( tcsetattr( ttyp, TCSANOW, &ttybuf ) < 0 )
|
|
#else
|
|
if ( ioctl( ttyp, TCSETS, ( char* )&ttybuf ) < 0 )
|
|
#endif
|
|
{
|
|
if ( config.verbose )
|
|
fprintf( stderr, "ioctl(wire, TCSETS) failed, errno = %d\n", errno );
|
|
wire_fd = -1;
|
|
ttyp = -1;
|
|
}
|
|
}
|
|
|
|
ir_fd = -1;
|
|
if ( config.useSerial ) {
|
|
sprintf( tty_dev_name, "%s", config.serialLine );
|
|
if ( ( ir_fd = open( tty_dev_name, O_RDWR | O_NDELAY ) ) >= 0 ) {
|
|
if ( config.verbose )
|
|
printf( "IR connection on %s\n", tty_dev_name );
|
|
ir_name = strdup( tty_dev_name );
|
|
}
|
|
}
|
|
|
|
if ( ir_fd >= 0 ) {
|
|
#if defined( TCSANOW )
|
|
if ( tcgetattr( ir_fd, &ttybuf ) < 0 )
|
|
#else
|
|
if ( ioctl( ir_fd, TCGETS, ( char* )&ttybuf ) < 0 )
|
|
#endif
|
|
{
|
|
if ( config.verbose )
|
|
fprintf( stderr, "ioctl(IR, TCGETS) failed, errno = %d\n", errno );
|
|
ir_fd = -1;
|
|
}
|
|
}
|
|
|
|
ttybuf.c_lflag = 0;
|
|
ttybuf.c_iflag = 0;
|
|
ttybuf.c_oflag = 0;
|
|
ttybuf.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
|
|
for ( n = 0; n < NCCS; n++ )
|
|
ttybuf.c_cc[ n ] = 0;
|
|
ttybuf.c_cc[ VTIME ] = 0;
|
|
ttybuf.c_cc[ VMIN ] = 1;
|
|
|
|
if ( ir_fd >= 0 ) {
|
|
#if defined( TCSANOW )
|
|
if ( tcsetattr( ir_fd, TCSANOW, &ttybuf ) < 0 )
|
|
#else
|
|
if ( ioctl( ir_fd, TCSETS, ( char* )&ttybuf ) < 0 )
|
|
#endif
|
|
{
|
|
if ( config.verbose )
|
|
fprintf( stderr, "ioctl(IR, TCSETS) failed, errno = %d\n", errno );
|
|
|
|
ir_fd = -1;
|
|
}
|
|
}
|
|
update_connection_display();
|
|
return 1;
|
|
}
|
|
|
|
void serial_baud( int baud )
|
|
{
|
|
int error = 0;
|
|
struct termios ttybuf;
|
|
|
|
if ( ir_fd >= 0 ) {
|
|
#if defined( TCSANOW )
|
|
if ( tcgetattr( ir_fd, &ttybuf ) < 0 )
|
|
#else
|
|
if ( ioctl( ir_fd, TCGETS, ( char* )&ttybuf ) < 0 )
|
|
#endif
|
|
{
|
|
if ( config.verbose )
|
|
fprintf( stderr, "ioctl(IR, TCGETS) failed, errno = %d\n", errno );
|
|
|
|
ir_fd = -1;
|
|
error = 1;
|
|
}
|
|
}
|
|
|
|
#if !defined( __APPLE__ )
|
|
# pragma GCC diagnostic push // save the actual diag context
|
|
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // disable maybe warnings
|
|
# pragma GCC diagnostic ignored "-Wuninitialized" // disable maybe warnings
|
|
ttybuf.c_cflag &= ~CBAUD;
|
|
# pragma GCC diagnostic pop // restore previous diag context
|
|
#endif
|
|
baud &= 0x7;
|
|
switch ( baud ) {
|
|
case 0: /* 1200 */
|
|
ttybuf.c_cflag |= B1200;
|
|
break;
|
|
case 1: /* 1920 */
|
|
#ifdef B1920
|
|
ttybuf.c_cflag |= B1920;
|
|
#endif
|
|
break;
|
|
case 2: /* 2400 */
|
|
ttybuf.c_cflag |= B2400;
|
|
break;
|
|
case 3: /* 3840 */
|
|
#ifdef B3840
|
|
ttybuf.c_cflag |= B3840;
|
|
#endif
|
|
break;
|
|
case 4: /* 4800 */
|
|
ttybuf.c_cflag |= B4800;
|
|
break;
|
|
case 5: /* 7680 */
|
|
#ifdef B7680
|
|
ttybuf.c_cflag |= B7680;
|
|
#endif
|
|
break;
|
|
case 6: /* 9600 */
|
|
ttybuf.c_cflag |= B9600;
|
|
break;
|
|
case 7: /* 15360 */
|
|
#ifdef B15360
|
|
ttybuf.c_cflag |= B15360;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
if ( ( ir_fd >= 0 ) && ( ( ttybuf.c_cflag & CBAUD ) == 0 ) ) {
|
|
if ( config.verbose )
|
|
fprintf( stderr, "can\'t set baud rate, using 9600\n" );
|
|
|
|
ttybuf.c_cflag |= B9600;
|
|
}
|
|
|
|
if ( ir_fd >= 0 ) {
|
|
#if defined( TCSANOW )
|
|
if ( tcsetattr( ir_fd, TCSANOW, &ttybuf ) < 0 )
|
|
#else
|
|
if ( ioctl( ir_fd, TCSETS, ( char* )&ttybuf ) < 0 )
|
|
#endif
|
|
{
|
|
if ( config.verbose )
|
|
fprintf( stderr, "ioctl(IR, TCSETS) failed, errno = %d\n", errno );
|
|
|
|
ir_fd = -1;
|
|
error = 1;
|
|
}
|
|
}
|
|
|
|
if ( ttyp >= 0 ) {
|
|
#if defined( TCSANOW )
|
|
if ( tcgetattr( ttyp, &ttybuf ) < 0 )
|
|
#else
|
|
if ( ioctl( ttyp, TCGETS, ( char* )&ttybuf ) < 0 )
|
|
#endif
|
|
{
|
|
if ( config.verbose )
|
|
fprintf( stderr, "ioctl(wire, TCGETS) failed, errno = %d\n", errno );
|
|
|
|
wire_fd = -1;
|
|
ttyp = -1;
|
|
error = 1;
|
|
}
|
|
}
|
|
|
|
if ( error )
|
|
update_connection_display();
|
|
}
|
|
|
|
void transmit_char( void )
|
|
{
|
|
if ( saturn.ir_ctrl & 0x04 ) {
|
|
if ( ir_fd == -1 ) {
|
|
saturn.tcs &= 0x0e;
|
|
if ( saturn.io_ctrl & 0x04 )
|
|
do_interupt();
|
|
|
|
return;
|
|
}
|
|
} else {
|
|
if ( wire_fd == -1 ) {
|
|
saturn.tcs &= 0x0e;
|
|
if ( saturn.io_ctrl & 0x04 )
|
|
do_interupt();
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( saturn.ir_ctrl & 0x04 ) {
|
|
if ( write( ir_fd, &saturn.tbr, 1 ) == 1 ) {
|
|
saturn.tcs &= 0x0e;
|
|
if ( saturn.io_ctrl & 0x04 )
|
|
do_interupt();
|
|
} else {
|
|
if ( errno != EAGAIN )
|
|
fprintf( stderr, "serial write error: %d\n", errno );
|
|
|
|
saturn.tcs &= 0x0e;
|
|
if ( saturn.io_ctrl & 0x04 )
|
|
do_interupt();
|
|
}
|
|
} else {
|
|
if ( write( wire_fd, &saturn.tbr, 1 ) == 1 ) {
|
|
saturn.tcs &= 0x0e;
|
|
if ( saturn.io_ctrl & 0x04 )
|
|
do_interupt();
|
|
} else {
|
|
if ( errno != EAGAIN && config.verbose )
|
|
fprintf( stderr, "serial write error: %d\n", errno );
|
|
|
|
saturn.tcs &= 0x0e;
|
|
if ( saturn.io_ctrl & 0x04 )
|
|
do_interupt();
|
|
}
|
|
}
|
|
}
|
|
|
|
#define NB_BUFFER 256
|
|
|
|
void receive_char( void )
|
|
{
|
|
struct timeval tout;
|
|
fd_set rfds;
|
|
int nfd;
|
|
static unsigned char buf[ NB_BUFFER + 1 ];
|
|
static int nrd = 0, bp = 0;
|
|
|
|
if ( saturn.ir_ctrl & 0x04 ) {
|
|
if ( ir_fd == -1 )
|
|
return;
|
|
} else if ( wire_fd == -1 )
|
|
return;
|
|
|
|
if ( saturn.rcs & 0x01 )
|
|
return;
|
|
|
|
if ( nrd == 0 ) {
|
|
tout.tv_sec = 0;
|
|
tout.tv_usec = 0;
|
|
FD_ZERO( &rfds );
|
|
if ( saturn.ir_ctrl & 0x04 ) {
|
|
FD_SET( ir_fd, &rfds );
|
|
nfd = ir_fd + 1;
|
|
} else {
|
|
FD_SET( wire_fd, &rfds );
|
|
nfd = wire_fd + 1;
|
|
}
|
|
if ( ( nfd = select( nfd, &rfds, ( fd_set* )0, ( fd_set* )0, &tout ) ) > 0 ) {
|
|
if ( saturn.ir_ctrl & 0x04 ) {
|
|
if ( FD_ISSET( ir_fd, &rfds ) ) {
|
|
nrd = read( ir_fd, buf, NB_BUFFER );
|
|
if ( nrd < 0 ) {
|
|
nrd = 0;
|
|
return;
|
|
}
|
|
bp = 0;
|
|
} else
|
|
return;
|
|
|
|
} else {
|
|
if ( FD_ISSET( wire_fd, &rfds ) ) {
|
|
nrd = read( wire_fd, buf, NB_BUFFER );
|
|
if ( nrd < 0 ) {
|
|
nrd = 0;
|
|
return;
|
|
}
|
|
bp = 0;
|
|
} else
|
|
return;
|
|
}
|
|
} else
|
|
return;
|
|
}
|
|
if ( nrd == 0 )
|
|
return;
|
|
|
|
if ( !( saturn.io_ctrl & 0x08 ) ) {
|
|
nrd = 0;
|
|
return;
|
|
}
|
|
saturn.rbr = buf[ bp++ ];
|
|
nrd--;
|
|
saturn.rcs |= 0x01;
|
|
|
|
if ( saturn.io_ctrl & 0x02 )
|
|
do_interupt();
|
|
}
|