Category : Assembly Language Source Code
Archive   : ASMDRV.ZIP
Filename : PRINTER.ASM

 
Output of file : PRINTER.ASM contained in archive : ASMDRV.ZIP
page 60,132
title A Printer Device Driver

;****************************************************************
;* This is a Printer Device Driver *
;****************************************************************

;****************************************************************
;* INSTRUCTING THE ASSEMBLER *
;****************************************************************

cseg segment para public 'code'
printer proc far
assume cs:cseg, es:cseg, ds:cseg

;structures

rh struc ;request header
rh_len db ? ;len of packet
rh_unit db ? ;unit code
;(block devices only)
rh_cmd db ? ;device driver command
rh_status dw ? ;returned by device driver
rh_res1 dd ? ;reserved
rh_res2 dd ? ;reserved
rh ends ;

rh0 struc ;Initialization (command 0)
rh0_rh db size rh dup (?) ;fixed portion
rh0_nunits db ? ;number of units
;(block devices only)
rh0_brk_ofs dw ? ;offset address for break
rh0_brk_seg dw ? ;segment address for break
rh0_bpb_tbo dw ? ;offset address of pointer
;to BPB array
rh0_bpb_tbs dw ? ;segment address of pointer
;to BPB array
rh0_drv_ltr db ? ;first available drive
;(DOS 3+) (block only)
rh0 ends ;

rh3 struc ;IOCTL_INPUT (command 3)
rh3_rh db size rh dup(?) ;fixed portion
rh3_media db ? ;media descriptor from DPB
rh3_buf_ofs dw ? ;offset address of
;data transfer area
rh3_buf_seg dw ? ;segment address of
;data transfer area
rh3_count dw ? ;transfer count
;(sectors for block)
;(bytes for character)
rh3_start dw ? ;start sector number
;(block only)
rh3 ends ;

rh8 struc ;OUTPUT (command 8)
rh8_rh db size rh dup(?) ;fixed portion
rh8_media db ? ;media descriptor from DPB
rh8_buf_ofs dw ? ;offset address of
;data transfer area
rh8_buf_seg dw ? ;segment address of
;data transfer area
rh8_count dw ? ;transfer count
;(sectors for block)
;(bytes for character)
rh8_start dw ? ;start sector number
;(block only)
rh8 ends ;

rh9 struc ;OUTPUT_VERIFY (command 9)
rh9_rh db size rh dup(?) ;fixed portion
rh9_media db ? ;media descriptor from DPB
rh9_buf_ofs dw ? ;offset address of
;data transfer area
rh9_buf_seg dw ? ;segment address of
;data transfer area
rh9_count dw ? ;transfer count
;(sectors for block)
;(bytes for character)
rh9_start dw ? ;start sector number (block only)
rh9 ends ;

rh10 struc ;Output_Status (command 10)
rh10_len db ? ;len of packet
rh10_unit db ? ;unit code
;(block devices only)
rh10_cmd db ? ;device driver command
rh10_status dw ? ;returned by device driver
rh10_res1 dd ? ;reserved
rh10_res2 dd ? ;reserved
rh10 ends ;

rh12 struc ;IOCTL_OUTPUT (command 12)
rh12_rh db size rh dup(?) ;fixed portion
rh12_media db ? ;media descriptor from DPB
rh12_buf_ofs dw ? ;offset address of
;data transfer area
rh12_buf_seg dw ? ;segment address of
;data transfer area
rh12_count dw ? ;transfer count
;(sectors for block)
;(bytes for character)
rh12_start dw ? ;start sector number
;(block only)
rh12 ends ;

rh16 struc ;OUTPUT_BUSY (command 16)
rh16_rh db size rh dup (?) ;fixed portion
rh16_media db ? ;media descriptor
rh16_buf_ofs dw ? ;offset address of
;data transfer area
rh16_buf_seg dw ? ;segment address of
;data transfer area
rh16_count dw ? ;byte count returned
;from device driver
rh16 ends ;

;commands that do not have unique portions to the request header:
; INPUT_STATUS (command 6)
; INPUT_FLUSH (command 7)
; OUTPUT_STATUS (command 10)
; OUTPUT_FLUSH (command 11)
; OPEN (command 13)
; CLOSE (command 14)
; REMOVEABLE (command 15)
;


