Skip to content
Snippets Groups Projects
Commit 867f66ff authored by Uwe Bonnes's avatar Uwe Bonnes Committed by Alexandre Julliard
Browse files

Implement WaitCommEvent by polling the appropriate data sources.

parent 635135ba
No related branches found
No related tags found
No related merge requests found
......@@ -16,37 +16,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* History:
*
* Apr 3, 1999. Lawson Whitney <lawson_whitney@juno.com>
* - Fixed the modem control part of EscapeCommFunction16.
*
* Mar 31, 1999. Ove Kven <ovek@arcticnet.no>
* - Implemented buffers and EnableCommNotification.
*
* Mar 3, 1999. Ove Kven <ovek@arcticnet.no>
* - Use port indices instead of unixfds for win16
* - Moved things around (separated win16 and win32 routines)
* - Added some hints on how to implement buffers and EnableCommNotification.
*
* Oktober 98, Rein Klazes [RHK]
* A program that wants to monitor the modem status line (RLSD/DCD) may
* poll the modem status register in the commMask structure. I update the bit
* in GetCommError, waiting for an implementation of communication events.
*
* July 6, 1998. Fixes and comments by Valentijn Sessink
* <vsessink@ic.uva.nl> [V]
*
* August 12, 1997. Take a bash at SetCommEventMask - Lawson Whitney
* <lawson_whitney@juno.com>
*
* May 26, 1997. Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
* - ptr->fd wasn't getting cleared on close.
* - GetCommEventMask() and GetCommError() didn't do much of anything.
* IMHO, they are still wrong, but they at least implement the RXCHAR
* event and return I/O queue sizes, which makes the app I'm interested
* in (analog devices EZKIT DSP development system) work.
*/
#include "config.h"
......@@ -94,7 +63,6 @@
#include "winbase.h"
#include "winerror.h"
#include "thread.h"
#include "wine/server.h"
#include "wine/unicode.h"
......@@ -122,18 +90,30 @@ static inline void release_comm_fd( HANDLE handle, int fd )
wine_server_release_fd( handle, fd );
}
/* serial_irq_info
* local structure holding the irq values we need for WaitCommEvent()
*
* Stripped down from struct serial_icounter_struct, which may not be available on some systems
* As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
* no need to carry them in the internal structure
*
*/
typedef struct serial_irq_info
{
int rx , tx, frame, overrun, parity, brk, buf_overrun;
}serial_irq_info;
/***********************************************************************
* Asynchronous I/O for asynchronous wait requests *
* Data needed by the thread polling for the changing CommEvent
*/
typedef struct async_commio
{
HANDLE handle;
PIO_APC_ROUTINE apc_internal;
int type;
char* buffer;
int fd;
HANDLE hEvent;
DWORD evtmask;
DWORD mstat;
serial_irq_info irq_info;
} async_commio;
/***********************************************************************/
......@@ -142,6 +122,29 @@ typedef struct async_commio
#define TIOCINQ FIONREAD
#endif
/***********************************************************************
* Get extended interrupt count info, needed for WaitCommEvent
*/
static int COMM_GetEInfo(int fd, serial_irq_info *irq_info)
{
#ifdef TIOCGICOUNT
struct serial_icounter_struct einfo;
if (!ioctl(fd,TIOCGICOUNT, &einfo))
{
irq_info->rx = einfo.rx;
irq_info->tx = einfo.tx;
irq_info->frame = einfo.frame;
irq_info->overrun = einfo.overrun;
irq_info->parity = einfo.parity;
irq_info->brk = einfo.brk;
irq_info->buf_overrun = einfo.buf_overrun;
return 0;
}
#endif
memset(irq_info,0, sizeof(serial_irq_info));
return -1;
}
static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie)
{
#ifdef TIOCMGET
......@@ -1907,33 +1910,103 @@ BOOL WINAPI GetCommModemStatus(
#endif
}
static DWORD WINAPI Comm_CheckEvents(int fd, DWORD mask, serial_irq_info *new, serial_irq_info *old, DWORD new_mstat, DWORD old_mstat)
{
DWORD ret = 0, queue;
TRACE("mask 0x%08lx\n", mask);
TRACE("old->rx 0x%08x vs. new->rx 0x%08x \n", old->rx, new->rx);
TRACE("old->tx 0x%08x vs. new->tx 0x%08x \n", old->tx, new->tx);
TRACE("old->frame 0x%08x vs. new->frame 0x%08x \n", old->frame, new->frame);
TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x \n", old->overrun, new->overrun);
TRACE("old->parity 0x%08x vs. new->parity 0x%08x \n", old->parity, new->parity);
TRACE("old->brk 0x%08x vs. new->brk 0x%08x \n", old->brk, new->brk);
TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x \n", old->buf_overrun, new->buf_overrun);
ret |= ((mask & EV_BREAK) && ( old->brk != new->brk))?EV_BREAK:0;
ret |= ((mask & EV_CTS ) && ((old_mstat&MS_CTS_ON )!=(new_mstat&MS_CTS_ON )))?EV_CTS :0;
ret |= ((mask & EV_DSR ) && ((old_mstat&MS_DSR_ON )!=(new_mstat&MS_DSR_ON )))?EV_DSR :0;
ret |= ((mask & EV_RING ) && ((old_mstat&MS_RING_ON)!=(new_mstat&MS_RING_ON)))?EV_RING :0;
ret |= ((mask & EV_RLSD ) && ((old_mstat&MS_RLSD_ON)!=(new_mstat&MS_RLSD_ON)))?EV_RLSD :0;
ret |= ((mask & EV_ERR ) && (( old->frame != new->frame) ||(old->overrun != new->overrun)
|| (old->parity != new->parity)) )?EV_ERR :0;
if (mask & EV_RXCHAR)
{
queue = 0;
#ifdef TIOCINQ
if(ioctl(fd, TIOCINQ, &queue))
WARN("TIOCINQ returned error\n");
#endif
if (queue)
ret |= EV_RXCHAR;
}
if (mask & EV_TXEMPTY)
{
queue = 0;
/* We really want to know when all characters have gone out of the transmitter */
#if defined(TIOCSERGETLSR)
if(ioctl(fd, TIOCSERGETLSR, &queue))
WARN("TIOCSERGETLSR returned error\n");
if (queue)
/* TIOCINQ only checks for an empty buffer */
#elif def(TIOCINQ)
if(ioctl(fd, TIOCOUTQ, &queue))
WARN("TIOCOUTQ returned error\n");
if (!queue)
#endif
ret |= EV_TXEMPTY;
}
TRACE("OUTQUEUE %ld, Transmitter %sempty\n", queue, (ret & EV_TXEMPTY)?"":"not ");
return ret;
}
/***********************************************************************
* COMM_WaitCommEventService (INTERNAL)
*
* This function is called while the client is waiting on the
* server, so we can't make any server calls here.
* We need to poll for what is interesting
* TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
*
*/
static void WINAPI COMM_WaitCommEventService(void* ovp, IO_STATUS_BLOCK* iosb, ULONG status)
static DWORD WINAPI COMM_WaitCommEventService(LPVOID arg)
{
async_commio *commio = (async_commio*) ovp;
async_commio *commio = (async_commio*) arg;
int waitmask = 0;
int rc, fd, abort;
serial_irq_info new_irq_info;
DWORD new_mstat, new_evtmask;
TRACE("iosb %p\n", iosb);
fd=get_comm_fd( commio->handle, GENERIC_READ );
switch (status)
TRACE("handle %p fd 0x%08x, mask 0x%08lx buffer %p event %p irq_info %p waitmask 0x%08x\n",
commio->handle, fd, commio->evtmask, commio->buffer, commio->hEvent, &commio->irq_info, waitmask);
do
{
case STATUS_ALERTED: /* got some new stuff */
/* FIXME: detect other events */
*commio->buffer = EV_RXCHAR;
iosb->u.Status = STATUS_SUCCESS;
break;
default:
iosb->u.Status = status;
break;
}
wine_server_release_fd( commio->handle, commio->fd );
if ( ((LPOVERLAPPED)iosb)->hEvent != INVALID_HANDLE_VALUE )
NtSetEvent( ((LPOVERLAPPED)iosb)->hEvent, NULL );
/*
* TIOCMIWAIT is not adequate
*
* FIXME:
* We don't handle the EV_RXFLAG (the eventchar)
*/
Sleep(1);
rc= COMM_GetEInfo(fd,&new_irq_info);
if (rc)
TRACE("TIOCGICOUNT err %s\n", strerror(errno));
rc = GetCommModemStatus(commio->handle, &new_mstat);
if (!rc)
TRACE("GetCommModemStatus failed\n");
rc = Comm_CheckEvents(fd, commio->evtmask,&new_irq_info,&commio->irq_info, new_mstat, commio->mstat);
GetCommMask(commio->handle, &new_evtmask);
abort = (commio->evtmask != new_evtmask);
TRACE("resulting Eventmask 0x%08x\n", rc);
} while (!rc && ! abort);
if (abort) rc = 0;
release_comm_fd( commio->handle, fd );
*commio->buffer = rc;
if (commio->hEvent != INVALID_HANDLE_VALUE )
NtSetEvent( commio->hEvent, NULL );
HeapFree(GetProcessHeap(), 0, commio );
return 0;
}
......@@ -1949,7 +2022,8 @@ static BOOL COMM_WaitCommEvent(
{
int fd;
async_commio* commio;
NTSTATUS status;
DWORD result_mask;
BOOL res;
if (!lpOverlapped)
{
......@@ -1971,32 +2045,70 @@ static BOOL COMM_WaitCommEvent(
}
commio->handle = hFile;
commio->type = ASYNC_TYPE_WAIT;
commio->apc_internal = COMM_WaitCommEventService;
commio->buffer = (char *)lpdwEvents;
commio->fd = fd; /* FIXME */
lpOverlapped->InternalHigh = 0;
lpOverlapped->u.s.Offset = 0;
lpOverlapped->u.s.OffsetHigh = 0;
commio->hEvent = lpOverlapped->hEvent;
GetCommMask(hFile, &commio->evtmask);
SERVER_START_REQ( register_async )
/* We may never return, if some capabilities miss
* Return error in that case
*/
#if !defined(TIOCINQ)
if(commio->evtmask & EV_RXCHAR)
goto error;
#endif
#if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
if(commio->evtmask & EV_TXEMPTY)
goto error;
#endif
#if !defined(TIOCMGET)
if(commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
goto error;
#endif
#if !defined(TIOCM_CTS)
if(commio->evtmask & EV_CTS)
goto error;
#endif
#if !defined(TIOCM_DSR)
if(commio->evtmask & EV_DSR)
goto error;
#endif
#if !defined(TIOCM_RNG)
if(commio->evtmask & EV_RING)
goto error;
#endif
#if !defined(TIOCM_CAR)
if(commio->evtmask & EV_RLSD)
goto error;
#endif
if(commio->evtmask & EV_RXFLAG)
FIXME("EV_RXFLAG not handled\n");
COMM_GetEInfo(fd,&commio->irq_info);
GetCommModemStatus(hFile, &commio->mstat);
/* We might have received something or the TX bufffer is delivered*/
result_mask = Comm_CheckEvents( fd, commio->evtmask, &commio->irq_info, &commio->irq_info,commio->mstat,commio->mstat);
if (result_mask)
{
req->handle = hFile;
req->io_apc = COMM_WaitCommEventService;
req->io_user = commio;
req->io_sb = (IO_STATUS_BLOCK*)lpOverlapped;
req->count = 0;
status = wine_server_call( req );
TRACE("Event already met\n");
*lpdwEvents = result_mask;
release_comm_fd( commio->handle, fd );
HeapFree(GetProcessHeap(), 0, commio );
res = TRUE;
}
SERVER_END_REQ;
if ( status ) SetLastError( RtlNtStatusToDosError(status) );
else NtCurrentTeb()->num_async_io++;
else
{
CreateThread(NULL, 0, COMM_WaitCommEventService, (LPVOID)commio, 0, NULL);
SetLastError(ERROR_IO_PENDING);
res = FALSE;
}
return res;
#if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) && !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
error:
FIXME("Returning error because of missing capabilities\n");
HeapFree(GetProcessHeap(), 0, commio );
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
#endif
}
/***********************************************************************
* WaitCommEvent (KERNEL32.@)
*
......@@ -2020,7 +2132,8 @@ BOOL WINAPI WaitCommEvent(
LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
{
OVERLAPPED ov;
int ret;
int ret = 0;
DWORD res, err;
TRACE("(%p %p %p )\n",hFile, lpdwEvents,lpOverlapped);
......@@ -2030,10 +2143,27 @@ BOOL WINAPI WaitCommEvent(
/* if there is no overlapped structure, create our own */
ov.hEvent = CreateEventW(NULL,FALSE,FALSE,NULL);
COMM_WaitCommEvent(hFile, lpdwEvents, &ov);
/* wait for the overlapped to complete */
ret = GetOverlappedResult(hFile, &ov, NULL, TRUE);
res = COMM_WaitCommEvent(hFile, lpdwEvents, &ov);
err = GetLastError();
if (!res)
{
if (err == ERROR_IO_PENDING)
{
do
{
res = WaitForSingleObjectEx(ov.hEvent, INFINITE, FALSE);
} while (res != WAIT_OBJECT_0);
TRACE("Event met\n:");
ret = TRUE;
}
else
{
FIXME("Unknown error 0x%08lx\n", err);
ret = FALSE;
}
}
else
ret = TRUE;
CloseHandle(ov.hEvent);
return ret;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment