Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

MS-DOS для программиста

© Александр Фролов, Григорий Фролов
Том 18, М.: Диалог-МИФИ, 1995, 254 стр.

[Назад] [Содеожание] [Дальше]

6.4. Команды для загружаемого драйвера

Как уже было сказано, номер команды, которую должен выполнить драйвер, передается операционной системой через поле cmd заголовка запроса. Рассмотрим отдельные команды.

Инициализация драйвера (0)

Эта команда выполняется только один раз при загрузке драйвера и подключении его к операционной системе.

Команда инициализации должна обрабатываться любым драйвером, так как она сообщает операционной системе сведения, необходимые для правильного подключения и использования драйвера.

Приведем формат запроса для команды инициализации:

Смещение, байт Размер, байт Имя поля Описание
0 13 header Заголовок запроса
13 1 n_units Количество устройств, обслуживаемых драйвером. Это поле заполняется только блочным драйвером. Для символьного драйвера в это поле нужно записать значение 0
14 4 end_addr Дальний адрес нижней границы резидентной части кода драйвера. В это поле драйвер записывает адрес байта памяти, следующего за областью драйвера, которая должна стать резидентной
18 4 parm Дальний адрес строки параметров инициализации драйвера из файла config.sys . Эта строка содержит все, что находится в строке файла после команды 'DEVICE='. Она заканчивается символами перевода строки и возврата каретки 0Ah, 0Dh. При возврате драйвер блочного устройства должен записать в поле parm адрес массива указателей на блоки параметров BIOS (BPB ), по одному указателю на каждое устройство, обслуживаемое драйвером
22 1 drive Номер устройства. В это поле при загрузке драйвера операционная система заносит номер, назначенный устройству, обслуживаемому драйвером. Например, для устройства А: это 0, для B: - 1 и т. д.
23 1 msg_flag 1 - отображение сообщения об ошибке, если в поле status заголовка запроса установлены соответствующие биты;0 - сообщение об ошибке не отображается

При инициализации драйвер символьного устройства сохраняет в своей внутренней области данных параметры инициализации, используя адрес parm. Если параметры содержат числовые значения, программа инициализации может выполнить их перекодировку и сохранить значения в двоичном формате.

Затем драйвер может выполнить инициализацию обслуживаемого периферийного устройства, инициализацию своих внутренних переменных, вывести на экран какие-либо сообщения, либо даже запросить у оператора дополнительные данные. Для организации диалога с оператором и других действий обработчик команды инициализации может пользоваться функциями прерывания INT 21h с номерами от 01h до 0Ch, 25h, 30h, 35h и функциями BIOS .

Кроме этого, драйвер должен записать в поле end_addr адрес конца резидентной части драйвера. Так как программа инициализации выполняется только один раз, обычно ее располагают в конце драйвера и для экономии памяти не оставляют резидентной.

Драйверы блочных устройств дополнительно должны возвратить MS-DOS количество обслуживаемых устройств (в поле n_units) и адрес массива указателей на блоки BPB (в поле parm).

Поле количества устройств используется MS-DOS для определения логических имен устройств. Например, если ваш драйвер обслуживает три логических устройства, и на момент его загрузки в системе имеются устройства A:, B: и C:, то устройства, обслуживаемые вашим драйвером, получат имена D:, E: и F:. Вы должны указать количество устройств также и в заголовке драйвера (в первом байте поля имени устройства dev_name).

Для каждого логического устройства драйвер должен подготовить так называемый блок параметров BIOS (BIOS Parameter Block - BPB ).

Блок BPB находится в загрузочном секторе диска и содержит информацию, необходимую BIOS для работы с диском. Приведем формат блока BPB:

Смещение, байт Размер, байт Имя поля Описание
0 2 sect_siz Количество байт данных в одном секторе диска
2 1 clustsiz Количество секторов в одном кластере
3 2 res_sect Количество зарезервированных секторов
5 1 fat_cnt Количество таблиц FAT
6 2 root_siz Максимальное количество дескрипторов файлов в корневом каталоге диска
8 2 tot_sect Общее количество секторов на носителе данных (в разделе MS-DOS)
10 1 media Байт-описатель среды носителя данных
11 2 fat_size Количество секторов, занимаемых одной копией FAT

