
pdfaoa / CH21
.PDF
|
|
|
The PC Parallel Ports |
SyncLoop: |
mov |
cx, 0 |
;For time out purposes. |
SyncLoop0: |
inc |
dx |
;Point at input port. |
|
in |
al, dx |
;Read our input bits. |
|
dec |
dx |
|
|
and |
al, 78h |
;Keep only the data bits. |
|
cmp |
al, 78h |
;Check for all ones. |
|
je |
Got1s |
;Branch if all ones. |
|
cmp |
al, 0 |
;See if all zeros. |
|
loopne |
SyncLoop0 |
|
; Since we just saw a zero, write all ones to the output port.
mov |
al, |
0FFh |
;Write all ones |
out |
dx, |
al |
|
; Now wait for all ones to arrive from the transmitting site.
SyncLoop1: |
inc |
dx |
;Point at status register. |
|
in |
al, dx |
;Read status port. |
|
dec |
dx |
;Point back at data register. |
|
and |
al, 78h |
;Keep only the data bits. |
|
cmp |
al, 78h |
;Are they all ones? |
|
loopne |
SyncLoop1 |
;Repeat while not ones. |
|
je |
Got1s |
;Branch if got ones. |
;If we’ve timed out, check to see if the user has pressed ctrl-C to
;abort.
call |
TestAbort |
;Check for ctrl-C. |
dec |
bx |
;See if we’ve timed out. |
jne |
SyncLoop |
;Repeat if time-out. |
|
|
|
byte |
“Receive: connection timed out during synchronization” |
|
byte |
cr,lf,0 |
|
clc |
|
;Signal time-out. |
ret |
|
|
;Jump down here once we’ve seen both a zero and a one. Send the two
;in combinations until we get a 05h from the transmitting site or the
;user presses Ctrl-C.
Got1s: |
inc |
dx |
;Point at status register. |
|
in |
al, dx |
;Just copy whatever appears |
|
dec |
dx |
; in our input port to the |
|
shr |
al, 3 |
; output port until the |
|
and |
al, 0Fh |
; transmitting site sends |
|
cmp |
al, 05h |
; us the value 05h |
|
je |
Synchronized |
|
|
not |
al |
;Keep inverting what we get |
|
out |
dx, al |
; and send it to xmitter. |
|
call |
TestAbort |
;Check for CTRL-C here. |
|
jmp |
Got1s |
|
; Okay, we’re synchronized. Return to the caller.
Synchronized: |
|
|
|
|
and |
al, 0Fh |
;Make sure busy bit is one |
|
out |
dx, al |
; (bit 4=0 for busy=1). |
|
|
|
|
|
byte |
“Synchronized with transmitting site” |
|
|
byte |
cr,lf,0 |
|
|
stc |
|
|
|
ret |
|
|
Synchronize |
endp |
|
|
;GetFileInfoThe transmitting program sends us the file length and a
;zero terminated filename. Get that data here.
GetFileInfo |
proc |
near |
|
|
mov |
dx, MyPortAdrs |
|
|
mov |
al, 10h |
;Set busy bit to zero. |
Page 1219
Chapter 21
out |
dx, al |
;Tell xmit pgm, we’re ready. |
; First four bytes contain the filesize:
call |
GetByte |
mov |
byte ptr FileSize, al |
call |
GetByte |
mov |
byte ptr FileSize+1, al |
call |
GetByte |
mov |
byte ptr FileSize+2, al |
call |
GetByte |
mov |
byte ptr FileSize+3, al |
; The next n bytes (up to a zero terminating byte) contain the filename:
|
mov |
bx, 0 |
GetFileName: |
call |
GetByte |
|
mov |
FileName[bx], al |
|
call |
TestAbort |
|
inc |
bx |
|
cmp |
al, 0 |
|
jne |
GetFileName |
|
ret |
|
GetFileInfo |
endp |
|
;GetFileDataReceives the file data from the transmitting site
;and writes it to the output file.
GetFileData |
proc |
near |
|
; First, see if we have more than 512 bytes left to go |
|
||
|
cmp |
word ptr FileSize+2, 0 |
;If H.O. word is not |
|
jne |
MoreThan512 |
; zero, more than 512. |
|
cmp |
word ptr FileSize, 512 |
;If H.O. is zero, just |
|
jbe |
LastBlock |
; check L.O. word. |
;We’ve got more than 512 bytes left to go in this file, read 512 bytes
;at this point.
MoreThan512: |
mov |
cx, 512 |
;Receive 512 bytes |
|
lea |
bx, FileBuffer |
; from the xmitter. |
ReadLoop: |
call |
GetByte |
;Read a byte. |
|
mov |
[bx], al |
;Save the byte away. |
|
inc |
bx |
;Move on to next |
|
loop |
ReadLoop |
; buffer element. |
; Okay, write the data to the file:
mov |
ah, 40h |
;DOS write opcode. |
mov |
bx, FileHandle |
;Write to this file. |
mov |
cx, 512 |
;Write 512 bytes. |
lea |
dx, Filebuffer |
;From this address. |
int |
21h |
|
jc |
BadWrite |
;Quit if error. |
; Decrement the file size by 512 bytes: |
|
|
sub |
word ptr FileSize, 512 |
;32-bit subtraction |
sbb |
word ptr FileSize, 0 |
; of 512. |
jmp |
GetFileData |
|
; Process the last block, that contains 1..511 bytes, here.
LastBlock: |
|
|
|
|
mov |
cx, word ptr FileSize |
;Receive the last |
|
lea |
bx, FileBuffer |
; 1..511 bytes from |
ReadLB: |
call |
GetByte |
; the transmitter. |
|
mov |
[bx], al |
|
|
inc |
bx |
|
|
loop |
ReadLB |
|
Page 1220
|
|
|
The PC Parallel Ports |
|
mov |
ah, 40h |
;Write the last block |
|
mov |
bx, FileHandle |
; of bytes to the |
|
mov |
cx, word ptr FileSize |
; file. |
|
lea |
dx, Filebuffer |
|
|
int |
21h |
|
|
jnc |
Closefile |
|
BadWrite: |
|
|
|
|
byte |
“DOS error #”,0 |
|
|
puti |
|
|
|
|
|
|
|
byte |
“ while writing data.”,cr,lf,0 |
|
; Close the file here. |
|
|
|
CloseFile: |
mov |
bx, FileHandle |
;Close this file. |
|
mov |
ah, 3Eh |
;DOS close opcode. |
|
int |
21h |
|
|
ret |
|
|
GetFileData |
endp |
|
|
; Here’s the main program that gets the whole ball rolling.
Main |
proc |
|
|
mov |
ax, dseg |
|
mov |
ds, ax |
|
meminit |
|
; First, get the address of LPT1: from the BIOS variables area.
|
mov |
ax, 40h |
;Point at BIOS variable segment. |
|
mov |
es, ax |
|
|
mov |
ax, es:[PrtrBase] |
|
|
mov |
MyPortAdrs, ax |
|
|
call |
Synchronize |
;Wait for the transmitter program. |
|
jnc |
Quit |
|
|
call |
GetFileInfo |
;Get file name and size. |
|
printf |
|
|
|
byte |
“Filename: %s\nFile size: %ld\n”,0 |
|
|
dword |
Filename, FileSize |
|
|
mov |
ah, 3Ch |
;Create file. |
|
mov |
cx, 0 |
;Standard attributes |
|
lea |
dx, Filename |
|
|
int |
21h |
|
|
jnc |
GoodOpen |
|
|
|
|
|
|
byte |
“Error opening file”,cr,lf,0 |
|
|
jmp |
Quit |
|
GoodOpen: |
mov |
FileHandle, ax |
|
|
call |
GetFileData |
;Get the file’s data. |
Quit: |
ExitPgm |
|
;DOS macro to quit program. |
Main |
endp |
|
|
cseg |
ends |
|
|
sseg |
segment |
para stack ‘stack’ |
|
stk |
byte |
1024 dup (“stack “) |
|
sseg |
ends |
|
|
zzzzzzseg |
segment |
para public ‘zzzzzz’ |
|
LastBytes |
byte |
16 dup (?) |
|
zzzzzzseg |
ends |
|
|
|
end |
Main |
|
Page 1221