;****************************************************************
;* MAIN PROCEDURE CODE *
;****************************************************************

begin:

;****************************************************************
;* DEVICE HEADER REQUIRED BY DOS *
;****************************************************************

next_dev dd -1 ;no other drivers following
attribute dw 0e000h ;char,IOCTL,output til busy
strategy dw dev_strategy ;Strategy routine address
interrupt dw dev_interrupt ;Interrupt routine address
dev_name db 'PRN ' ;name of our Printer driver

;****************************************************************
;* WORK SPACE FOR OUR DEVICE DRIVER *
;****************************************************************

rh_ofs dw ? ;offset address of the request header
rh_seg dw ? ;segment address of the request header

device db 0 ;0=parallel, 1= serial
dev_num db 0 ;0,1,2 depending on configuration

;****************************************************************
;* THE STRATEGY PROCEDURE *
;****************************************************************

dev_strategy: mov cs:rh_seg,es ;save the segment address
mov cs:rh_ofs,bx ;save the offset address
ret ;return to DOS

;****************************************************************
;* THE INTERRUPT PROCEDURE *
;****************************************************************

;device interrupt handler - 2nd call from DOS

dev_interrupt:

cld ;save machine state on entry
push ds
push es
push ax
push bx
push cx
push dx
push di
push si

mov ax,cs:rh_seg ;restore ES as saved by STRATEGY call
mov es,ax ;
mov bx,cs:rh_ofs ;restore BX as saved by STRATEGY call

;jump to appropriate routine to process command

mov al,es:[bx].rh_cmd ;get request header header command
rol al,1 ;times 2 for index into word table
lea di,cmdtab ;function (command) table address
mov ah,0 ;clear hi order
add di,ax ;add the index to start of table
jmp word ptr[di] ;jump indirect

;CMDTAB is the command table that contains the word address
;for each command. The request header will contain the
;command desired. The INTERRUPT routine will jump through an
;address corresponding to the requested command to get to
;the appropriate command processing routine.

CMDTAB label byte ;* = char devices only
dw INITIALIZATION ; initialization
dw MEDIA_CHECK ; media check (block only)
dw GET_BPB ; build bpb
dw IOCTL_INPUT ; ioctl in
dw INPUT ; input (read)
dw ND_INPUT ;*non destructive input no wait
dw INPUT_STATUS ;*input status
dw INPUT_FLUSH ;*input flush
dw OUTPUT ; output (write)
dw OUTPUT_VERIFY ; output (write) with verify
dw OUTPUT_STATUS ;*output status
dw OUTPUT_FLUSH ;*output flush
dw IOCTL_OUT ; ioctl output
dw OPEN ; device open
dw CLOSE ; device close
dw REMOVEABLE ; removeable media
dw OUTPUT_BUSY ; output til busy

;****************************************************************
;* YOUR LOCAL PROCEDURES *
;****************************************************************


;****************************************************************
;* DOS COMMAND PROCESSING *
;****************************************************************

;command 0 Initialization
Initialization:

call initial ;display message
lea ax,initial ;set Break Addr. at initial
mov es:[bx].rh0_brk_ofs,ax ;store offset address
mov es:[bx].rh0_brk_seg,cs ;store segment address
jmp done ;set done status and exit

;command 1 Media_Check
Media_Check:

jmp done ;set done bit and exit

;command 2 Get_BPB
Get_BPB:

jmp done ;set done bit and exit

;command 3 IOCTL_Input
IOCTL_Input:

mov di,es:[bx].rh3_buf_ofs ;get buffer offset
mov ax,es:[bx].rh3_buf_seg ;get buffer
mov es,ax ; segment to es
cmp cs:device,0 ;is it currently parallel?
jne inio1 ;no - check for serial
mov al,'P' ;yes - ASCII P
jmp inioctl ;store it
inio1: mov al,'S' ;assume [S]erial
inioctl:mov es:[di],al ;Store printer type
inc di ;next location
mov al,cs:dev_num ;get device number
mov es:[di],al ;store it
mov cx,cs:rh_seg ;restore request header
mov es,cx ; segment to es
mov bx,cs:rh_ofs ;same for offset
jmp done ;set done bit and exit

