diff --git a/sim_serial.c b/sim_serial.c index dcbb91b8..fb271673 100644 --- a/sim_serial.c +++ b/sim_serial.c @@ -392,7 +392,7 @@ if ((strlen(devname) <= 5) if (savname == NULL) { /* didn't translate */ if (stat) *stat = SCPE_OPENERR; - return port; + return INVALID_HANDLE; } } 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) { int ports = 0; @@ -560,6 +568,7 @@ return ports; static SERHANDLE sim_open_os_serial (char *name) { +HANDLE hPort; SERHANDLE port; DCB dcb; COMMCONFIG commdefault; @@ -576,10 +585,10 @@ if (!GetDefaultCommConfig (name, &commdefault, &commsize)) { /* get default c return INVALID_HANDLE; /* indicate bad port name */ } -port = CreateFile (name, GENERIC_READ | GENERIC_WRITE, /* open the port */ - 0, NULL, OPEN_EXISTING, 0, 0); +hPort = CreateFile (name, GENERIC_READ | GENERIC_WRITE, /* open the port */ + 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 */ 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 */ } -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 */ if (error != ERROR_INVALID_PARAMETER) /* not a serial port name? */ 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 */ } @@ -608,10 +620,10 @@ dcb.fInX = commdefault.dcb.fInX; 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 */ (int) GetLastError ()); - CloseHandle (port); /* close port */ + sim_close_os_serial (port); /* close port */ return INVALID_HANDLE; /* and indicate failure to caller */ } @@ -621,10 +633,52 @@ cto.ReadTotalTimeoutConstant = 0; cto.WriteTotalTimeoutMultiplier = 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 */ (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 */ } @@ -665,7 +719,7 @@ DCB dcb; DWORD error; 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 */ (int) GetLastError ()); return SCPE_IOERR; /* return failure status */ @@ -696,7 +750,7 @@ else if (config.stopbits == 0) /* 0 implies 1.5 stop bi else 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 */ 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 */ return SCPE_ARG; if (bits_to_set&TMXR_MDM_DTR) - if (!EscapeCommFunction (port, SETDTR)) { + if (!EscapeCommFunction (port->hPort, SETDTR)) { sim_error_serial ("EscapeCommFunction", (int) GetLastError ()); return SCPE_IOERR; } if (bits_to_clear&TMXR_MDM_DTR) - if (!EscapeCommFunction (port, CLRDTR)) { + if (!EscapeCommFunction (port->hPort, CLRDTR)) { sim_error_serial ("EscapeCommFunction", (int) GetLastError ()); return SCPE_IOERR; } if (bits_to_set&TMXR_MDM_RTS) - if (!EscapeCommFunction (port, SETRTS)) { + if (!EscapeCommFunction (port->hPort, SETRTS)) { sim_error_serial ("EscapeCommFunction", (int) GetLastError ()); return SCPE_IOERR; } if (bits_to_clear&TMXR_MDM_RTS) - if (!EscapeCommFunction (port, CLRRTS)) { + if (!EscapeCommFunction (port->hPort, CLRRTS)) { sim_error_serial ("EscapeCommFunction", (int) GetLastError ()); return SCPE_IOERR; } if (incoming_bits) { DWORD ModemStat; - if (GetCommModemStatus (port, &ModemStat)) { + if (GetCommModemStatus (port->hPort, &ModemStat)) { sim_error_serial ("GetCommModemStatus", (int) GetLastError ()); return SCPE_IOERR; } @@ -790,14 +844,14 @@ DWORD commerrors; COMSTAT cs; 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 */ (int) GetLastError ()); return -1; /* return failure to caller */ } -if (!ReadFile (port, (LPVOID) buffer, /* read any available characters */ - (DWORD) count, &read, NULL)) { +if (!ReadFile (port->hPort, (LPVOID) buffer, /* read any available characters */ + (DWORD) count, &read, &port->oReadSync)) { sim_error_serial ("ReadFile", /* function failed; report unexpected error */ (int) GetLastError ()); 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) { -DWORD written; - -if (!WriteFile (port, (LPVOID) buffer, /* write the buffer to the serial port */ - (DWORD) count, &written, NULL)) { - sim_error_serial ("WriteFile", /* function failed; report unexpected error */ +if (WaitForSingleObject (port->oWriteReady.hEvent, 0) == WAIT_TIMEOUT) + return 0; +if ((!WriteFile (port->hPort, (LPVOID) buffer, /* write the buffer to the serial port */ + (DWORD) count, NULL, &port->oWriteSync)) && + (GetLastError () != ERROR_IO_PENDING)) { + sim_error_serial ("WriteFile", /* function failed; report unexpected error */ (int) GetLastError ()); - return -1; /* return failure to caller */ + return -1; /* return failure to caller */ } -else - return written; /* return number of characters written */ +if ((!WaitCommEvent (port->hPort, &port->dwEvtMask, &port->oWriteReady)) && + (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) { -CloseHandle (port); /* close the port */ -return; +if (port->oWriteReady.hEvent) + 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) +struct SERPORT { + int port; + }; + #if defined(__linux) || defined(__linux__) #include #include @@ -1028,9 +1099,8 @@ static const tcflag_t l_clear = ISIG | /* enable signals */ IEXTEN; /* enable extended functions */ static const tcflag_t l_set = 0; - - -SERHANDLE port; +int port; +SERHANDLE serport; struct termios tio; 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 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 }; -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 */ return SCPE_IOERR; /* return failure status */ } @@ -1176,7 +1248,7 @@ else if (config.stopbits == 2) /* two stop bits? */ else /* some other number? */ 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 */ 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) { bits = ((bits_to_set&TMXR_MDM_DTR) ? TIOCM_DTR : 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 */ return SCPE_IOERR; /* return failure status */ } @@ -1216,13 +1288,13 @@ if (bits_to_set) { if (bits_to_clear) { bits = ((bits_to_clear&TMXR_MDM_DTR) ? TIOCM_DTR : 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 */ return SCPE_IOERR; /* return failure status */ } } 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 */ return SCPE_IOERR; /* return failure status */ } @@ -1264,7 +1336,7 @@ int read_count; char *bptr, *cptr; 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 (errno == EAGAIN) /* no characters available? */ @@ -1314,7 +1386,7 @@ int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count) { 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 (errno == EWOULDBLOCK) @@ -1338,8 +1410,8 @@ return (int32) written; /* return number of static void sim_close_os_serial (SERHANDLE port) { -close (port); /* close the port */ -return; +close (port->port); /* close the port */ +free (port); } @@ -1385,6 +1457,11 @@ typedef struct { void *return_length_address; } ITEM; +struct SERPORT { + uint32 port; + IOSB write_iosb; + }; + /* Enumerate the available serial ports. 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}}; SENSE_BUF start_mode = { 0 }; SENSE_BUF run_mode = { 0 }; +SERHANDLE port; devnam.dsc$w_length = strlen (devnam.dsc$a_pointer); status = sys$assign (&devnam, &chan, 0, 0); @@ -1519,7 +1597,10 @@ if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) { sys$dassgn (chan); 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]); -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) status = iosb.status; if (status != SS$_NORMAL) { @@ -1610,7 +1691,7 @@ switch (config.stopbits) { 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); if (status == SS$_NORMAL) 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_to_clear&TMXR_MDM_RTS) ? TT$M_DS_RTS : 0)) << 24; 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); if (status == SS$_NORMAL) status = iosb.status; @@ -1663,7 +1744,7 @@ if (bits_to_set || bits_to_clear) { if (incoming_bits) { 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); if (status == SS$_NORMAL) status = iosb.status; @@ -1713,7 +1794,7 @@ unsigned char buf[4]; IOSB iosb; 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); if (status == SS$_NORMAL) status = iosb.status; @@ -1723,7 +1804,7 @@ if (status != SS$_NORMAL) { } if (sense.sense_count == 0) /* no characters available? */ 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); if (status == SS$_NORMAL) status = iosb.status; @@ -1745,30 +1826,16 @@ return (int32)iosb.count; /* return the number int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count) { 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 (status == SS$_NORMAL) - status = iosb.status; -if (status != SS$_NORMAL) { - 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 (port->write_iosb.status == 0) /* Prior write not done yet? */ + return 0; +status = sys$qio (0, port->port, IO$_WRITELBLK | IO$M_NOFORMAT, + &port->write_iosb, 0, 0, buffer, count, 0, 0, 0, 0); if (status != SS$_NORMAL) { sim_error_serial ("write", status); /* report unexpected error */ 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) { -sys$dassgn (port); /* close the port */ -return; +sys$dassgn (port->port); /* close the port */ +free (port); } - #else /* Non-implemented stubs */ @@ -1839,7 +1905,6 @@ return -1; static void sim_close_os_serial (SERHANDLE port) { -return; } diff --git a/sim_serial.h b/sim_serial.h index 48587fd0..caa6acf6 100644 --- a/sim_serial.h +++ b/sim_serial.h @@ -34,6 +34,11 @@ extern "C" { #endif +#ifndef SIMH_SERHANDLE_DEFINED +#define SIMH_SERHANDLE_DEFINED 0 +typedef struct SERPORT *SERHANDLE; +#endif /* SERHANDLE_DEFINED */ + #if defined (_WIN32) /* Windows definitions */ /* We need the basic Win32 definitions, but including "windows.h" also includes @@ -47,7 +52,7 @@ extern "C" { #endif #include #if !defined(INVALID_HANDLE) -#define INVALID_HANDLE INVALID_HANDLE_VALUE +#define INVALID_HANDLE (SERHANDLE)INVALID_HANDLE_VALUE #endif /* !defined(INVALID_HANDLE) */ #elif defined (__unix__) || defined (__APPLE__) || defined (__hpux) /* UNIX definitions */ @@ -61,31 +66,22 @@ extern "C" { #include #if !defined(INVALID_HANDLE) -#define INVALID_HANDLE -1 +#define INVALID_HANDLE ((SERHANDLE)(void *)-1) #endif /* !defined(INVALID_HANDLE) */ #elif defined (VMS) /* VMS definitions */ #if !defined(INVALID_HANDLE) -#define INVALID_HANDLE (uint32)(-1) +#define INVALID_HANDLE ((SERHANDLE)(void *)-1) #endif /* !defined(INVALID_HANDLE) */ #else /* Non-implemented definitions */ #if !defined(INVALID_HANDLE) -#define INVALID_HANDLE -1 +#define INVALID_HANDLE ((SERHANDLE)(void *)-1) #endif /* !defined(INVALID_HANDLE) */ #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 */ diff --git a/sim_tmxr.h b/sim_tmxr.h index 6d84aa8e..053f3a2f 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -53,11 +53,7 @@ extern "C" { #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 +typedef struct SERPORT *SERHANDLE; #endif #include "sim_sock.h"