Подробно формат и назначение полей BPB будут описаны в томе, посвященном файловой системе MS-DOS.

Приведем фрагмент исходного текста драйвера, возвращающего при инициализации указатель на массив BPB :

	lea	dx,bpb_ptr
	mov	es:[bx+18],dx
	mov	es:[bx+20],cs
	. . . . . . . . . .

В этом примере предполагается, что в регистрах ES:BX находится адрес заголовка запроса.

Указатель и массив BPB может быть определен, например, следующим образом:

bpb:		DW	512	; количество байт в секторе
		DB	1	; количество секторов в кластере
		DW	1	; зарезервировано секторов
		DB	2	; количество копий FAT 
		DW	64	; максимальное количество файлов 
				; в корневом каталоге
		DW	360    ; общее число секторов на диске
		DB	0FCh   ; описатель среды
		DW	2	; количество секторов в FAT 
;
bpb_ptr	DW	bpb    ; таблица для трех одинаковых
		DW	bpb    ; логических устройств
		DW	bpb

Если ваш драйвер работает с несколькими разными по параметрам логическими устройствами, для каждого устройства необходимо подготовить свой BPB и занести его адрес в место таблицы указателей на блоки BPB, соответствующее порядковому номеру устройства.

Какие действия должна выполнить команда инициализации, если выяснилось, что по тем или иным причинам установка драйвера невозможна? Например, ошибочно заданы параметры, не хватает оперативной памяти, других ресурсов или, наконец, отсутствует само обслуживаемое устройство.

Драйвер символьного устройства при этом может указать в качестве конечного адреса резидентной части программы адрес начала драйвера, т. е. адрес заголовка драйвера. Размер резидентной части при этом будет равен нулю. Блочные драйверы дополнительно должны записать нуль в поле количества обслуживаемых логических устройств n_units.

В обоих случаях драйвер не будет включен в состав операционной системы.

Проверка замены носителя данных (1)

Эту команду операционная система MS-DOS выдает драйверу, когда ей нужно определить, заменил ли пользователь носитель данных (например, дискету).

В любой момент времени пользователь может заменить носитель данных. Если он сделал это в неудачный момент времени, такая замена может привести к неприятным последствиям. При смене носителя данных накопитель на гибких магнитных дисках вырабатывает специальный сигнал, который может быть проанализирован драйвером для правильного ответа операционной системе.

Возможны три варианта ответа на вопрос о замене носителя данных:

  • Да, носитель данных заменен.
  • Нет, носитель данных все тот же.
  • Неизвестно, произошла замена носителя данных, или нет.

Если MS-DOS получила ответ, что носитель данных не заменен, она продолжает работу, которой занималась раньше.

Если пришел ответ, что носитель данных заменен, MS-DOS выдает драйверу команду с кодом 2. Это запрос драйверу на построение нового блока BPB . При этом все буферы, связанные с данным устройством, очищаются, и, если они не были записаны на диск, может произойти потеря информации. Затем выполняется чтение каталога и таблицы размещения файлов FAT .

Если пришел третий ответ (неизвестно, сменили носитель данных или нет), действия MS-DOS зависят от наличия в данный момент непустых дисковых буферов. Если непустых буферов нет, MS-DOS считает, что носитель сменился, и ведет себя так, как это было описано раньше. Если есть непустые буферы, MS-DOS записывает их на диск. При этом структура информации на новой дискете может оказаться полностью нарушенной.

Приведем формат запроса для команды проверки замены носителя:

Смещение, байт Размер, байт Имя поля Описание
0 13 header Заголовок запроса
13 1 media В этом поле драйверу передается байт-описатель среды носителя данных, с которым MS-DOS работала раньше
14 1 reply В это поле драйвер должен поместить ответ о факте замены среды:
1 - диск не заменяли;
0 - неизвестно, заменяли диск, или нет;
0FFh - диск был заменен
15 4 vol_id Указатель на предыдущую метку тома (если установлен бит 11 слова атрибута устройства и диск был заменен)

Если драйвер поддерживает команду проверки замены среды носителя данных (бит 11 слова атрибута установлен в 1) и оказалось, что произошла замена диска, драйвер должен вернуть в поле vol_id указатель на область памяти, содержащую предыдущую метку тома в формате ASCIIZ . Если метка тома не используется драйвером, а бит 11 слова атрибутов установлен, необходимо вернуть указатель на строку "NO_NAME", закрытую двоичным нулем.

Байт-описатель среды media классифицирует используемую среду носителя данных, но делает это неоднозначно. Мы приведем характерные для этого байта параметры дисков:

Значение Количество сторон Количество секторов Диаметр, дюймы Емкость, Кбайт
F0h 2 18 3,5 1440
- " - 2 36 3,5 2880
- " - 2 15 5,25 1200
F8h - -   Жесткий диск любой емкости
F9h 2 9 3,5 720
- " - 2 15 5,25 1200
FAh 1 8 5,25 320
FBh 2 8 3,5 640
FCh 1 9 5,25 180
FDh 2 9 5,25 360
FEh 1 8 5,25, 8 160
FFh 2 8 5,25, 8 320

Более подробно все, что касается дисков, будет изложено в следующем томе нашей серии книг, посвященной файловой системе.

Построить блок BPB (2)

Эта команда имеет смысл только для блочных устройств и вызывается после предыдущей команды, если произошла смена носителя данных.

Драйвер должен возвратить адрес нового блока BPB .

Формат запроса для этой команды:

Смещение, байт Размер, байт Имя поля Описание
0 13 header Заголовок запроса
13 1 media В этом поле драйверу передается байт-описатель среды носителя данных, с которым MS-DOS работала раньше
14 4 buf_adr Адрес буфера обмена. Содержимое этого буфера при вызове драйвера зависит от установки бита 13 слова атрибутов устройства. Если этот бит равен 0, буфер содержит первый сектор первой копии FAT . В противном случае содержимое буфера неопределено
18 4 bpb_adr Указатель на новый BPB ; записывается в это поле драйвером

Операционная система MS-DOS версии 3.0 и более поздних версий включает поддержку аппаратных средств проверки смены носителя данных. Если драйвер обнаружил, что смена носителя данных произошла неправильно, например, в неподходящий момент времени, он может вернуть ошибку с кодом 15 (неразрешенная замена диска).

Чтение через интерфейс IOCTL (3)
Чтение (4)
Запись (8)
Запись с проверкой (9)
Запись через интерфейс IOCTL (0Ch)
Вывод, пока не занято (10h)

Все эти команды используются для передачи данных между операционной системой и устройством. Они имеют практически одинаковый формат запроса, поэтому мы их будем рассматривать вместе.

В операциях чтения или записи участвуют секторы (для блочных устройств) или байты (для символьных устройств). Область запроса содержит указатель на буфер обмена. В этот буфер нужно поместить прочитанные данные или взять из него данные для записи. Далее следует поле количества передаваемых байт для символьных устройств или секторов для блочных.

Кроме того, драйвер должен вернуть количество действительно прочитанных или записанных байт или секторов.

Приведем формат запроса для этих команд:

Смещение, байт Размер, байт Имя поля Описание
0 13 header Заголовок запроса
13 1 media В этом поле драйверу передается байт-описатель среды носителя данных
14 4 buf_adr Адрес буфера для передачи данных
18 2 count Количество передаваемых байтов для символьных устройств или секторов для блочных устройств
20 2 sector Номер начального логического сектора, если драйвер использует 16-битовую адресацию секторов, или 0FFFFh для 32-битовой адресации. Это поле не используется символьными драйверами
22 4 vol_id Указатель на метку тома в формате ASCIIZ . Возвращается блочным драйвером, если он возвращает код ошибки 15 (неправильная смена диска). Это поле должно содержать ссылку на метку требуемого диска
26 4 sect32 Номер начального сектора, если содержимое поля sector равно 0FFFFh. Первым идет старшее слово номера сектора. Если обнаружена ошибка с кодом 15, в это поле записывается указатель на метку тома