;command 4 Input
Input:

jmp done ;set done bit and exit

;command 5 ND_Input
ND_Input:

jmp busy ;set busy bit and exit

;command 6 Input_Status
Input_Status:

jmp done ;set done bit and exit

;command 7 Input_Flush
Input_Flush:

jmp done ;set done bit and exit

;command 8 Output
Output:

mov cx,es:[bx].rh8_count ;load output count
mov di,es:[bx].rh8_buf_ofs ;load offset address
mov ax,es:[bx].rh8_buf_seg ;load segment address
mov es,ax ; into es

mov dl,cs:dev_num ;load printer #
mov dh,0 ;clear hi-order DX
mov bx,0 ;set current count to 0

;check for device type
cmp cs:device,0 ;to parallel device?
je pout ;yes
jmp sout ;no - assume serial


;process output to parallel printer
pout: cmp bx,cx ;is current = output?
je pout2 ;yes - we are done
mov al,es:[di] ;get output character
inc di ;point to next byte
mov ah,2 ;service = status check
int 17h ;Printer BIOS call
test ah,80h ;not busy (=1)?
jne pout1 ;yes - continue
jmp pout3 ;no - exit with error
pout1: mov ah,0 ;service = print
int 17h ;Printer BIOS call
test ah,9h ;I/O error or Timeout?
jne perr1 ;yes
inc bx ;increment current count
jmp pout ;go back for more

;process printer errors

pout2: mov ax,0 ;no error
jmp load_status ;load status & exit
pout3: mov ax,8002h ;set error bit & 'not ready'
jmp load_status ;load status & exit

perr1: test ah,1 ;Timeout?
jz perr2 ;no - go to next test
mov ax,8002h ;set error bit & not ready
jmp load_status ;go to cleanup
perr2: test ah,8 ;I/O Error?
jz perr3 ;no - go to next test
mov ax,800ah ;set error bit & Write Fault
jmp load_status ;go to cleanup
perr3: test ah,20h ;No Paper (printer off)?
jz perr4 ;no - go to last step
mov ax,8009h ;set error bit & No Paper
jmp load_status ;go to cleanup
perr4: mov ax,800ch ;set error bit & General Failure
jmp load_status ;go to cleanup

;process output to serial printer

sout: cmp bx,cx ;is current = request count?
je sout2 ;yes - set status & exit
mov ah,3 ;service = status check
int 14h ;RS232 BIOS call
test ah,20h ;xfer hold register empty?
jnz st1 ;yes (implies not busy)
jmp sout3 ;no - set error & exit
st1: test al,20h ;is data set ready =1?
jnz sout1 ;yes (implies not busy)
jmp sout3 ;no - set error & exit
sout1: mov al,es:[di] ;get output character
inc di ;increment for next char
mov ah,1 ;service = transmit 1 char
int 14h ;RS232 BIOS call
test ah,80h ;transmit error?
jnz sout3 ;yes - set error & exit
inc bx ;no - increment output count
jmp sout ;go back for more


sout2: mov ax,0 ;no errors - we are done
jmp load_status ;load status word & exit
sout3: mov ax,800ah ;set error bit & 'write fault'
jmp load_status ;set status word & exit

;command 9 Output_Verify
Output_Verify:

jmp output ;same as output

;command 10 Output_Status
Output_Status:

;The DOS BUSY bit of the status word is set to indicate to DOS
;that DOS should wait. If BUSY is not set (eg DONE bit only),
;this means that device is ready for more output.

;determine device type and unit number
mov dl,cs:dev_num ;load printer #
mov dh,0 ;clear hi-order DX

;check for device type
cmp cs:device,0 ;to parallel device?
je pstatus ;yes
jmp sstatus ;no - assume serial

;get status from parallel device
; if bit 7 in ah is set this means device is not busy
; so we do not set BUSY in status word.
pstatus:
mov ah,2 ;service = status check
int 17h ;Printer BIOS call
test ah,80h ;not busy or other?
jne pstat1 ;yes
jmp busy ;no (not busy) - set BUSY!
pstat1: test ah,9h ;I/O Error or Timeout?
jz pstat2 ;no - exit with BUSY not set!
mov es:[bx].rh_status,8009h ;set error bit & 'No Paper'
pstat2: jmp done ;set done bit and exit

