Драйвер устройства в системе MS-DOS
На листинге 1 показана программа dostest.asm, представляющая собой обычный драйвер устройства для системы MS-DOS, который общается с устройством. Несмотря на простоту и малый размер данная программа содержит основные компоненты драйвера устройства, который обрабатывает прерывания.
_____________________________________________________________________
page ,132
; masm tisr ; >err
.286p
.xlist
include ..\..\include\bogus.inc
.list
Words struc
LoWord dw ?
HiWord dw ?
Words ends
EOI equ 020h ; команда EOI для контроллера PIC
INTA00 equ 020h ; управление главным контроллером PIC
INTA01 equ 021h ; регистр маски главного контроллера PIC
INT_MASTER_0 equ 08h ;номер INT главн. контроллера PIC
INTB00 equ 0A0h ; управление подчиненным контроллером PIC
INTB01 equ 0A1h ;регистр маски подчиненного контроллера PIC
INT_SLAVE_0 EQU 70h ; номер INT подчиненного контроллера PIC
;
; Установить переменные для нашего номера прерывания
;
ife (FAKE_IRQ GE 8)
INT_DEV equ (INT_MASTER_0+(FAKE_IRQ AND 7))
PIC00 equ INTA00
PIC01 equ INTA01
else
INT_DEV equ (INT_SLAVE_0+(FAKE_IRQ AND 7))
INT_MASK equ 1 SHL (FAKE_IRQ AND 7)
PIC00 equ INTB00
PIC01 equ INTB01
endif
CONST SEGMENT DWORD PUBLIC 'DATA'
sdNoBogus db 'I do not see the bogus device.',Odh,Oah,'$'
sdPrompt db Odh,Oah,'S)tart, or Q)uit: ','$'
sdCRLF db Odh,Oah,'$'
sdDot db '.','$'
CONST ENDS
DATA SEGMENT DWORD PUBLIC 'DATA'
dwCount1 dw 0
dwCount2 dw 0
lpPrevISR dd 0 ; адрес предыдущей программы ISR
fStopping db 0 ; значение TRUE при завершении
DATA ENDS
STACK SEGMENT DWORD STACK 'STACK'
db 512 dup (?)
STACK ENDS
DGroup GROUP CONST,DATA,STACK
;IP IntSvcRtn - The Interrupt Service Routine (Программа
обслуживания
; прерывания)
; WARNINGS (предупреждения)
;
; NOTES (примечания)
; Данная программа ISR увеличивает счетчик прерываний (dwCount1)
; и заново маскирует устройство.
;
; Если установлен флаг "fStopping", устройство не маскируется заново.
;
FIXED_TEXT SEGMENT PARA PUBLIC 'CODE'
segData1 dw DGroup
assume CS:FIXED_TEXT,DS:NOTHING
IntSvcRtn proc far
push ax
push dx
push ds
mov ds,segDatal
assume ds:DGroup
inc dwCount1
mov al,NOT FAKE_CTL_EOI
mov dx,FAKE_PORT
out dx,al ; послать EOI устройству
mov al,EOI
out PIC00,al ; послать EOI контроллеру PIC
ife (PIC00 EQ INTA00)
out INTA00,al ; послать EOI главн. контроллеру PIC также
endif
cmp fStopping,0 ; существует?
jnz isr9 ; если да, то не нужен перезапуск
mov al,NOT FAKE_CTL_START
mov dx,FAKE_PORT
out dx,al ; перезапуск ввода-вывода
isr9:
pop ds
assume ds:NOTHING
pop dx
pop ax
iret
IntSvcRtn endp
FIXED_TEXT ENDS
;IP_main - точка входа в программу
; NOTES (примечания)
; Драйвер устройства выдает для пользователя приглашение:
;S)tart(начать) или Q)uit(выйти). Если пользователь нажимает S,
;программа разрешает прерывания и вооружает устройство, печатая точку
;каждый раз, как устройство прерывается.
;
_TEXT SEGMENT PARA PUBLIC 'CODE'
segData2 dw DGroup
segfixed dw FIXED_TEXT
assume cs:_TEXT,ds:NOTHING
_main label far
mov ds,segData2 ;инициализируется сегмент данных по умолчанию
assume ds:DGroup
mov dx,FAKE_PORT
in al,dx ; присутствует ли фиктивное устройство?
or al,al
jns m10 ;пропустить, если да
mov dx,OFFSET DGroup:sdNoBogus
mov ah,9
int 21h ; в противном случае печатать сообщение об ошибке
mov ax,4C01h
int 21h ; и выйти из системы
m10:
mov ax,3500h+INT_DEV
cli
int 21h ; запросить текущую программу ISR
mov lpPrevISR.LoWord,bx
mov lpPrevISR.HiWord,es ; сохранить ее
mov dx,OFFSET FIXED_TEXT:IntSvcRtn
push ds
mov ds,segFixed
assume ds:NOTHING
mov ax,2500h+INT_DEV
int 21h ; установить нашу программу ISR
pop ds
assume ds:DGroup
sti
mov dx,OFFSET DGroup:sdPrompt
mov ax,9
int 21h ; S)tart или Q)uit
ml1:
mov dl,0PFh
mov ah,6
int 21h ; читать с консоли, не ожидая
jz ml3
or al,40h
cmp al,'q'
je ml8 ; пропустить, если нажато "Q"
cmp al,'s'
jne ml3 ; пропустить, если не нажато "S"
cli
in al,PIC01 ; размаскировать прерывание
and al,NOT INT_MASK
out PIC01,al
sti
mov al,NOT FAKE_CTL_START
mov dx,FAKE_PORT
out dx,al ; начать ввод-вывод с устройства
ml3:
mov ax,dwCount1
cmp ax,dwCount2
je ml4 ; пропустить, если счетчик прерываний не изменился
mov dwCount2,ax
mov dx,OFFSET DGroup:sdDot
mov ah,9
int 21,h ;в противном случае выдать точку
ml4:
jmp ml1 ; цикл
ml8:
mov fStopping,1 ; указание для программы ISR завершить работу
mov dx,FAKE_PORT
ml9:
in al,dx
rcr al,1
jnc ml9 ; цикл, если занято
cli
in al,PIC01
or al,INT_MASK
out PIC01,al ; маскировать уровень прерывания
sti
push ds
lds dx,lpPrevISR
assume ds:NOTHING
mov ax,2500h+INT_DEV
int 21h ; восстановить предыдущую программу ISR
pop ds
assume ds:DGroup
mov ax,4C00h
int 21h ; выход
_TEXT ENDS
end_main
_____________________________________________________________________
Листинг 1. Программа dostest.asm
Драйвер устройства начинает работу с проверки старшего бита порта состояния, чтобы убедиться в наличии устройства. Затем он устанавливает связь с вектором прерывания MS-DOS для прерывания 11.
Драйвер сохраняет предыдущее значение, хранимое в этом векторе, так чтобы можно было заменить значение, если программа существует.
Далее драйвер устройства выдает приглашение для пользователя : Start(начать) или Quit(выйти). Если пользователь нажимает S, программа начинает пересылку ввода-вывода. Если пользователь нажимает Q, то программа отключает устройство, восстанавливает вектор прерывания и завершается.
Чтобы начать операцию ввода-вывода, драйвер MS-DOS сначада размаскирует программируемый контроллер прерываний (programmable interrupt controller - PIC) для уровня прерывания устройства (в примере прерывание 11). Затем драйвер начинает операцию ввода-вывода для устройства путем записи 1 в бит 0 порта управления. Так как прерывания включены, то при возникновении прерываний на устройстве получит управление программа обслуживания прерываний (interrupt service routine - ISR).
Если происходит прерывание на устройстве, то программа ISR подтверждает прием прерывания, посылая значение EOI устройству (т.е. записывая 1 в бит 1 порта управления устройства) и контроллеру PIC. Если программа, выполняющая ввод-вывод, существует, то программа ISR выполняется. В противном случае программа ISR осуществляет инициализацию пересылки ввода-вывода вновь, записывая 1 в бит 0 порта управления устройства. Итак, программа ISR возобновляет ввод-вывод всякий раз, когда происходит прерывание, таким образом устройство непрерывно выполняет операцию ввода-вывода. Кроме обеспечения непрерывного ввода-вывода программа ISR увеличивает счетчик (dwCount1) всякий раз, когда обрабатывает прерывание.
В процессе выполнения ввода-вывода программа следит за счетчиком прерываний, отображает точку (".") для каждой законченной пересылки ввода-вывода и продолжает сканировать клавиатуру, чтобы определить, хочет ли пользователь остановить пересылку.
Чтобы завершить программу, пользователь нажимает клавишу Q.Программа устанавливает флаг, который информирует программу ISR о том, что следует остановить обработку. После того, как операция ввода-вывода остановлена, программа маскирует уровень прерывания в контроллере PIC и восстанавливает вектор прерывания.