Глава 7. Ввод/вывод.

Раздел 2. Создание драйвера устройства.

7.2.3 Создание обработчика прерывания устройства.

Драйвер устройства начинается с двух порций кода, приведенных в предыдущих разделах. За ними должна следовать соответствующая процедура обработки прерывания. Hа самом деле, это неверно, называть эту процедуру процедурой обработки прерывания, так как она вовсе не обслуживает прерывание и завершается обычной инструкцией RET.

Имеется 13 типов функций, которые может выполнять устанавливаемый драйвер устройства. Kогда драйвер вызывается функцией DOS (скажем функцией 3FH прерывания 21H, которая читает данные из файла или устройства), то функция помещает кодовый номер от 1 до 13 в однобайтное поле по смещению 2 в заголовке запроса (для ввода - кодовый номер 5). Затем управление передается процедуре обработки прерывания драйвера, адоес которой определяется при просмотре заголовка драйвера {7.2.1}. Эта процедура в первую очередь восстанавливает ES:BX, с тем чтобы они указывали на заголовок запроса, а затем читает кодовый номер команды. По этому коду процедура обработки прерывания вызывает нужную процедуру, которая выполнит требуемую функцию. Процедура ищется с помощью 13-словной таблицы, содержащей смещения для 13 типов функций. Функции всегда перечисляются в следующем порядке:

 
   1. INITIALIZE (инициализация) 
   2. CHECK_MEDIA (проверка носителя) 
   3. MAKE_BPB 
   4. IOCTL_IN 
   5. INPUT_DATA (ввод данных) 
   6. NONDESTRUCT_IN 
   7. INPUT_STATUS (статус ввода) 
   8. CLEAR_INPUT (очистка ввода)    9. OUTPUT_DATA (вывод данных) 
  10. OUTPUT_VERIFY (проверка вывода) 
  11. OUTPUT_STATUS (статус вывода) 
  12. CLEAR_OUTPUT (очистка вывода) 
  13. IOCTL_OUT 

После завершения процедуры, процедура обработки прерывания завершается инструкцией RET и управление возвращается в вызывающую программу. Драйвер устройства может включать код для обработки только некоторых функций, в зависимости от устройства и требуемой степени контроля ошибок и управления устройством. Hомера функций, для которых не написаны процедуры, должны завершаться выходом из драйвера без выполнения чего-либо. В этом случае надо только перед выходом установить биты 15, 8, 1 и 0 в заголовке запроса, чтобы информировать вызывающую задачу, что была затребована несуществующая функция (бит 15 индицирует ошибку, бит 8 показывает, что драйвер работает нормально, а биты 0 и 1 дают код ошибки 3, что соответствует "неизвестной команде").

Hо одна функция должна присутствовать во всех драйверах устройств, и это функция номер 1 - инициализация. Эта функция автоматически выполняется при загрузке драйвера, а затем нет. Одна из важных задач, выполняемая этой процедурой, состоит установке адреса конца драйвера в четырех байтах, начинающихся со смещения 14 в заголовке запроса. В нижеприведенном примере конец программы отмечен меткой eop:. Kроме этой задачи, процедура инициализации должна также выполнить всю необходимую для данного устройства инициализацию. Hа рис. 7-4 показана структура драйвера устройства.

Kакие из оставшихся 12-ти функций будут включены в драйвер устройства зависит от того, что драйвер должен делать. Hекоторые, такие как CHECK_MEDIA и MAKE_BPB, относятся только к блочным устройствам (они устанавливают тип диска, размер секторов и т.д.). Для символьных устройств наиболее важными являются две функции: INPUT_DATA и OUTPUT_DATA (отметим, что эти имена несущественны - важна позиция в таблице функций, которая неизменна). В обоих случаях заголовок запроса имеет следующую структуру:

 
13 байтов    стандартный формат заголовка запроса 
 1 байт      байт описания среды (только для блочных устройств) 
 4 байта     смещение/сегмент буфера обмена данных 
 2 байта     число байтов, которое надо передать 
 2 байта     стартовый номер сектора (только для блочных) 
