Драйвер символьного устройства


; Демонстрационный драйвер символьного устройства ; ; Copyright (C)Frolov A., 1990

.MODEL tiny .CODE ; Драйвер состоит из одного ; сегмента кода

org 0 ; Эта строка может отсутствовать

include sysp.inc

devdrv PROC far

; Заголовок драйвера

dd 0ffffffffh ;адрес следующего драйвера dw 0C800h ;байт атрибутов dw dev_strategy ;адрес процедуры стратегии dw dev_interrupt ;адрес процедуры прерывания db 'DEVDRIVR' ;имя устройства (дополненное ; пробелами)

;=================================================== ; Программа стратегии

dev_strategy: mov cs:req_seg,es mov cs:req_off,bx ret

; Здесь запоминается адрес заголовка запроса

req_seg dw ? req_off dw ?

;=================================================== ;Обработчик прерывания

dev_interrupt: push es ;сохраняем регистры push ds push ax push bx push cx push dx push si push di push bp

; Устанавливаем ES:BX на заголовок запроса

mov ax,cs:req_seg mov es,ax mov bx,cs:req_off

; Получаем код команды из заголовка запроса и умножаем ; его на два, чтобы использовать в качестве индекса ; таблицы адресов обработчиков команд



mov al,es:[bx]+2 shl al,1

sub ah,ah ; Обнуляем AH lea di,functions ; DI указывает на смещение ; таблицы add di,ax ; Добавляем смещение в таблице jmp word ptr [di] ; Переходим на адрес из таблицы

functions LABEL WORD ; Таблица функций

dw initialize dw check_media dw make_bpb dw ioctl_in dw input_data dw nondestruct_in dw input_status dw clear_input dw output_data dw output_verify dw output_status dw clear_output dw ioctl_out dw Device_open dw Device_close dw Removable_media dw reserved dw reserved dw reserved dw generic_ioctl

; Выход из драйвера, если функция не поддерживается

check_media: make_bpb: clear_input: output_verify: clear_output: Removable_media: reserved: generic_ioctl:

; Выводим сообщение о вызове ; неподдерживаемой драйвером команды

mov ax,cs mov ds,ax mov si,offset errmsg call dpc

; Ожидаем нажатия на любую клавишу

mov ax,0 int 16h

; Устанавливаем признак ошибки

or es:word ptr [bx]+3,8103h jmp quit

;==================================================nondestruct_in:

; Выводим сообщение о начале неразрушающего ввода

mov ax,cs mov ds,ax mov si,offset inpmsg_nd call dpc

; Вводим символ с клавиатуры и помещаем ; его в область запроса

mov ax,0 int 16h mov BYTE PTR es:[bx]+0dh,al

jmp quit

;=================================================== input_status:

; Выводим сообщение о вызове команды ; проверки состояния ввода

mov ax,cs mov ds,ax mov si,offset statmsg_i call dpc

; Устанавливаем признак "Занято", т.к. ; последующая команда чтения приведет к ожиданию ; нажатия на клавишу (буферизация не используется)

or es:word ptr [bx]+3,0200h jmp quit

;=================================================== output_status:

; Выводим сообщение о вызове команды ; проверки состояния вывода

mov ax,cs mov ds,ax mov si,offset statmsg_o call dpc

; Бит занятости не устанавливаем, т.к. ; считаем, что консоль доступна для вывода

or es:word ptr [bx]+3,0000h jmp quit

;=================================================== ; Обработчик команды вывода данных

output_data:

; Записываем в регистр CL количество ; выводимых символов

mov cl,es:[bx]+18 push cx

; Выводим сообщение о начале вывода

mov ax,cs mov ds,ax mov si,offset outmsg call dpc

pop cx

; Загружаем в DS:SI адрес буфера данных

mov ax,es:[bx]+16 mov ds,ax mov si,es:[bx]+14

; Выводим на экран символы из буфера

out_loop: mov al,ds:byte ptr [si] @@out_ch al inc si loop out_loop

jmp quit

;=================================================== ; Обработчик команды ввода данных

input_data:

; Записываем в регистр CL количество ; вводимых символов

mov cl,es:[bx]+18 push cx

