virtual com question , help !

i’ve written a virtual com driver, this driver is kind of like a pipe,
tranfers write to read.

when i test this driver by mscomm control, the write works fine, but read returns run time error 8020 in oncomm event handler.

anyone can tell me what’s wrong with the driver ? any IOCTL didn’t handle properly ?

thanks in advance.

I found this on the web.

Set comm state failure error - often occurs when the ‘handshake’ is
in-correct.
i.e. you might be using odd parity when it should be even.

Also the following link:

http://support.microsoft.com/default.aspx?scid=kb;en-us;318784

You Virtural must be made to be Synchronous only it appears. I would also
look at the events that are set up by the MSCOMM.OCX to you virtual driver
to make sure you are emulating correctly.

You could use the UART 16500/8250 Serial.sys with MSCOMM.OCX and run a small
repeatable test. Use Portmon from SysInternals.com to get a trace of the
messaging, whoops IRPs.

Now use your Virtual Serial, do the same sequence in you application and get
a trace of the IRPs.

See where they differ! Analyze your code then to see what is wrong if indeed
it is not a bad application that is using MSCOMM.OCX. If it is bad
application you should probably get the same error results with Serial.sys
as with your virtual serial loopback driver.

-William Michael Jones

wrote in message news:xxxxx@ntdev…
> i’ve written a virtual com driver, this driver is kind of like a pipe,
> tranfers write to read.
>
> when i test this driver by mscomm control, the write works fine, but read
> returns run time error 8020 in oncomm event handler.
>
> anyone can tell me what’s wrong with the driver ? any IOCTL didn’t handle
> properly ?
>
> thanks in advance.
>

Thanks for reply !
I can’t save this problem yet.

The test app is as follow :

OnInitDialog handler :

m_Comm.SetCommPort(3);
m_Comm.SetInBufferSize(1024);
m_Comm.SetOutBufferSize(1024);
m_Comm.SetInputLen(0);
m_Comm.SetInputMode(1);
m_Comm.SetRThreshold(1);
m_Comm.SetSettings(“9600,n,8,1”);

if(!m_Comm.GetPortOpen())
{
m_Comm.SetPortOpen(TRUE);
}

OnComm event handler :

switch (m_Comm.GetCommEvent())
{
case 2:// comEvReceive
nCount = m_Comm.GetInBufferCount();
if (nCount > 0)
{
input = m_Comm.GetInput();

}

GetInput method always fail. However, if using ReadFile API in OnComm event to read input,
it succeeds. Is there error in the app ?

I got the problem :

ReadFile in Nonoverlapped mode works well.
But Overlapped mode got ERROR_IO_PENDING, though datas’re read.

Anyone can tell me how to save this problem ??

When reading in overlapped mode, you will get ERROR_IO_PENDING —
overlapped mode is asynchronous by definition. Use
WaitFor{Single|Multiple}Objects to wait on the event handle you set in the
OVERLAPPED struct – that event will be set when the I/O has finished. Then
call GetOverlappedResult to get the results of the I/O operation – if it
returns TRUE, the OVERLAPPED::InternalHigh field will contain the number of
bytes read/written by the I/O operation.

wrote in message news:xxxxx@ntdev…
>I got the problem :
>
> ReadFile in Nonoverlapped mode works well.
> But Overlapped mode got ERROR_IO_PENDING, though datas’re read.
>
> Anyone can tell me how to save this problem ??
>

Thank you for reply.
But my virtual com driver must support that be read by mscomm control.
And i guess mscomm is using overlaped mode for reading.
Now, mscomm’s ‘GetInput’ method fails every time.
What’s the modification i have to do for my driver ?

In addition, i found from driver’s tracing that the datas have been read while ‘GetInput’ method got exception. Now, how do i make my driver support mscomm’s reading ?

Did a search on google and found two sample code projects.

http://www.codeguru.com/cpp/com-tech/activex/misc/article.php/c7349/

http://www.codeguru.com/forum/archive/index.php/t-84112.html

Just included to give you some more samples.

Now the problem may be in your virtual serial driver. You need to look at
the IRPs sent to driver from your application. You need to see why you are
failing the call to read when you have data. I would assume that settine
SetInputLen(0) causes your driver to return any received data and is
translated into SERIAL_EV_RXFLAG. The two samples are only included and not
to throw you off to give you more data points. I would do as I suggested in
the my first email. Look at Serial.sys and the IRPs then look at your
virtual driver and their IRPs. You will have to step into your virtual
serial driver as well I would think. You have to analyze the problem. Best
of luck.

-William Michael Jones

wrote in message news:xxxxx@ntdev…
> In addition, i found from driver’s tracing that the datas have been read
> while ‘GetInput’ method got exception. Now, how do i make my driver
> support mscomm’s reading ?
>

Thank you william.
I may take your suggestion that use portmon and serial.sys later.
(actualy i don’t know how to use serial.sys, install it for a real port device ?).

Now, I’m realy confusing !
Every thing works well on my driver, unless using mscomm for reading.
Although driver’s tracing shows the read IRP’s been complited,
‘GetInput’ method still got an exception at final.

The read/write callbacks of my driver is as follow,
Can somebody tell me what’s the problem with the driver ?

VOID
EvtIoRead(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t Length
)
{
NTSTATUS status;
PDEVICE_EXTENSION devExt = GetDeviceContext(WdfIoQueueGetDevice(Queue));
ULONG information = 0;
PUCHAR systemBuffer = NULL;
size_t bufLen;

status = WdfRequestRetrieveOutputBuffer(Request, Length, &systemBuffer, &bufLen);
if (!NT_SUCCESS(status)) {
WdfRequestComplete(Request, status);
return;
}

if (devExt->BytesInReadBuffer > 0)
{
ProcessReadBuffer(devExt,
systemBuffer,
(ULONG) Length,
&information);
WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, information);

return;
}
else
{
//
// No data to read. Queue the request for later processing.
//
status = WdfRequestForwardToIoQueue(Request, devExt->ReadQueue);
if (!NT_SUCCESS(status)) {
KdPrint( (“EvtIoRead: ForwardToIoQueue failed with Status code 0x%x\n”, status));
WdfRequestCompleteWithInformation(Request, status, 0);
return;
}
}
}

