Страница 19 из 27
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 общая ошибка
|