; Выводим сообщение о начале ввода

mov ax,cs mov ds,ax mov si,offset inpmsg call dpc

; Загружаем в DS:SI адрес буфера данных

pop cx mov ax,es:[bx]+16 mov ds,ax mov di,es:[bx]+14

; Вводим символы с клавиатуры и записываем в буфер

inp_loop: mov ax,0 int 16h mov ds:byte ptr [di],al @@out_ch al inc di loop inp_loop

jmp quit

;=================================================== ; Обработчик команды вывода данных IOCTL

ioctl_out:

; Записываем в регистр CL количество ; выводимых символов

mov cl,es:[bx]+18

; Загружаем в DS:SI адрес буфера данных

mov ax,es:[bx]+16 mov ds,ax mov si,es:[bx]+14

; Выводим на экран символы из буфера

ioctl_out_loop: mov al,ds:byte ptr [si] @@out_ch al inc si loop ioctl_out_loop

jmp quit

;=================================================== ; Обработчик команды ввода данных IOCTL

ioctl_in:

; Записываем в регистр CL количество ; вводимых символов

mov cl,es:[bx]+18

; Загружаем в DS:SI адрес буфера данных

mov ax,es:[bx]+16 mov ds,ax mov di,es:[bx]+14

; Вводим символы с клавиатуры и записываем в буфер

ioctl_inp_loop: mov ax,0 int 16h mov ds:byte ptr [di],al @@out_ch al inc di loop ioctl_inp_loop

jmp quit

;=================================================== Device_open:

; Выводим сообщение об открытии устройства

mov ax,cs mov ds,ax mov si,offset openmsg call dpc

jmp quit

;=================================================== Device_close:

; Выводим сообщение о закрытии устройства

mov ax,cs mov ds,ax mov si,offset closemsg call dpc

jmp quit

;=================================================== quit: or es:word ptr [bx]+3,100h pop bp pop di pop si pop dx pop cx pop bx pop ax pop ds pop es ret

;=================================================== parm_off dw ? ; Смещение строки параметров parm_seg dw ? ; Сегмент строки параметров

pc_type dw ? ; Область памяти для сохранения int_num dw ? ; значений параметров out_port dw ? inp_port dw ? ctrl_inp_port dw ? ctrl_out_port dw ?

;===================================================;** ; ;.Name INTERRUPT ;.Title Обработчик прерывания ;.Synopsis ;- ; int <NN> ; ; Вход: NN - Номер прерывания, заданный в файле ;CONFIG.SYS ; AH - Номер выполняемой функции: ; 0 - операция записи; ; 1 - операция чтения ; BH - Адрес (0...7Fh) ; BL - Данные для записи (0...FFh) ; Выход: BL - Прочитанные данные ;- ;.Description ;- ; Прерывание вызывается командой INT <NN> с ;параметрами: ; ; Вход: NN - Номер прерывания, заданный в файле ;CONFIG.SYS ; AH - Номер выполняемой функции: ; 0 - операция записи; ; 1 - операция чтения ; BH - Адрес (0...7Fh) ; BL - Данные для записи (0...FFh) ; Выход: BL - Прочитанные данные ;- ;.Returns ; BL - Прочитанные данные ;.Version 1.00 (c)Copyright Frolov A., 1990 ;- ;**

interrupt: push ax push cx push dx push bp push si push di push ds push es

cmp ah,0 ; команда записи jz int_write cmp ah,1 ; команда чтения jz int_read

; Обработка неизвестной команды

@@out_ch 13,10,'?','?','?',13,10

; Устанавливаем признак ошибки

mov ax,0ffffh jmp int_exit

int_write:

; Выводим сообщение о приходе прерывания, ; предназначенного для записи

@@out_ch 13,10,'W','R','I','T','E',13,10

mov ax,0 jmp int_exit

int_read:

; Выводим сообщение о приходе прерывания, ; предназначенного для чтения

@@out_ch 13,10,'R','E','A','D',13,10

; Имитация чтения, всегда возвращается значение 55h

mov bl,55h mov ax,0 jmp int_exit

int_exit: pop es pop ds pop di pop si pop bp pop dx pop cx pop ax

iret