VOID
EvtIoWrite(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t Length
)
{
NTSTATUS status;
PDEVICE_EXTENSION devExt = GetDeviceContext(WdfIoQueueGetDevice(Queue));
PUCHAR systemBuffer = NULL;
size_t length;
ULONG information = 0;
WDFREQUEST readRequest;
WDFREQUEST currentWaitRequest = NULL;

status = WdfRequestRetrieveInputBuffer(Request, Length, &systemBuffer, &length);
if (!NT_SUCCESS(status)) {
WdfRequestComplete(Request, status);
return;
}

ProcessWriteBuffer(devExt, systemBuffer, Length);

//
// Process read requests and complete them here.
//

while (devExt->BytesInReadBuffer > 0) {
ULONG bytesToMove;

status = WdfIoQueueRetrieveNextRequest(devExt->ReadQueue, &readRequest);

if (!NT_SUCCESS(status)) {
break;
}

status = WdfRequestRetrieveOutputBuffer(readRequest, 0, &systemBuffer, &length);
ASSERT(NT_SUCCESS(status));

ProcessReadBuffer(devExt,
systemBuffer,
(ULONG) length,
&bytesToMove);

WdfRequestCompleteWithInformation(readRequest, STATUS_SUCCESS, bytesToMove);
}

//
// process event
//
if (devExt->BytesInReadBuffer > 0)
{
if (devExt->CurrentMask & SERIAL_EV_RXCHAR) {
status = WdfIoQueueRetrieveNextRequest(devExt->MaskWaitQueue,
&currentWaitRequest);

if (NT_SUCCESS(status) && currentWaitRequest != NULL) {

PULONG outBuffer;
size_t bufSize;

KdPrint((“VCom: process event\n”));

//
// The length was validated already.
//

(VOID)WdfRequestRetrieveOutputBuffer(currentWaitRequest,
sizeof(ULONG),
&outBuffer,
&bufSize);

if (outBuffer) { // FIXME SAL
*outBuffer = SERIAL_EV_RXCHAR;//SERIAL_EV_RXFLAG,SERIAL_EV_RLSD
}

WdfRequestCompleteWithInformation(currentWaitRequest,
STATUS_SUCCESS,
sizeof(ULONG));

}
}
}

WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, Length);
}

victor bao wrote:

Every thing works well on my driver, unless using mscomm
for reading. Although driver’s tracing shows the read IRP’s
been complited, ‘GetInput’ method still got an exception at
final.

Have you read this knowledge base article?

http://support.microsoft.com/default.aspx?scid=kb;en-us;318784

Here’s my theory:

  1. MSCOMM calls ClearCommError() or something else that eventually results in IOCTL_SERIAL_GET_COMMSTATUS.

  2. As a result of 1), you report that you have N bytes in your buffer.

  3. MSCOMM calls ReadFile on your device asking for N bytes. You complete the request synchronously, but by this point, KMDF has already pended the original I/O from userspace since it was delivered into an I/O queue. (?)

  4. MSCOMM balks at ERROR_IO_PENDING because you said you bytes to return right away.

