home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programming
/
powerprogramming1994.iso
/
progtool
/
microcrn
/
issue_32.arc
/
DRIVER.ASM
< prev
next >
Wrap
Assembly Source File
|
1979-12-31
|
8KB
|
276 lines
;************************************************************************
; *
; PARALLEL PRINTER DRIVER *
; *
; Written by Don Fletcher *
; *
;************************************************************************
;
;
;================== DEVICE HEADER BLOCK =================================
;
; All device drivers start with a defined 18 byte block
; of data called the 'Device Header', which must start at
; origin 0 within the device driver segment.
;
CODE SEGMENT PUBLIC 'CODE'
DEVICE Proc far
ASSUME CS:CODE,DS:CODE,ES:CODE
;
Org 0
;
; Data Constants
;
; If you have a monochrome display and printer adapter,
; add 44H to the three addresses that follow.
;
Print_Dat Equ 378H ;or 3BCH - Printer data port
Print_Stat Equ 379H ;or 3BDH - Printer status port
Print_Out Equ 37AH ;or 3BEH - Status output port
;
Busy Equ 80H ;Busy test mask
Strobe_Hi Equ 0DH ;Strobe output high
Strobe_Low Equ 0CH ;Strobe output low
;
;
;
; Within this 'Device Header' block must be:
;
; 1) The Device Chain Pointer -- Double word, set to -1,-1
; (FFFF:FFFF) in your code. MS-DOS uses this location
; for a double wide pointer to the next device in the
; chain.
;
DW -1,-1 ;Pointer to the next device
;
; 2) The Device Header Attribute word -- 16 single bit fields
; that tell MS-DOS the type and capabilities of the device
; driver. We will use the standard character device for
; our printer driver - 8000H.
;
DW 8000H ;Standard Character device
;
; 3) The Strategy entry pointer -- Holds the entry offset
; address if the Strategy code. Since the offset is only
; 16 bits, the strategy code must be in the same segment as
; the device header block.
;
DW Strategy ;Strategy code offset
;
; 4) The Interrupt entry pointer -- Sixteen bit entry offset
; for the Interrupt code. As with the strategy code above,
; the Interrupt code must be in the same segment as the
; device header block.
;
DW Interrupt;Interrupt code offset
;
; 5) An 8 byte block which, if a character driver, contains the
; name of the device driver padded with blanks. If a block mode
; driver, only the first byte is used to indicate how many
; separate devices are supported by this driver.
;
DB 'SAMPLE ' ;Device name
;
;
;=================== REQUEST HEADER BLOCK ==============================
;
; When MS-DOS invokes a device driver, commands and data to the
; device driver are assembled into a Request header. A pointer
; to this data is passed to the device driver in the ES:BX register
; pair. Since the memory allocation is dynamic in this case, a
; block of equates must be allocated referenced to the above
; pointer. By far the easiest method of accessing this block
; of data is to use the Structure command for the MS assembler.
;
Request equ ES:[DI] ;Set base address of Header block
;
Reqhdr Struc
Numb DB ? ;num of bytes in block -byte 0
Unit DB ? ;unit number [block drivers] -byte 1
Cmmd DB ? ;command byte -byte 2
Stat DW ? ;return status -bytes 3-4
Dos DB 4 dup(?);addr link used by DOS -bytes 5-8
Intlnk DB 4 dup(?);linkage to other blocks -bytes 9-12
;
; After the above 'standard' locations, come the following
; locations in the Header block used for init, read and write
; operations.
;
Media DB ? ;Media Descripter -byte 13
Address DD ? ;Data transfer address -bytes 14-17
Count DW ? ;Byte count value -bytes 18-19
Reqhdr Ends
;
;=================== COMMAND OFFSET TABLE =============================
;
; Jump table for the commands passed in byte 2 (Cmmd) of the
; Request Header Block.
;
Jumptbl:
DW Allinit ;Init device driver # 0
DW Exitt ;(media check) block command # 1
DW Exitt ;(Build Bios Parm Block) # 2
DW Exitt ;(IOCTL for input) not sup # 3
DW Exitt ;(Input - read) not used # 4
DW Exitt ;(Input non destructive) # 5
DW Exitt ;(Input Status) # 6
DW Exitt ;(Input Flush) # 7
DW Outchar ;Output character # 8
DW Outchar ;Output char with verify # 9
DW Outstat ;Output status # 10
DW Exitt ;(Output flush) # 11
DW Exitt ;(IOCTL for output) # 12
DW Exitt ;(Device open) # 13
DW Exitt ;(Device close) # 14
DW Exitt ;(Removable media) # 15
;
;
;=================== STRATEGY CODE BLOCK ===============================
;
; The sole purpose of the Strategy code is to accept and store
; the passed pointer to the Request Header Block. After MS-Dos
; calls the Strategy code in the correct device driver, it then
; calls the Interrupt code to execute the command.
;
Savadd DD ? ;reserve a double word for the pointer
;
; Pointer to request header block is in ES:BX registers
; saved in Savadd area.
;
Strategy proc far
;
Mov CS:word ptr [Savadd],BX ;Save pointer address
Mov CS:word ptr [Savadd + 2],ES
Ret
Strategy endp
;
;
;=================== INTERRUPT ROUTINES ===============================
;
; The Interrupt code area handles the actual work of the device
; driver. The command is decoded, then done, any errors are
; returned to MS-DOS. The pointer to the interrupt commands
; is contained in Savadd in the form OFFSET:Segment.
;
Interrupt proc far
;
Push AX ;save all registers
Push BX
Push CX
Push DX
Push BP
Push SI
Push DI
Push DS
Push ES
Pushf
;
Push CS ;Since we're in only one segment,
Pop DS ;equate CS and DS making local data
;available
;
Les DI,[Savadd] ;ES:DI = Request Header block pointer
Xor BH,BH ;clear AH
Mov BL,Request.Cmmd ;get the command byte
;
Cmp BX,16 ;Check that command is in range
Jle Exx ;OK
Jmp Exitt ;Error exit
;
Exx: Shl BX,1 ;Multiply by 2 and go to command
;
Call Word ptr [BX+Jumptbl] ;Return AX = error status
Jmp Exit ;Go back to MS-Dos
;
Exitt: ;Unsupported commands
Mov AX,3 ;Signal command error
Or AX,8000H ;Add error bit
Exit: ;Common exit return AX contains error status
Les DI,[Savadd] ;Restore pointer
Or AX,100H ;Set the done bit
Mov Request.Stat,AX ;put error status in block
Popf ;Restore all registers and flags
Pop ES
Pop DS
Pop DI
Pop SI
Pop BP
Pop DX
Pop CX
Pop BX
Pop AX
Ret ;Go back to MS-Dos
Outchar proc near ;Output character(s) to printer
;
Lds BX,[Request.Address] ;Get pointer to transferred data
Mov CX,[Request.Count] ;Get byte transfer count
;
Outlp: Mov AL,DS:[BX] ;Go get character
Call Prntout ;Print it
Inc BX ;Point to next character
Dec CX ;Decrement character pointer
Jnz Outlp ;Repeat until CX = 0
;
; Number of bytes passed is the number of bytes printed
; which is already in the proper location within the
; Request Header Block.
;
Xor AX,AX ;No errors
Ret ;Exit
Outchar Endp
;
Outstat proc near ;Get printer status
;
Mov DX,Print_Stat ;Point to 'Input Status' Port
In AL,DX ;Read the printer status
Shl AX,1 ;Put busy status bit in proper location
Shl AX,1
Not AX ;Invert busy bit
And AX,200H ;Clear all but busy bit
Ret ;Go back
Outstat Endp
;
;
Prntout proc near ;Character output is in AL
;
;
Mov DX,Print_Dat ;Address of 'Output Data' Port
Out DX,AL ;Output the char to be printed
;
; Check the input status
;
Mov DX,Print_Stat ;Address of 'Input Status' Port
Wait: In AL,DX ;Read the printer status
Test AL,Busy ;Check the busy bit
Jz Wait ;Stay in loop until printer isn't busy
;
; When we reach here, the printer isn't busy
;
Mov DX,Print_Out ;Address of 'Output control' port
Mov AL,Strobe_Hi ;Strobe bit = 1
Out DX,AL ;Strobe the printer
Mov AL,Strobe_Low ;Strobe bit = 0
Out DX,AL ;Turn Printer Strobe off
Ret
Prntout Endp
;
Allinit proc near ;Called once, must return end address of
;code and proper status
;
Mov Request.Address,offset Allinit ;End of program code
Mov Request.Address+2,CS ;Segment
Xor AX,AX ;no errors
Ret
Allinit endp
;
Interrupt Endp
Device Endp
Code Ends
End