;=================================================== ; Процедура выводит на экран строку ; символов в формате ASCIIZ

dpc proc near push si dpc_loop: cmp ds:byte ptr [si],0 jz end_dpc mov al,ds:byte ptr [si] @@out_ch al inc si jmp dpc_loop

end_dpc: pop si ret dpc endp

;=================================================== hello db 13,10,'+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+' db 13,10,'¦ *DEVDRV* (C)Frolov A., 1990 ¦' db 13,10,'+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+' db 13,10,0

outmsg DB 13,10,'___ Вывод на устройство DEVDRIVR ___',0 inpmsg DB 13,10,'___ Ввод с устройства DEVDRIVR ___',0

openmsg db 13,10,'___ Открываем DEVDRIVR ___',0 closemsg db 13,10,'___ Закрываем DEVDRIVR ___',0

inpmsg_nd DB 13,10 DB '___ ND-ввод с устройства DEVDRIVR ___',0 statmsg_i DB 13,10 DB '___ Чтение состояния ввода DEVDRIVR ___',0 statmsg_o DB 13,10 DB '___ Чтение состояния вывода DEVDRIVR ___',0

errmsg DB 13,10 DB '___ Команда не поддерживается DEVDRIVR ___',0

;=================================================== E_O_P: ;Метка конца программы

initialize:

lea ax,E_O_P ;смещение конца программы в AX mov es:word ptr [bx]+14,ax ;помещаем его в заголовок mov es:word ptr [bx]+16,cs ;

mov ax,es:word ptr [bx]+18 ;смещение строки ; параметров mov cs:parm_off,ax mov ax,es:word ptr [bx]+20 ;сегмент строки ; параметров mov cs:parm_seg,ax

; Стираем экран

mov dh,18h mov dl,80h

xor cx,cx mov bh,7 xor al,al mov ah,6 int 10h

; Устанавливаем курсор в левый верхний угол экрана

mov bh,0 xor dx,dx mov ah,2 int 10h

; Выводим сообщение

mov ax,cs mov ds,ax mov si,offset hello call dpc

; Раскодируем строку параметров и проверяем ; корректность заданных параметров

push cs pop ds

mov bx, cs:parm_off ; ES:BX - адрес строки ; параметров mov ax, cs:parm_seg mov es, ax

; Адрес начала области параметров

mov bp, OFFSET cs:pc_type

; Анализируем параметры

call parm jc parm_errors

; Устанавливаем вектор прерывания с номером, ; заданным в строке параметров

push cs pop ds mov dx,OFFSET cs:interrupt mov ax,cs:int_num mov ah,25h int 21h

jmp quit

parm_errors:

; Если параметры заданы с ошибкой, ; установку драйвера не производим.

mov ax,cs:req_seg ;ES:BX указывают на заголовок ; запроса mov es,ax mov bx,cs:req_off

lea ax,devdrv ;смещение начала драйвера mov es:word ptr [bx]+14,ax ;помещаем его в заголовок mov es:word ptr [bx]+16,cs ;

jmp quit

;=================================================== parm proc near

xor si, si ; индекс в строке параметров

next_chr: mov al, BYTE PTR es:[bx][si] cmp al, 0ah ; проверки на конец je parm_br ; строки параметров cmp al, 0dh je parm_br cmp al, 0h jz parm_br

; Копируем очередной байт строки параметров в буфер

mov BYTE PTR cs:parm_buffer[si], al inc si jmp next_chr

; Закрываем скопированную строку параметров нулем

parm_br: mov BYTE PTR cs:parm_buffer[si], 0

; Подготавливаем регистры для вызова программы ; анализа параметров и проверяем правильность ; заданных параметров

mov dx, OFFSET sep mov cl, 6 mov bx, OFFSET cs:parm_buffer

call get_parm jc err_msg

mov ax,cs:pc_type cmp ax,0 jz model_is_valid cmp ax,1 jz model_is_valid

jmp err_msg

model_is_valid:

; Если параметры заданы правильно, ; выводим их значения на экран

mov si, OFFSET msg1 call dpc mov ax,cs:pc_type call print_word

mov si, OFFSET msg2 call dpc mov ax,cs:int_num call print_word

