| Операционная система MS-DOS© Александр Фролов, Григорий ФроловТом 1, книги 1-2, М.: Диалог-МИФИ, 1991. 
 6.5. Функции загружаемого драйвераКак уже было сказано, номер функции, которую должен выполнить драйвер, передается операционной системой через поле cmd заголовка запроса. Рассмотрим отдельные функции. 1 - Проверка замены носителя данных 3 - IOCTL чтение 4 - Чтение 5 - Неразрушающее чтение без ожидания 6 - Проверить состояние устройства ввода 7 - Сброс буфера устройства ввода 8 - Запись 10 - Проверить состояние устройства вывода 11 - Сброс буфера устройства вывода 12 - IOCTL запись 13 - Открыть устройство 14 - Закрыть устройство 15 - Проверка сменяемости диска 19 - Функции управления вводом/выводом (IOCTL) 23 - Получить активное логическое устройство 24 - Установить активное логическое устройство # 0 - Инициализация драйвераЭта функция выполняется только один раз при загрузке драйвера и подключении его к операционной системе. Функция инициализации должна поддерживаться любым драйвером, так как она сообщает операционной системе сведения, необходимые DOS для правильного подключения и использования драйвера. Приведем формат запроса для команды инициализации: 
 При инициализации драйвер символьного устройства сохраняет в своей внутренней области данных параметры инициализации, используя адрес parm. Если параметры содержат числовые величины, программа инициализации может произвести их перекодировку и сохранить значения в двоичном формате. Затем драйвер может выполнить инициализацию обслуживаемого физического устройства ввода/вывода, инициализацию своих внутренних переменных, вывести на экран какие-либо сообщения либо даже запросить у оператора дополнительные данные - функция инициализации может пользоваться для организации диалога с оператором и других действий функциями прерывания 21h с номерами от 01h до 0Ch, 25h, 30h, 35h и функциями BIOS. Кроме этого, драйвер должен заполнить поле end_addr адресом конца резидентной части драйвера. Так как программа инициализации выполняется только один раз, обычно ее располагают в конце драйвера и для экономии памяти не оставляют резидентной. Драйверы блочных устройств дополнительно должны возвратить DOS количество обслуживаемых устройств (в поле n_units) и указатель на массив указателей на блоки BPB (в поле parm). Количество устройств используется DOS для определения логических имен устройств. Например, если Ваш драйвер обслуживает три логических устройства, и на момент его загрузки в системе имеются устройства A:, B: и C:, то устройства, обслуживаемые Вашим драйвером, получат имена D:, E: и F:. Количество устройств необходимо указывать также и в заголовке драйвера, в первом байте поля имени устройства dev_name. Для каждого логического устройства драйвер должен содержать так называемый блок параметров BIOS (BIOS Parameter Block) BPB. Блок BPB содержится в загрузочном секторе диска и содержит информацию, необходимую BIOS для работы с диском. Приведем формат BPB: 
 Подробно формат и назначение полей BPB будут описаны в разделе, посвященном файловой системе DOS. Приведем фрагмент исходного текста драйвера, возвращающего при инициализации указатель на массив BPB: 
        lea     dx,bpb_ptr
        mov     es:[bx+18],dx
        mov     es:[bx+20],cs
        . . . . . . . . . .
В этом примере предполагается, что ES:BX содержит адрес заголовка запроса. Область данных может содержать, например, такое описание bpb_ptr: 
bpb:            DW      512     ; количество байтов на сектор
                DB      1       ; количество секторов на кластер
                DW      1       ; зарезервировано секторов
                DB      2       ; количество копий FAT
                DW      64      ; максимальное количество файлов 
                                ; в корневом каталоге
                DW      360     ; общее число секторов на диске
                DB      0FCh    ; описатель среды
                DW      2       ; количество секторов в FAT
;
bpb_ptr DW      bpb         ; таблица для трех одинаковых
                DW      bpb ; логических устройств
                DW      bpb
Если Ваш драйвер работает с несколькими разными по параметрам логическими устройствами, для каждого устройства необходимо подготовить свой BPB и занести его адрес в соответствующее порядковому номеру устройства место таблицы указателей на блоки BPB. Какие действия должна выполнить функция инициализации, если выяснилось, что по тем или иным причинам установка драйвера невозможна? Например, ошибочно заданы параметры, не хватает оперативной памяти, других ресурсов или, наконец, отсутствует само обслуживаемое устройство. Драйвер символьного устройства при этом может указать в качестве конечного адреса резидентной части программы адрес начала драйвера, т.е. адрес заголовка драйвера. Размер резидентной части при этом будет равен нулю. Блочные драйверы дополнительно должны записать ноль в поле количества обслуживаемых логических устройств n_units. В обоих случаях включения драйвера в состав операционной системы не произойдет. Приведем пример простейшего драйвера символьного устройства, который обслуживает только команду инициализации. Фактически этот драйвер не работает ни с каким физическим устройством. Он просто стирает содержимое экрана при инициализации, выводит сообщение и ожидает нажатия оператором любой клавиши. После нажатия драйвер завершает свою работу без включения себя в состав DOS. Исходный текст драйвера: 
          .MODEL tiny
          .CODE        ; Драйвер состоит из одного
                                ; сегмента кода
          org 0        ; Эта строка может отсутствовать
          include sysp.inc
;========================================================
simple    PROC far  ; Драйвер - это FAR-процедура
;========================================================
E_O_P:              ;Метка конца программы,
                                ;устанавливаем ее в начало
                                ;драйвера, т.к. не надо
                                ;оставлять драйвер резидентно
                                ;в памяти
; Заголовок драйвера
          dd   0ffffffffh       ;адрес следующего драйвера
          dw   8000h            ;байт атрибутов
          dw   dev_strategy     ;адрес процедуры стратегии
          dw   dev_interrupt    ;адрес процедуры прерывания
          db   'SIMPLE_D'       ;имя устройство (дополненное
                                            ;пробелами)
;========================================================
; Программа стратегии
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
; Выход из драйвера, если функция не поддерживается
check_media:
make_bpb:
ioctl_in:
nondestruct_in:
input_status:
clear_input:
output_verify:
output_status:
clear_output:
ioctl_out:
Removable_media:
Device_open:
Device_close:
output_data:
input_data:
        or   es:word ptr [bx]+3,8103h
     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
;========================================================
; Процедура выводит на экран строку
; символов в формате 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,'¦  *SIMPLE* (C)Frolov A., 1990   ¦'
        db 13,10,'++'
        db 13,10
        db 13,10,'Hit any key...'
        db 13,10,0
;========================================================
initialize:
   lea  ax,E_O_P      ;смещение конца программы в AX
   mov  es:word ptr [bx]+14,ax   ;помещаем его в заголовок
   mov  es:word ptr [bx]+16,cs   ;
; Стираем экран
        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
; Ожидаем нажатия на любую клавишу
        mov   ax,0
        int   16h
        jmp  quit
simple   ENDP
            END simple
В программе используется макро @@out_ch, описанное в файле sysp.inc и предназначенное для вывода символов на экран дисплея. Файл sysp.inc имеется на дискете, прилагающейся к книге. Приведем текст макро @@out_ch: 
@@out_ch  MACRO c1,c2,c3,c4,c5,c6,c7,c8,c9,c10
                mov   ah,02h
                IRP   chr,<c1,c2,c3,c4,c5,c6,c7,c8,c9,c10>
                IFB   <chr>
                EXITM
                ENDIF
                mov   dl,chr
                int   21h
                ENDM
                ENDM