(By the way, if I’m right about 3), is there a way to avoid that?)

Hi, Chris :

My driver reports the bytes in readbuffer correctly at IOCTL_SERIAL_GET_COMMSTATUS.

For your theory 3), will i understand that my driver’s read routine must support asynchronous
reading ? how do i do it ?

Sorry for my fool, Can you give me straightforword answer for saving this problem ?
I’m new in driver writting. Please help !

Hi,

I am new to WDF Programming but I will try to help. Looking at EvtIoRead
you can put some Kdprint statements in an hookup the kernel debugger to look
at the output. I put some suggestions in all CAPS.

VOID EvtIoRead( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length )
{
NTSTATUS status;
PDEVICE_EXTENSION devExt = GetDeviceContext(WdfIoQueueGetDevice(Queue));
ULONG information = 0;
PUCHAR systemBuffer = NULL;
size_t bufLen;

status = WdfRequestRetrieveOutputBuffer(Request, Length, &systemBuffer,
&bufLen);
if (!NT_SUCCESS(status))
{
WdfRequestComplete(Request, status);
return;
}

if (devExt->BytesInReadBuffer > 0)
{
ProcessReadBuffer(devExt, systemBuffer, (ULONG) Length,
&information);

// PUT KDPRINT HERE COULD BE A SYNCHROUSCOMPLETEION
// Got a question here just because BytesInReadBuffer > 0 how do know
that this will satisfy the Read IRP

WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS,
information);
return;
}
else
{
//
// No data to read. Queue the request for later processing.
//
status = WdfRequestForwardToIoQueue(Request, devExt->ReadQueue);

// PUT KDPRINT HERE COULD BE A ASYNCHRONCOMPLETEION

if (!NT_SUCCESS(status))
{
KdPrint( (“EvtIoRead: ForwardToIoQueue failed with Status code
0x%x\n”, status));
WdfRequestCompleteWithInformation(Request, status, 0);
return;
}
}
}

VOID EvtIoWrite( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t
Length )
{
NTSTATUS status;
PDEVICE_EXTENSION devExt = GetDeviceContext(WdfIoQueueGetDevice(Queue));
PUCHAR systemBuffer = NULL;
size_t length;
ULONG information = 0;
WDFREQUEST readRequest;
WDFREQUEST currentWaitRequest = NULL;

status = WdfRequestRetrieveInputBuffer(Request, Length, &systemBuffer,
&length);
if (!NT_SUCCESS(status))
{
WdfRequestComplete(Request, status);
return;
}

ProcessWriteBuffer(devExt, systemBuffer, Length);

//
// Process read requests and complete them here.
//

while (devExt->BytesInReadBuffer > 0)
{
ULONG bytesToMove;

// PUT KDPRINT

status = WdfIoQueueRetrieveNextRequest(devExt->ReadQueue,
&readRequest);

if (!NT_SUCCESS(status))
{
break;
}

status = WdfRequestRetrieveOutputBuffer(readRequest, 0, &systemBuffer,
&length);
ASSERT(NT_SUCCESS(status));

ProcessReadBuffer(devExt, systemBuffer, (ULONG) length, &bytesToMove);

// PUT KDPRINT !!! NOTE THAT THE IRP_MJ_READ IS COMPLETED HERE and
NOT in EvtIoRead

WdfRequestCompleteWithInformation(readRequest, STATUS_SUCCESS,
bytesToMove);
}

//
// process event
//
if (devExt->BytesInReadBuffer > 0)
{

// PUT KDPRINT !!! Note that this will Fire you event in MSComm.

if (devExt->CurrentMask & SERIAL_EV_RXCHAR)
{
// PUT KDPRINT !!!

status = WdfIoQueueRetrieveNextRequest(devExt->MaskWaitQueue,
&currentWaitRequest);

if (NT_SUCCESS(status) && currentWaitRequest != NULL)
{

PULONG outBuffer;
size_t bufSize;

KdPrint((“VCom: process event\n”));

//
// The length was validated already.
//

(VOID)WdfRequestRetrieveOutputBuffer(currentWaitRequest,
sizeof(ULONG), &outBuffer, &bufSize);

if (outBuffer)
{ // FIXME SAL
*outBuffer =
SERIAL_EV_RXCHAR;//SERIAL_EV_RXFLAG,SERIAL_EV_RLSD
}

// PUT KDPRINT !!! Here you compete the IRP_SERIAL_WAIT_MASK

WdfRequestCompleteWithInformation(currentWaitRequest,
STATUS_SUCCESS, sizeof(ULONG));

}
}
}

// PUT KDPRINT !!! Here you Synchronizely complete the IRP_MJ_WRITE

WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, Length);
}

