io<base>,<length> Mandatory I/O ports <base> and <length> in hex
irq<number> Optional IRQ <number> in decimal
override Optional Use these resources even if they cannot be allocated
Issuing Commands

Listing 15.1 shows the commands that initialize the printer. It also shows how DeviceIoControl is called with the IOCTL_PHDIO_RUN_CMDS IOCTL code to run these commands.

First, three constants are defined to represent the offsets to each register in the parallel port electronics.

The InitPrinter BYTE array stores the commands to initialize the printer. Each line has one command and its parameters. First, the Control port INIT# line is set low by writing 0xC8 using the PHDIO_WRITE command. The PHDIO_DELAY command then waits for 60µs. The INIT# signal is set high. The write value of 0xDC also selects the printer and enables interrupts. A further delay of 60us completes the operation.

The DeviceIoControl Win32 function is used to issue the IOCTL_PHDIO_RUN_CMDS IOCTL. This IOCTL runs the given commands straightaway. The InitPrinter array is passed as the input to the IOCTL. IOCTL_PHDIO_RUN_CMDS can optionally be passed an output buffer.

If there is an output buffer that is big enough, the first two 16-bit words in the output indicate any problems that the WdmIo driver found. The first word is an error code. The second word is the zero-based index into the command buffer in which the problem was found. Both are zero if there were no problems. The possible error codes are also found in Ioctl.h in the WdmIoSys directory.

The WdmIoTest code rather sloppily does not bother to check the returned error code. If using this driver for real, make sure that you check all error codes.

Listing 15.1 WdmIo Test issuing commands to run straightaway

const BYTE PARPORT_DATA = 0;

const BYTE PARPORT_STATUS = 1;

const BYTE PARPORT_CONTROL = 2;

BYTE InitPrinter[] = {

 PHDIO_WRITE, PARPORT_CONTROL, 0xC8, // Take INIT# low

 PHDIO_DELAY, 60, // Delay 60us

 PHDIO_WRITE, PARPORT_CONTROL, 0xDC, // INIT# high, select printer,

                                     // enable interrupts

 PHDIO_DELAY, 60, // Delay 60us

};

int main(int argc, char* argv[]) {

 // …

 DWORD BytesReturned;

 WORD rv[3];

 if (DeviceIoControl(hWdmIo, IOCTL_PHDIO_RUN_CMDS,

  InitPrinter, length(InitPrinter), // Input

  rv, sizeof(rv), // Output

  &BytesReturned, NULL)) {

  printf(' InitPrinter OK. rv=%d at %d ', rv[0], rv[13);

 } else {

  printf('XXX InitPrinter failed %d ',GetLastError());

  goto fail;

 }

 // …

Reading Data

If you use the PHDIO_READ or PHDIO_READS commands, you must provide an output buffer that is big enough to receive the read data. Remember that the first four bytes of the output buffer are always used for the error code and location.

Listing 15.2 shows how the ReadStatus commands are issued. It simply reads a byte value from the Status port. After DeviceIoControl has returned, the fifth byte of the output buffer contains the Status register contents. WdmIoTest checks that the BUSY# and ONLINE signals are 1 before continuing.

Listing 15.2 Reading data

BYTE ReadStatus[] = {

 PHDIO_READ, PARPORT_STATUS, // Read status

};

int main(int argc, char* argv[]) { //…

 DWORD BytesReturned;

 WORD rv[3];

 if (DeviceIoControl(hWdmIo, IOCTL_PHDIO_RUN_CMDS,

  ReadStatus, length(ReadStatus), // Input

  rv, sizeof(rv), // Output

  &BytesReturned, NULL)) {

  PBYTE pbrv = (PBYTE)&rv[2];

  printf(' ReadStatus OK. rv=%d at %d status=%02X ', rv[0], rv[l], *pbrv);

  if ( (*pbrv&0x88)==0x88) {

   busy = false;

   break;

  }

 }

Writing Data Using Interrupt Driven I/O

The WriteFile Win32 call is used to pass output data to the WdmIo driver. However, it needs to know how to process the data and handle interrupts. Two steps are required before WriteFile is called. First, connect to the interrupt. Second, pass WdmIo a series of commands that it will run to send the first byte and process each write interrupt.

Connecting to an Interrupt

When the WdmIo device is started, it is told which interrupt to use. However, it does not connect to the interrupt (i.e., install its interrupt handler), as it does not yet know how to handle the interrupt.

The ConnectToInterrupts commands shown here are used to initialize WdmIo's interrupt handling. The first write command tells the parallel port hardware not to generate interrupts. The second command tells the WdmIo driver to use a time-out of 10 seconds when processing subsequent WriteFile (and ReadFile) requests. WdmIo must have a time-out; a default of 10 seconds is used if no PHDIO_TIMEOUT command is given.

BYTE ConnectToInterrupts[] = {

 PHDIO_WRITE, PARPORT_CONTROL, 0xCC, // Disable interrupts

 PHDICO_TIMEOUT, 10, // Write time-out in seconds

 PHDIO_IRQ_CONNECT, PARPORT_STATUS, 0x00, 0x00, // Connect to interrupt

};

The last command, PHDIO_IRQ_CONNECT, connects the WdmIo driver to its interrupt. As mentioned before, the actual interrupt number is passed as a resource when the WdmIo device is started. WdmIo starts servicing a hardware interrupt by reading a hardware register; in this case, the Status register is read. It must determine whether the interrupt was caused by its hardware or not.

The two final parameters to the PHDIO_IRQ_CONNECT command are a mask and a value. The register contents are ANDed with the mask and compared to the value, as shown in the following

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату
×