TMXR: Reworked output to physical Serial ports for VMS and Windows hosts

The goal being to have output to physical serial ports complete without host
OS level buffering so that what is transmitted via the serial port has correct
timing with respect to I/O completion status within a simulator.

Linux, OS X, and various other *nix host platforms still need work here.
This commit is contained in:
Mark Pizzolato 2016-07-14 13:53:41 -07:00
parent 83bf230a47
commit c3496e4aa6
3 changed files with 148 additions and 91 deletions

View file

@ -392,7 +392,7 @@ if ((strlen(devname) <= 5)
if (savname == NULL) { /* didn't translate */ if (savname == NULL) { /* didn't translate */
if (stat) if (stat)
*stat = SCPE_OPENERR; *stat = SCPE_OPENERR;
return port; return INVALID_HANDLE;
} }
} }
else { else {
@ -500,6 +500,14 @@ return r;
*/ */
struct SERPORT {
HANDLE hPort;
DWORD dwEvtMask;
OVERLAPPED oReadSync;
OVERLAPPED oWriteReady;
OVERLAPPED oWriteSync;
};
static int sim_serial_os_devices (int max, SERIAL_LIST* list) static int sim_serial_os_devices (int max, SERIAL_LIST* list)
{ {
int ports = 0; int ports = 0;
@ -560,6 +568,7 @@ return ports;
static SERHANDLE sim_open_os_serial (char *name) static SERHANDLE sim_open_os_serial (char *name)
{ {
HANDLE hPort;
SERHANDLE port; SERHANDLE port;
DCB dcb; DCB dcb;
COMMCONFIG commdefault; COMMCONFIG commdefault;
@ -576,10 +585,10 @@ if (!GetDefaultCommConfig (name, &commdefault, &commsize)) { /* get default c
return INVALID_HANDLE; /* indicate bad port name */ return INVALID_HANDLE; /* indicate bad port name */
} }
port = CreateFile (name, GENERIC_READ | GENERIC_WRITE, /* open the port */ hPort = CreateFile (name, GENERIC_READ | GENERIC_WRITE, /* open the port */
0, NULL, OPEN_EXISTING, 0, 0); 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (port == INVALID_HANDLE_VALUE) { /* open failed? */ if (hPort == INVALID_HANDLE_VALUE) { /* open failed? */
error = GetLastError (); /* get error code */ error = GetLastError (); /* get error code */
if ((error != ERROR_FILE_NOT_FOUND) && /* bad filename? */ if ((error != ERROR_FILE_NOT_FOUND) && /* bad filename? */
@ -589,13 +598,16 @@ if (port == INVALID_HANDLE_VALUE) { /* open failed? */
return INVALID_HANDLE; /* indicate bad port name */ return INVALID_HANDLE; /* indicate bad port name */
} }
if (!GetCommState (port, &dcb)) { /* get the current comm parameters */ port = (SERHANDLE)calloc (1, sizeof(*port)); /* instantiate the SERHANDLE */
port->hPort = hPort;
if (!GetCommState (port->hPort, &dcb)) { /* get the current comm parameters */
error = GetLastError (); /* function failed; get error */ error = GetLastError (); /* function failed; get error */
if (error != ERROR_INVALID_PARAMETER) /* not a serial port name? */ if (error != ERROR_INVALID_PARAMETER) /* not a serial port name? */
sim_error_serial ("GetCommState", (int) error); /* no, so report unexpected error */ sim_error_serial ("GetCommState", (int) error); /* no, so report unexpected error */
CloseHandle (port); /* close the port */ sim_close_os_serial (port); /* close port */
return INVALID_HANDLE; /* and indicate bad port name */ return INVALID_HANDLE; /* and indicate bad port name */
} }
@ -608,10 +620,10 @@ dcb.fInX = commdefault.dcb.fInX;
dcb.fDtrControl = DTR_CONTROL_DISABLE; /* disable DTR initially until poll connects */ dcb.fDtrControl = DTR_CONTROL_DISABLE; /* disable DTR initially until poll connects */
if (!SetCommState (port, &dcb)) { /* configure the port with default parameters */ if (!SetCommState (port->hPort, &dcb)) { /* configure the port with default parameters */
sim_error_serial ("SetCommState", /* function failed; report unexpected error */ sim_error_serial ("SetCommState", /* function failed; report unexpected error */
(int) GetLastError ()); (int) GetLastError ());
CloseHandle (port); /* close port */ sim_close_os_serial (port); /* close port */
return INVALID_HANDLE; /* and indicate failure to caller */ return INVALID_HANDLE; /* and indicate failure to caller */
} }
@ -621,10 +633,52 @@ cto.ReadTotalTimeoutConstant = 0;
cto.WriteTotalTimeoutMultiplier = 0; cto.WriteTotalTimeoutMultiplier = 0;
cto.WriteTotalTimeoutConstant = 0; cto.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts (port, &cto)) { /* configure port timeouts */ if (!SetCommTimeouts (port->hPort, &cto)) { /* configure port timeouts */
sim_error_serial ("SetCommTimeouts", /* function failed; report unexpected error */ sim_error_serial ("SetCommTimeouts", /* function failed; report unexpected error */
(int) GetLastError ()); (int) GetLastError ());
CloseHandle (port); /* close port */ sim_close_os_serial (port); /* close port */
return INVALID_HANDLE; /* and indicate failure to caller */
}
/* Create an event object for use by WaitCommEvent. */
port->oWriteReady.hEvent = CreateEvent(NULL, /* default security attributes */
TRUE, /* manual-reset event */
TRUE, /* signaled */
NULL); /* no name */
if (port->oWriteReady.hEvent == NULL) {
sim_error_serial ("CreateEvent", /* function failed; report unexpected error */
(int) GetLastError ());
sim_close_os_serial (port); /* close port */
return INVALID_HANDLE; /* and indicate failure to caller */
}
port->oReadSync.hEvent = CreateEvent(NULL, /* default security attributes */
TRUE, /* manual-reset event */
FALSE, /* not signaled */
NULL); /* no name */
if (port->oReadSync.hEvent == NULL) {
sim_error_serial ("CreateEvent", /* function failed; report unexpected error */
(int) GetLastError ());
sim_close_os_serial (port); /* close port */
return INVALID_HANDLE; /* and indicate failure to caller */
}
port->oWriteSync.hEvent = CreateEvent(NULL, /* default security attributes */
TRUE, /* manual-reset event */
FALSE, /* not signaled */
NULL); /* no name */
if (port->oWriteSync.hEvent == NULL) {
sim_error_serial ("CreateEvent", /* function failed; report unexpected error */
(int) GetLastError ());
sim_close_os_serial (port); /* close port */
return INVALID_HANDLE; /* and indicate failure to caller */
}
if (!SetCommMask (port->hPort, EV_TXEMPTY)) {
sim_error_serial ("SetCommMask", /* function failed; report unexpected error */
(int) GetLastError ());
sim_close_os_serial (port); /* close port */
return INVALID_HANDLE; /* and indicate failure to caller */ return INVALID_HANDLE; /* and indicate failure to caller */
} }
@ -665,7 +719,7 @@ DCB dcb;
DWORD error; DWORD error;
int32 i; int32 i;
if (!GetCommState (port, &dcb)) { /* get the current comm parameters */ if (!GetCommState (port->hPort, &dcb)) { /* get the current comm parameters */
sim_error_serial ("GetCommState", /* function failed; report unexpected error */ sim_error_serial ("GetCommState", /* function failed; report unexpected error */
(int) GetLastError ()); (int) GetLastError ());
return SCPE_IOERR; /* return failure status */ return SCPE_IOERR; /* return failure status */
@ -696,7 +750,7 @@ else if (config.stopbits == 0) /* 0 implies 1.5 stop bi
else else
return SCPE_ARG; /* not a valid number of stop bits */ return SCPE_ARG; /* not a valid number of stop bits */
if (!SetCommState (port, &dcb)) { /* set the configuration */ if (!SetCommState (port->hPort, &dcb)) { /* set the configuration */
error = GetLastError (); /* check for error */ error = GetLastError (); /* check for error */
if (error == ERROR_INVALID_PARAMETER) /* invalid configuration? */ if (error == ERROR_INVALID_PARAMETER) /* invalid configuration? */
@ -729,28 +783,28 @@ if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) || /* Assure only settable bits
(bits_to_set & bits_to_clear)) /* and can't set and clear the same bits */ (bits_to_set & bits_to_clear)) /* and can't set and clear the same bits */
return SCPE_ARG; return SCPE_ARG;
if (bits_to_set&TMXR_MDM_DTR) if (bits_to_set&TMXR_MDM_DTR)
if (!EscapeCommFunction (port, SETDTR)) { if (!EscapeCommFunction (port->hPort, SETDTR)) {
sim_error_serial ("EscapeCommFunction", (int) GetLastError ()); sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
return SCPE_IOERR; return SCPE_IOERR;
} }
if (bits_to_clear&TMXR_MDM_DTR) if (bits_to_clear&TMXR_MDM_DTR)
if (!EscapeCommFunction (port, CLRDTR)) { if (!EscapeCommFunction (port->hPort, CLRDTR)) {
sim_error_serial ("EscapeCommFunction", (int) GetLastError ()); sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
return SCPE_IOERR; return SCPE_IOERR;
} }
if (bits_to_set&TMXR_MDM_RTS) if (bits_to_set&TMXR_MDM_RTS)
if (!EscapeCommFunction (port, SETRTS)) { if (!EscapeCommFunction (port->hPort, SETRTS)) {
sim_error_serial ("EscapeCommFunction", (int) GetLastError ()); sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
return SCPE_IOERR; return SCPE_IOERR;
} }
if (bits_to_clear&TMXR_MDM_RTS) if (bits_to_clear&TMXR_MDM_RTS)
if (!EscapeCommFunction (port, CLRRTS)) { if (!EscapeCommFunction (port->hPort, CLRRTS)) {
sim_error_serial ("EscapeCommFunction", (int) GetLastError ()); sim_error_serial ("EscapeCommFunction", (int) GetLastError ());
return SCPE_IOERR; return SCPE_IOERR;
} }
if (incoming_bits) { if (incoming_bits) {
DWORD ModemStat; DWORD ModemStat;
if (GetCommModemStatus (port, &ModemStat)) { if (GetCommModemStatus (port->hPort, &ModemStat)) {
sim_error_serial ("GetCommModemStatus", (int) GetLastError ()); sim_error_serial ("GetCommModemStatus", (int) GetLastError ());
return SCPE_IOERR; return SCPE_IOERR;
} }
@ -790,14 +844,14 @@ DWORD commerrors;
COMSTAT cs; COMSTAT cs;
char *bptr; char *bptr;
if (!ClearCommError (port, &commerrors, &cs)) { /* get the comm error flags */ if (!ClearCommError (port->hPort, &commerrors, &cs)) { /* get the comm error flags */
sim_error_serial ("ClearCommError", /* function failed; report unexpected error */ sim_error_serial ("ClearCommError", /* function failed; report unexpected error */
(int) GetLastError ()); (int) GetLastError ());
return -1; /* return failure to caller */ return -1; /* return failure to caller */
} }
if (!ReadFile (port, (LPVOID) buffer, /* read any available characters */ if (!ReadFile (port->hPort, (LPVOID) buffer, /* read any available characters */
(DWORD) count, &read, NULL)) { (DWORD) count, &read, &port->oReadSync)) {
sim_error_serial ("ReadFile", /* function failed; report unexpected error */ sim_error_serial ("ReadFile", /* function failed; report unexpected error */
(int) GetLastError ()); (int) GetLastError ());
return -1; /* return failure to caller */ return -1; /* return failure to caller */
@ -825,16 +879,22 @@ return read; /* return the number of
int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count) int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count)
{ {
DWORD written; if (WaitForSingleObject (port->oWriteReady.hEvent, 0) == WAIT_TIMEOUT)
return 0;
if (!WriteFile (port, (LPVOID) buffer, /* write the buffer to the serial port */ if ((!WriteFile (port->hPort, (LPVOID) buffer, /* write the buffer to the serial port */
(DWORD) count, &written, NULL)) { (DWORD) count, NULL, &port->oWriteSync)) &&
(GetLastError () != ERROR_IO_PENDING)) {
sim_error_serial ("WriteFile", /* function failed; report unexpected error */ sim_error_serial ("WriteFile", /* function failed; report unexpected error */
(int) GetLastError ()); (int) GetLastError ());
return -1; /* return failure to caller */ return -1; /* return failure to caller */
} }
else if ((!WaitCommEvent (port->hPort, &port->dwEvtMask, &port->oWriteReady)) &&
return written; /* return number of characters written */ (GetLastError () != ERROR_IO_PENDING)) {
sim_error_serial ("WaitCommEvent", /* function failed; report unexpected error */
(int) GetLastError ());
return -1; /* return failure to caller */
}
return count; /* return number of characters written/queued */
} }
@ -845,14 +905,25 @@ else
static void sim_close_os_serial (SERHANDLE port) static void sim_close_os_serial (SERHANDLE port)
{ {
CloseHandle (port); /* close the port */ if (port->oWriteReady.hEvent)
return; CloseHandle (port->oWriteReady.hEvent); /* close the event handle */
if (port->oReadSync.hEvent)
CloseHandle (port->oReadSync.hEvent); /* close the event handle */
if (port->oWriteSync.hEvent)
CloseHandle (port->oWriteSync.hEvent); /* close the event handle */
if (port->hPort)
CloseHandle (port->hPort); /* close the port */
free (port);
} }
#elif defined (__unix__) || defined(__APPLE__) || defined(__hpux) #elif defined (__unix__) || defined(__APPLE__) || defined(__hpux)
struct SERPORT {
int port;
};
#if defined(__linux) || defined(__linux__) #if defined(__linux) || defined(__linux__)
#include <dirent.h> #include <dirent.h>
#include <libgen.h> #include <libgen.h>
@ -1028,9 +1099,8 @@ static const tcflag_t l_clear = ISIG | /* enable signals */
IEXTEN; /* enable extended functions */ IEXTEN; /* enable extended functions */
static const tcflag_t l_set = 0; static const tcflag_t l_set = 0;
int port;
SERHANDLE serport;
SERHANDLE port;
struct termios tio; struct termios tio;
port = open (name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ port = open (name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */
@ -1092,7 +1162,9 @@ if (tcsetattr (port, TCSANOW, &tio)) { /* set the terminal attr
return INVALID_HANDLE; /* and return failure to caller */ return INVALID_HANDLE; /* and return failure to caller */
} }
return port; /* return port fd for success */ serport = (SERHANDLE)calloc (1, sizeof(*serport));
serport->port = port;
return serport; /* return port fd for success */
} }
@ -1131,7 +1203,7 @@ static const int32 baud_count = sizeof (baud_map) / sizeof (baud_map [0]);
static const tcflag_t charsize_map [4] = { CS5, CS6, CS7, CS8 }; static const tcflag_t charsize_map [4] = { CS5, CS6, CS7, CS8 };
if (tcgetattr (port, &tio)) { /* get the current configuration */ if (tcgetattr (port->port, &tio)) { /* get the current configuration */
sim_error_serial ("tcgetattr", errno); /* function failed; report unexpected error */ sim_error_serial ("tcgetattr", errno); /* function failed; report unexpected error */
return SCPE_IOERR; /* return failure status */ return SCPE_IOERR; /* return failure status */
} }
@ -1176,7 +1248,7 @@ else if (config.stopbits == 2) /* two stop bits? */
else /* some other number? */ else /* some other number? */
return SCPE_ARG; /* not a valid number of stop bits */ return SCPE_ARG; /* not a valid number of stop bits */
if (tcsetattr (port, TCSAFLUSH, &tio)) { /* set the new configuration */ if (tcsetattr (port->port, TCSAFLUSH, &tio)) { /* set the new configuration */
sim_error_serial ("tcsetattr", errno); /* function failed; report unexpected error */ sim_error_serial ("tcsetattr", errno); /* function failed; report unexpected error */
return SCPE_IERR; /* return failure status */ return SCPE_IERR; /* return failure status */
} }
@ -1208,7 +1280,7 @@ if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) || /* Assure only settable bits
if (bits_to_set) { if (bits_to_set) {
bits = ((bits_to_set&TMXR_MDM_DTR) ? TIOCM_DTR : 0) | bits = ((bits_to_set&TMXR_MDM_DTR) ? TIOCM_DTR : 0) |
((bits_to_set&TMXR_MDM_RTS) ? TIOCM_RTS : 0); ((bits_to_set&TMXR_MDM_RTS) ? TIOCM_RTS : 0);
if (ioctl (port, TIOCMBIS, &bits)) { /* set the desired bits */ if (ioctl (port->port, TIOCMBIS, &bits)) { /* set the desired bits */
sim_error_serial ("ioctl", errno); /* report unexpected error */ sim_error_serial ("ioctl", errno); /* report unexpected error */
return SCPE_IOERR; /* return failure status */ return SCPE_IOERR; /* return failure status */
} }
@ -1216,13 +1288,13 @@ if (bits_to_set) {
if (bits_to_clear) { if (bits_to_clear) {
bits = ((bits_to_clear&TMXR_MDM_DTR) ? TIOCM_DTR : 0) | bits = ((bits_to_clear&TMXR_MDM_DTR) ? TIOCM_DTR : 0) |
((bits_to_clear&TMXR_MDM_RTS) ? TIOCM_RTS : 0); ((bits_to_clear&TMXR_MDM_RTS) ? TIOCM_RTS : 0);
if (ioctl (port, TIOCMBIC, &bits)) { /* clear the desired bits */ if (ioctl (port->port, TIOCMBIC, &bits)) { /* clear the desired bits */
sim_error_serial ("ioctl", errno); /* report unexpected error */ sim_error_serial ("ioctl", errno); /* report unexpected error */
return SCPE_IOERR; /* return failure status */ return SCPE_IOERR; /* return failure status */
} }
} }
if (incoming_bits) { if (incoming_bits) {
if (ioctl (port, TIOCMGET, &bits)) { /* get the modem bits */ if (ioctl (port->port, TIOCMGET, &bits)) { /* get the modem bits */
sim_error_serial ("ioctl", errno); /* report unexpected error */ sim_error_serial ("ioctl", errno); /* report unexpected error */
return SCPE_IOERR; /* return failure status */ return SCPE_IOERR; /* return failure status */
} }
@ -1264,7 +1336,7 @@ int read_count;
char *bptr, *cptr; char *bptr, *cptr;
int32 remaining; int32 remaining;
read_count = read (port, (void *) buffer, (size_t) count); /* read from the serial port */ read_count = read (port->port, (void *) buffer, (size_t) count);/* read from the serial port */
if (read_count == -1) /* read error? */ if (read_count == -1) /* read error? */
if (errno == EAGAIN) /* no characters available? */ if (errno == EAGAIN) /* no characters available? */
@ -1314,7 +1386,7 @@ int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count)
{ {
int written; int written;
written = write (port, (void *) buffer, (size_t) count); /* write the buffer to the serial port */ written = write (port->port, (void *) buffer, (size_t) count);/* write the buffer to the serial port */
if (written == -1) { if (written == -1) {
if (errno == EWOULDBLOCK) if (errno == EWOULDBLOCK)
@ -1338,8 +1410,8 @@ return (int32) written; /* return number of
static void sim_close_os_serial (SERHANDLE port) static void sim_close_os_serial (SERHANDLE port)
{ {
close (port); /* close the port */ close (port->port); /* close the port */
return; free (port);
} }
@ -1385,6 +1457,11 @@ typedef struct {
void *return_length_address; void *return_length_address;
} ITEM; } ITEM;
struct SERPORT {
uint32 port;
IOSB write_iosb;
};
/* Enumerate the available serial ports. /* Enumerate the available serial ports.
The serial port names generated by attempting to open /dev/ttyS0 thru The serial port names generated by attempting to open /dev/ttyS0 thru
@ -1492,6 +1569,7 @@ ITEM items[] = { {sizeof (devclass), DVI$_DEVCLASS, &devclass, NULL},
{ 0, 0, NULL, NULL}}; { 0, 0, NULL, NULL}};
SENSE_BUF start_mode = { 0 }; SENSE_BUF start_mode = { 0 };
SENSE_BUF run_mode = { 0 }; SENSE_BUF run_mode = { 0 };
SERHANDLE port;
devnam.dsc$w_length = strlen (devnam.dsc$a_pointer); devnam.dsc$w_length = strlen (devnam.dsc$a_pointer);
status = sys$assign (&devnam, &chan, 0, 0); status = sys$assign (&devnam, &chan, 0, 0);
@ -1519,7 +1597,10 @@ if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) {
sys$dassgn (chan); sys$dassgn (chan);
return INVALID_HANDLE; return INVALID_HANDLE;
} }
return chan; /* return channel for success */ port = (SERHANDLE)calloc (1, sizeof(*port));
port->port = chan;
port->write_iosb.status = 1;
return port; /* return channel for success */
} }
@ -1556,7 +1637,7 @@ static const struct {
static const int32 baud_count = sizeof (baud_map) / sizeof (baud_map [0]); static const int32 baud_count = sizeof (baud_map) / sizeof (baud_map [0]);
status = sys$qiow (0, port, IO$_SENSEMODE, &iosb, 0, 0, &sense, sizeof(sense), 0, NULL, 0, 0); status = sys$qiow (0, port->port, IO$_SENSEMODE, &iosb, 0, 0, &sense, sizeof(sense), 0, NULL, 0, 0);
if (status == SS$_NORMAL) if (status == SS$_NORMAL)
status = iosb.status; status = iosb.status;
if (status != SS$_NORMAL) { if (status != SS$_NORMAL) {
@ -1610,7 +1691,7 @@ switch (config.stopbits) {
return SCPE_ARG; /* not a valid number of stop bits */ return SCPE_ARG; /* not a valid number of stop bits */
} }
status = sys$qiow (0, port, IO$_SETMODE, &iosb, 0, 0, status = sys$qiow (0, port->port, IO$_SETMODE, &iosb, 0, 0,
&sense, sizeof (sense), speed, 0, parity | charsize | stopbits, 0); &sense, sizeof (sense), speed, 0, parity | charsize | stopbits, 0);
if (status == SS$_NORMAL) if (status == SS$_NORMAL)
status = iosb.status; status = iosb.status;
@ -1651,7 +1732,7 @@ if (bits_to_clear)
bits[0] |= (((bits_to_clear&TMXR_MDM_DTR) ? TT$M_DS_DTR : 0) | bits[0] |= (((bits_to_clear&TMXR_MDM_DTR) ? TT$M_DS_DTR : 0) |
((bits_to_clear&TMXR_MDM_RTS) ? TT$M_DS_RTS : 0)) << 24; ((bits_to_clear&TMXR_MDM_RTS) ? TT$M_DS_RTS : 0)) << 24;
if (bits_to_set || bits_to_clear) { if (bits_to_set || bits_to_clear) {
status = sys$qiow (0, port, IO$_SETMODE|IO$M_SET_MODEM|IO$M_MAINT, &iosb, 0, 0, status = sys$qiow (0, port->port, IO$_SETMODE|IO$M_SET_MODEM|IO$M_MAINT, &iosb, 0, 0,
bits, 0, 0, 0, 0, 0); bits, 0, 0, 0, 0, 0);
if (status == SS$_NORMAL) if (status == SS$_NORMAL)
status = iosb.status; status = iosb.status;
@ -1663,7 +1744,7 @@ if (bits_to_set || bits_to_clear) {
if (incoming_bits) { if (incoming_bits) {
uint32 modem; uint32 modem;
status = sys$qiow (0, port, IO$_SENSEMODE|IO$M_RD_MODEM, &iosb, 0, 0, status = sys$qiow (0, port->port, IO$_SENSEMODE|IO$M_RD_MODEM, &iosb, 0, 0,
bits, 0, 0, 0, 0, 0); bits, 0, 0, 0, 0, 0);
if (status == SS$_NORMAL) if (status == SS$_NORMAL)
status = iosb.status; status = iosb.status;
@ -1713,7 +1794,7 @@ unsigned char buf[4];
IOSB iosb; IOSB iosb;
SENSE_BUF sense; SENSE_BUF sense;
status = sys$qiow (0, port, IO$_SENSEMODE | IO$M_TYPEAHDCNT, &iosb, status = sys$qiow (0, port->port, IO$_SENSEMODE | IO$M_TYPEAHDCNT, &iosb,
0, 0, &sense, 8, 0, term, 0, 0); 0, 0, &sense, 8, 0, term, 0, 0);
if (status == SS$_NORMAL) if (status == SS$_NORMAL)
status = iosb.status; status = iosb.status;
@ -1723,7 +1804,7 @@ if (status != SS$_NORMAL) {
} }
if (sense.sense_count == 0) /* no characters available? */ if (sense.sense_count == 0) /* no characters available? */
return 0; /* return 0 to indicate */ return 0; /* return 0 to indicate */
status = sys$qiow (0, port, IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED | IO$M_TRMNOECHO, status = sys$qiow (0, port->port, IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED | IO$M_TRMNOECHO,
&iosb, 0, 0, buffer, (count < sense.sense_count) ? count : sense.sense_count, 0, term, 0, 0); &iosb, 0, 0, buffer, (count < sense.sense_count) ? count : sense.sense_count, 0, term, 0, 0);
if (status == SS$_NORMAL) if (status == SS$_NORMAL)
status = iosb.status; status = iosb.status;
@ -1745,30 +1826,16 @@ return (int32)iosb.count; /* return the number
int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count) int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count)
{ {
uint32 status; uint32 status;
static uint32 term[2] = {0, 0};
unsigned char buf[4];
IOSB iosb;
uint32 devsts = 0;
#define UCB$M_BSY 0x100 /* Device I/O busy flag */
ITEM items[] = { {sizeof (devsts), DVI$_STS, &devsts, NULL},
{ 0, 0, NULL, NULL}};
status = sys$getdviw (0, port, NULL, items, &iosb, NULL, 0, 0); if (port->write_iosb.status == 0) /* Prior write not done yet? */
if (status == SS$_NORMAL) return 0;
status = iosb.status; status = sys$qio (0, port->port, IO$_WRITELBLK | IO$M_NOFORMAT,
if (status != SS$_NORMAL) { &port->write_iosb, 0, 0, buffer, count, 0, 0, 0, 0);
sim_error_serial ("write-GETDVI", status); /* report unexpected error */
return -1;
}
if (devsts & UCB$M_BSY)
return 0; /* Would block */
status = sys$qiow (0, port, IO$_WRITELBLK | IO$M_NOFORMAT,
NULL, 0, 0, buffer, count, 0, 0, 0, 0);
if (status != SS$_NORMAL) { if (status != SS$_NORMAL) {
sim_error_serial ("write", status); /* report unexpected error */ sim_error_serial ("write", status); /* report unexpected error */
return -1; return -1;
} }
return (int32)iosb.count; /* return number of characters written */ return (int32)count; /* return number of characters written */
} }
@ -1779,11 +1846,10 @@ return (int32)iosb.count; /* return number of char
static void sim_close_os_serial (SERHANDLE port) static void sim_close_os_serial (SERHANDLE port)
{ {
sys$dassgn (port); /* close the port */ sys$dassgn (port->port); /* close the port */
return; free (port);
} }
#else #else
/* Non-implemented stubs */ /* Non-implemented stubs */
@ -1839,7 +1905,6 @@ return -1;
static void sim_close_os_serial (SERHANDLE port) static void sim_close_os_serial (SERHANDLE port)
{ {
return;
} }

View file

@ -34,6 +34,11 @@
extern "C" { extern "C" {
#endif #endif
#ifndef SIMH_SERHANDLE_DEFINED
#define SIMH_SERHANDLE_DEFINED 0
typedef struct SERPORT *SERHANDLE;
#endif /* SERHANDLE_DEFINED */
#if defined (_WIN32) /* Windows definitions */ #if defined (_WIN32) /* Windows definitions */
/* We need the basic Win32 definitions, but including "windows.h" also includes /* We need the basic Win32 definitions, but including "windows.h" also includes
@ -47,7 +52,7 @@ extern "C" {
#endif #endif
#include <windows.h> #include <windows.h>
#if !defined(INVALID_HANDLE) #if !defined(INVALID_HANDLE)
#define INVALID_HANDLE INVALID_HANDLE_VALUE #define INVALID_HANDLE (SERHANDLE)INVALID_HANDLE_VALUE
#endif /* !defined(INVALID_HANDLE) */ #endif /* !defined(INVALID_HANDLE) */
#elif defined (__unix__) || defined (__APPLE__) || defined (__hpux) /* UNIX definitions */ #elif defined (__unix__) || defined (__APPLE__) || defined (__hpux) /* UNIX definitions */
@ -61,31 +66,22 @@ extern "C" {
#include <sys/ioctl.h> #include <sys/ioctl.h>
#if !defined(INVALID_HANDLE) #if !defined(INVALID_HANDLE)
#define INVALID_HANDLE -1 #define INVALID_HANDLE ((SERHANDLE)(void *)-1)
#endif /* !defined(INVALID_HANDLE) */ #endif /* !defined(INVALID_HANDLE) */
#elif defined (VMS) /* VMS definitions */ #elif defined (VMS) /* VMS definitions */
#if !defined(INVALID_HANDLE) #if !defined(INVALID_HANDLE)
#define INVALID_HANDLE (uint32)(-1) #define INVALID_HANDLE ((SERHANDLE)(void *)-1)
#endif /* !defined(INVALID_HANDLE) */ #endif /* !defined(INVALID_HANDLE) */
#else /* Non-implemented definitions */ #else /* Non-implemented definitions */
#if !defined(INVALID_HANDLE) #if !defined(INVALID_HANDLE)
#define INVALID_HANDLE -1 #define INVALID_HANDLE ((SERHANDLE)(void *)-1)
#endif /* !defined(INVALID_HANDLE) */ #endif /* !defined(INVALID_HANDLE) */
#endif /* OS variants */ #endif /* OS variants */
#ifndef SIMH_SERHANDLE_DEFINED
#define SIMH_SERHANDLE_DEFINED 0
#if defined (_WIN32) /* Windows definitions */
typedef void *SERHANDLE;
#else /* all other platforms */
typedef int SERHANDLE;
#endif
#endif /* SERHANDLE_DEFINED */
/* Common definitions */ /* Common definitions */

View file

@ -53,11 +53,7 @@ extern "C" {
#ifndef SIMH_SERHANDLE_DEFINED #ifndef SIMH_SERHANDLE_DEFINED
#define SIMH_SERHANDLE_DEFINED 0 #define SIMH_SERHANDLE_DEFINED 0
#if defined (_WIN32) /* Windows definitions */ typedef struct SERPORT *SERHANDLE;
typedef void *SERHANDLE;
#else /* all other platforms */
typedef int SERHANDLE;
#endif
#endif #endif
#include "sim_sock.h" #include "sim_sock.h"