13.3 Machine Language Control of Printer Adapter

BIOS calls or DOS functions are most likely adequate for the control of a printer in the polled mode. Direct machine-language control is necessary, however, in situations such as the following:

Figure 13-2. Simplified Logic Diagram of the Printer Adapter

Machine-language control uses OUT instructions to transfer a byte from register AL of the CPU to the adapter's Out latches, or IN instructions to transfer data from the In buffers to register AL. A simplified logic diagram is shown in Figure 13-2. Machine language control is straightforward but several peculiarities of the adapter logic must be noted:

The control signals at the connector may be read back into register AL (bits 0-4 only) via the Control In Buffer. There are corresponding complementations between the connector and the In buffer (and bit 4 is simply a copy of the Out latch bit 4) so that Table 13-4 can be used in reverse for input. Note that since the Control Out Latch outputs are buffered, the control signal pins corresponding to control bits 0-3 can be used for input.

Table 13-4. Register AL Bit Assignments for Printer Control Signals

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
n.c. n.c. n.c. IRQ Enable Select ~Initialize Auto Feed Strobe
  Pin 17 Pin 16 Pin 14 Pin 1
  ~Select ~Initialize ~Autofeed ~Strobe

To illustrate machine language control, a program fragment corresponding to subfunction 0 ("print the character in register AL") of BIOS call 17h is shown below:

        sti             ; allow higher-priority interrupt
        ...
        mov     si, dx  ; printer number
        mov     bl, [PrintTimeout+si]
                ; load timeout parameter byte (=10 for PC)
        shl     si, 1
        mov     dx, [PrinterBase+si]
                ; Data port address of printer in DX
        ...
        OR      AH, AH
        JZ      .B2
        ...
.B2:                    ; subfunction 0
        push    ax
        out     dx, al  ; send character to Data Out latch
        inc     dx      ; point to Status port
.B3:                    ; loop while BUSY until timeout
        sub     cx, cx  ; outer loop
.B3_1:                  ; inner loop
        in      al, dx  ; read printer status
        test    al, 80h ; test the BUSY status bit
        jnz     .B4     ; not busy
        loop    .B3_1   ; busy: repeat inner loop
        dec     bl      ; decr. outer loop counter
        jnz     .B3     ; repeat outer loop
        or      ah, 1   ; set timeout flag
        and     ah, 0F9h; clear unused bits
        jmp     ...     ; go to return with error flag set
        ...
.B4:                    ; NOT BUSY: send ~STROBE
        inc     dx      ; point to Control port
        mov     al, 0Dh ; set bit 0 (=STROBE) high -- also sets
                        ;   IRQ ENABLE low, SELECT high,
                        ;   ~INITIALIZE high, and AUTO FEED low
        out     dx, al  ; send character to Control port
        mov     al, 0Ch ; set STROBE low again
        out     dx, al
        pop     ax
        ...             ; go to read the status into AH
        iret