diff --git a/bochs/iodev/serial_raw.cc b/bochs/iodev/serial_raw.cc index 77587e7a6..6bd52b776 100644 --- a/bochs/iodev/serial_raw.cc +++ b/bochs/iodev/serial_raw.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: serial_raw.cc,v 1.14 2004-03-28 12:41:12 vruppert Exp $ +// $Id: serial_raw.cc,v 1.15 2004-05-13 16:23:14 vruppert Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2004 MandrakeSoft S.A. @@ -36,10 +36,15 @@ #define LOG_THIS +#ifdef WIN32_RECEIVE_RAW +DWORD WINAPI RawSerialThread(VOID *this_ptr); +#endif + serial_raw::serial_raw (char *devname) { #ifdef WIN32 char portstr[MAX_PATH]; + DWORD threadID; #endif put ("SERR"); @@ -50,6 +55,10 @@ serial_raw::serial_raw (char *devname) dcb.fBinary = 1; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fRtsControl = RTS_CONTROL_ENABLE; + dcb.Parity = NOPARITY; + dcb.ByteSize = 8; + dcb.StopBits = ONESTOPBIT; + dcb.BaudRate = CBR_115200; DCBchanged = FALSE; if (lstrlen(devname) > 0) { wsprintf(portstr, "\\\\.\\%s", devname); @@ -57,6 +66,16 @@ serial_raw::serial_raw (char *devname) OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (hCOM != INVALID_HANDLE_VALUE) { present = 1; + GetCommModemStatus(hCOM, &MSR_value); + SetupComm(hCOM, 8192, 2048); + PurgeComm(hCOM, PURGE_TXABORT | PURGE_RXABORT | + PURGE_TXCLEAR | PURGE_RXCLEAR); +#ifdef WIN32_RECEIVE_RAW + SetCommMask(hCOM, EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_RXCHAR); + memset(&rx_ovl, 0, sizeof(OVERLAPPED)); + rx_ovl.hEvent = CreateEvent(NULL,TRUE,FALSE,"receive"); + hRawSerialThread = CreateThread(NULL, 0, RawSerialThread, this, 0, &threadID); +#endif } else { present = 0; BX_ERROR(("Raw device '%s' not present", devname)); @@ -76,6 +95,14 @@ serial_raw::~serial_raw (void) { if (present) { #ifdef WIN32 +#ifdef WIN32_RECEIVE_RAW + thread_quit = TRUE; + SetCommMask(hCOM, 0); + while (thread_active) Sleep(10); + CloseHandle(thread_ovl.hEvent); + CloseHandle(rx_ovl.hEvent); + CloseHandle(hRawSerialThread); +#endif CloseHandle(hCOM); #endif } @@ -187,14 +214,10 @@ serial_raw::set_modem_control (int ctrl) int serial_raw::get_modem_status () { -#ifdef WIN32 - DWORD mstat; -#endif int status = 0; #ifdef WIN32 - GetCommModemStatus(hCOM, &mstat); - status = mstat & 0xf0; + status = MSR_value; #endif BX_DEBUG (("get modem status returns 0x%02x", status)); return status; @@ -208,13 +231,15 @@ serial_raw::setup_port () COMMTIMEOUTS ctmo; ClearCommError(hCOM, &DErr, NULL); - SetupComm(hCOM, 2048, 2048); PurgeComm(hCOM, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); memset(&ctmo, 0, sizeof(ctmo)); SetCommTimeouts(hCOM, &ctmo); SetCommState(hCOM, &dcb); - SetCommMask(hCOM, 0); + rxdata_count = 0; +#ifdef WIN32_RECEIVE_RAW + thread_rxdata_count = 0; +#endif #endif } @@ -260,6 +285,12 @@ serial_raw::ready_transmit () bx_bool serial_raw::ready_receive () { +#ifdef WIN32_RECEIVE_RAW + if ((rxdata_count == 0) && (thread_rxdata_count > 0)) { + SetEvent(thread_ovl.hEvent); + SetEvent(rx_ovl.hEvent); + } +#endif BX_DEBUG (("ready_receive returning %d", (rxdata_count > 0))); return (rxdata_count > 0); } @@ -267,17 +298,197 @@ serial_raw::ready_receive () int serial_raw::receive () { - BX_DEBUG (("receive returning 'A'")); +#ifdef WIN32 + int data; +#endif + if (present) { #ifdef WIN32 if (DCBchanged) { setup_port(); } -#endif + data = rxdata_buffer[0]; + if (rxdata_count > 0) { + memcpy(&rxdata_buffer[0], &rxdata_buffer[1], sizeof(Bit16s)*(RX_BUFSIZE-1)); + rxdata_count--; + } + if (data < 0) { + switch (data) { + case RAW_EVENT_CTS_ON: + MSR_value |= 0x10; + break; + case RAW_EVENT_CTS_OFF: + MSR_value &= ~0x10; + break; + case RAW_EVENT_DSR_ON: + MSR_value |= 0x20; + break; + case RAW_EVENT_DSR_OFF: + MSR_value &= ~0x20; + break; + case RAW_EVENT_RING_ON: + MSR_value |= 0x40; + break; + case RAW_EVENT_RING_OFF: + MSR_value &= ~0x40; + break; + case RAW_EVENT_RLSD_ON: + MSR_value |= 0x80; + break; + case RAW_EVENT_RLSD_OFF: + MSR_value &= ~0x80; + break; + } + } + return data; +#else + BX_DEBUG (("receive returning 'A'")); return (int)'A'; +#endif } else { + BX_DEBUG (("receive returning 'A'")); return (int)'A'; } } +#ifdef WIN32_RECEIVE_RAW + +DWORD WINAPI RawSerialThread(VOID *this_ptr) +{ + serial_raw *class_ptr = (serial_raw *) this_ptr; + class_ptr->serial_thread(); + return 0; +} + +void +serial_raw::serial_thread () +{ + DWORD DErr, Len2; + DWORD EvtMask, MSR, Temp; + char s1[2]; + + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE); + thread_active = TRUE; + thread_quit = FALSE; + memset(&thread_ovl, 0, sizeof(OVERLAPPED)); + thread_ovl.hEvent = CreateEvent(NULL,TRUE,TRUE,"thread"); + thread_rxdata_count = 0; + while (!thread_quit) { + if ((rxdata_count == 0) && (thread_rxdata_count > 0)) { + if (thread_rxdata_count > RX_BUFSIZE) { + memcpy(&rxdata_buffer[0], &thread_rxdata_buffer[0], sizeof(Bit16s)*RX_BUFSIZE); + memcpy(&thread_rxdata_buffer[0], &thread_rxdata_buffer[RX_BUFSIZE], sizeof(Bit16s)*(thread_rxdata_count-RX_BUFSIZE)); + rxdata_count = RX_BUFSIZE; + thread_rxdata_count -= RX_BUFSIZE; + } else { + memcpy(&rxdata_buffer[0], &thread_rxdata_buffer[0], sizeof(Bit16s)*thread_rxdata_count); + rxdata_count = thread_rxdata_count; + thread_rxdata_count = 0; + } + } + ClearCommError(hCOM, &DErr, NULL); + EvtMask = 0; + if (!WaitCommEvent(hCOM, &EvtMask, &thread_ovl)) { + if (GetLastError() == ERROR_IO_PENDING) { + if (WaitForSingleObject(thread_ovl.hEvent, INFINITE) == WAIT_OBJECT_0) { + GetOverlappedResult(hCOM, &thread_ovl, &Temp, FALSE); + } + } + } + if (EvtMask & EV_RXCHAR) { + if (thread_rxdata_count < THREAD_RX_BUFSIZE) { + do { + ClearCommError(hCOM, &DErr, NULL); + if (!ReadFile(hCOM, s1, 1, &Len2, &rx_ovl)) { + if (GetLastError() == ERROR_IO_PENDING) { + if (WaitForSingleObject(rx_ovl.hEvent, INFINITE) != WAIT_OBJECT_0) { + Len2 = 0; + } else { + GetOverlappedResult(hCOM, &rx_ovl, &Len2, FALSE); + } + } else { + Len2 = 0; + } + } + if (Len2 > 0) { + enq_event(s1[0]); + } + if ((rxdata_count == 0) && (thread_rxdata_count > 0)) { + if (thread_rxdata_count > RX_BUFSIZE) { + memcpy(&rxdata_buffer[0], &thread_rxdata_buffer[0], sizeof(Bit16s)*RX_BUFSIZE); + memcpy(&thread_rxdata_buffer[0], &thread_rxdata_buffer[RX_BUFSIZE], sizeof(Bit16s)*(thread_rxdata_count-RX_BUFSIZE)); + rxdata_count = RX_BUFSIZE; + thread_rxdata_count -= RX_BUFSIZE; + } else { + memcpy(&rxdata_buffer[0], &thread_rxdata_buffer[0], sizeof(Bit16s)*thread_rxdata_count); + rxdata_count = thread_rxdata_count; + thread_rxdata_count = 0; + } + } + } while ((Len2 != 0) && (thread_rxdata_count < THREAD_RX_BUFSIZE)); + ClearCommError(hCOM, &DErr, NULL); + } + } + if (EvtMask & EV_BREAK) { + enq_event(RAW_EVENT_BREAK); + } + if (EvtMask & EV_ERR) { + ClearCommError(hCOM, &DErr, NULL); + if (DErr & CE_FRAME) { + enq_event(RAW_EVENT_FRAME); + } + if (DErr & CE_OVERRUN) { + enq_event(RAW_EVENT_OVERRUN); + } + if (DErr & CE_RXPARITY) { + enq_event(RAW_EVENT_PARITY); + } + } + if (EvtMask & (EV_CTS | EV_DSR | EV_RING | EV_RLSD)) { + GetCommModemStatus(hCOM, &MSR); + } + if (EvtMask & EV_CTS) { + if (MSR & MS_CTS_ON) { + enq_event(RAW_EVENT_CTS_ON); + } else { + enq_event(RAW_EVENT_CTS_OFF); + } + } + if (EvtMask & EV_DSR) { + if (MSR & MS_DSR_ON) { + enq_event(RAW_EVENT_DSR_ON); + } else { + enq_event(RAW_EVENT_DSR_OFF); + } + } + if (EvtMask & EV_RING) { + if (MSR & MS_RING_ON) { + enq_event(RAW_EVENT_RING_ON); + } else { + enq_event(RAW_EVENT_RING_OFF); + } + } + if (EvtMask & EV_RLSD) { + if (MSR & MS_RLSD_ON) { + enq_event(RAW_EVENT_RLSD_ON); + } else { + enq_event(RAW_EVENT_RLSD_OFF); + } + } + } + CloseHandle(thread_ovl.hEvent); + thread_active = FALSE; +} + +void +serial_raw::enq_event (Bit16s event) +{ + if (thread_rxdata_count < THREAD_RX_BUFSIZE) { + thread_rxdata_buffer[thread_rxdata_count++] = event; + } else { + fprintf(stderr, "receive buffer overflow\n"); + } +} +#endif + #endif diff --git a/bochs/iodev/serial_raw.h b/bochs/iodev/serial_raw.h index b32e053b3..a8407db74 100644 --- a/bochs/iodev/serial_raw.h +++ b/bochs/iodev/serial_raw.h @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: serial_raw.h,v 1.10 2004-03-28 12:41:12 vruppert Exp $ +// $Id: serial_raw.h,v 1.11 2004-05-13 16:23:15 vruppert Exp $ ///////////////////////////////////////////////////////////////////////// // @@ -9,6 +9,11 @@ #include #endif +#ifdef WIN32 +// experimental raw serial receive support on win32 +//#define WIN32_RECEIVE_RAW +#endif + #define P_NONE 0 #define P_ODD 1 #define P_EVEN 2 @@ -28,6 +33,9 @@ #define RAW_EVENT_OVERRUN -11 #define RAW_EVENT_PARITY -12 +#define THREAD_RX_BUFSIZE 8192 +#define RX_BUFSIZE 256 + class serial_raw : public logfunctions { public: serial_raw (char *devname); @@ -43,15 +51,32 @@ class serial_raw : public logfunctions { bx_bool ready_transmit (); bx_bool ready_receive (); int receive (); +#ifdef WIN32_RECEIVE_RAW + void serial_thread (); +#endif private: void setup_port (); +#ifdef WIN32_RECEIVE_RAW + void enq_event (Bit16s event); +#endif bx_bool present; - Bit8u rxdata_count; + unsigned rxdata_count; #ifdef WIN32 HANDLE hCOM; DCB dcb; BOOL DCBchanged; + DWORD MSR_value; + Bit16s rxdata_buffer[RX_BUFSIZE]; +#ifdef WIN32_RECEIVE_RAW + HANDLE hRawSerialThread; + BOOL thread_active; + BOOL thread_quit; + OVERLAPPED rx_ovl; + OVERLAPPED thread_ovl; + unsigned thread_rxdata_count; + Bit16s thread_rxdata_buffer[THREAD_RX_BUFSIZE]; +#endif #endif }; #endif