WdmIo code snippet. If they are not equal, the interrupt must be intended for another driver.
// See if interrupt is ours
UCHAR StatusReg = ReadByte(dx, dx->InterruptReg);
if ((StatusReg&dx->InterruptRegMask) != dx->InterruptRegValue) return FALSE; // Not ours
Suppose the Status register really did reset its bit 2 to 0 when it generated an interrupt. Specifying 0x04, as the mask would isolate bit 2. If the ANDed result is equal to 0x00, the interrupt is ours. Therefore, specifying a PHDIO_IRQ_CONNECT mask of 0x04 and value of 0x00 would have correctly detected when the parallel port interrupted.
However, as stated earlier, I found that there is no interrupt indication in the Status register. I simply have to assume that if an interrupt arrives, it came from the correct parallel port. To persuade the WdmIo code to continue regardless, a mask of 0x00 and a value of 0x00 was specified in the ConnectToInterrupts code.
Storing the Write Byte Commands
The WdmIo driver needs to be told a series of commands that write a single byte of data. These commands are used both to write the first output byte and to process an interrupt to send another byte.
IOCTL_PHDIO_CMDS_FOR_WRITE is used to store the commands used to write data. This IOCTL is issued using
Listing 15.3 shows the WriteByte commands that
Listing 15.3 Stored write byte commands
BYTE WriteByte[] = {
PHDIO_WRITE, PARPORT_CONTROL, 0xDC, // Ensure STROBE off
PHDIO_WRITE_NEXT, PARPORT_DATA, // Write next byte
PHDIO_DELAY, 1, // Delay 1us
PHDIO_WRITE, PARPORT_CONTROL., 0xDD, // STROBE on
PHDIO_DELAY, 1, // Delay 1us
PHDIO_WRITE, PARPORT_C0NTROL. 0xDC, // STROBE off
PHDIO_DELAY, 1, // Delay 1us
PHDIO_READ, PARPORT_STATUS, // Read status
};
The PHDIO_WRITE_NEXT command is crucial to these data transfer commands. The WdmIo driver keeps track of the current position in the output buffer passed by
Writing Data
The
char* Msg = 'Hello from WdmIo example
Chris Cant, PHD Computer Consultants Ltd
';
DWORD Ten = strlen(Msg);
if (!WriteFile(hWdmIo, Msg, Ten, &BytesReturned, NULL)) printf('XXX Could not write message %d
', GetLastError());
else if (BytesReturned==len) printf(' Write succeeded
');
else printf('XXX Wrong number of bytes written: %d
', BytesReturned);
The WdmIo driver uses the WriteByte commands to output the first byte, H. It then expects an interrupt when each byte has been printed. The WriteByte commands are run again by the interrupt handler to output each following byte. Assuming all goes well, when an interrupt is received after the last byte has been sent, WdmIo completes the WriteFile call successfully.
If there is a problem,
Getting
Each time the write commands are run, WdmIo gives its command processor a 5-byte output buffer. The first two words (4 bytes) are used for the error code and location. The fifth byte is filled with any output data that the commands produce. In
However, what is really wanted is the value of the Status register after each byte is processed by the printer. At this point, the Status register contains some useful information, such as whether the printer is off-line or has run out of paper.
While
IOCTL_PHDIO_GET_RW_RESULTS is used to obtain the write (and read) results. Table 15.5 recaps the contents of the 6-byte buffer that is returned. Listing 15.4 shows how DeviceIoControl is used to read and display the results. When
Note that the command output buffer and the last interrupt register value locations are reused each time an interrupt occurs and the commands are run. This is not a problem. As soon as any fault occurs, processing stops with the most useful information in the results buffer.
Table 15.5 Read/Write results
Bytes | Description |
---|---|
2 | Command error code |
2 | Command error offset |
1 | Command output value |
1 | Last interrupt register |
Listing 15.4 Getting Write/Read command results
if (DeviceIoControl(hWdmIo, IOCTL_PHDIO_GET_RW_RESULTS,
NULL, 0, // Input
rv, sizeof(rv), // Output
&BytesReturned, NULL)) {
printf(' Get RW Results OK. rv=%d at %d
', rv[0], rv[l]);
BYTE* pbuf = (BYTE*)(&rv[2]);
printf(' cmd status=%02x
', pbuf[0]);
printf(' int status=%02x
', pbuf[l]);
}
Reading data is a process similar to writing data. This time, two sets of commands need to be passed to WdmIo before the actual
Use IOCTL_PHDIO_CMDS_FOR_READ_START to tell WdmIo which commands to use to start the read process. Typically, these commands might simply enable input interrupts from the device. IOCTL_PHDIO_CMDS_FOR_READ passes WdmIo the commands used to process each interrupt.
The