Поля media, sector, vol_id и sect32 используются только для функций с кодом 4, 8 и 9.

После выполнения операций чтения или записи драйвер обязательно должен записать в поле count количество действительно переданных байт для символьных устройств или секторов для блочных. В случае ошибки недостаточно только установить признак и код ошибки в слове состояния драйвера - требуется также записать правильное значение в поле count.

Для команды 9 (запись с проверкой) драйвер должен проверить записанные данные после выполнения записи. Если с консоли введена команда VERIFY ON , то для дисковых устройств вместо команды записи 8 используется команда записи с проверкой 9.

Драйвер может передать меньше байт, чем было запрошено, что само по себе не является ошибкой.

Иногда может получиться так, что нужно выполнить запись 64 Кбайт данных. Такая операция может вызвать переход за границу сегмента в буфере передачи данных. В этом случае драйвер должен проигнорировать лишние байты. Например, надо записать 10000h байтов, распределенных по секторам из области памяти с адресом ХХХХ:0001. В этом случае драйвер должен проигнорировать последние два байта. Они будут записаны в следующий раз.

Команды чтения и записи с использованием интерфейса IOCTL предназначены, как правило, для управления устройством.

Команда с кодом 10h ("вывод, пока не занято") предназначена для работы с такими периферийными устройствами, которые имеют свой собственный буфер, например, принтеры.

Неразрушающее чтение без ожидания (5)

Эта команда предназначена для выборки одного байта из буфера символьного устройства. Для блочных устройств такая команда не используется.

Если в буфере символьного устройства есть байты, которые могут быть прочитаны командой чтения, драйвер возвращает следующий символ, который был бы прочитан.

Если в результате проверки выяснится, что в буфере есть символы, драйвер должен сбросить бит 9 слова состояния устройства (занятость), в противном случае - установить этот бит в 1.

Эта команда используется перед командой чтения для того чтобы проверить, есть ли в буфере данные, готовые для чтения. Такая проверка позволяет избежать длительного ожидания готовности данных при вводе. Кроме того, команда используется для проверки наличия в буфере клавиатуры кода комбинации клавиш <Ctrl+Break>.

Формат запроса для команды 5:

Смещение, байт Размер, байт Имя поля Описание
0 13 header Заголовок запроса
13 1 byte В это поле драйвер записывает извлеченный из буфера байт, который будет считан следующей командой ввода

Проверить состояние устройства ввода (6)
Проверить состояние устройства вывода (0Ah)

Эти команды проверяют состояние, соответственно, устройств ввода и вывода. Они действительны только для символьных устройств.

Для устройства ввода бит занятости слова состояния (бит 9) сбрасывается в нуль, если буфер устройства не пуст и в нем есть готовые для чтения символы. Этот бит устанавливается драйвером в единицу, когда буфер пуст, и последующая команда чтения приведет к ожиданию ввода от устройства.

Для устройства вывода бит занятости в слове состояния (бит 9) сбрасывается в нуль в том случае, когда нет текущих запросов на вывод, ожидающих готовности устройства, и последующая команда вывода может быть выполнена немедленно. Бит устанавливается в 1, если предыдущий запрос на вывод еще не обработан.

Для команд проверки состояния запрос состоит только из заголовка. Переменная часть запроса отсутствует.

Если у устройства нет буфера ввода, бит занятости должен быть равен 0.

Освобождение буфера устройства ввода (7)
Освобождение буфера устройства вывода (0Bh)

Эти функции заставляют драйвер завершить все текущие запросы, соответственно, на ввод и вывод, а также освободить буферы ввода и вывода.