;get serial printer status
sstatus:
mov ah,3 ;service = status check
int 14h ;RS232 BIOS call
test ah,20h ;xfer hold register empty?
jz sstat ;no - set BUSY!
test al,20h ;data set ready?
jz sstat ;no - set BUSY!
jmp done ;device is ready!
sstat: jmp busy ;device is not ready!

;command 11 Output_Flush
Output_Flush:

jmp done ;set done bit and exit

;command 12 IOCTL_Out
IOCTL_Out:
mov cx,es:[bx].rh12_count ;load output count
mov di,es:[bx].rh12_buf_ofs ;load offset address
mov ax,es:[bx].rh12_buf_seg ;load segment address
mov es,ax ; into es

mov al,es:[di] ;pickup Device
cmp al,'P' ;is it parallel?
jne IOCTL1 ;no - test for serial
mov cs:device,0 ;yes - move 0
jmp IOCTL2 ;now get device number
IOCTL1: cmp al,'S' ;is it serial?
jne IOCTL3 ;no - wrong IOCTL data
mov cs:device,1 ;yes - move 1
IOCTL2: inc di ;next character
mov al,es:[di] ;pickup device number
mov cs:dev_num,al ;store it
mov ax,0 ;no error
jmp IOCTL4 ;load status & exit

IOCTL3: mov ax,8003 ;not P or S - error

IOCTL4: mov cx,cs:rh_seg ;restore request header
mov es,cx ; segment to es
mov bx,cs:rh_ofs ;restore offset also
mov es:[bx].rh_status,ax ;return status
jmp done ;set done bit and exit

;command 13 Open
Open:

jmp done ;set done bit and exit

;command 14 Close
Close:

jmp done ;set done bit and exit

;command 15 Removeable
Removeable:

jmp unknown ;set error bit/code and exit

;command 16 Output Til Busy
Output_Busy:

jmp output ;use Output code to process

;****************************************************************
;* ERROR EXIT *
;****************************************************************

unknown:
or es:[bx].rh_status,8003h ;set error bit and error code
jmp done ;set done and exit

;****************************************************************
;* COMMON EXIT *
;****************************************************************
load_status:
mov cx,cs:rh_seg ;restore request header
mov es,cx ; segment to es
mov cx,cs:rh_ofs ;restore offset also
xchg bx,cx ;switch them
mov es:[bx].rh_status,ax ;return status
mov es:[bx].rh8_count,cx ;return output count
jmp done ;set done bit and exit

busy: or es:[bx].rh_status,0200h ;set busy bit

done: or es:[bx].rh_status,0100h ;set done

pop si ;restore all registers
pop di
pop dx
pop cx
pop bx
pop ax
pop es
pop ds
ret ;return to DOS

;****************************************************************
;* END OF PROGRAM *
;****************************************************************

;this procedure is called from the Initialization command and
;is executed only once. We tell DOS that the next available
;memory location (Break Address) is here. This allows DOS to over
;write this code; we save space.

initial proc near ;display message on console
int 11h ;equipment check
push ax ;save for parallel calculation
mov cl,9 ;shift count
shr ax,cl ;get serial ports
and al,7 ;keep 3 right bits
add al,30h ;make it an ASCII number
mov msg1b,al;store it
pop ax ;restore for parallel calculation
mov cl,14 ;shift count
shr ax,cl ;get parallel ports
and al,3 ;keep 2 right bits
add al,30h ;make it an ASCII number
mov msg1c,al;store it
lea dx,msg1 ;message to be displayed
mov ah,9 ;display
int 21h ;DOS call
ret ;return to caller
initial endp

msg1 db 'The Waite Group Printer Driver',0dh,0ah,
db ' supporting',0dh,0ah,' ',
msg1b db '0 parallel printers',0dh,0ah,' ',
msg1c db '0 serial printers',0dh,0ah,'$'

printer endp ;end of printer procedure
cseg ends ;end of cseg segment
end begin ;end of program


  3 Responses to “Category : Assembly Language Source Code
Archive   : ASMDRV.ZIP
Filename : PRINTER.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/