Текст этого драйвера транслировался при помощи ассемблера, входящего в состав Quick C 2.01. Полученный объектный модуль обрабатывался пакетным файлом: link %1.obj; exe2bin %1.exe %1.sys Вы можете также использовать макроассемблер MASM версии 5.0 или более поздней версии. Нетрудно заметить, что процедура получения загрузочного модуля драйвера действительно похожа на процедуру получения COM-программы. Сообщение редактора об отсутствии сегмента стека следует проигнорировать, сегмента стека действительно нет и быть не может, так как драйвер состоит из единственного сегмента кода. Для испытания этого и других драйверов запишите драйвер в корневой каталог системной дискеты (с которой можно загрузить операционную систему) и поместите в файл CONFIG.SYS, находящийся на этой дискете строку: DEVICE=a:\simple.sys Когда Ваш драйвер будет отлажен, его можно переписать на диск и подключить к файлу CONFIG.SYS, находящемуся на диске С:. # 1 - Проверка замены носителя данныхЭту команду DOS выдает драйверу, когда она хочет проверить, не произошла ли замена носителя данных, например, замена дискеты. Вообще говоря, довольно трудно определить, заменил ли оператор дискету или там все еще стоит старая, с которой DOS начала работу. Наиболее достоверные результаты можно было бы получить от аппаратуры, если бы она следила за заменой дискет. Но когда аппаратура не отслеживает замены дискет, приходится анализировать метку диска или как-то иначе определять, поменялась дискета или нет. Метка диска - слабое подспорье в этом вопросе, так как обычно при форматировании дискет пользователь не задает метку. Однако MS-DOS 4.01 при форматировании автоматически записывает на дискету уникальный серийный номер, который можно использовать для проверки факта замены дискеты в приемном кармане дисковода. Можно отслеживать время доступа к диску и считать, что для смены носителя нужно не менее двух секунд. К чему может привести некорректный ответ DOS на вопрос о замене дискеты? К очень тяжелым последствиям. Возможны три варианта ответа на вопрос о замене дискеты: 
 Если DOS получила ответ, что дискета не заменена, она продолжает работу, которой занималась раньше. Если пришел ответ, что носитель данных заменен, DOS выдает драйверу команду с номером 2. Это запрос драйверу на построение нового BPB. Все буфера, связанные с данным устройством, при этом очищаются, и, если они не были записаны на диск, может произойти потеря информации. Осуществляется чтение каталога и FAT. Если пришел ответ, что неизвестно, сменили ли носитель данных или нет, действия DOS зависят от наличия в данный момент непустых дисковых буферов. Если непустых буферов нет, DOS считает, что носитель сменился, и ведет себя так, как это было описано раньше. Если есть непустые буфера, DOS записывает буфера на диск. При этом структура информации на новой дискете может оказаться полностью нарушенной. Приведем формат запроса для команды проверки замены носителя: 
 Если драйвер поддерживает функцию проверки замены среды носителя данных (бит 11 слова атрибута установлен в 1) и оказалось, что произошла замена диска, драйвер должен вернуть в поле vol_id указатель на область памяти, содержащую предыдущую метку тома в формате ASCIIZ. Если метка тома не используется драйвером, а бит 11 слова атрибутов установлен, необходимо вернуть указатель на строку "NO_NAME", закрытую двоичным нулем. Байт-описатель среды media классифицирует используемую среду носителя данных, но делает это неоднозначно. Мы приведем характерные для этого байта параметры дисков: 
 Более подробно все, что касается дисков, будет изложено в разделах, посвященных файловой системе. # 2 - Построить блок BPBЭта команда имеет смысл только для блочных устройств и вызывается после предыдущей команды, если произошла смена носителя данных. Драйвер должен возвратить адрес нового блока BPB. Формат запроса для этой команды: 
 Операционная система MS-DOS версии 3.0 и более поздних версий включает поддержку аппаратных средств проверки смены носителя данных. Если драйвер обнаружил, что смена носителя данных произошла неправильно, в неподходящий момент времени, он может вернуть ошибку с кодом 15 (неразрешенная замена диска). # 3 - IOCTL чтение, 4 - Чтение, 8 - Запись, 9 - Запись с проверкой,12 - IOCTL запись, 16 - Вывод, пока не занятоВсе эти команды используются для чтения/записи информации из устройства или в устройство соответственно. Они имеют практически одинаковый формат запроса, поэтому мы их будем рассматривать вместе. В операциях чтения или записи участвуют сектора для блочных устройств и байты для символьных устройств. Область запроса содержит указатель на буфер обмена, куда нужно поместить прочитанные данные или откуда взять данные для записи, поле количества записываемых/читаемых байт для символьных устройств или секторов для блочных. Кроме того, драйвер должен вернуть количество действительно прочитанных или записанных байт/секторов. Приведем формат запроса для этих команд: 
 После выполнения операций чтения или записи драйвер обязательно должен записать в поле count количество действительно переданных байтов для символьных устройств или секторов для блочных. В случае ошибки также требуется запись правильного значения в поле count, недостаточно только установить признак и код ошибки в слове состояния драйвера. Для команды 9 (запись с проверкой) драйвер должен после выполнения записи проверить записанные данные. Если с консоли введена команда DOS VERIFY ON, то для дисковых устройств DOS вместо команды записи 8 использует команду записи с проверкой 9. Драйвер может возвратить количество переданных байтов меньше запрошенного, это само по себе не является ошибкой. Иногда может получиться так, что надо выполнить запись 64 Кбайтов. Такая операция может вызвать переход за границу сегмента в буфере передачи данных. В этом случае драйвер должен проигнорировать лишние байты. Например, надо записать 10000h байтов, распределенных по секторам из буфера с адресом ХХХХ:0001. В этом случае драйвер должен проигнорировать последние два байта. Они будут записаны в следующий раз. IOCTL чтение/запись - это обмен с устройством управляющей информацией. Мы будем подробно говорить об этом ниже. Команда с кодом 16 - "вывод, пока не занято", предназначена для работы с такими устройствами ввода/вывода, которые имеют свой собственный буфер, например, принтеры. Приведем исходный текст программы драйвера, использующего команды ввода и вывода. Для ввода драйвер использует клавиатуру, вывод осуществляется на экран дисплея. 
          .MODEL tiny
          .CODE        ; Драйвер состоит из одного
                       ; сегмента кода
          org 0        ; Эта строка может отсутствовать
          include sysp.inc