Команда освобождения буфера входного устройства используется, например, для удаления всех символов из буфера клавиатуры. После выполнения очистки буферов драйвер выставляет слово состояния и возвращает управление операционной системе.

Запрос состоит только из заголовка.

Открыть устройство (0Dh)
Закрыть устройство (0Eh)

Для того чтобы драйвер мог использовать эти команды, бит 11 в слове атрибутов устройства в заголовке драйвера должен быть установлен в 1. Кроме того, необходимо загрузить резидентную программу share.exe.

По команде "открыть устройство" драйверы символьных устройств могут посылать инициализирующие последовательности символов в устройство. Например, в принтер могут посылаться команды установки шрифта, формата бумаги и т. д.), а также команды, устанавливающие устройство в исходное состояние. Обработчик этой команды может также обнаружить и пресечь попытку получения многократного доступа к устройству. В этом случае вторая команда открытия устройства должна возвратить ошибку (если повторное открытие устройства запрещено).

Драйвер блочного устройства с помощью команд "открыть устройство" и "закрыть устройство" может выполнять подсчет открытых файлов. Если содержимое счетчика открытых файлов для данного устройства равно 0, то на этом устройстве нет открытых файлов. Стандартные устройства CON , AUX и PRN открыты всегда.

Запрос для этих команд состоит только из заголовка.

Проверка возможности замены носителя данных (0Fh)

Эта команда используется только для тех драйверов, в слове атрибутов которых бит 11 установлен в 1. При получении этой команды драйвер должен сообщить MS-DOS, возможна ли замена носителя данных. Например, замена жесткого диска обычно невозможна, хотя есть накопители со сменными жесткими дисками.

Драйвер возвращает информацию о возможности замены носителя в бите 9 слова состояния устройства. Драйвер устанавливает значение этого бита, равное 0, в том случае, если замена носителя данных возможна. В противном случае устанавливается значение, равное 1.

Запрос состоит только из заголовка.

Функции общего управления вводом/выводом GENERIC IOCTL (13h)

Команда с кодом 13h предназначена для выполнения нескольких функций и поддерживается только теми драйверами, у которых в слове атрибутов устройства бит поддержки IOCTL (бит 14) установлен в 1.

Команда используется для выполнения ряда операций с дисками, доступных обычно лишь на уровне BIOS , таких, например, как форматирование диска, чтение или запись секторов по их абсолютному адресу на диске и т. д.

Специальная функция прерывания INT 21h c номером 44h, имеющая множество подфункций, предназначена для поддержки IOCTL . Очень скоро мы займемся этой функцией, а сейчас приведем формат запроса для команды с кодом 13h:

Смещение, байт Размер, байт Имя поля Описание
0 13 header Заголовок запроса
13 1 category Категория устройства:01h - последовательное устройство;03h - консоль (видеомонитор);05h - параллельный принтер;08h - диск
14 1 subfunc Код подфункции для функции funct
15 2 si_reg Значение регистра SI при вызове функции 44h прерывания INT 21h
17 2 di_reg Значение, передаваемое при вызове функции 44h прерывания INT 21h через регистр DI
19 4 buf Указатель на область памяти, содержащую управляющую информацию для устройства или предназначенную для приема информации от устройства

Определить активное логическое устройство (17h)
Установить активное логическое устройство (18h)

Эти команды обрабатываются только теми драйверами, у которых в слове атрибутов установлен бит 6 - поддержка логических устройств.

Команды обеспечивают метод для определения номера текущего активного логического устройства на физическом диске или установки активного логического устройства.

Запрос состоит только из заголовка.

По команде 18h ("получить активное логическое устройство") драйвер должен поместить идентификатор устройства в поле unit заголовка устройства. Для устройства А: помещается 1, для В: - 2 и т. д. Если драйвер управляет единственным устройством, он должен записать в поле unit нуль.

Команда 18h позволяет установить активное устройство, определенное в поле unit.

[Назад] [Содеожание] [Дальше]