MOV CS:KEEP_BX,BX
RET
KEEP_CS DW ?
KEEP_BX DW ?
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,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.4 Доступ к драйверу устройства.
Драйвер устройства устанавливается путем включения имени гото-
вой программы в файл конфигурации системы. Для установки пробной
программы поместите в файл CONFIG.SYS строку DEVICE = DEVI-
CE12.COM. Затем перезагрузите систему для установки драйвера.
Если машина не будет загружаться, то скорее всего имеется ошибка
в коде инициализации драйвера.
После того как драйвер установлен, для доступа к нему пользуй-
тесь обычными функциями MS DOS прерывания 21H. Kакие функции
можно использовать зависит от того, заменяет ли устройство стан-
дартное устройство DOS (как в приведенном примере) или оно добав-
ляется как совершенно новое устройство. Для замены стандартного
последовательного устройства, назовите драйвер AUX, после чего
функции 3 [7.1.7] и 4 [7.1.6] прерывания 21H будут осуществлять
соответственно ввод и вывод. Если устройство параллельное, то
назовите его PRN, после чего функция 5 [6.3.1] будет выводить
данные на принтер. Другой возможностью является использование
функции 3FH [5.4.4] для ввода и [5.4.3] для вывода. В этом случае
используйте номер файла 3 - для последовательного устройства и 4
- для параллельного. Hапоминаем, что при использовании предопре-
деленных номеров файла нет необходимости открывать устройство.
Если устройство не заменяет одно из стандартных устройств MS
DOS (т.е. если оно не названо одним из резервных слов, таким как
PRN, AUX и т.д.), то Вы можете открыть устройство с помощью одной
из функций для открытия файла. Вы можете использовать как метод
доступа с помощью управляющего блока файла, так и метод дескрип-
тора файла, хотя последний предпочтительнее. Чтобы быть уверен-
ным, что Вы по ошибке не откроете дисковый файл, поместите номер
файла в BX, 0 - в AL, посде чего выполните функцию 44H прерывания
21H. Это функция IOCTL и если бит 7 значения, возвращаемого в DL
установлен, то драйвер устройства загружен.
IOCTL требует, чтобы в байте атрибутов драйвера была соот-
ветствующая установка битов и чтобы по крайней мере основы проце-
дуры обработки IOCTL имелись в процедуре обработчика прерывания
драйвера. Функция IOCTL имеет 8 подфункций, пронумерованных от 0
до 7, при этом соответствующий кодовый номер помещается в AL при
вызове функции:
0 Возвратить информацию об устройстве в DX
1 Установить информацию об устройстве, используя DL (DH=0)
2 Считать CX байтов от драйвера устройства через управля-
щий канал и поместить их начиная с DS:DX
3 Записать CX байтов в драйвер устройства через управляющий
канал, взяв их начиная с DS:DX
4 То же, что и 2, но использовать номер накопителя в BL,
где 0 = накопитель по умолчанию, 1 = A и т.д.
5 То же, что и 3, но использовать номер накопителя как в 5
6 Получить статус ввода
7 Получить статус вывода
В ответ возвращается различная информация, в зависимости от
того, какая функция вызвана. Для подфункций 0 и 1 значение битов
регистра DX следующее (при условии, что бит 7 = 1, что означает,
что доступ получен к устройству, а не к файлу):
0 1 = устройство консольного ввода
1 1 = устройство консольного вывода
2 1 = нулевое устройство
3 1 = устройство часы
4 резерв
5 1 = нет проверки на Ctrl-Z, 0 = есть проверка на Ctrl-Z
6 1 = не конец файла, 0 = конец файла
7 1 = устройство, 0 = дисковый файл
8-13 резерв
14 1 = если можно использовать подфункции 2 и 3, 0 = нельзя
15 резерв
Подфункции 2-5 позволяют программе и устройству обмениваться
произвольными управляющими строками. Это позволяет передавать