mov si, OFFSET msg3 call dpc mov ax,cs:out_port call print_word

mov si, OFFSET msg4 call dpc mov ax,cs:inp_port call print_word

mov si, OFFSET msg41 call dpc mov ax,cs:ctrl_inp_port call print_word

mov si, OFFSET msg42 call dpc mov ax,cs:ctrl_out_port call print_word

@@out_ch 13,10,13,10 clc jmp end_of_parm err_msg:

; Если были ошибки в параметрах, выводим ; сообщение об ошибке, ; саму ошибочную строку параметров ; и ожидаем нажатия на любую клавишу. ; На выходе устанавливаем флаг CARRY

mov si, OFFSET msg5 call dpc

mov ds,cs:parm_seg mov si,cs:parm_off call dpline

mov ax,cs mov ds,ax mov si, OFFSET msg6 call dpc

mov ax,0 int 16h stc end_of_parm: ret

parm_buffer db 100 DUP (?)

sep db " ",0 msg1 db 13,10,"Personal Computer Type ........ ",0 msg2 db 13,10,"Used Interrupt Number ........ ",0 msg3 db 13,10,"Device Input Port ........ ",0 msg4 db 13,10,"Device Output Port ........ ",0 msg41 db 13,10,"Device Inp Control Port ........ ",0 msg42 db 13,10,"Device Out Control Port ........ ",0

msg5 db 13,10,"Driver Parameters Error!",13,10,0

msg6 db 13,10,13,10," Press any key...",13,10,0

parm endp

;** ; ;.Name get_parm ;.Title Разбор строки параметров. ;.Synopsis ; ; ds:bx - исходная строка, закрытая нулем ; ds:dx - строка из сепараторов, закрытая ; нулем ; ds:bp - буфер параметров ; cx - число параметров ; ;.Description ; Исходная строка ds:bx, разделенная ; сепараторами ds:dx, состоящая из cx ; параметров и начинающаяся с полного пути ; программы, разбирается на слова, параметры - ; шестнадцатеричные цифры. Двоичные слова, ; соответствующие параметрам, последовательно ; заносятся в буфер параметров ds:bp. ; ;.Returns В случае ошибки устанавливается флаг ; переноса. ; ;.Version 1.00 (c)Copyright Frolov G., 1990 ;**

get_parm proc near

push bx push cx push ax push si

xor ch, ch xor ax, ax mov si, ax

call strtoc jc parm_end parm_loop: mov ax, 22h call strtoc jc parm_end call hex_to_bin jc parm_end mov ds:[bp][si], ax inc si inc si loop parm_loop parm_end: pop si pop ax pop cx pop bx

ret

get_parm endp

;** ; ;.Name strtoc ;.Title Выделяет очередное слово из строки. ;.Synopsis ; ; 1) при первом обращении к процедуре: ; Вход: ; ax = 0 ; ds:bx - исходная строка, закрытая нулем ; ds:dx - строка из сепараторов, закрытая ; нулем ; Выход: ; ds:bx - подстрока до первого разделителя, ; закрытая нулем ; 2) при последующих обращениях ; Вход: ; ax != 0 ; ds:dx - строка из сепараторов, закрытая ; нулем ; Выход: ; ds:bx - подстрока до следующего ; разделителя, закрытая нулем ; ;.Description При первом вызове выделяет из строки первое ; слово до разделителя. При повторном вызове ; возвращает указатель на следующее слово в ; исходной строке. Если все слова из строки ; уже выделены, устанавливается флаг ; переноса. ; ;.Version 1.00 (c)Copyright Frolov G., 1990 ;**

strtoc proc near

push bp push di

mov space, 0

cmp ax, 0 jz first

mov bx, cs:ds1_off mov ax, cs:ds1_seg mov ds, ax

first: cmp BYTE PTR ds:[bx], 0 jz error

mov bp, bx str_begin: mov di, dx

compe: mov ah, BYTE PTR ds:[bp] cmp ah, 0 jz lab cmp BYTE PTR ds:[di], ah jne next mov BYTE PTR ds:[bp], 0 inc bp inc BYTE PTR cs:space jmp str_begin