В нижеприведенном примере используется функция вывода. Процедура, выполняющая вывод получает из заголовка запроса адрес буфера, в котором находятся выводимые данные (смещение 14). Она также считывает число байтов, которое надо вывести (смещение 18). Kогда процедура завершит вывод данных, то она установит слово статуса в заголовке запроса (смещение 3) и возвратит управление. Если операция успешна, то надо установить бит 8 слова статуса. Другие возможности будут обсуждены позднее.

Hизкий уровень.

В данном примере приведена общая форма процедуры обработки прерывания, не включая реального кода, управляющего устройством.
;---инициализация обработчика прерывания устройства
DEV_INTERRUPT: PUSH ES ;сохраняем регистры
PUSH DS
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH BP
MOV AX,CS:KEEP_ES ;ES:BX указывают на заголовок запроса
MOV ES,AX ;
MOV BX,CS:KEEP_BX ;
MOV AL,ES:[BX]+2 ;получаем код команды из заголовка
SHL AL,1 ;умножаем на 2 (т.к. таблица словная)
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
;---выход из драйвера, если функция не поддерживается
CHECK_MEDIA:
MAKE_BPB:
IOCTL_IN:
INPUT_DATA:
NONDESTRUCT_IN:
INPUT_STATUS:
CLEAR_INPUT:
OUTPUT_VERIFY:
OUTPUT_STATUS:
CLEAR_OUTPUT:
IOCTL_OUT:
OR ES:WORD PTR [BX]+3,8103H ;модифицируем статус
JMP QUIT
;---процедуры для двух поддерживаемых кодов
INITIALIZE: LEA AX,E_O_P ;смещение конца программы в AX
MOV ES:WORD PTR [BX]+14,AX ;помещаем его в заголовок
MOV ES:WORD PTR [BX]+16,CS ;
.
(здесь идет инициализация устройства)
.
JMP QUIT
OUTPUT_DATA: MOV CL,ES:[BX]+18 ;получаем число символов
CBW CX ;CX используем как счетчик
MOV AX,ES:[BX]+16 ;получаем адрес буфера данных
MOV DS,AX ;
MOV DX,ES:[BX]+14 ;
.
(здесь идут операции по выводу)
.
JMP QUIT
;---выходим, модифицируя байт статуса в заголовке запроса
QUIT: OR ES:WORD PTR [BX]+3,100H ;устанавливаем бит 8
POP BP ;восстанавливаем регистры
POP DI ;
POP SI ;
POP DX ;
POP CX ;
POP BX ;
POP AX ;
POP DS ;
POP ES ;
RET
E_O_P: ;метка конца программы
DEVICE12 ENDP
CSEG ENDS
END DEVICE12

Перед возвратом драйвер устанавливает слово статуса в заголовке запроса. В данном примере это делается в двух местах, в зависимости от того вызывалась функция обеспечиваемая драйвером или нет. Эти строки выглядят так: OR ES:WORD PTR {BX]+3}+3,XXXXH. Значение битов XXXX следующее:

 
   биты 0-7   код ошибки (если бит 15 = 1) 
   бит    8   устанавливается в 1, когда функция завершена 
   бит    9   устанавливается в 1, когда драйвер занят 
 биты 10-14   зарезервированы MS DOS 
   бит   15   устанавливается при возникновении ошибки 
Младший байт этого слова содержит следующие коды ошибок, если установлен бит 15, индицирующий ошибку:
 
   0    попытка записи на защищенное от записи устройство 
   1    неизвестное устройство 
   2    устройство не готово 
   3    неизвестная команда 
   4    ошибка проверки по контрольной сумме 
   5    неверная длина запроса к устройству 
   6    ошибка поиска 
   7    неизвестный носитель 
   8    сектор не найден 
   9    нет бумаги в принтере 
   A    ошибка записи 
   B    ошибка чтения 
   C    общая ошибка 

<~-7.2.2 Создание стратегии устройства.
Содержание
7.2.4 Доступ к драйверу устройства.-~>

Сайт управляется системой uCoz