;========================================================
iodrv    PROC far         ;драйвер - это FAR-процедура
;========================================================
; Заголовок драйвера
          dd   0ffffffffh       ;адрес следующего драйвера
          dw   8000h            ;байт атрибутов
          dw   dev_strategy     ;адрес процедуры стратегии
          dw   dev_interrupt    ;адрес процедуры прерывания
          db   'IODRIVER'       ;имя устройства (дополненное
                                            ; пробелами)
;========================================================
; Программа стратегии
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
; Выход из драйвера, если функция не поддерживается
check_media:
make_bpb:
ioctl_in:
nondestruct_in:
input_status:
clear_input:
output_verify:
output_status:
clear_output:
ioctl_out:
Removable_media:
Device_open:
Device_close:
        or   es:word ptr [bx]+3,8103h
        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
;========================================================
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
;========================================================
; Процедура выводит на экран строку
; символов в формате 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,'¦   *IODRV* (C)Frolov A., 1990   ¦'
        db 13,10,'++'
        db 13,10,0
outmsg   DB 13,10,'___ Вывод на устройство IODRIVER ___',0
inpmsg   DB 13,10,'___ Ввод с устройства   IODRIVER ___',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   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
        jmp  quit
iodrv   ENDP
                  END iodrv
Для работы с этим драйвером можно использовать приводимую ниже программу, составленную на языке Си. Программа открывает устройство, вводит из него восемь символов, печатает введенные символы на экране и выводит их обратно на устройство: 
#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);
int main(void) {
    char buf[100];
         int io_handle;
         unsigned count;
         // Открываем устройство с именем IODRIVER
         if( (io_handle = open("IODRIVER", O_RDWR)) == - 1 ) {
                // Если открыть не удалось, выводим
                // код ошибки
                printf("Ошибка при открытии устройства %d",errno);
                return errno;
         }
         // Читаем 8 байт из устройства в буфер buf
         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;
        }
        // Закрываем устройство
        close(io_handle);
        exit(0);
}
Эта программа служит примером того, как можно организовать взаимодействие драйвера и прикладной программы, работающей с драйвером. Позже мы приведем пример более сложного драйвера символьного устройства. # 5 - Неразрушающее чтение без ожиданияЭта команда предназначена для выборки одного байта из буфера символьного устройства. Для блочных устройств эта команда не используется. Если в буфере символьного устройства есть байты, которые могут быть прочитаны командой чтения, драйвер возвращает следующий символ, который был бы прочитан. Если в результате проверки выяснится, что в буфере есть символы, драйвер должен установить бит 9 слова состояния устройства (занятость) в 0, в противном случае - в 1. Эта команда используется перед выдачей команды чтения для проверки, есть ли в буфере готовые для чтения данные. Такая проверка позволяет избежать длительного ожидания готовности данных при вводе. Кроме того, команда используется для проверки наличия в буфере клавиатуры символа CTRL-BREAK. Формат запроса для команды 5: 
 # 6 - Проверить состояние устройства ввода.10 - Проверить состояние устройства вывода.Эти команды проверяют состояние устройства ввода и устройства вывода соответственно (только символьные устройства). Для устройства ввода бит занятости слова состояния (бит 9) сбрасывается в ноль, если буфер устройства не пуст и в нем есть готовые для чтения символы. Этот бит устанавливается драйвером в единицу, когда буфер пуст, и последующая команда чтения приведет к ожиданию ввода от устройства, например, к ожиданию нажатия на клавишу. Для устройства вывода бит занятости в слове состояния (бит 9) сбрасывается в ноль, если нет текущих ожидающих готовности устройства запросов на вывод и последующая команда вывода может быть немедленно выполнена. Бит устанавливается в 1, если предыдущий запрос на вывод еще не обработан. Для команд проверки состояния запрос состоит только из заголовка, область переменного формата отсутствует. # 7 - Сброс буфера устройства ввода11 - Сброс буфера устройства выводаЭти функции заставляют драйвер сбросить все текущие запросы на ввод/вывод. Сброс буфера входного устройства используется, например, для удаления всех символов из буфера клавиатуры. После выполнения очистки буферов драйвер выставляет слово состояния и возвращает управление операционной системе. Запрос состоит только из заголовка. # 13 - Открыть устройство14 - Закрыть устройствоДля того чтобы драйвер мог использовать эти команды, бит 11 в слове атрибутов устройства в заголовке драйвера должен быть установлен в 1. Драйверы символьных устройств по этой команде могут посылать инициализирующие последовательности символов на устройства (например, на принтер могут посылаться команды установки типа шрифта, формата бумаги и т.д.) или устанавливать устройство в исходное состояние. Можно также обнаруживать попытки получения многократного доступа к устройству. В этом случае вторая команда открытия должна возвратить ошибку (если многократный доступ к устройству запрещен). Драйвер блочного устройства с помощью этих команд может производить подсчет открытых файлов. Если содержимое счетчика открытых файлов для данного устройства равно 0, то открытых файлов на этом устройстве нет. Если драйвер теперь сбросит все буфера на диск, пользователь сможет заменить диск на другой. Однако если программы открывают файлы без их закрытия, то могут возникнуть ошибки при использовании этого метода. Стандартные устройства CON, AUX, PRN всегда открыты. Запрос для этих команд состоит только из заголовка. # 15 - Проверка сменяемости дискаЭта команда используется только для тех драйверов, в слове атрибутов которых бит 11 установлен в 1. Драйвер должен сообщить DOS, возможна ли замена носителя данных. Например, замена жесткого диска обычно невозможна, хотя есть накопители со сменными жесткими дисками. Драйвер возвращает информацию о возможности замены носителя в бите 9 слова состояния устройства. Значение этого бита, равное 0, драйвер устанавливает, если возможна замена носителя данных, в противном случае устанавливается значение, равное 1. Запрос состоит только из заголовка. # 19 - Функции управления вводом/выводом (IOCTL)Команда с кодом 19 предназначена для выполнения нескольких функций и поддерживается только теми драйверами, у которых в слове атрибутов устройства установлен в 1 бит поддержки IOCTL (бит 14). Эта команда поддерживается DOS версии 3.2 и более поздних версий. Команда используется для выполнения ряда операций с дисками, доступных обычно лишь на уровне BIOS, например, форматирования, чтение/запись секторов по их абсолютному номеру и т.д. Имеется стандартный интерфейс для различных типов дисков, обеспечиваемых драйвером логических дисков DRIVER.SYS. DOS имеет специальную функцию номер 44h прерывания 21h. Эта функция имеет множество подфункций и предназначена для поддержки IOCTL. Очень скоро мы займемся этой функцией DOS, а сейчас приведем формат запроса для команды с кодом 19: 
 # 23 - Получить активное логическое устройство24 - Установить активное логическое устройствоЭти команды обрабатываются только теми драйверами, у которых в слове атрибутов установлен бит 6 - поддержка логических устройств. Команды используются в DOS версии 3.2 и в более поздних версиях. Команды обеспечивают метод опроса номера текущего активного логического устройства на физическом диске или установления активного логического устройства. Приведем формат запроса: 
 По команде 23 (получить активное логическое устройство) драйвер должен поместить идентификатор устройства в поле unit, для устройства А: помещается 1, для В: - 2 и т.д. Если драйвер управляет единственным устройством, он должен записать в поле unit ноль. После обзора команд перейдем к описанию функции 44h прерывания 21h. Эта функция предназначена для управления вводом/выводом и обладает широкими возможностями. 
 | 


![[Назад]](prev.gif)
![[Содеожание]](sod.gif)