1456 lines
37 KiB
C
1456 lines
37 KiB
C
/*
|
|
* rdevice.c - Atari850 emulation
|
|
*
|
|
* Copyright (c) ???? Tom Hunt, Chris Martin
|
|
* Copyright (c) 2003-2005,2007-2008 Atari800 development team (see DOC/CREDITS)
|
|
*
|
|
* This file is part of the Atari800 emulator project which emulates
|
|
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
|
*
|
|
* Atari800 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.
|
|
*
|
|
* Atari800 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 Atari800; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/* Originally From Closer To Home (Tom Hunt)
|
|
*
|
|
* 2003.04.03 cmartin@ti.com - Added connecting Host name lookup and port
|
|
* changing as well as CONNECT_STRING changing...
|
|
* 2003.04.03 cmartin@ti.com - Added setsockopt SO_REUSEADDR for socket to
|
|
* allow reconnections
|
|
* 2003.04.05 cmartin@ti.com - Added sighandler for catching SIGPIPE error...
|
|
* can get this and cause the emu to crash if
|
|
* the other end disconnects prematurely...
|
|
* 2003.04.06 cmartin@ti.com - Added translation on/off and line feeds
|
|
* - Fixed IP address lookup (print ip address if
|
|
* lookup fails...)
|
|
* 2003.04.07 cmartin@ti.com - Added Local echo when not connected.
|
|
* 2003.04.17 cmartin@ti.com - Added Telnet escape sequence parsing for
|
|
* connecting to telnet
|
|
* 2003.09.02 cmartin@ti.com - Cleaned up Serial port (/dev/ttyS*) Handling
|
|
* 2003.09.05 cmartin@ti.com - Included minor bug fixes submitted from
|
|
* Christian Groessler (thanks Chris!)
|
|
* - Removed erroneous return in RREAD().
|
|
* - Fixed typo for 9600 baud in xio_36()
|
|
* - Modified serial port dev_name generation in
|
|
* open_connection_serial()
|
|
* - Now we only modify the serial port options if
|
|
* we can open a port (in open_connection_serial())
|
|
* - Removed Telnet IAC escape sequence handling in
|
|
* RWRIT() and now we only
|
|
* write to the port if we are connected.
|
|
* 2003.09.08 cmartin@ti.com - Added missing baud rates and data word
|
|
* lengths (5,6,7,8)
|
|
* 2003.09.11 cmartin@ti.com - Fixed Address lookup in open_connection()
|
|
* - Reformatted and cleaned whole file.
|
|
* - Removed all memory writes to addresses
|
|
* 746 - 749 except within the RSTAT function.
|
|
*
|
|
* TODO:
|
|
* create a new socket and a buffer for each port number....
|
|
* non-concurrent mode error reporting to 747
|
|
* error bits in location 746
|
|
* implement xio 32?
|
|
* error reporting to CPU_regY
|
|
* heavy ASCII translation
|
|
* controlling DTR, RTS, & XMT - xio 34
|
|
*
|
|
* Dialing out via telnet:
|
|
* Type "ATDL" to toggle Linefeeds on/off (normally off)
|
|
* Type "ATDI <hostname> <port>" example: "ATDI localhost 23"
|
|
* if the port is omitted, then 23 is assumed.
|
|
*
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef DEBUG
|
|
#define DBG_APRINT(x) Log_print(x)
|
|
#else
|
|
#define DBG_APRINT(x)
|
|
#endif
|
|
|
|
#if 0 /* debug stuff */
|
|
#ifdef R_NETWORK
|
|
#warning R_NETWORK defined
|
|
#endif
|
|
#ifdef R_SERIAL
|
|
#warning R_SERIAL defined
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#ifdef R_SERIAL
|
|
#error The Windows version does not support the serial R: device
|
|
#endif
|
|
#ifndef R_NETWORK
|
|
#error R_NETWORK must be defined to use the Windows R: device
|
|
#endif
|
|
#include <winsock2.h>
|
|
#define F_SETFL 0
|
|
#define O_NONBLOCK 0
|
|
#define WM_SOCKET (WM_USER+20)
|
|
#define inet_pton(fam,ip,addr) ((addr)->s_addr = inet_addr(ip), 0)
|
|
static u_long ioctlsocket_non_block = 1; /* for ioctlsocket */
|
|
#define perror(a) printf("%s:WSA error code:%d\n",a,WSAGetLastError())
|
|
#define close(a) closesocket(a)
|
|
typedef char *caddr_t;
|
|
static void catch_disconnect(int sig);
|
|
static int rdevice_win32_read(SOCKET s, char *buf, int len) {
|
|
int r;
|
|
r = recv(s, buf, len, 0);
|
|
if (r <= 0 ) {
|
|
switch (WSAGetLastError()) {
|
|
case WSAECONNRESET:
|
|
case WSAECONNABORTED:
|
|
case WSAESHUTDOWN:
|
|
catch_disconnect(0);
|
|
break;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static int rdevice_win32_write(SOCKET s, char *buf, int len) {
|
|
int r;
|
|
r = send(s, buf, len, 0);
|
|
if (r <= 0 ) {
|
|
switch (WSAGetLastError()) {
|
|
case WSAECONNRESET:
|
|
case WSAECONNABORTED:
|
|
case WSAESHUTDOWN:
|
|
catch_disconnect(0);
|
|
break;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
#define read(a,b,c) rdevice_win32_read(a,b,c)
|
|
#define write(a,b,c) rdevice_win32_write(a,b,c)
|
|
|
|
#elif defined(DREAMCAST) /* above WIN32, below DREAMCAST */
|
|
|
|
/* these functions reside in dc/atari_dc.c */
|
|
extern void dc_init_serial(void);
|
|
extern int dc_write_serial(unsigned char byte);
|
|
extern int dc_read_serial(unsigned char *byte);
|
|
extern void dc_set_baud(int baud);
|
|
|
|
#else /* above DREAMCAST, below not WIN32 and not DREAMCAST */
|
|
|
|
#if !defined(R_SERIAL) && !defined(R_NETWORK)
|
|
#error R: device needs serial or network or both
|
|
#endif
|
|
#ifdef R_NETWORK
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netdb.h>
|
|
#include <arpa/inet.h>
|
|
#include <sys/time.h>
|
|
#endif /* R_NETWORK */
|
|
#include <sys/types.h>
|
|
#include <fcntl.h>
|
|
#endif /* not WIN32 and not DREAMCAST */
|
|
|
|
#if defined(R_SERIAL) && !defined(DREAMCAST)
|
|
#include <termios.h>
|
|
#endif /* defined(R_SERIAL) && !defined(DREAMCAST) */
|
|
|
|
#include "atari.h"
|
|
#include "rdevice.h"
|
|
#include "cpu.h"
|
|
#include "devices.h"
|
|
#include "log.h"
|
|
#include "memory.h"
|
|
#include "util.h"
|
|
|
|
#define Peek(a) MEMORY_dGetByte(a)
|
|
#define DPeek(a) MEMORY_dGetWord(a)
|
|
#define Poke(x,y) MEMORY_dPutByte(x, y)
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Global Variables
|
|
---------------------------------------------------------------------------*/
|
|
static int connected;
|
|
static int do_once;
|
|
static int rdev_fd;
|
|
|
|
#ifdef R_NETWORK
|
|
static struct sockaddr_in in;
|
|
static struct sockaddr_in peer_in;
|
|
static int sock;
|
|
static int portnum = 9000;
|
|
static char inetaddress[256];
|
|
static char CONNECT_STRING[40] = "\r\n_CONNECT 2400\r\n";
|
|
static int retval;
|
|
#endif /* R_NETWORK */
|
|
|
|
static char MESSAGE[256];
|
|
static char command_buf[256];
|
|
static char bufout[256];
|
|
static int concurrent;
|
|
|
|
static int command_end = 0;
|
|
static int translation = 1;
|
|
static int trans_cr = 0;
|
|
static int linefeeds = 1;
|
|
static int bufend = 0;
|
|
|
|
#ifndef R_NETWORK
|
|
int RDevice_serial_enabled = 1;
|
|
#else
|
|
int RDevice_serial_enabled = 0; /* Default to network, if enabled. Use parameter to -rdevice command line switch to enable serial mode. */
|
|
#endif
|
|
char RDevice_serial_device[FILENAME_MAX];
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Host Support Function - If Disconnect signal is found, then close socket
|
|
and clean up.
|
|
---------------------------------------------------------------------------*/
|
|
#ifdef R_NETWORK
|
|
static void catch_disconnect(int sig)
|
|
{
|
|
DBG_APRINT("R*: Disconnected....");
|
|
close(rdev_fd);
|
|
connected = 0;
|
|
do_once = 0;
|
|
bufout[0] = 0;
|
|
strcat(bufout, "\r\nNO CARRIER\r\n");
|
|
bufend = 13;
|
|
#if 0
|
|
Poke(747,bufend);
|
|
Poke(748,0);
|
|
#endif
|
|
}
|
|
#endif /* R_NETWORK */
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Host Support Function - XIO 34 - Called from RDevice_SPEC
|
|
Controls handshake lines DTR, RTS, SD
|
|
---------------------------------------------------------------------------*/
|
|
static void xio_34(void)
|
|
{
|
|
#ifndef DREAMCAST /* Dreamcast port doesn't currently support handshake lines */
|
|
int temp;
|
|
/*int fid;*/
|
|
#ifdef R_SERIAL
|
|
struct termios options;
|
|
#endif /* R_SERIAL */
|
|
/*int status;*/
|
|
|
|
/*fid = MEMORY_dGetByte(0x2e) >> 4;*/
|
|
temp = MEMORY_dGetByte(Devices_ICAX1Z);
|
|
|
|
#ifdef R_SERIAL
|
|
if(RDevice_serial_enabled)
|
|
{
|
|
tcgetattr(rdev_fd, &options);
|
|
/*ioctl(rdev_fd, TIOCMGET, &status);*/
|
|
}
|
|
#endif /* R_SERIAL */
|
|
|
|
if(temp & 0x80)
|
|
{
|
|
if(temp & 0x40)
|
|
{
|
|
/* turn DTR on */
|
|
#ifdef R_SERIAL
|
|
if(RDevice_serial_enabled)
|
|
{
|
|
/*status |= TIOCM_DTR;*/
|
|
}
|
|
#endif /* R_SERIAL */
|
|
}
|
|
else
|
|
{
|
|
/*Drop DTR*/
|
|
#ifdef R_SERIAL
|
|
if(RDevice_serial_enabled)
|
|
{
|
|
cfsetispeed(&options, B0);
|
|
cfsetospeed(&options, B0);
|
|
}
|
|
#endif /* R_SERIAL */
|
|
|
|
if(connected != 0)
|
|
{
|
|
close ( rdev_fd );
|
|
connected = 0;
|
|
do_once = 0;
|
|
/*bufend = 0;*/
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef R_SERIAL
|
|
if(RDevice_serial_enabled)
|
|
{
|
|
/* RTS Set/Clear*/
|
|
if(temp & 0x20)
|
|
{
|
|
if(temp & 0x10)
|
|
{
|
|
/*status |= TIOCM_RTS;*/
|
|
}
|
|
else
|
|
{
|
|
/*status &= ~TIOCM_RTS;*/
|
|
}
|
|
}
|
|
|
|
if(temp & 0x02)
|
|
{
|
|
if(temp & 0x01)
|
|
{
|
|
/*status |= TIOCM_RTS;*/
|
|
}
|
|
else
|
|
{
|
|
/*status &= ~TIOCM_RTS;*/
|
|
}
|
|
}
|
|
}
|
|
#endif /* R_SERIAL */
|
|
|
|
#ifdef R_SERIAL
|
|
if(RDevice_serial_enabled)
|
|
{
|
|
tcsetattr(rdev_fd, TCSANOW, &options);
|
|
/*ioctl(rdev_fd, TIOCMSET, &status);*/
|
|
}
|
|
#endif /* R_SERIAL */
|
|
#endif /* not defined DREAMCAST */
|
|
|
|
CPU_regA = 1;
|
|
CPU_regY = 1;
|
|
CPU_ClrN;
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Host Support Function - XIO 36 - Called from RDevice_SPEC
|
|
Sets baud, stop bits, and ready monitoring.
|
|
---------------------------------------------------------------------------*/
|
|
static void xio_36(void)
|
|
{
|
|
int aux1, aux2;
|
|
#if defined(R_SERIAL) && !defined(DREAMCAST)
|
|
struct termios options;
|
|
#endif /* defined(R_SERIAL) && !defined(DREAMCAST) */
|
|
|
|
aux1 = MEMORY_dGetByte(Devices_ICAX1Z);
|
|
aux2 = MEMORY_dGetByte(Devices_ICAX2Z);
|
|
|
|
#ifdef R_SERIAL
|
|
if(RDevice_serial_enabled)
|
|
{
|
|
#ifndef DREAMCAST
|
|
tcgetattr(rdev_fd, &options);
|
|
|
|
/*Set Stop bits*/
|
|
if(aux1 & 0x80)
|
|
{ /*2 Stop bits*/
|
|
options.c_cflag |= CSTOPB;
|
|
}
|
|
else
|
|
{ /*1 Stop bit*/
|
|
options.c_cflag &= ~CSTOPB;
|
|
}
|
|
|
|
/*Set word size*/
|
|
if((aux1 & 0x30) == 0)
|
|
{ /*8 bit word size*/
|
|
options.c_cflag &= ~CSIZE;
|
|
options.c_cflag |= CS8;
|
|
}
|
|
else if((aux1 & 0x30) == 0x10)
|
|
{ /*7 bit word size*/
|
|
options.c_cflag &= ~CSIZE;
|
|
options.c_cflag |= CS7;
|
|
}
|
|
else if((aux1 & 0x30) == 0x20)
|
|
{ /*6 bit word size*/
|
|
options.c_cflag &= ~CSIZE;
|
|
options.c_cflag |= CS6;
|
|
}
|
|
else if((aux1 & 0x30) == 0x30)
|
|
{ /*5 bit word size*/
|
|
options.c_cflag &= ~CSIZE;
|
|
options.c_cflag |= CS5;
|
|
}
|
|
else
|
|
{ /*8 bit word size*/
|
|
options.c_cflag &= ~CSIZE;
|
|
options.c_cflag |= CS8;
|
|
}
|
|
|
|
/*Set Baud Rate*/
|
|
if((aux1 & 0x0f) == 0)
|
|
{ /*300 Baud*/
|
|
cfsetispeed(&options, B300);
|
|
cfsetospeed(&options, B300);
|
|
}
|
|
else if((aux1 & 0x0f) == 1)
|
|
{ /* 45.5 Baud (unsupported) - now 57600 */
|
|
#ifdef B57600
|
|
cfsetispeed(&options, B57600);
|
|
cfsetospeed(&options, B57600);
|
|
#else
|
|
cfsetispeed(&options, B50);
|
|
cfsetospeed(&options, B50);
|
|
#endif
|
|
}
|
|
else if ((aux1 & 0x0f) == 2)
|
|
{ /* 50 Baud */
|
|
cfsetispeed(&options, B50);
|
|
cfsetospeed(&options, B50);
|
|
}
|
|
else if ((aux1 & 0x0f) == 3)
|
|
{ /* 56.875 Baud (unsupported) - now 115200 */
|
|
#ifdef B115200
|
|
cfsetispeed(&options, B115200);
|
|
cfsetospeed(&options, B115200);
|
|
#else
|
|
cfsetispeed(&options, B50);
|
|
cfsetospeed(&options, B50);
|
|
#endif
|
|
}
|
|
else if((aux1 & 0x0f) == 4)
|
|
{ /* 75 Baud */
|
|
cfsetispeed(&options, B75);
|
|
cfsetospeed(&options, B75);
|
|
}
|
|
else if((aux1 & 0x0f) == 5)
|
|
{ /* 110 Baud */
|
|
cfsetispeed(&options, B110);
|
|
cfsetospeed(&options, B110);
|
|
}
|
|
else if((aux1 & 0x0f) == 6)
|
|
{ /* 134.5 Baud */
|
|
cfsetispeed(&options, B134);
|
|
cfsetospeed(&options, B134);
|
|
}
|
|
else if((aux1 & 0x0f) == 7)
|
|
{ /* 150 Baud */
|
|
cfsetispeed(&options, B150);
|
|
cfsetospeed(&options, B150);
|
|
}
|
|
else if((aux1 & 0x0f) == 8)
|
|
{ /* 300 Baud */
|
|
cfsetispeed(&options, B300);
|
|
cfsetospeed(&options, B300);
|
|
}
|
|
else if((aux1 & 0x0f) == 9)
|
|
{ /* 600 Baud */
|
|
cfsetispeed(&options, B600);
|
|
cfsetospeed(&options, B600);
|
|
}
|
|
else if((aux1 & 0x0f) == 10)
|
|
{ /* 1200 Baud */
|
|
cfsetispeed(&options, B1200);
|
|
cfsetospeed(&options, B1200);
|
|
}
|
|
else if((aux1 & 0x0f) == 12)
|
|
{ /* 2400 Baud */
|
|
cfsetispeed(&options, B2400);
|
|
cfsetospeed(&options, B2400);
|
|
}
|
|
else if((aux1 & 0x0f) == 13)
|
|
{ /* 4800 Baud */
|
|
cfsetispeed(&options, B4800);
|
|
cfsetospeed(&options, B4800);
|
|
}
|
|
else if((aux1 & 0x0f) == 14)
|
|
{ /* 9600 Baud */
|
|
cfsetispeed(&options, B9600);
|
|
cfsetospeed(&options, B9600);
|
|
}
|
|
else if((aux1 & 0x0f) == 15)
|
|
{ /* 19200 Baud */
|
|
#ifdef B19200
|
|
cfsetispeed(&options, B19200);
|
|
cfsetospeed(&options, B19200);
|
|
#else
|
|
cfsetispeed(&options, B9600);
|
|
cfsetospeed(&options, B9600);
|
|
#endif
|
|
}
|
|
else
|
|
{ /* 115200 Baud (can add 38400, 76800 if wanted) */
|
|
#ifdef B115200
|
|
cfsetispeed(&options, B115200);
|
|
cfsetospeed(&options, B115200);
|
|
#else
|
|
cfsetispeed(&options, B9600);
|
|
cfsetospeed(&options, B9600);
|
|
#endif
|
|
}
|
|
|
|
if(aux1 & 0x40)
|
|
{ /* 230400 Baud */
|
|
#ifdef B230400
|
|
cfsetispeed(&options, B230400);
|
|
cfsetospeed(&options, B230400);
|
|
#endif
|
|
}
|
|
|
|
tcsetattr(rdev_fd, TCSANOW, &options);
|
|
#else /* below DREAMCAST, above not; both R_SERIAL */
|
|
/* Set Stop bits */
|
|
if(aux1 & 0x80)
|
|
{ /* 2 Stop bits */
|
|
/* currently not supported on DC */
|
|
}
|
|
else
|
|
{ /* 1 Stop bit */
|
|
/* currently not supported on DC */
|
|
}
|
|
|
|
/* Set word size */
|
|
if((aux1 & 0x30) == 0)
|
|
{ /* 8 bit word size */
|
|
/* currently not supported on DC */
|
|
}
|
|
else if((aux1 & 0x30) == 0x10)
|
|
{ /* 7 bit word size */
|
|
/* currently not supported on DC */
|
|
}
|
|
else if((aux1 & 0x30) == 0x20)
|
|
{ /* 6 bit word size */
|
|
/* currently not supported on DC */
|
|
}
|
|
else if((aux1 & 0x30) == 0x30)
|
|
{ /* 5 bit word size */
|
|
/* currently not supported on DC */
|
|
}
|
|
else
|
|
{ /* 8 bit word size */
|
|
/* currently not supported on DC */
|
|
}
|
|
|
|
/* Set Baud Rate */
|
|
if((aux1 & 0x0f) == 0)
|
|
{ /* 300 Baud */
|
|
dc_set_baud(300);
|
|
}
|
|
else if((aux1 & 0x0f) == 1)
|
|
{ /* 45.5 Baud (unsupported) - now 57600 */
|
|
dc_set_baud(57600);
|
|
}
|
|
else if ((aux1 & 0x0f) == 2)
|
|
{ /* 50 Baud */
|
|
dc_set_baud(50);
|
|
}
|
|
else if ((aux1 & 0x0f) == 3)
|
|
{ /* 56.875 Baud (unsupported) - now 115200 */
|
|
dc_set_baud(115200);
|
|
}
|
|
else if((aux1 & 0x0f) == 4)
|
|
{ /* 75 Baud */
|
|
dc_set_baud(75);
|
|
}
|
|
else if((aux1 & 0x0f) == 5)
|
|
{ /* 110 Baud */
|
|
dc_set_baud(110);
|
|
}
|
|
else if((aux1 & 0x0f) == 6)
|
|
{ /* 134.5 Baud */
|
|
dc_set_baud(134);
|
|
}
|
|
else if((aux1 & 0x0f) == 7)
|
|
{ /* 150 Baud */
|
|
dc_set_baud(150);
|
|
}
|
|
else if((aux1 & 0x0f) == 8)
|
|
{ /* 300 Baud */
|
|
dc_set_baud(300);
|
|
}
|
|
else if((aux1 & 0x0f) == 9)
|
|
{ /* 600 Baud */
|
|
dc_set_baud(600);
|
|
}
|
|
else if((aux1 & 0x0f) == 10)
|
|
{ /* 1200 Baud */
|
|
dc_set_baud(1200);
|
|
}
|
|
else if((aux1 & 0x0f) == 12)
|
|
{ /* 2400 Baud */
|
|
dc_set_baud(2400);
|
|
}
|
|
else if((aux1 & 0x0f) == 13)
|
|
{ /* 4800 Baud */
|
|
dc_set_baud(4800);
|
|
}
|
|
else if((aux1 & 0x0f) == 14)
|
|
{ /* 9600 Baud */
|
|
dc_set_baud(9600);
|
|
}
|
|
else if((aux1 & 0x0f) == 15)
|
|
{ /* 19200 Baud */
|
|
dc_set_baud(19200);
|
|
}
|
|
else
|
|
{ /* 115200 Baud (can add 38400, 76800 if wanted) */
|
|
dc_set_baud(115200);
|
|
}
|
|
|
|
if(aux1 & 0x40)
|
|
{ /* 230400 Baud */
|
|
dc_set_baud(230400);
|
|
}
|
|
#endif /* DREAMCAST */
|
|
}
|
|
#endif /* R_SERIAL */
|
|
|
|
CPU_regA = 1;
|
|
CPU_regY = 1;
|
|
CPU_ClrN;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Host Support Function - XIO 38 - Called from RDevice_SPEC
|
|
Sets Translation and parity
|
|
---------------------------------------------------------------------------*/
|
|
static void xio_38(void)
|
|
{
|
|
int aux1;
|
|
#if defined(R_SERIAL) && !defined(DREAMCAST)
|
|
struct termios options;
|
|
#endif /* defined(R_SERIAL) && !defined(DREAMCAST) */
|
|
|
|
CPU_regA = 1;
|
|
CPU_regY = 1;
|
|
CPU_ClrN;
|
|
|
|
aux1 = Peek(Devices_ICAX1Z);
|
|
#if defined(R_SERIAL) && !defined(DREAMCAST)
|
|
if(RDevice_serial_enabled)
|
|
{
|
|
if(aux1 & 0x04)
|
|
{ /*Odd Parity*/
|
|
tcgetattr(rdev_fd, &options);
|
|
options.c_cflag |= PARENB;
|
|
options.c_cflag |= PARODD;
|
|
tcsetattr(rdev_fd, TCSANOW, &options);
|
|
}
|
|
else if(aux1 & 0x08)
|
|
{ /*Even Parity*/
|
|
tcgetattr(rdev_fd, &options);
|
|
options.c_cflag |= PARENB;
|
|
options.c_cflag &= ~PARODD;
|
|
tcsetattr(rdev_fd, TCSANOW, &options);
|
|
|
|
}
|
|
else
|
|
{ /*No Parity*/
|
|
tcgetattr(rdev_fd, &options);
|
|
options.c_cflag &= ~PARENB;
|
|
tcsetattr(rdev_fd, TCSANOW, &options);
|
|
}
|
|
}
|
|
#endif /* defined(R_SERIAL) && !defined(DREAMCAST) */
|
|
|
|
if(aux1 & 0x20)
|
|
{ /* No Translation */
|
|
DBG_APRINT("R*: No ATASCII/ASCII TRANSLATION");
|
|
translation = 0;
|
|
}
|
|
else
|
|
{
|
|
translation = 1;
|
|
}
|
|
|
|
if(aux1 & 0x40)
|
|
{ /* Append line feed */
|
|
DBG_APRINT("R*: Append Line Feeds");
|
|
linefeeds = 1;
|
|
}
|
|
else
|
|
{
|
|
linefeeds = 0;
|
|
}
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Host Support Function - XIO 40 - Called from RDevice_SPEC
|
|
Sets concurrent mode. Also checks for dropped carrier.
|
|
---------------------------------------------------------------------------*/
|
|
static void xio_40(void)
|
|
{
|
|
|
|
int aux1;
|
|
/*
|
|
if(connected == 0)
|
|
Poke(747,0);
|
|
*/
|
|
CPU_regA = 1;
|
|
CPU_regY = 1;
|
|
CPU_ClrN;
|
|
|
|
aux1 = Peek(Devices_ICAX1Z);
|
|
|
|
if(aux1 >= 12)
|
|
{
|
|
concurrent = 1;
|
|
DBG_APRINT("R*: Entering concurrent IO mode...");
|
|
}
|
|
else
|
|
{
|
|
concurrent = 0;
|
|
sprintf(MESSAGE, "R*: XIO 40, %d", aux1);
|
|
DBG_APRINT(MESSAGE);
|
|
}
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Host Support Function - Internet Socket Open Connection
|
|
---------------------------------------------------------------------------*/
|
|
#ifdef R_NETWORK
|
|
static void open_connection(char * address, int port)
|
|
{
|
|
struct hostent *host;
|
|
#ifdef WIN32
|
|
static int winsock_started;
|
|
WSADATA wdata;
|
|
WORD ver = MAKEWORD(1,1);
|
|
int ret;
|
|
if (!winsock_started) {
|
|
ret = WSAStartup(ver, &wdata);
|
|
if (ret) {
|
|
printf("Error in WSAStartup,return code:%d\n", ret);
|
|
}
|
|
winsock_started = 1;
|
|
}
|
|
#endif /* WIN32 */
|
|
if((address != NULL) && (strlen(address) > 0))
|
|
{
|
|
close(rdev_fd);
|
|
close(sock);
|
|
do_once = 1;
|
|
connected = 1;
|
|
memset ( &peer_in, 0, sizeof ( struct sockaddr_in ) );
|
|
/*rdev_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);*/
|
|
rdev_fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
#ifdef WIN32
|
|
ioctlsocket(rdev_fd, FIONBIO, &ioctlsocket_non_block);
|
|
#else
|
|
fcntl(rdev_fd, F_SETFL, O_NONBLOCK);
|
|
#endif
|
|
peer_in.sin_family = AF_INET;
|
|
if(inet_pton(AF_INET, address, &peer_in.sin_addr) == 0)
|
|
{ /* invalid address if zero */
|
|
if((peer_in.sin_addr.s_addr == -1) || (peer_in.sin_addr.s_addr == 0))
|
|
{
|
|
host = gethostbyname(address);
|
|
if(host != NULL)
|
|
{
|
|
sprintf(MESSAGE, "R*: Host = '%s'.", host->h_name);
|
|
DBG_APRINT(MESSAGE);
|
|
memcpy((caddr_t)&peer_in.sin_addr, host->h_addr_list[0], host->h_length);
|
|
}
|
|
else
|
|
{
|
|
perror("gethostbyname");
|
|
}
|
|
}
|
|
}
|
|
|
|
if(port > 0)
|
|
{
|
|
peer_in.sin_port = htons (port);
|
|
}
|
|
else
|
|
{ /* telnet port */
|
|
peer_in.sin_port = htons (23);
|
|
}
|
|
if(connect(rdev_fd, (struct sockaddr *)&peer_in, sizeof(peer_in)) < 0)
|
|
{
|
|
#ifdef DEBUG
|
|
sprintf(MESSAGE, "R*: connect: '%s'", strerror(errno));
|
|
DBG_APRINT(MESSAGE);
|
|
#endif
|
|
}
|
|
#ifndef WIN32
|
|
signal(SIGPIPE, catch_disconnect); /*Need to see if the other end disconnects...*/
|
|
signal(SIGHUP, catch_disconnect); /*Need to see if the other end disconnects...*/
|
|
#endif /* WIN32 */
|
|
sprintf(MESSAGE, "R*: Connecting to %s", address);
|
|
DBG_APRINT(MESSAGE);
|
|
#ifdef WIN32
|
|
ioctlsocket(rdev_fd, FIONBIO, &ioctlsocket_non_block);
|
|
#else
|
|
fcntl(rdev_fd, F_SETFL, O_NONBLOCK);
|
|
#endif /* WIN32 */
|
|
|
|
/* Telnet negotiation */
|
|
sprintf(MESSAGE, "%c%c%c%c%c%c%c%c%c", 0xff, 0xfb, 0x01, 0xff, 0xfb, 0x03, 0xff, 0xfd, 0x0f3);
|
|
write(rdev_fd, MESSAGE, 9);
|
|
DBG_APRINT("R*: Negotiating Terminal Options...");
|
|
}
|
|
}
|
|
#endif /* R_NETWORK */
|
|
|
|
|
|
#if defined(R_SERIAL) && !defined(DREAMCAST)
|
|
#ifdef __linux__
|
|
#define TTY_DEV_NAME "/dev/ttyS0" /* Linux */
|
|
#elif defined (__NetBSD__) && defined(__i386__)
|
|
#define TTY_DEV_NAME "/dev/tty00" /* NetBSD/x86 */
|
|
#elif defined (__FreeBSD__) && defined(__i386__)
|
|
#define TTY_DEV_NAME "/dev/ttyd1" /* FreeBSD/x86 */
|
|
#elif defined (__sun__)
|
|
#define TTY_DEV_NAME "/dev/ttya" /* Solaris */
|
|
#else
|
|
#error tty name unknown!
|
|
#endif
|
|
#endif /* defined(R_SERIAL) && !defined(DREAMCAST) */
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Host Support Function - Serial Open Connection
|
|
---------------------------------------------------------------------------*/
|
|
#ifdef R_SERIAL
|
|
static void open_connection_serial(int port)
|
|
{
|
|
#ifdef DREAMCAST
|
|
dc_init_serial();
|
|
connected = 1;
|
|
#else /* above DREAMCAST, below not */
|
|
char dev_name[FILENAME_MAX] = TTY_DEV_NAME; /* reinitialize each time */
|
|
struct termios options;
|
|
|
|
if(connected)
|
|
close(rdev_fd);
|
|
do_once = 1;
|
|
|
|
if (*RDevice_serial_device) /* got a device name from command line */
|
|
{
|
|
strcpy(dev_name, RDevice_serial_device);
|
|
}
|
|
|
|
dev_name[strlen(dev_name) - 1] += port - 1;
|
|
|
|
sprintf(MESSAGE, "R*: using serial device %s", dev_name);
|
|
DBG_APRINT(MESSAGE);
|
|
|
|
rdev_fd = open(dev_name, O_RDWR | O_NOCTTY | O_NDELAY);
|
|
if(rdev_fd == -1)
|
|
{
|
|
connected = 0;
|
|
perror("R*: open_port: Unable to open serial Port - ");
|
|
}
|
|
else
|
|
{
|
|
connected = 1;
|
|
#if 0
|
|
fcntl(rdev_fd, F_SETFL, O_NONBLOCK);
|
|
#endif
|
|
/*Set 8N1 by default on open*/
|
|
/*Set Baud to 115200 by default;*/
|
|
tcgetattr(rdev_fd, &options);
|
|
options.c_lflag = 0;
|
|
options.c_iflag = 0;
|
|
options.c_oflag = 0;
|
|
options.c_cc[VMIN] = 1;
|
|
options.c_cc[VTIME] = 0;
|
|
|
|
options.c_cflag = CS8 | CREAD | CLOCAL;
|
|
#if 0
|
|
cfmakeraw(&options);
|
|
/*#else*/
|
|
/* from glibc 2.3.2 */
|
|
options.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
|
|
options.c_oflag &= ~OPOST;
|
|
options.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
|
options.c_cflag &= ~(CSIZE|PARENB);
|
|
options.c_cflag |= CS8;
|
|
options.c_cc[VMIN] = 1; /* read returns when one char is available. */
|
|
options.c_cc[VTIME] = 0;
|
|
#endif
|
|
|
|
cfsetispeed(&options, B115200);
|
|
cfsetospeed(&options, B115200);
|
|
tcsetattr(rdev_fd, TCSANOW, &options);
|
|
}
|
|
#endif /* not DREAMCAST */
|
|
}
|
|
#endif /* R_SERIAL */
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Host Support Function - Retrieve address from open command:
|
|
From Basic: OPEN #1,8,23,"R:JYBOLAC.HOMELINUX.COM"
|
|
Returns: "jybolac.homelinux.com"
|
|
---------------------------------------------------------------------------*/
|
|
#ifdef R_NETWORK
|
|
static void RDevice_GetInetAddress(void)
|
|
{
|
|
UWORD bufadr = Devices_SkipDeviceName();
|
|
char *p;
|
|
|
|
if (bufadr == 0) {
|
|
/* XXX: signal error */
|
|
inetaddress[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
p = inetaddress;
|
|
while (p < inetaddress + sizeof(inetaddress) - 1) {
|
|
char c = (char) MEMORY_dGetByte(bufadr);
|
|
if (c < '!' || c > '\x7e')
|
|
break;
|
|
if (c >= 'A' && c <= 'Z')
|
|
c += 'a' - 'A';
|
|
*p++ = c;
|
|
bufadr++;
|
|
}
|
|
*p = '\0';
|
|
}
|
|
#endif /* R_NETWORK */
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
R Device OPEN vector - called from Atari OS Device Handler Address Table
|
|
---------------------------------------------------------------------------*/
|
|
void RDevice_OPEN(void)
|
|
{
|
|
int port;
|
|
int direction;
|
|
int devnum;
|
|
|
|
CPU_regA = 1;
|
|
CPU_regY = 1;
|
|
CPU_ClrN;
|
|
|
|
bufend = 0;
|
|
|
|
port = Peek(Devices_ICAX2Z);
|
|
direction = Peek(Devices_ICAX1Z);
|
|
devnum = MEMORY_dGetByte(Devices_ICDNOZ);
|
|
if(direction & 0x04)
|
|
{
|
|
DBG_APRINT("R*: Open for Reading...");
|
|
}
|
|
|
|
if(direction & 0x08)
|
|
{
|
|
DBG_APRINT("R*: Open for Writing...");
|
|
#ifdef R_SERIAL
|
|
if(RDevice_serial_enabled)
|
|
{
|
|
DBG_APRINT("R*: serial mode.");
|
|
open_connection_serial(devnum);
|
|
}
|
|
#endif /* R_SERIAL */
|
|
#if defined(R_SERIAL) && defined(R_NETWORK)
|
|
else
|
|
#endif
|
|
#ifdef R_NETWORK
|
|
{
|
|
DBG_APRINT("R*: Socket mode.");
|
|
RDevice_GetInetAddress();
|
|
open_connection(inetaddress, port);
|
|
}
|
|
#endif /* R_NETWORK */
|
|
}
|
|
if(direction & 0x01)
|
|
{
|
|
/* Open for concurrent mode */
|
|
}
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
R Device CLOSE vector - called from Atari OS Device Handler Address Table
|
|
---------------------------------------------------------------------------*/
|
|
void RDevice_CLOS(void)
|
|
{
|
|
CPU_regA = 1;
|
|
CPU_regY = 1;
|
|
CPU_ClrN;
|
|
concurrent = 0;
|
|
bufend = 0;
|
|
close(rdev_fd);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
R Device READ vector - called from Atari OS Device Handler Address Table
|
|
---------------------------------------------------------------------------*/
|
|
void RDevice_READ(void)
|
|
{
|
|
int j;
|
|
|
|
/*bufend = Peek(747);*/
|
|
/*printf("Bufend = %d.\n", bufend);*/
|
|
|
|
/* if(bufend >= 0) */
|
|
/* { */
|
|
if(translation)
|
|
{
|
|
if(bufout[0] == 0x0d)
|
|
{
|
|
CPU_regA = 0x9b;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CPU_regA = bufout[0];
|
|
}
|
|
|
|
bufend--;
|
|
|
|
for(j = 0; j <= bufend; j++)
|
|
{
|
|
bufout[j] = bufout[j+1];
|
|
}
|
|
|
|
/*Cycle the buffer again to skip over linefeed....*/
|
|
if(translation && linefeeds && (bufout[0] == 0x0a))
|
|
{
|
|
for(j = 0; j <= bufend; j++)
|
|
{
|
|
bufout[j] = bufout[j+1];
|
|
}
|
|
}
|
|
/*return; ???*/
|
|
/* } */
|
|
|
|
CPU_regY = 1;
|
|
CPU_ClrN;
|
|
}
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
R Device WRITE vector - called from Atari OS Device Handler Address Table
|
|
---------------------------------------------------------------------------*/
|
|
void RDevice_WRIT(void)
|
|
{
|
|
unsigned char out_char;
|
|
#ifdef R_NETWORK
|
|
int port;
|
|
#endif
|
|
|
|
CPU_regY = 1;
|
|
CPU_ClrN;
|
|
|
|
/*bufend = Peek(747);*/
|
|
|
|
/* Translation mode */
|
|
if(translation)
|
|
{
|
|
if(CPU_regA == 0x9b)
|
|
{
|
|
out_char = 0x0d;
|
|
if(linefeeds)
|
|
{
|
|
if((RDevice_serial_enabled == 0) && (connected == 0))
|
|
{ /* local echo */
|
|
bufend++;
|
|
bufout[bufend-1] = out_char;
|
|
bufout[bufend] = 0;
|
|
|
|
command_end = 0;
|
|
command_buf[command_end] = 0;
|
|
strcat(bufout, "OK\r\n");
|
|
bufend += 4;
|
|
|
|
}
|
|
else
|
|
{
|
|
#ifndef DREAMCAST
|
|
write(rdev_fd, (char *)&out_char, 1); /* Write return */
|
|
#else
|
|
dc_write_serial(out_char);
|
|
#endif
|
|
}
|
|
out_char = 0x0a; /*set char for line feed to be output later....*/
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
out_char = CPU_regA;
|
|
}
|
|
|
|
/* Translate the CR to a LF for telnet, ftp, etc */
|
|
if(connected && trans_cr && (out_char == 0x0d))
|
|
{
|
|
out_char = 0x0a;
|
|
}
|
|
|
|
/*if((RDevice_serial_enabled == 0) && (out_char == 255))*/
|
|
/*{*/
|
|
/* DBG_APRINT("R: Writing IAC..."); */
|
|
/* retval = write(rdev_fd, &out_char, 1);*/ /* IAC escape sequence */
|
|
/*}*/
|
|
/*if(retval == -1)*/
|
|
|
|
#ifdef R_NETWORK
|
|
if((RDevice_serial_enabled == 0) && (connected == 0))
|
|
{ /* Local echo - only do if in socket mode */
|
|
bufend++;
|
|
bufout[bufend-1] = out_char;
|
|
bufout[bufend] = 0;
|
|
|
|
/* Grab Command */
|
|
if((out_char == 0x9b) || (out_char == 0x0d))
|
|
{ /*process command with a return/enter*/
|
|
command_end = 0;
|
|
|
|
/*Make out going connection command 'ATDI'*/
|
|
if((command_buf[0] == 'A') && (command_buf[1] == 'T') && (command_buf[2] == 'D') && (command_buf[3] == 'I'))
|
|
{
|
|
/*DBG_APRINT(command_buf);*/
|
|
if(strchr(command_buf, ' ') != NULL)
|
|
{
|
|
if(strrchr(command_buf, ' ') != strchr(command_buf, ' '))
|
|
{
|
|
port = atoi((char *)(strrchr(command_buf, ' ')+1));
|
|
* strrchr(command_buf, ' ') = '\0'; /*zero last space in line*/
|
|
}
|
|
else
|
|
{
|
|
port = 23;
|
|
}
|
|
open_connection((char *)(strchr(command_buf, ' ')+1), port); /*send string after first space in line*/
|
|
}
|
|
command_buf[command_end] = 0;
|
|
strcat(bufout, "OK\r\n");
|
|
bufend += 4;
|
|
/*Change translation command 'ATDL'*/
|
|
}
|
|
else if((command_buf[0] == 'A') && (command_buf[1] == 'T') && (command_buf[2] == 'D') && (command_buf[3] == 'L'))
|
|
{
|
|
trans_cr = (trans_cr + 1) % 2;
|
|
|
|
command_buf[command_end] = 0;
|
|
strcat(bufout, "OK\r\n");
|
|
bufend += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(((out_char == 0x7f) || (out_char == 0x08)) && (command_end > 0))
|
|
{
|
|
command_end--; /* backspace */
|
|
command_buf[command_end] = 0;
|
|
}
|
|
else
|
|
{
|
|
command_buf[command_end] = out_char;
|
|
command_buf[command_end+1] = 0;
|
|
command_end = (command_end + 1) % 256;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif /* R_NETWORK */
|
|
#ifndef DREAMCAST
|
|
if((connected) && (write(rdev_fd, (char *)&out_char, 1) < 1))
|
|
{ /* returns -1 if disconnected or 0 if could not send */
|
|
perror("write");
|
|
DBG_APRINT("R*: ERROR on write.");
|
|
CPU_SetN;
|
|
CPU_regY = 135;
|
|
/*bufend = 13;*/ /* To catch NO CARRIER message */
|
|
}
|
|
#else
|
|
if (connected)
|
|
{
|
|
if (dc_write_serial(out_char) != 1)
|
|
{
|
|
Log_print("R*: ERROR on write.");
|
|
CPU_SetN;
|
|
CPU_regY = 135;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
CPU_regA = 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
R Device GET STATUS vector - called from Device Handler Address Table
|
|
---------------------------------------------------------------------------*/
|
|
void RDevice_STAT(void)
|
|
{
|
|
#ifdef WIN32
|
|
int len;
|
|
#else
|
|
#ifdef R_NETWORK
|
|
unsigned int len;
|
|
#endif
|
|
#endif
|
|
int bytesread;
|
|
unsigned char one;
|
|
int devnum;
|
|
int on;
|
|
unsigned char telnet_command[2];
|
|
/*static char IACctr = 0;*/
|
|
on = 1;
|
|
|
|
if(Peek(764) == 1)
|
|
{ /* Hack for Ice-T Terminal program to work! */
|
|
Poke(764, 255);
|
|
}
|
|
devnum = MEMORY_dGetByte(Devices_ICDNOZ);
|
|
|
|
#ifdef R_NETWORK
|
|
if(connected == 0)
|
|
{
|
|
if(RDevice_serial_enabled == 0)
|
|
{
|
|
if(do_once == 0)
|
|
{
|
|
|
|
/*strcpy(PORT,"23\n");*/
|
|
/*strcpy(PORT,"8000\n");*/
|
|
/*sprintf(PORT, "%d", 8000 + devnum);*/
|
|
portnum = portnum + devnum - 1;
|
|
|
|
/* Set up the listening port. */
|
|
do_once = 1;
|
|
memset ( &in, 0, sizeof ( struct sockaddr_in ) );
|
|
sock = socket ( AF_INET, SOCK_STREAM, 0 );
|
|
in.sin_family = AF_INET;
|
|
in.sin_addr.s_addr = INADDR_ANY;
|
|
/*in.sin_port = htons ( atoi ( PORT ) );*/
|
|
in.sin_port = htons (portnum);
|
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on) ); /* cmartin */
|
|
if(bind ( sock, (struct sockaddr *)&in, sizeof ( struct sockaddr_in ) ) < 0) perror("bind");
|
|
listen ( sock, 5 );
|
|
/* sethostent(1); */
|
|
#ifdef WIN32
|
|
retval = ioctlsocket(sock, FIONBIO, &ioctlsocket_non_block);
|
|
#else
|
|
retval = fcntl( sock, F_SETFL, O_NONBLOCK);
|
|
#endif /* WIN32 */
|
|
len = sizeof ( struct sockaddr_in );
|
|
/*bufend = 0;*/
|
|
sprintf(MESSAGE, "R%d: Listening on port %d...", devnum, portnum);
|
|
DBG_APRINT(MESSAGE);
|
|
}
|
|
|
|
rdev_fd = accept ( sock, (struct sockaddr *)&peer_in, &len );
|
|
if(rdev_fd != -1)
|
|
{
|
|
struct hostent *host;
|
|
if (getpeername(rdev_fd, (struct sockaddr *) &peer_in, &len) < 0)
|
|
{
|
|
perror("getpeername");
|
|
}
|
|
else
|
|
{
|
|
sprintf(MESSAGE, "R%d: Serving Connection from %s...", devnum, inet_ntoa(peer_in.sin_addr));
|
|
if ((host = gethostbyaddr((char *) &peer_in.sin_addr, sizeof peer_in.sin_addr, AF_INET)) == NULL)
|
|
{
|
|
/*perror("gethostbyaddr");*/
|
|
/*DBG_APRINT("Connected.");*/
|
|
} else {
|
|
sprintf(MESSAGE, "R%d: Serving Connection from %s.", devnum, host->h_name);
|
|
}
|
|
}
|
|
DBG_APRINT(MESSAGE);
|
|
#ifndef WIN32
|
|
signal(SIGPIPE, catch_disconnect); /*Need to see if the other end disconnects...*/
|
|
signal(SIGHUP, catch_disconnect); /*Need to see if the other end disconnects...*/
|
|
#endif /* WIN32 */
|
|
#ifdef WIN32
|
|
retval = ioctlsocket(rdev_fd, FIONBIO, &ioctlsocket_non_block);
|
|
#else
|
|
retval = fcntl( rdev_fd, F_SETFL, O_NONBLOCK);
|
|
#endif /* WIN32 */
|
|
|
|
/* Telnet negotiation */
|
|
sprintf(MESSAGE, "%c%c%c%c%c%c%c%c%c", 0xff, 0xfb, 0x01, 0xff, 0xfb, 0x03, 0xff, 0xfd, 0x0f3);
|
|
write(rdev_fd, MESSAGE, 9);
|
|
DBG_APRINT("R*: Negotiating Terminal Options...");
|
|
|
|
connected = 1;
|
|
/*
|
|
retval = write(rdev_fd, &IACdoBinary, 3);
|
|
retval = write(rdev_fd, &IACwillBinary, 3);
|
|
retval = write(rdev_fd, &IACdontLinemode, 3);
|
|
retval = write(rdev_fd, &IACwontLinemode, 3);
|
|
*/
|
|
bufout[0] = 0;
|
|
strcat(bufout, CONNECT_STRING);
|
|
bufend = strlen(CONNECT_STRING);
|
|
close(sock);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif /* R_NETWORK */
|
|
{
|
|
/* Actually reading and setting the Atari input buffer here */
|
|
if(concurrent)
|
|
{
|
|
#ifndef DREAMCAST
|
|
bytesread = read(rdev_fd, (char *)&one, 1);
|
|
#else
|
|
bytesread = dc_read_serial(&one);
|
|
#endif
|
|
if(bytesread > 0)
|
|
{
|
|
if((RDevice_serial_enabled == 0) && (one == 0xff))
|
|
{
|
|
/* Start Telnet escape seq processing... */
|
|
while(read(rdev_fd, (char *)telnet_command,2) != 2) {};
|
|
|
|
/*sprintf(MESSAGE, "Telnet Command = 0x%x 0x%x", telnet_command[0], telnet_command[1]);*/
|
|
/*DBG_APRINT(MESSAGE);*/
|
|
if(telnet_command[0] == 0xfd)
|
|
{ /*DO*/
|
|
if((telnet_command[1] == 0x01) || (telnet_command[1] == 0x03))
|
|
{ /* WILL ECHO and GO AHEAD (char mode) */
|
|
telnet_command[0] = 0xfb; /* WILL */
|
|
}
|
|
else
|
|
{
|
|
telnet_command[0] = 0xfc; /* WONT */
|
|
}
|
|
}
|
|
else if(telnet_command[0] == 0xfb)
|
|
{ /*WILL*/
|
|
/*telnet_command[0] = 0xfd;*/ /*DO*/
|
|
telnet_command[0] = 0xfe; /*DONT*/
|
|
}
|
|
else if(telnet_command[0] == 0xfe)
|
|
{ /*DONT*/
|
|
telnet_command[0] = 0xfc;
|
|
}
|
|
else if(telnet_command[0] == 0xfc)
|
|
{ /*WONT*/
|
|
telnet_command[0] = 0xfe;
|
|
}
|
|
|
|
if(telnet_command[0] == 0xfa)
|
|
{ /* subnegotiation */
|
|
while(read(rdev_fd, (char *)&one, 1) != 1) {};
|
|
|
|
while(one != 0xf0)
|
|
{ /* wait for end of sub negotiation */
|
|
while(read(rdev_fd, (char *)&one, 1) != 1) {};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
write(rdev_fd, (char *)&one, 1);
|
|
write(rdev_fd, (char *)telnet_command, 2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bufend++;
|
|
bufout[bufend-1] = one;
|
|
bufout[bufend] = 0;
|
|
/*return;*/
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set all values at all memory locations we modify on exit */
|
|
Poke(746,0);
|
|
Poke(748,0);
|
|
Poke(749,0);
|
|
CPU_regA = 1;
|
|
CPU_regY = 1;
|
|
CPU_ClrN;
|
|
|
|
if(concurrent)
|
|
{
|
|
Poke(747,bufend);
|
|
}
|
|
else
|
|
{
|
|
DBG_APRINT("R*: Not in concurrent mode....");
|
|
/*Poke(747,8);*/
|
|
Poke(747,(12+48+192)); /* Write 0xfc to address 747 */
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
R Device SPECIAL vector - called from Atari OS Device Handler Address Table
|
|
---------------------------------------------------------------------------*/
|
|
void RDevice_SPEC(void)
|
|
{
|
|
int iccom;
|
|
|
|
iccom = Peek(Devices_ICCOMZ);
|
|
sprintf(MESSAGE, "R*: XIO %d", iccom);
|
|
DBG_APRINT(MESSAGE);
|
|
|
|
/*
|
|
DBG_APRINT("Devices_ICCOMZ =");
|
|
DBG_APRINT("%d",iccom);
|
|
DBG_APRINT("^^ in Devices_ICCOMZ");
|
|
*/
|
|
|
|
switch (iccom)
|
|
{
|
|
case 32: /*Force Short Block*/
|
|
break;
|
|
case 34:
|
|
xio_34();
|
|
break;
|
|
case 36:
|
|
xio_36();
|
|
break;
|
|
case 38:
|
|
xio_38();
|
|
break;
|
|
case 40:
|
|
xio_40();
|
|
break;
|
|
default:
|
|
DBG_APRINT("R*: Unsupported XIO #.");
|
|
break;
|
|
}
|
|
/*
|
|
CPU_regA = 1;
|
|
CPU_regY = 1;
|
|
CPU_ClrN;
|
|
*/
|
|
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
R Device INIT vector - called from Atari OS Device Handler Address Table
|
|
---------------------------------------------------------------------------*/
|
|
void RDevice_INIT(void)
|
|
{
|
|
DBG_APRINT("R*: INIT");
|
|
CPU_regA = 1;
|
|
CPU_regY = 1;
|
|
CPU_ClrN;
|
|
}
|
|
|
|
void RDevice_Exit(void)
|
|
{
|
|
#ifdef WIN32
|
|
WSACleanup();
|
|
#endif /* WIN32 */
|
|
}
|