Now just trying to help you know. To complete everything synchronizely
which I have my doubts about but anyway since I have analyzed MSComm for
real only read the Internet lets assume this is true. I would get rid of
completing the Read Irp in your IoEvWrite routine. I would copy the the
Write Data to a buffer in you in Virtural Com Driver. You will have to
allocate the memory for this. That I would do instead of Completing the
IRP. I would then always complete the READ in the EvIoRead routine.

-William Michael Jones

wrote in message news:xxxxx@ntdev…
> i’ve written a virtual com driver, this driver is kind of like a pipe,
> tranfers write to read.
>
> when i test this driver by mscomm control, the write works fine, but read
> returns run time error 8020 in oncomm event handler.
>
> anyone can tell me what’s wrong with the driver ? any IOCTL didn’t handle
> properly ?
>
> thanks in advance.
>

Thank you william for persisting help!

There are trace message in my driver, i just didn’t attatch them
at the code i listed above.

I’d tell you my driver is working correctly at following operation:

1).Writting is always no problem (both using ‘WriteFile’ API or
MSCOMM’s ‘SetOutput’ method).

2).Reading is always correct at Nonoverlapped ‘ReadFile’ API.

3).Reading is correct after Overlapped ‘ReadFile’ returns FALSE,
and analyze ‘GetLastError() == ERROR_IO_PENDING’,
‘WaitForSingleObject’, ‘GetOverlappedResult’ etc.

4).Correctly fire MSCOMM’s ‘comEvReceive’ event.

Just get exception at MSCOMM’s ‘GetInput’ method. (error 8020)

I’m suspicious of that whether MSCOMM is using Overlapped mode for
ReadFile and not analyzing ‘GetLastError() == ERROR_IO_PENDING’,
‘WaitForSingleObject’, ‘GetOverlappedResult’ etc. ??

How do i return success for MSCOMM’s ReadFile.(not ERROR_IO_PENDING)

However, look at my driver’s EvtIoRead callback, it does completing
the request success. confusing …

by the way, my virtual com driver is base on kmdf’s ‘fakemodem’ sample.

Hi,

Thank you for being polite. I plan to work in the WDF / KMDF / UMDF soon.
Hey I got an idea:

How do i return success for MSCOMM’s ReadFile.(not ERROR_IO_PENDING) Try
returning Success but with a count of 0 since there are no chars anyway.

My question is why you get a count of 2 bytes but when you do the read your
virtual driver does not have the bytes there. It must be that your
EvtIOWrite is completing the read request. You do not call the GetInput
unless there are chars.

You may want to not queue the READS in your EvtIORead() but only return from
EvtIORead when your EvtIOWrite is called. Use a synchronization object
between the EvtIOWrite and EvtIORead. Wait on the object in EvIORead(). Do
not queue your READS but only return when you have data or better yet return
a count of 0 for your EveIORead unless there are chars i.e. there has been a
Write.

I will look at the fakemodem sample tonight.

-William Michael Jones

wrote in message news:xxxxx@ntdev…
> Thank you william for persisting help!
>
> There are trace message in my driver, i just didn’t attatch them
> at the code i listed above.
>
> I’d tell you my driver is working correctly at following operation:
>
> 1).Writting is always no problem (both using ‘WriteFile’ API or
> MSCOMM’s ‘SetOutput’ method).
>
> 2).Reading is always correct at Nonoverlapped ‘ReadFile’ API.
>
> 3).Reading is correct after Overlapped ‘ReadFile’ returns FALSE,
> and analyze ‘GetLastError() == ERROR_IO_PENDING’,
> ‘WaitForSingleObject’, ‘GetOverlappedResult’ etc.
>
> 4).Correctly fire MSCOMM’s ‘comEvReceive’ event.
>
>
> Just get exception at MSCOMM’s ‘GetInput’ method. (error 8020)
>
>
> I’m suspicious of that whether MSCOMM is using Overlapped mode for
> ReadFile and not analyzing ‘GetLastError() == ERROR_IO_PENDING’,
> ‘WaitForSingleObject’, ‘GetOverlappedResult’ etc. ??
>
> How do i return success for MSCOMM’s ReadFile.(not ERROR_IO_PENDING)
>
> However, look at my driver’s EvtIoRead callback, it does completing
> the request success. confusing …
>
> by the way, my virtual com driver is base on kmdf’s ‘fakemodem’ sample.
>

