Справочник программиста на персональном компьютере фирмы IBM. Ввод/вывод - Создание обработчика прерывания устройства
ОГЛАВЛЕНИЕ
7.2.3 Создание обработчика прерывания устройства.
Драйвер устройства начинается с двух порций кода, приведенных
в предыдущих разделах. За ними должна следовать соответствующая
процедура обработки прерывания. На самом деле, это неверно, назы-
вать эту процедуру процедурой обработки прерывания, так как она
вовсе не обслуживает прерывание и завершается обычной инструкцией
RET.
Имеется 13 типов функций, которые может выполнять устанавли-
ваемый драйвер устройства. Когда драйвер вызывается функцией 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 и управление возвращается в вызываю-
щую программу. Драйвер устройства может включать код для обработ-
ки только некоторых функций, в зависимости от устройства и тре-
буемой степени контроля ошибок и управления устройством. Номера
функций, для которых не написаны процедуры, должны завершаться
выходом из драйвера без выполнения чего-либо. В этом случае надо
только перед выходом установить биты 15, 8, 1 и 0 в заголовке
запроса, чтобы информировать вызывающую задачу, что была затребо-
вана несуществующая функция (бит 15 индицирует ошибку, бит 8
показывает, что драйвер работает нормально, а биты 0 и 1 дают код
ошибки 3, что соответствует "неизвестной команде").
Но одна функция должна присутствовать во всех драйверах уст-
ройств, и это функция номер 1 - инициализация. Эта функция авто-
матически выполняется при загрузке драйвера, а затем нет. Одна из
важных задач, выполняемая этой процедурой, состоит установке
адреса конца драйвера в четырех байтах, начинающихся со смещения
14 в заголовке запроса. В нижеприведенном примере конец программы
отмечен меткой eop:. Кроме этой задачи, процедура инициализации
должна также выполнить всю необходимую для данного устройства
инициализацию. На рис. 7-4 показана структура драйвера устройст-
ва.
Какие из оставшихся 12-ти функций будут включены в драйвер
устройства зависит от того, что драйвер должен делать. Некоторые,
такие как CHECK_MEDIA и MAKE_BPB, относятся только к блочным
устройствам (они устанавливают тип диска, размер секторов и
т.д.). Для символьных устройств наиболее важными являются две
функции: INPUT_DATA и OUTPUT_DATA (отметим, что эти имена несу-
щественны - важна позиция в таблице функций, которая неизменна).
В обоих случаях заголовок запроса имеет следующую структуру:
13 байтов стандартный формат заголовка запроса
1 байт байт описания среды (только для блочных устройств)
4 байта смещение/сегмент буфера обмена данных
2 байта число байтов, которое надо передать
2 байта стартовый номер сектора (только для блочных)
В нижеприведенном примере используется функция вывода. Процедура,
выполняющая вывод получает из заголовка запроса адрес буфера, в
котором находятся выводимые данные (смещение 14). Она также счи-
тывает число байтов, которое надо вывести (смещение 18). Когда
процедура завершит вывод данных, то она установит слово статуса в
заголовке запроса (смещение 3) и возвратит управление. Если опе-
рация успешна, то надо установить бит 8 слова статуса. Другие
возможности будут обсуждены позднее.
Низкий уровень.
В данном примере приведена общая форма процедуры обработки
прерывания, не включая реального кода, управляющего устройством.
;---инициализация обработчика прерывания устройства
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,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 общая ошибка