Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система MS-DOS

© Александр Фролов, Григорий Фролов
Том 1, книги 1-2, М.: Диалог-МИФИ, 1991.

[Назад] [Содеожание]

6.9. Пример драйвера символьного устройства

Приведем пример драйвера символьного устройства, который Вы можете взять в качестве прототипа своей разработки. Этот драйвер выполняет следующие действия:

  • принимает и анализирует строку параметров из команды "DEVICE=" файла CONFIG.SYS, преобразует параметры из символьной формы в двоичную и проверяет их на корректность;
  • если параметры заданы неправильно, в процессе инициализации выводится сообщение, и драйвер не подключается к операционной системе;
  • драйвер переназначает одно прерывание, номер которого задается в строке параметров;
  • обработчик переназначенного прерывания моделирует выполнение функций ввода, вывода и выполняет обработку неправильной функции;
  • демонстрируется использование функций IOCTL и ввода/вывода, ввод данных драйвер производит с клавиатуры, вывод осуществляет на экран дисплея.

Приведем полный текст драйвера:

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

; Демонстрационный драйвер символьного устройства
;
; 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

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

Работа с драйвером символьного устройства

// Данная прорамма использует прерывание 80h,
// которое устанавливается демонстрационным
// драйвером. Для правильной установки файл
// CONFIG.SYS должен содержать, например,
// такую строку для подключения драйвера:
//
// device=e:\sysprg\devdrv.sys  1 80 378 379 37a 37a
//
// Число 80 означает номер используемого прерывания.


#include <io.h>
#include <conio.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <malloc.h>
#include <errno.h>
#include <dos.h>

int main(void);

union  REGS  inregs, outregs;
struct SREGS segregs;

int main(void) {

         char buf[100], ch;
         int io_handle;
         unsigned count;


         // Открываем устройство с именем DEVDRIVR

         if( (io_handle = open("DEVDRIVR", O_RDWR)) == - 1 ) {

                // Если открыть устройство не удалось, выводим
                // код ошибки

                printf("Ошибка при открытии устройства %d",errno);
                return errno;
         }

         // Читаем 8 байт из устройства в буфер buf

         printf("\nВведите 8 символов с клавиатуры\n");

         if( (count = read(io_handle, buf, 8)) == -1 ) {

                 // Если при чтении произошла ошибка,
                 // выводим ее код

                 printf("Ошибка чтения %d",errno);
            return errno;
        }

        // Закрываем прочитанную строку нулем
        // для последующего вывода функцией printf

        buf[8]=0;

        printf("\n___ Введена строка: %s ___",buf);

        // Выводим только что прочитанные данные
        // обратно на то же устройство

        if( (count = write(io_handle, buf, 8)) == -1 ) {

                 // Если при записи произошла ошибка,
                 // выводим ее код

                 printf("Ошибка записи %d",errno);
            return errno;
        }

        // Вводим строку IOCTL из устройства

        printf("\nВведите строку IOCTL (8 символов): ");

        inregs.h.ah = 0x44;
        inregs.h.al = 2;
        inregs.x.bx = io_handle;
        inregs.x.dx = (unsigned)buf;
        inregs.x.cx = 8;
        intdos( &inregs, &outregs );
        if(outregs.x.cflag == 1) {

                // При ошибке выводим код ошибки

                printf("IOCTL error %x\n",&outregs.x.ax);
                exit(-1);
        }
        buf[8]=0;
        printf("\n___ Введена строка IOCTL: %s ___",buf);

        // Выводим строку IOCTL на устройства из buf

        printf("\nВыведена строка IOCTL: ");

        inregs.h.ah = 0x44;
        inregs.h.al = 3;
        inregs.x.bx = io_handle;
        inregs.x.dx = (unsigned)buf;
        inregs.x.cx = 8;
        intdos( &inregs, &outregs );
        if(outregs.x.cflag == 1) {

                // При ошибке выводим код ошибки

                printf("IOCTL error %x\n",&outregs.x.ax);
                exit(-1);
        }

         printf("\n\n\nПроверяем вызов прерывания."
                          "\n"
                          "\nНажмите любую клавишу...\n\n");
         getch();

         printf("\nКоманда записи:\n");

         inregs.h.ah = 0x0; /* WRITE */
         inregs.h.bh = 0x777;
         inregs.h.bl = 0x13;
         int86( 0x80, &inregs, &outregs );

         printf("\nКоманда чтения:\n");

         inregs.h.ah = 0x1; /* READ */
         inregs.h.bh = 0x776;
         int86( 0x80, &inregs, &outregs );
         ch=outregs.h.bl;

         printf("Полученное значение: %x\n",ch);

         printf("\nНеизвестная команда:\n");

         inregs.h.ah = 0x2; /* ??? */
         int86( 0x80, &inregs, &outregs );

        // Закрываем устройство
        close(io_handle);
        exit(0);
}
[Назад] [Содеожание]