ERROR_IO_PENDING has nothing to do with what status you use when
completing the IRP. It happens because the driver’s IRP dispatch
routine (and if this is a WDF driver then WDF owns those routines) is
pushing the I/O request into a queue and then returning STATUS_PENDING
indicating that the I/O will be completed asynchronously. The handle
MSCOMM is using must have been opened for overlapped I/O (probably so
they could pend some of the wait i/o controls that serial supports) and
this is the status the I/O manager returns from
ReadFile/WriteFile/DeviceIoControl when the driver indicates
asynchronous completion.

You may be able to handle this in KMDF by setting a request
pre-processing callback but you lose all of the automatic flow control
and locking in that callback.

This seems like it’s a bug in MSCOMM. It should be waiting for the I/O
request to complete when it gets ERROR_IO_PENDING, not assume that the
I/O will be completed synchronously.

-p

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of William Michael
Jones
Sent: Wednesday, September 27, 2006 9:12 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] virtual com question , help !

Hi,

Thank you for being polite. I plan to work in the WDF / KMDF / UMDF
soon.
Hey I got an idea:

How do i return success for MSCOMM’s ReadFile.(not ERROR_IO_PENDING)
Try
returning Success but with a count of 0 since there are no chars anyway.

My question is why you get a count of 2 bytes but when you do the read
your
virtual driver does not have the bytes there. It must be that your
EvtIOWrite is completing the read request. You do not call the GetInput

unless there are chars.

You may want to not queue the READS in your EvtIORead() but only return
from
EvtIORead when your EvtIOWrite is called. Use a synchronization object
between the EvtIOWrite and EvtIORead. Wait on the object in EvIORead().
Do
not queue your READS but only return when you have data or better yet
return
a count of 0 for your EveIORead unless there are chars i.e. there has
been a
Write.

I will look at the fakemodem sample tonight.

-William Michael Jones

wrote in message news:xxxxx@ntdev…
> Thank you william for persisting help!
>
> There are trace message in my driver, i just didn’t attatch them
> at the code i listed above.
>
> I’d tell you my driver is working correctly at following operation:
>
> 1).Writting is always no problem (both using ‘WriteFile’ API or
> MSCOMM’s ‘SetOutput’ method).
>
> 2).Reading is always correct at Nonoverlapped ‘ReadFile’ API.
>
> 3).Reading is correct after Overlapped ‘ReadFile’ returns FALSE,
> and analyze ‘GetLastError() == ERROR_IO_PENDING’,
> ‘WaitForSingleObject’, ‘GetOverlappedResult’ etc.
>
> 4).Correctly fire MSCOMM’s ‘comEvReceive’ event.
>
>
> Just get exception at MSCOMM’s ‘GetInput’ method. (error 8020)
>
>
> I’m suspicious of that whether MSCOMM is using Overlapped mode for
> ReadFile and not analyzing ‘GetLastError() == ERROR_IO_PENDING’,
> ‘WaitForSingleObject’, ‘GetOverlappedResult’ etc. ??
>
> How do i return success for MSCOMM’s ReadFile.(not ERROR_IO_PENDING)
>
> However, look at my driver’s EvtIoRead callback, it does completing
> the request success. confusing …
>
> by the way, my virtual com driver is base on kmdf’s ‘fakemodem’
sample.
>


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Hi, Peter :

I think you said at the point of this problem.
I’ll try to get some knowledge about how to
set a request pre-processing callback to save this problem,
because my driver have to support mscomm’s reading.

I’m wondering, if this is a bug of mscomm, why system’s
standard serial driver can react correctly at mscomm ?

Hi, William :

I think no reason to return count 0 with read request,
because there are bytes in read buffer before read happens,
and i have put the bytes into the output buffer of read request.

EvtIOWrite is not completing the read request, because the read
queue in my device extention is empty at that time.

Thank you again, hoping your continuous help after you’ve read the
fakemodom sample.

If you are going to go the preprocess route, you need to use a WDM preprocess routine (set up by WdfDeviceInitAssignWdmIrpPreprocessCallback) and do not use in the in process callback (setup by WdfDeviceInitSetIoInCallerContextCallback). The in process callback is already in the path where KMDF returns STATUS_PENDING.

d

Doron, Thanks for your suggestion !

I have registed the read callback function using
‘WdfDeviceInitAssignWdmIrpPreprocessCallback’, it seems working
well. MSCOMM’s ‘GetInput’ mothod nolonger report error.

But the overlaped ‘ReadFile’ API is also returning immediately.

How to avoid from this ?