Chapter 21
21.5Summary
The PC’s parallel port, though originally designed for controlling parallel printers, is a general purpose eight bit output port with several handshaking lines you can use to control many other devices in addition to printers.
In theory, parallel communications should be many times faster than serial communications. In practice, however, real world constraints and economics prevent this from being the case. Nevertheless, you can still connect high performance devices to the PC’s parallel port.
The PC’s parallel ports come in two varieties: unidirectional and bidirectional. The bidirectional versions are available only on PS/2s, certain laptops, and a few other machines. Whereas the eight data lines are output only on the unidirectional ports, you can program them as inputs or outputs on the bidirectional port. While this bidirectional operation is of little value to a printer, it can improve the performance of other devices that connect to the parallel port, such as disk and tape drives, network adapters, SCSI adapters, and so on.
When the system communicates with some other device over the parallel port, it needs some way to tell that device that data is available on the data lines. Likewise, the devices needs some way to tell the system that it is not busy and it has accepted the data. This requires some additional signals on the parallel port known as handshaking lines. A typical PC parallel port provides three handshaking signals: the data available strobe, the data taken acknowledge signal, and the device busy line. These lines easily control the flow of data between the PC and some external device.
In addition to the handshaking lines, the PC’s parallel port provides several other auxiliary I/O lines as well. In total, there are 12 output lines and five input lines on the PC’s parallel port. There are three I/O ports in the PC’s address space associated with each I/O port. The first of these (at the port’s base address) is the data register. This is an eight bit output register on unidirectional ports, it is an input/output register on bidirectional ports. The second register, at the base address plus one, is the status register. The status register is an input port. Five of those bits correspond to the five input lines on the PC’s parallel port. The third register (at base address plus two) is the control register. Four of these bits correspond to the additional four output bits on the PC, one of the bits controls the IRQ line on the parallel port, and a sixth bit controls the data direction on the birdirectional ports.
For more information on the parallel port’s hardware configuration, see:
•“Basic Parallel Port Information” on page 1199
•“The Parallel Port Hardware” on page 1201
Although many vendors use the parallel port to control lots of different devices, a parallel printer is still the device most often connected to the parallel port. There are three ways application programs commonly send data to the printer: by calling DOS to print a character, by calling BIOS’ int 17h ISR to print a character, or by talking directly to the parallel port. You should avoid this last technique because of possible software incompatibilities with other devices that connect to the parallel port. For more information on printing data, including how to write your own int 17h ISR/printer driver, see:
•“Controlling a Printer Through the Parallel Port” on page 1202
•“Printing via DOS” on page 1203
•“Printing via BIOS” on page 1203
•“An INT 17h Interrupt Service Routine” on page 1203
One popular use of the parallel port is to transfer data between two computers; for example, transferring data between a desktop and a laptop machine. To demonstrate how to use the parallel port to control other devices besides printers, this chapter presents a program to transfer data between computers on the unidirectional parallel ports (it also works on bidirectional ports). For all the details, see
•“Inter-Computer Communications on the Parallel Port” on page 1209
Page 1222