Справочник программиста на персональном компьютере фирмы IBM. Ввод/вывод
Страница 19. Создание обработчика прерывания устройства


     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    общая ошибка


 
« Предыдущая статья   Следующая статья »