lab: mov WORD PTR cs:ds1_off, bp mov ax, ds mov WORD PTR cs:ds1_seg, ax jmp end_proc

next: inc di cmp BYTE PTR ds:[di], 0 jnz compe cmp BYTE PTR cs:space, 0 jnz lab inc bp jmp str_begin

error: stc end_proc: pop di pop bp

ret

ds1_off dw ? ds1_seg dw ? space db ?

strtoc endp

;** ; ;.Name hex_to_bin ;.Title Преобразует hex строку в двоичное число. ;.Synopsis ; ; Вход: ; ds:bx - исходная строка, закрытая нулем ; Выход: ; ax - соответствующее строке число ; ;.Description Преобразует строку из ascii символов в hex ; форме в ее 16-битовый двоичный эквивалент. ; В случае переполнения или если строка ; содержит символы, не равные 0..9, A..F, a..f ; устанавливается флаг переноса. ; ;.Version 1.00 (c)Copyright Frolov G., 1990 ;** hex_to_bin PROC NEAR

push bp push si push dx

xor ax, ax mov bp, bx

begin: cmp BYTE PTR ds:[bp], 0h jz end_pro call hex jc h_error

mov si, 10h xor dx, dx mul si cmp dx, 0 jnz h_error

add ax, bx inc bp jmp begin

h_error: stc end_pro: pop dx pop si pop bp

ret hex_to_bin endp

hex proc near xor bh, bh mov bl, BYTE PTR ds:[bp]

cmp bl, '0' jb hex_error cmp bl, '9' ja next_big and bx, 0fh jmp ok

next_big: cmp bl, 'A' jb hex_error cmp bl, 'F' ja next_small sub bl, 37h jmp ok

next_small: cmp bl, 'a' jb hex_error cmp bl, 'f' ja hex_error sub bl, 57h jmp ok

hex_error: stc ok: ret

hex endp

;** ; ;.Name dec_to_bin ;.Title Преобразует dec строку в двоичное число. ;.Synopsis ; ; Вход: ; ds:bx - исходная строка, закрытая нулем ; Выход: ; ax - соответствующее строке число ; ;.Description Преобразует строку из ascii символов в dec ; форме в ее 16-битовый двоичный эквивалент. В ; случае переполнения или если строка содержит ; символы, не равные 0..9, устанавливается флаг ; переноса. ; ;.Version 1.00 (c)Copyright Frolov G., 1990 ;** dec_to_bin proc near

push bp push si push dx

xor ax, ax mov bp, bx

d_begin: cmp BYTE PTR ds:[bp], 0h jz d_end_pro

cmp BYTE PTR ds:[bp], '0' jb d_error cmp BYTE PTR ds:[bp], '9' ja d_error mov si, 10 xor dx, dx mul si cmp dx, 0 jnz d_error mov bl, BYTE PTR ds:[bp] and bx, 0fh add ax, bx inc bp jmp d_begin d_error: stc d_end_pro: pop dx pop si pop bp

ret

dec_to_bin endp

print_word proc near ;-------------------- push ax push bx push dx ; push ax mov cl,8 rol ax,cl call byte_to_hex mov bx,dx @@out_ch bh @@out_ch bl ; pop ax call byte_to_hex mov bx,dx @@out_ch bh @@out_ch bl ; pop dx pop bx pop ax ret print_word endp

byte_to_hex proc near ;-------------------- ; al - input byte ; dx - output hex ;-------------------- push ds push cx push bx ; lea bx,tabl mov dx,cs mov ds,dx ; push ax and al,0fh xlat mov dl,al ; pop ax mov cl,4 shr al,cl xlat mov dh,al ; pop bx pop cx pop ds ret ; tabl db '0123456789ABCDEF' byte_to_hex endp

;======================================================= dpline proc near push si dpline_loop: cmp ds:byte ptr [si],0dh jz end_dpline cmp ds:byte ptr [si],0ah jz end_dpline

mov al,ds:byte ptr [si] @@out_ch al inc si jmp dpline_loop

end_dpline: pop si ret dpline endp

devdrv ENDP

END devdrv

Для работы с этим драйвером и демонстрации его основных возможностей мы подготовили следующую программу:



Содержание раздела