|
ГЛАВА 2 MS-DOS ДРАЙВЕРЫ УСТРОЙСТВ
_________________________________________________________
2.1 Введение
2.2 Формат драйвера устройства
2.3 Как написать дравер устройства
2.3.1 Программа стратегии драйвера
2.3.2 Программа прерывания
2.4 Загрузка драйвера
2.5 Заголовок устройства
2.5.1 Указатель на следующий драйвер
2.5.2 Поле атрибута
2.5.3 Программы стратегии и прерывания
2.5.4 Поле имени
2.6 Заголовок запроса
2.6.1 Поле длины запроса
2.6.2 Поле кода устройства
2.6.3 Поле кода команды
2.6.4 Поле состояния
2.7 Функции драйвера устройства
2.7.1 Инициализация
2.7.2 Проверка диска
2.7.3 Построение BPB ( Блок Параметров БСВВ )
2.7.4 Запись или чтение
2.7.5 Небуферизированное чтение
2.7.6 Открытие или закрытие
2.7.7 Сменяемый диск
2.7.8 Проверка состояния
2.7.9 Снос
2.7.10 Общее УВВ ( Управление вводом/выводом )
2.7.11 Получение/установка карты логического дисковода
2.8 Байт описатель диска
2.9 Формат таблицы описания диска
2.10 Устройство ЧАСЫ
2.11 Порядок обращения к устройству
2.12 Два примера драйверов устройств
- 178 -
2.1 Введение
Файл io.sys включает резидентные драйверы устройств,
формирующие базовую систему ввода/вывода (БСВВ) MS-DOS. Эти
драйверы вызываются системой для обработки запросов прикладных
программ на ввод/вывод. Возможности MS-DOS позволяют
вводить новые устройства, например, принтеры, плоттеры и мыши
без модификации БСВВ. Нерезидентные или загружаемые драйверы
могут быть легко включены во время начальной загрузки
командной строкой DEVICE в файле config.sys.
Во время начальной загрузки должны присутствовать как
минимум пять резидентных драйверов. Все они находятся в
связном списке - заголовок каждого содержит DWORD указатель на
следующий. Заголовок последнего содержит маркер конца списка
-1,-1 (все биты установлены).
Каждый драйвер в этой цепи имеет две точки входа -
указатели на программу стратегии и программу прерывания.
MS-DOS сразу после программы стратегии вызывает программу
прерывания.
Такое двухвходовое построение обеспечит работу будущих
мультипрограммных версий MS-DOS. В многозадачном режиме
ввод/вывод должен быть асинхронным. Для этого программа
стратегии должна выстраивать очередь из запросов и быстро
возвращать управление. Дальше вся ответственность за
выполнение поступивших запросов лежит на программе прерывания,
которая считывает запросы из очереди. После выполнения запроса
программа прерывания флажирует его как "выполнен". MS-DOS
периодически сканирует список запросов в поисках таких
запросов, а затем "будит" соответствующую программу, ожидающую
выполнения этого запроса.
Запросы различаются размером и форматом и состоят из двух
секций:
1. Заголовок запроса, имеющий стандартный формат для
всех запросов
2. Конкретная информация к запросу
Драйвер вызывается с указателем на этот "пакет".
Программа стратегии должна сохранить адрес этого пакета в
фиксированном месте, после чего сразу вызывается программа
прерывания, обрабатывающая этот пакет. Запрос считается
выполненным по возвращении из программы прерывания.
Файл драйвера должен иметь формат .bin или .exe и иметь в
своем начале заголовок устройства.
Загружаемые драйверы с форматом .exe могут быть
использованы в не-IBM версиях MS-DOS. На персональных
компьютерах IBM загрузчик .exe файлов находится в command.com,
который не присутствует во время загрузки загружаемых
драйверов.
2.2 Формат драйвера устройства
Драйвер устройства это программный сегмент, отвечающий за
коммуникацию между DOS и аппаратной частью. Он имеет в своем
начале заголовок, идентифицирующий его как драйвер устройства,
определяющий точки входа и описывающий различные атрибуты
файла.
- 179 -
_________________________________________________________
Примечание
Файл драйвера не должен использовать ORG 100H,
т.к. он не использует Префикс сегмента кодов
(PSP). Файл должен начинаться с нуля (ORG 0 или
отсутствие директивы ORG).
_________________________________________________________
Существует два типа драйверов:
- Драйвер символьного устройства
- Драйвер блокового устройства
Символьные устройства осуществляют последовательный
символьный ввод/вывод. Такими устройствами являются консоль,
последовательный порт и принтер (CON, AUX, CLOCK и т.д.).
Блоковые устройства включают все дисководы в системе. Они
могут осуществлять выборочный ввод/вывод блоков данных (обычно
равных физическому размеру сектора). Все они имеют свои номера
и идентифицируются буквами A, B, C и т.д.
Один драйвер блокового устройства может отвечать за один
или несколько логически связных дисководов. Например, драйвер
ALPHA может отвечать за дисководы A,B,C и D. Это значит, что
для него определено четыре номера (0-3), а сам он занимает
четыре буквы. Положение драйвера в списке определяет, каким
буквам соответствуют его номера. Если в нашем примере BETA
является вторым драйвером в списке и для него определено три
номера (0-2), то этим номерам уже будут соответствовать буквы
E,F и G. Теоретическая граница - 63, однако нужно учесть, что
загрузка драйвера не будет выполнена, если получится буква
больше Z(5АН). Все резидентные драйверы помещаются впереди
загружаемых драйверов.
_________________________________________________________
Примечание
Драйверы символьных устройств не могут отвечать
за несколько устройств, т.к. имеют только одно
имя.
_________________________________________________________
2.3 Как создать драйвер устройства
Для создания загружаемого драйвера вам необходимо
програмный файл (формат .com или .exe) с заголовком в начале.
Не забудьте, что код должен начинаться не с 100Н, а с 00Н.
Указатель на следующий драйвер должен быть выставлен в -1,
если файл содержит только один драйвер. Соответствующим
образом устанавливаются поля атрибута и точек входа.
В случае с символьным устройством поле имени содержит имя
символьного устройства. Если длина имени меньше восьми
символов, то оно дополняется пробелами (20Н). Обратите
внимание, что имена устройств не включают двоеточие (:).
MS-DOS всегда обрабатывает в первую очередь загружаемые
драйверы перед резидентными. Поэтому для установки нового
драйвера устройства CON нужно просто указать имя CON. Не
забудьте установить биты стандартного ввода/вывода в слове
атрибута нового драйвера. Сканирование по списку драйверов
останавливается на первом подходящем, поэтому загружаемые
драйверы имеют преимущество.
- 180 -
Не разрешается заменять резидентные драйверы блоковых
устройств, как, например, вы это можете сделать с другими
драйверами БСВВ. Драйверы блоковых устройств могут быть
использованы только для устройств, не поддерживаемых напрямую
резидентными драйверами из файла io.sys.
2.3.1 Программа стратегии
Эта программа отвечает за помещение поступающих запросов
в очередь. Она вызывается системой и предназначена для
применения в будущих мультипрограммных версиях MS-DOS. Текущая
версия не поддерживает этих возможностей и обслуживает только
один запрос в каждый момент времени, поэтому программа
стратегии максимально проста - каждый запрос просто
сохраняется в одной области ( см. Раздел 2.12 "Два примера
драйверов устройств").
2.3.2 Программа прерывания
Программа прерывания содержит код, необходимый для
обработки запросов и отвечает за коммуникацию между DOS и
аппаратной частью.
2.4 Загрузка драйверов устройств
Загрузка новых драйверов происходит во время начальной
загрузки системы. Загрузка выполняется кодом инициализации,
находящимся в файле io.sys, и обрабатывающем файл config.sys.
MS-DOS вызывает драйверы устройств следующим образом:
1. MS-DOS делает дальний вызов программы стратегии.
2. MS-DOS передает информацию из заголовка запроса
программе стратегии.
3. MS-DOS делает дальний вызов программы прерывания.
Такая структура вызова создана для облегчения ее
модификации к будущим мультипрограммным версиям системы.
2.5 Заголовок устройства
Заголовок устройства помещается в начало драйвера и
выглядит следующим образом:
DWORD Указатель на следующий драйвер
(Обычно равен -1, если драйвер последний или един-
ственный в файле)
WORD Атрибуты
WORD Указатель на программу стратегии
WORD Указатель на программу прерывания
8-BYTE Поле имени символьного устройства
(Для блоковых устройств первый байт содержит
количество устройств).
Обратите внимание, что точки входа являются словами. Они
должны быть смещениями от сегмента, используемого для адресации
заголовка.
Подробное описание этих полей приводится ниже.
- 181 -
2.5.1 Поле указателя на следующий драйвер
Содержит адрес (смещение:сегмент) следующего драйвера в
файле. Если драйвер является единственным или последним в
списке, то это поле должно быть выставлено в -1.
2.5.2 Поле атрибута
Используется для идентификации типа устройства. Обратите
внимание, что, если бит в слове атрибута определен только для
одного типа устройства, то драйвер для другого устройства
должен установить этот бит в 0.
Таблица 2.1
Для символьных устройств:
__________________________________________________________
Бит Сост. Значение
__________________________________________________________
0 1 Консоль ввода
1 1 Консоль вывода
2 1 Нулевое устройство
3 1 Часы
4-5 Зарезервировано (должны быть нулями)
6 1 Поддерживает функции 3.2
7-10 Зарезервировано (должны быть нулями)
11 1 Понимает Открыть/закрыть
12 Зарезервирован (должен быть нулем)
13 1 Поддерживает режим OUB (вывод пока не занят)
14 1 Поддерживает управляющие последовательности
15 1 Символьное устройство
__________________________________________________________
Таблица 2.2
Для блоковых устройств:
__________________________________________________________
Бит Сост. Значение
__________________________________________________________
0 Зарезервирован (должен быть нулем)
1 1 Поддерживает 32-битную адресацию сектора
2-5 Зарезервировано (должны быть нулями)
6 1 Поддерживает функции 3.2 и функции общего УВВ
7-10 Зарезервировано (должны быть нулями)
11 1 Понимает Открыть/закрыть/сменный
12 Зарезервирован (должен быть нулем)
13 1 Определяет диск проверкой байта FAT ID
14 1 Поддерживает управляющие последовательности УВВ
15 0 Блоковое устройство
__________________________________________________________
Допустим, вы хотите иметь новый драйвер, вместо
стандартных ввода/вывода. Для этого вам необходимо установить
биты 0 и 1 равными 1. Хотя предусмотрен бит признак нулевого
устройства, этот бит применяется MS-DOS для определения,
используется ли нулевое устройство. Нулевое устройство не
может быть переназначено.
Бит 13 в блоковых устройствах имеет дело с операцией
Построить БПБ (Блок параметров Базовой Системы Ввода/Вывода).
При его установке первый сектор FAT (Таблица размещения
файлов) должен всегда начинаться с одного и того же места.
- 182 -
Этот бит имеет другое значение на символьных устройствах. Он
показывает, может ли устройство выполнить запрос на вывод в
режиме OUB (Вывод пока не занято).
Бит 14 сообщает MS-DOS может ли устройство обрабатывать
управляющие последовательности функции 44Н (УВВ).
Если драйвер не может обрабатывать управляющие
последовательности, то этот бит должен быть равен нулю. В этом
случае MS-DOS возвращает ошибку при попытке передать
или получить управляющие последовательности с помощью функциии
44Н.
Бит 11 сообщает MS-DOS 3.X и более поздних версий,
поддерживает ли устройство дополнительные функции MS-DOS 3.X.
В MS-DOS 2.X этот бит был зарезервирован и равен нулю. Все
новые драйверы должны поддерживать операции
Открыть/Закрыть/Сменный-диск и установить этот бит в 1. Так
как MS-DOS 2.X никогда не использует этот бит, новый драйвер
будет совместим со старыми версиями системы.
Бит 6 сообщает системе, поддерживает ли устройство
функции 440СН, 440DH, 440EH и 440FH.
Бит 1 в блоковых устройствах индицирует 32-битовую
адресацию сектора. Если он установлен, то поле номера сектора
всех запросов является двойным словом (DWORD), добавляемым в
конец заголовка запроса. Старое WORD номера сектора должно
быть равно -1.
Если бит 1 равен 0, то используется 16-битовая адресация
сектора.
Слово атрибута символьного устройства:
t1
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
_______________________________________________________________
і С і У і і і О і і і і і 3 і і і Ч і Н і С і С і
і И і В і і і Т і і і і і . і і і А і У і В і В і
і М і В і і і К і і і і і 2 і і і С і Л і В і Ы і
_______________________________________________________________
Слово атрибута блокового устройства:
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
_______________________________________________________________
і і У і Т і і О і і і і і 3 і і і і і > і і
і і В і Р і і Т і і і і і . і і і і і 3 і і
і і В і Ф і і К і і і і і 2 і і і і і 2 і і
_______________________________________________________________
t0
2.5.3 Программы стратегии и прерывания
Эти поля содержат указатели на программы стратегии и
прерывания. Сегментный адрес тот же, что и у заголовка
устройства.
2.5.4 Поле имени
Это поле содержит имя символьного устройства или
количество блоковых устройств. Последнее не обязательно, т.к.
MS-DOS заполняет эту позицию значением, возвращаемым операцией
Инициализации драйвера. Подробнее, см. Раздел 2.4.
- 183 -
2.6 Заголовок запроса
Когда MS-DOS вызывает драйвер устройства для выполнения
какой-либо функции, программе стратегии передается адрес
заголовка запроса в ES:BX. Это область фиксированной длины, за
которой следуют данные, необходимые для выполняемой операции.
Не забудьте, что на драйвере лежит ответственность за
сохранение регистров и флагов. Для этого, как правило,
требуется не более 20 команд POP-PUSH. Если требуется больше
места, то драйвер может создать свой собственный стэк.
t1 Заголовок запроса:
_______________________________________________________
і BYTE Длина в байтах заголовка запроса і
і BYTE Код устройства, к которому обращается операцияі
і BYTE Код операции і
і WORD Слово состояния і
і 8 БАЙТ Зарезервировано і
_______________________________________________________
t0
2.6.1 Длина заголовка запроса
Это поле содержит длину в байтах заголовка запроса.
2.6.2 Код устройства
Код устройства, к которому обращается операция. Например,
если за драйвером закреплено три устройства (буквы), то
возможными значениями этого поля будут 0, 1 и 2.
2.6.3 Код операции
Код Операция
__________________________________________________________
0 Инициализация
1 Проверка диска (только для блоковых устройств)
2 Построить БПБ (только для блоковых устройств)
3 УВВ Ввод (если устройство имеет УВВ)
4 Ввод (чтение)
5 Небуферизированное чтение
6 Состояние ввода (только для символьных устройств)
7 Сброс (ввод) (только для символьных устройств)
8 Вывод (запись)
9 Вывод (запись) с проверкой
10 Состояние вывода (только для символьных устройств)
11 Сброс (вывод) (только для символьных устройств)
12 УВВ Вывод (если устройство имеет УВВ)
13 Открыть (если установлен бит 11 слова атрибута)
14 Закрыть (если установлен бит 11 слова атрибута)
15 Сменный диск (если установлен бит 11 слова атрибута
на блоковом устройстве)
16 Вывод пока не занято (если установлен бит 13 на
символьном устройстве)
19 Общее УВВ
23 Получить карту логического дисковода
24 Установить карту логического дисковода
__________________________________________________________
- 184 -
2.6.4 Слово состояния
t1 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
___________________________________________________
і О і і З і В і і
і Ш і Зарезервиро- і А і Ы і Код ошибки і
і Б і вано і Н і П і (если бит 15 = 1) і
___________________________________________________
t0
На входе слово состояния равно нулю и заполняется
программой прерывания драйвера по возвращении.
После выполнения операции драйвер устанавливает бит 8.
Бит 9 (Занято) устанавливается только операциями
Состояние и Сменный диск.
Если по возвращении установлен бит 15, то младший байт
слова состояния содержит код ошибки:
Код Значение
__________________________________________________________
0 Защищено по записи
1 Неизвестное устройство
2 Дисковод не готов
3 Неизвестная операция
4 Ошибка циклического кода проверки
5 Неразрешенная длина запроса
6 Ошибка поиска
7 Неизвестный диск
8 Сектор не найден
9 Нет бумаги в принтере
А Ошибка записи
В Ошибка чтения
С Общий сбой
D Зарезервировано
Е Зарезервировано
F Неразрешенная смена диска
__________________________________________________________
2.7 Функции драйвера устройства
Драйверы устройств могут выполнять все или некоторые из
этих общих функций. В некоторых случаях эти функции делятся на
несколько кодов операций. В этом разделе описываются следующие
общие функции (операции) драйвера:
- Инициализация
- Проверка диска
- Построить БПБ
- Чтение, Запись, Вывод пока не занято, Запись с проверкой
УВВ чтение, УВВ запись
- Небуферизированное чтение
- Открыть или Закрыть (3.Х)
- Сменный диск (3.Х)
- Проверка состояния
- Сброс
- Общее УВВ
- Получить/установить карту логического дисковода
- 185 -
Все программы стратегии вызываются при ES:BX содержащими
указатель на заголовок запроса. Программа прерывания получает
указатели на заголовки запросов из очереди, создаваемой
программой стратегии. Код операции в заголовке запроса
сообщает драйверу, какую функцию выполнить и какая информация
содержится в хвосте заголовка запроса.
__________________________________________________________
Примечание
Все двусловные (DWORD) указатели содержат первым
смещение, а потом сегмент.
__________________________________________________________
2.7.1 Функция инициализации
t1 Код операции - 0
___________________________________________________
ES:BX - і 13 БАЙТ Заголовок запроса і
і BYTE Количество устройств і
і DWORD Конечный адрес і
і DWORD Указатель на массив БПБ (не устанавливаі
і ется символьными устройствами) і
і BYTE Номер блокового устройства і
___________________________________________________
t0
Одной из функций, определенных для каждого драйвера
является функция Инициализации. Этот код вызывается только
однажды при загрузке драйвера. Программа инициализации должна
возвращать конечный адрес, являющийся DWORD указателем на
конец той части драйвера, которая должна остаться резидентом.
Для экономии места вы можете использовать этот указатель для
удаления кода инициализации, который нужен только один раз.
Поля Количество устройств, Конечный адрес и Указатель на
массив БПБ устанавливаются драйвером. Однако на входе, DWORD
указатель на массив БПБ содержит указатель на символ,
следующий за "=" в командной строке файла config.sys,
вызвавшей загрузку этого файла. Это позволяет драйверу
сканировать строку в поисках параметров, которые возможно были
переданы драйверу. Эта строка заканчивается ВК или ПС. Данные
строки могут быть только прочитаны.
Кроме того, для блоковых устройств номер дисковода,
назначенный первому устройству драйвера (А=0) содержится в
поле номера блокового устройства. Эти данные тоже только для
чтения.
__________________________________________________________
Примечание
Программа Инициализации может работать только с
функциями 01Н-0СН, 25Н, 30Н и 35Н.
__________________________________________________________
Загружаемые драйверы символьных устройств должны
возвращать конечный адрес. Им является указатель на первый
свободный байт памяти после кода драйвера. Он может быть
использован для удаления ставшего не нужным кода инициализации.
Драйверы блоковых устройств должны возвращать следующую
информацию:
1. Количество устройств. Система использует это значение
для определения логических имен устройств. Если на время
- 186 -
загрузки драйвера максимальной текущей буквой логического
устройства была F, а программа инициализации вернула 4, то
логическими именами устройств загруженного драйвера будут уже
G, H, I и J. Соответствие определяется позицией драйвера в
списке устройств и значением поля Имя устройства в заголовке
драйвера (первый байт для блоковых устройств содержит
количество устройств).
2. DWORD указатель на массив WORD смещений (указателей)
на БПБ (Блоки параметров БСВВ). Передаваемые драйвером БПБ
используются системой для создания внутренних структур. В этом
массиве для каждого устройства должна быть своя точка входа.
Если все устройства одинаковы, то все указатели адресуют один
и тот же БПБ. Формат БПБ описан в Разделе 2.7.3 "Построение
БПБ".
Обратите внимание на то, что массив указателей должен быть
защищен (указатель массива указывает на первый свободный байт
после массива), т.к. структуры DOS выстраиваются, начиная с
байта, адресуемого указателем массива указателей. Указываемый
размер сектора должен быть меньше или равен максимальному
размеру сектора, определяемого резидентными драйверами (БСВВ)
во время инициализации. В противном случае, инициализация не
будет выполнена.
3. Байт описатель диска. Этот байт не имеет значения для
MS-DOS, однако передается устройствам, чтобы те могли знать,
какие параметры MS-DOS в данный момент использует для
конкретного дисковода.
__________________________________________________________
Примечание
Если в файле содержится несколько драйверов, то
MS-DOS использует конечный адрес, возвращенный
последней вызванной функцией инициализации. Все
драйверы в одном файле должны возвращать
одинаковый конечный адрес. Код инициализации
для всех драйверов должен идти после этих
драйверов .
__________________________________________________________
2.7.2 Функция проверки диска
Код операции - 1
t1 ___________________________________________________
ES:BX - і 13 БАЙТ Заголовок запроса і
і BYTE Описатель диска из БПБ і
і BYTE Код возврата і
і DWORD Указатель на предыдущую метку тома і
і (если установлен бит 11 слова атрибута і
і и код возврата равен -1) і
__________________________________________________
t0
Эта функция используется только с блоковыми устройствами.
Она вызывается, когда поступил запрос на доступ к диску не для
файловых чтения или записи, например, при открытии, закрытии
или переименования. Функция предназначена для определения, был
ли сменен диск в дисководе. Если драйвер подтвердит, что диск
не был сменен (через механизм замка), то MS-DOS уже не нужно
будет повторять целый ряд операций - чтение FAT и инвалидацию
буферов.
При вызове функции DOS для доступа к диску (отличной от
чтения или записи) имеет место следующий порядок действий:
- 187 -
1. DOS преобразует имя дисковода в номер устройства
конкретного блокового устройства.
2. После этого вызывается драйвер устройства с операцией
проверки диска на предмет смены. MS-DOS передает старый байт
описатель диска. Драйвер возвращает код возврата:
Код Значение
__________________________________________________________
1 Диск не был сменен
0 Неизвестно
-1 Диск был сменен
Величина Ошибка (Величина - стандартный код ошибки)
__________________________________________________________
Если диск не был сменен, то система продолжает работу с
диском.
Если код возврата равен -1 и остались модифицированные
сектора, не записанные обратно на диск, то MS-DOS считает, что
диск не был сменен. MS-DOS делает недействительными все другие
буферы для этого устройства и вызывает функцию драйвера
Построить БПБ.
Если диск был сменен, то MS-DOS делает недействительными
все буферы, соотнесенные с этим устройством и ждущие своей
записи на диск, а затем вызывает функцию Построить БПБ.
3. По возвращении драйвером БПБ, MS-DOS корректирует свои
внутренние структуры для драйвера из нового БПБ и осуществляет
доступ после чтения каталога и FAT.
Обратите внимание на то, что драйверу передается
предыдущий байт описатель диска.
Если бит 11 слова атрибута равен 1, а драйвер вернул -1
(диск был сменен), то драйвер должен выставить DWORD указа-
тель на поле предыдущей метки тома. Если DOS определит, что
"диск был сменен" является ошибкой, связанной с состоянием
системного каше, то она сгенерирует код ошибки 0FH от имени
устройства. Если драйвер не применяет метку тома, а бит 11
установлен, то он должен установить фиксированный указатель
на строку "NO NAME",0 (Нет имени).
Пользователь не может сменить диск за меньше чем две се-
кунды, поэтому если функция проверки диска вызвана в течение
первых двух секунд доступа, то драйвер возвращает (1). Это
значительно оптимизирует работу системы.
_________________________________________________________
Примечание
Если байт-метка в возвращаемом БПБ равен пре-
дыдущему байту-метке, то MS-DOS будет считать,
что формат диска такой же (даже если диск был
сменен) и не выполняет обновления внутренних
структур. Поэтому все БПБ должны иметь уни-
кальные байты-метки, независимо от байта FAT ID.
_________________________________________________________
- 188 -
2.7.3 Функция построения БПБ
Код операции - 2
t1 _________________________________________________
ES:BX - і 13 БАЙТ Заголовок запроса і
і BYTE Описатель диска из БПБ і
і DWORD Указатель на буфер обмена і
і ( указывает на односекторный буфер і
і или первый сектор FAT, в зависимости і
і от значения бита 13 слова атрибута) і
і DWORD Указатель на БПБ і
_________________________________________________
t0
Эта функция используется только с блоковыми устройства-
ми. Она вызывается всякий раз, когда предыдущая функция про-
верки диска соосбщает о смене диска. Драйвер должен возвра-
щать указатель на БПБ.
Функция построения БПБ возвращает DWORD указатель на од-
носекторный буфер. Содержимое буфера зависит от значения бита
13 в слове атрибута. Если бит равен нулю, то буфер содержит
первый сектор первой FAT. Его первым байтом является байт FAT
ID. В этом случае драйвер не должен изменять этот буфер. Об-
ратите внимание, что позиция первой FAT должна быть оди-
наковой для всех возможных дисков, т.к. первый сектор FAT
должен быть прочитан до того, как возвращен дейсивительный БПБ.
Если бит равен 1, то указатель адресует один свободный сектор.
MS-DOS включает дополнительную поддержку для устройств,
имеющих замки дисководов или другие средства сообщения
системе о смене диска. Существует ошибка, которая может быть
возвращена драйвером (ошибка 15). Эта ошибка означает, что
диск был сменен тогда, когда он не должен был быть смененным.
Драйвер может генерировать эту ошибку при чтении или при
записи. DOS может генерировать эту ошибку при вызове функции
драйвера Проверка диска, когда драйвер сигнализирует смену
диска, а в буферах системного каше осталась информация,
требующая своей записи на предыдущий диск.
Для драйверов, поддерживающих эту ошибку, функция
построения БПБ является своего рода триггером, инициирующим
считывание с диска новой метки тома. Эта процедура
свидетельствует о том, что диск был сменен правильно. Метка
тома помещается на диск командой FORMAT в корневой каталог.
Она хранится драйвером как строка ASCIZ.
Требования к возвращаемой драйвером метке тома не
исключают использование некоторых других идентификаторов
тома, главное, при этом должны использоваться строки ASCIZ.
По соглашениям, нулевая метка тома (отсутствующая) является
строкой:
db "no name",0 ; "нет имени"
- 189 -
2.7.4 Функции чтения и записи
Коды операций - 3, 4, 8, 9, 12 и 16
t1 _________________________________________________
ES:BX - і 13 БАЙТ Заголовок запроса і
і BYTE Описатель диска из БПБ і
і DWORD Указатель на буфер обмена і
і WORD Счетчик байт/сектор і
і WORD Номер начального сектора і
і (или -1, если драйвер поддерживает і
і 16-битовую адресацию сектора) і
і (игнорируется на символьных устройствах) і
і DWORD Указатель на метку тома і
і DWORD Номер начального сектора і
і (если WORD поле с тем же именем равно -1) і
і (старшее слово идет первым) і
і ИЛИ і
і Указатель на метку тома і
і (в случае ошибки 0FH) і
__________________________________________________
t0
Код Операция
_________________________________________________________
3 УВВ чтение
4 Чтение (для блоковых или символьных устройств)
8 Запись (для блоковых или символьных устройств)
9 Запись с проверкой
12 УВВ запись
16 Вывод пока не занято
(только для символьных устройств)
Драйвер должен выполнять чтение/запись в зависимости от
установленного кода операции. Блоковые устройства читают и
записывают сектора; символьные устройства читают и записывают
байты.
По завершении ввода/вывода драйвер устройства должен
выставить слово состояния и сообщить количество успешно
переданных байт. Это должно быть сделано, даже в случае
ошибки. Установка одного лишь бита ошибки и кода ошибки НЕ
достаточно.
Кроме того, дравер должен установить счетчик
ДЕЙСТВИТЕЛЬНО переданных секторов (байт).
Если установлен режим проверки, то драйвер должен
вызываться с кодом операции 9. Ваш драйвер в этом случае берет
на себя всю работу по проверке записи.
Если драйвер возвращает код ошибки 0FH (неразрешенная
смена диска), то он должен вернуть DWORD указатель на строку
ASCIZ с правильной меткой тома. Возвращаенный код заставляет
систему выдать запрос пользователю на установку нужного диска.
Драйвер читает метку тома как результат функции Построить БПБ.
Драйверы могут вести счет открытых файлов путем
мониторинга функций Открыть и Закрыть. Это позволяет им
в нужное время возвращать код ошибки 0FH. Действительно, если
открытых файлов нет (счетчик=0), и диск не был сменен, то
ввод/вывод будет выполнен успешно. Если есть открытые файлы
при смене диска, то возможно будет выдан код ошибки 0FH.
Обратите внимание на то , что возврат драйвером количес-
тва переданных байт меньшего запрошенного не является ошибкой.
Режим OUB (Вывод пока не занято) позволяет программам
- 190 -
обслуживания спулеров использовать "взрывной" характер этих
принтеров. Многие принтеры имеют оперативную память, исполь-
зуемую в качестве буфера, который в свою очередь заполняется
свободно, т.е. принтер не дает состояния "занят" или дает на
короткие промежутки времени (менее десяти команд) между сим-
волами. Строка символов может быть быстро загружена в прин-
тер, после чего принтер долго занят распечаткой введенных
символов. При такой загрузке драйверу нет необходимости ждать
готовности устройства.
_________________________________________________________
Примечание для блоковых устройств
MS-DOS поддерживает две Таблицы размещения файлов (FAT).
Если возникают проблемы с чтением первой, то
автоматически делается попытка прочитать вторую перед
сообщением об ошибке. Ответственность за повторные попытки
лежит на БСВВ.
Хотя command.com не делает автоматически повторных
попыток, некоторые прикладные программы имеют свои
процедуры обслуживания прерывания 24Н, которые делают
повторные попытки при определенных ошибках перед
их сигнализацией.
2.7.5 Небуферизированное чтение
Код операции - 5
t1 _______________________________
ES:BX - і 13 БАЙТ Заголовок запроса і
і BYTE Байт от устройства і
_______________________________
t0
Эта функция позволяет MS-DOS просматривать входной буфер
на один символ вперед. Драйвер устанавливает бит "выполнено"
в слове состояния.
Если символьоне устройство возвращает бит "занято"
равным нулю (есть символы в буфере), то возвращен следующий
символ, который был бы прочитан. Этот символ не удаляется из
входного буфера. Если этот бит равен 1, то в буфере нет
символов.
2.7.6 Функции открытия и закрытия
Коды операций - 13 и 14
______________________________
ES:BX - і 13 БАЙТ Заголовок запроса і
------------------------------
Функции открытия и закрытия вызываются MS-DOS только,
если бит 11 в заголовке устройства равен 1. Они предназначены
для того, чтобы информировать драйвер о текущей активности
файлов. Драйвер может вести счет открытых файлов и каждый
вызов функции драйвера Открыть производит инкремент этого
счетчика, а каждое Закрыть - декремент. Если счетчик равен
нулю, то нет открытых файлов на этом устройстве. Поэтому
драйвер должен сбросить все буферы, т.к. теперь пользователь
может "легально" сменить диск в дисководе.
Могут возникнуть сложности с этим механизмом на блоковых
устройствах, т.к. программы использующие FCB могут открывать
файлы без их закрытия. Поэтому рекомендуется сбрасывать
- 191 -
счетчик в ноль без сброса буферов, когда ответ на "был ли
диск сменен" положительный и вызвана функция драйвера
Построить БПБ.
Эти функции более полезны на символьных устройствах.
Например, функция Открыть может быть использована для
передачи устройству инициализирующей последовательности.
Механизм счетчика может быть использован для обнаружения
одновременного доступа к устройству. В этом случае второе
Открыть должно возвращать ошибку.
Обратите внимание на то, что раз все программы имеют
доступ к стандартным устройствам (хендлы 0,1,2,3,4), то
устройства CON, AUX и PRN всегда открыты.
2.7.7 Сменный диск (функция проверки типа диска)
Код операции - 15
t1 ______________________________
ES:BX - і 13 БАЙТ Заголовок запроса і
______________________________
t0
Эта функция вызывается, только если бит 11 в слове
атрибута заголовка устройства равен 1. Некоторым утилитам
иногда необходимо знать, с каким диском они имеют дело - с
флоппи диском или жестким диском. Примером является команда
FORMAT, которая выводит различные варианты некоторых запросов.
Информация возвращается в бите "занято" слова состояния.
Если этот бит равен 1, то диск жесткий. Если бит равен нулю,
то диск сменяемый (флоппи). Обратите внимание на то, что бит
ошибки не проверяется. Считается, что эта функция не дает
сбоев.
2.7.8 Функция проверки состояния
Код операции - 6 и 10
t1 ______________________________
ES:BX - і 13 БАЙТ Заголовок запроса і
______________________________
t0
При вызове системой этой функции драйвер должен
выставить слово состояния следующим образом:
- Для вывода на символьные устройства - если драйвер
установит бит 9 в 1, то это значит для системы,
что запрос на запись (если сделан) будет ожидать
завершения текущего запроса. Если этот бит равен
нулю, то текущих запросов нет и выполнение
сделанного запроса начнется немедленно.
- Для ввода с символьного устройства с буфером - возврат
единицы означает отсутствие символов в буфере, а
поступивший запрос на чтение пойдет к физическому
устройству . Если бит равен нулю, то в буфере
устройства есть символы и чтение не будет
блокировано. Возврат нуля означает, что
пользователь нажал на какую-либо клавишу. MS-DOS
считает, что все символьные устройства имеют
промежуточный буфер. Устройства, не имеющие буфера
должны всегда возвращать бит 9 равным нулю, чтобы
DOS не ожидала ввода в несуществующий буфер.
- 192 -
2.7.9 Функция сброса
Коды операций - 7 и 11
t1 ______________________________
ES:BX - і 13 БАЙТ Заголовок запроса і
______________________________
t0
Функция сброса приказывает драйверу сбросить все текущие
запросы. Эта функция используется для сброса входной очереди
на символьных устройствах.
Дравер устройства выполняет сброс, выставляет слово
состояния и возвращает управление.
2.7.10 Функции общего УВВ
Код операции - 19
t1 ___________________________________________
ES:BX - і 13 БАЙТ Заголовок запроса і
і BYTE Код категории (главный) і
і BYTE Код функции (вспомогательный) і
і WORD Содержимое (SI) і
і WORD Содержимое (DI) і
і DWORD Указатель на буфер данных і
___________________________________________
t0
Функции общего УВВ дают расширенное средство управления
вводом/выводом. Они заменяют и делают функции драйвера УВВ
чтение/запись абсолютными. Функция общего УВВ содержит код
категории и код функции. DOS считывает это поле для перехвата
и выполнения команд драйвера, которые обслуживаются кодом DOS.
Все остальные категории команд направляются для обслуживания
драйверу.
Более подробно коды функций и категорий даны в описании
функций 440СН и 440DH в Главе 1, "Системные вызовы".
2.7.11 Установить/получить карту логического дисковода
t1 Код операции - 23 (получить) и 24 (установить)
_______________________________________________
ES:BX - і 13 БАЙТ Заголовок запроса і
і BYTE Ввод (код устройства) і
і BYTE Вывод (текущий логический дисковод)і
і BYTE Код команды і
і WORD Состояние і
і DWORD Зарезервировано і
_______________________________________________
t0
Эта функция вызывается MS-DOS, только если установлен
бит 6 в слове атрибута заголовка устройства. Активизируемый
логический дисковод передается в поле Код устройства
заголовка запроса. Драйвер устройства возвращает текущий
логический дисковод , соответствующий запрашиваемому
физическому.
- 193 -
2.8 Байт описатель диска
В MS-DOS байт описатель диска используется для сообщения
DOS о наличии другого типа диска. Этот байт может иметь
значение от 0 до FFH. Он необязательно должен совпадать с
байтом FAT ID (метка таблицы размещения файлов). Байт FAT ID,
являющийся первым байтом FAT, использовался в MS-DOS 1.00
для различения типов дисков может использоваться драйверами
версий 2.X и 3.X. Байт FAT ID имеет значение только для
блоковых устройств, где бит 13 слова атрибута равен нулю.
Байт описатель диска и байт FAT ID не имеют значения для
MS-DOS. Они передаются драйверу так, чтобы программы могли
определить тип диска.
2.9 Формат таблицы описания диска
Файловая система MS-DOS использует связный список
указателей (один для каждого кластера), называемый Таблицей
размещения файлов (FAT). Неиспользуемые кластеры представлены
нулем, а конец файла FFFH (или FFFFH на устройствах с
16-битовыми элемениами таблицы). Используемые элементы
никогда не должны адресовать нулевые элементы. Если все же
это происходит, то первый элемент FAT (который адресуется
нулевым элементом) зарезервирован и содержит "конец" цепочки.
Обычно предусмотрено несколько признаков конца цепочки,
используемых для различения типов дисков ( [F]FF8H [F]FFFH ).
Предпочтительнее писать полную таблицу описания диска в
секторе начальной загрузки и использовать ее для
идентификации диска. Для обеспечения совместимости с ранними
версиями системы, чьи драйверы не устанавливают бит 13,
необходимо также записывать байты FAT ID во время процесса
форматирования.
Для большей гибкости в поддержке различных дисковых
форматов, рекомендуется хранить информацию, касающуюся БПБ
для конкретных дисков, в секторе начальной загрузки. Формат
такого сектора показан ниже:
t1 __________________________________________________________
і 3 БАЙТА Близкий переход на код начальной загрузки і
і 8 БАЙТ Имя и версия і
Б і WORD Байт в секторе і
П і BYTE Секторов в кластере і
Б і WORD Зарезервировано секторов і
і і BYTE Количество FAT і
і WORD Количество входов корневого каталога і
Б і WORD Количество секторов в логическом образе или 0 і
П і BYTE Байт описатель диска і
Б і WORD Количество секторов FAT і
і WORD Cекторов на дорожке і
і WORD Количество головок і
і WORD Количество скрытых секторов (младшее слово) і
і WORD Количество скрытых секторов (старшее слово) і
і DWORD Количество логических секоров і
__________________________________________________________
t0
Хотя MS-DOS не использует пять полей, следующих за БПБ,
драйверы устройств могут использовать их для анализа диска.
Поля "количество секторов на дорожке" и "количество
головок" необходимы для поддержки различных типов дисков,
- 194 -
имеющих одинаковую логическую разметку, но разную физическую
(например, 40 дорожек, двусторонний и 80 дорожек,
односторонний).
Поле "количество логических секторов" сообщает драйверу,
сколько секторов резервировать, если поле "количество секто-
ров в логическом образе" равно нулю.
Рекомендуется следующая процедура определения диска
драйверами, устанавливающими бит 13 слова атрибута:
1. Считать сектор начальной загрузки в область памяти,
адресуемую DWORD указателем на буфер обмена.
2. Определить, является ли первый байт сектора начальной
загрузки Е9Н или ЕВН (для определения длины кода перехода).
Если так, то БПБ имеет смещение 3. Вернуть указатель на него.
3. Если сектор начальной загрузки не имеет БПБ, то
вероятно диск форматировался 1.Х версией MS-DOS и возможно
использует байт FAT ID для идентификации диска.
Драйвер может прочитать первый сектор Таблицы размещения
файлов (FAT) в буфер обмена и прочитать первый байт этого
сектора, после чего вернуть указатель на "зашитый" БПБ.
2.10 Устройство Часы
MS-DOS расчитана также на работу с системными часами.
Ими могут быть CMOS часы реального времени или интервальный
таймер, инициализируемый пользователем во время загрузки
системы. Устройство Часы функционирует также, как и любое
другое символьное устройство, за исключением того, что оно
идентифицируется битом 3 слова атрибута. DOS использует этот
бит; в последующем устройство Часы может иметь любое имя. На
IBM компьютерах используется имя $CLOCK для предотвращения
конфликтов с существующими файлами, имеющими имя clock.
Уникальность этого устройства состоит в том, что MS-DOS
читает и записывает 6-байтную последовательность, кодирующую
дату и время. Запись на это устройство означает установку
даты и времени; чтение - их вывод.
Ниже приведен двоичный формат, используемый устройством
часы:
t1
байт 0 байт 1 байт 2 байт 3 байт 4 байт 5
_____________________________________________________________
і і і і і і і
і дней после 1.1.80 і минуты і часы і сек/100 і секунды і
і младш. і старш. і і і і і
____________________________________________________________
t0
2.11 Порядок обращения к устройству
Нижеприведенные пункты иллюстрируют цепь событий,
происходящих при вызове MS-DOS драйвера блокового устройства
для выполнения операции Запись:
1. MS-DOS заполняет заголовок запроса в фиксированной
области памяти.
2. MS-DOS вызывает программу стратегии драйвера
блокового устройства.
3. Драйвер устройства сохраняет регистры ES и BX (ES:BX
адресуют заголовок запроса) и выполняет дальний
возврат.
- 195 -
4. MS-DOS вызывает программу прерывания.
5. Драйвер считывает из заголовка запроса код операции
(смещение 2). Драйвер преобразует код операции в
индекс таблицы адресов процедур, выполняющих
соответствующие операции и передает управление
процедуре с этим индексом.
6. Драйвер считывает код устройства (смещение 1) для
определения диска, на который выполняется запись.
7. Так как операцией является Запись на диск, то драйвер
должен получить адрес буфера обмена с диском
(смещение 14), количество секторов (смещение 18) и
начальный сектор (смещение 20) в заголовке запроса.
8. Драйвер устройства преобразует номер первого
логического сектора в номера дорожки, головки и
сектора.
9. Драйвер устройства записывает указанное количество
секторов на диск из буфера обмена, указанного в
запросе. Обратите внимание на то, что может
понадобится несколько команд Записи.
10. После завершения записи, драйвер должен сообщить
MS-DOS результат установкой бита "выполнено" в слове
состояния (смещение 3 в заголовке запроса). Кроме
того, он должен сообщить количество действительно
переданных байт в поле Счетчик сектор/байт.
11. В случае ошибки драйвер устанавливает бит 8 и 15 в
слове состояния и заполняет младший его байт кодом
ошибки. Количество действительно переданных байт
помещается в соответствующее поле заголовка запроса,
т.к. недостаточно устанавливать один лишь бит ошибки.
12. Драйвер устройства выполняет дальний возврат в MS-DOS.
Драйверы должны сохранять состояние системы, т.е.
сохранять все регистры, включая регистр флагов. Флаги DF и IF
наиболее важны. При вызове программы прерывания драйвера,
MS-DOS содержит 40-50 байт свободного пространства во
внутреннем стэке. Если драйвер выполняет значительные
стэковые операции, то он должен переключиться на свой стэк.
2.12 Два примера драйверов устройств
Следующие два примера иллюстрируют программы драйверов
блокового и символьного устройств. Ваши драйверы могут
отличаться от приведенных ниже, в зависимости от аппаратной
реализации.
; ********** Драйвер блокового устройства **********
;
; Поддерживает до четырех 5.25-дюймовых дисководов на
; одном дисковом контроллере. Поддерживает все стандартные
; форматы IBM PC.
false equ 0
true equ not false
;Адрес порта ввода/вывода дискового контроллера
disk equ 0E0H
;disk+0
; 1793 Команда/состояние
- 196 -
;disk+1
; 1793 Дорожка
;disk+2
; 1793 Сектор
;disk+3
; 1793 Данные
;disk+4
; AUX Команда/состояние
;disk+5
; Ожид. Синх.
;Бит выбора обратной стороны
backbit equ 04H
;Бит выбора 5 1/4"
smalbit equ 10H
;Бит двойной плотности
ddbit equ 08H
;Бит "выполнено" в регистре состояния
donebit equ 01H
;Используйте эту таблицу для выбора скорости шага
;головки. Значения для 5" дисководов вдвое больше
;указанных в таблице значений.
; Шаг 1771 1793
;
; 0 6ms 3ms
; 1 6ms 6ms
; 2 10ms 10ms
; 3 20ms 15ms
stpspd equ 1
numerr equ errout-errin
cr equ 0DH
lf equ 0AH
code segment
assume cs:code,ds:nothing,es:nothing,ss:nothing
;--------------------------------------------------------
;
; Заголовок устройства
;
drvdev label word
dw -1,-1
dw 0000 ; Блоковое, IBM формат
dw strategy
dw drv$in
drvmax db 4
drvtbl label word
dw drv$init
dw media$chk
dw get$bpb
dw cmderr
dw drv$read
dw exit
dw exit
dw exit
dw drv$writ
- 197 -
dw drv$writ
dw exit
dw exit
dw exit
;--------------------------------------------------------
;
; Программа стратегии
;
ptrsav dd 0
stratp proc far
strategy:
mov word ptr [ptrsav],bx
mov word ptr [ptrsav+2],es
ret
stratp endp
;--------------------------------------------------------
; Главный вход
;
cmdlen = 0 ; Длина команды
unit = 1 ; Указанное устройство
cmdc = 2 ; Код операции
status = 3 ; Состояние
media = 13 ; Описатель диска
trans = 14 ; Буфер обмена
count = 18 ; Счетчик блоков или символов
start = 20 ; Первый блок для передачи
;
drv$in:
push si
push ax
push cx
push dx
push di
push bp
push ds
push es
push bx
lds bx,[ptrsav] ; Получить указатель
; на заголовок
mov al,byte ptr [bx].unit ; al = код устройства
mov ah,byte ptr [bx].media ; ah = описатель дис-
; ка
mov cx,word ptr [bx].count ; cx = счетчик
mov dx,word ptr [bx].start ; dx = начальный сек-
; тор
push ax
mov al,byte ptr [bx].cmdc ; Код операции
cmp al,15 ;
ja cmderrp ; Не тот код
cbw
shl ax,1 ; умноженный на 2 =
; индексу в таблице
; адресов
mov si,offset drvtbl ; ES:DI = буфер
; обмена
add si,ax
pop ax
- 198 -
les di,dword ptr [bx].trans
push cs
pop ds
assume ds:code
jmp word ptr [si] ; переход на выполнение
; команды
;--------------------------------------------------------
;
; EXIT (выход) - все программы выходят через эту
; процедуру
;
assume ds:nothing
cmderrp:
pop ax ; Очистить стэк
cmderr:
mov al,3 ; Неизвестная команда
jmp short err$exit
err$cnt:
lds bx,[ptrsav]
sub word ptr [bx].count,cx
err$exit: ; В AL код ошибки
mov ah,10000001B ; Возврат ошибки
jmp short err1
exitp proc far
exit: mov ah,00000001B
err1: lds bx,[ptrsav]
mov word ptr [bx].status,ax ; Отметить заверше-
; ние операции
pop bx
pop es
pop ds
pop bp
pop di
pop dx
pop cx
pop ax
pop si
ret ; Восстановление регистров и возврат
exitp endp
;--------------------------------------------------------
curdrv db -1
trktab db -1,-1,-1,-1
seccnt dw 0
drvlim = 8 ; Количество секторов на устройстве
seclim = 13 ; Максимальный сектор
hdlim = 15 ; Максимальная головка
;
; Предостережение: сохраняйте порядок drive - curhd !
;
drive db 0 ; Код физического дисковода
curhd db 0 ; Текущая головка
cursec db 0 ; Текущий сектор
curtrk dw 0 ; Текущая дорожка
;
media$chk: ; Всегда показывает "не знаю"
assume ds:code
test ah,00000100B ; Сменяемый ли диск?
- 199 -
jz media$ext
xor di,di ; Я не знаю
media$ext:
lds bx,[ptrsav]
mov word ptr [bx].trans,di
jmp exit
build$bpb:
assume ds:code
mov ah,byte ptr es:[di] ; Получить байт FAT ID
call buildbp ; Перевести
setbpb: lds bx,[ptrsav]
mov [bx].media,ah
mov [bx].count,di
mov [bx].count+2,cs
jmp exit
buildbp:
assume ds:nothing
; В АН байт FAT ID
; DI указывает на правильный БПБ по возвращении
push ax
push cx
push dx
push bx
mov cl,ah ; Сравнить с правильным
and cl,0F8H ; байтом FAT ID
cmp cl,0F8H
jz goodid
mov ah,0FEH ; По умолчанию 8 секторов
goodid: ; двусторонний
mov al,1 ; Количество секторов FAT
mov bx,64*256+8 ; Каталоговые входы и сект. макс.
mov cx,40*8 ; Размер диска
mov dx,01*256+1
mov di,offset drvbpb
test ah,00000010B ; Проверка на 8 или 9 сект.
jny has8 ; has8 = имеет 8 секторов
inc al ; Инкремент секторов FAT,
inc bl ; максимума секторов и
add cx,40 ; размера диска
has8: test ah,00000001B ; Проверка кол-ва головок
jz has1 ; Z = 1 головка
add cx,cx ; Удвоить размер диска
mov bh,112 ; Увел. кол-ва кат. входов
inc dh ; Инкремент сект/все устр. и
inc dl ; головок
;
has1: mov byte ptr [di].2,dh
mov byte ptr [di].6,bh
mov word ptr [di].8,cx
mov byte ptr [di].10,ah
mov byte ptr [di].11,al
mov byte ptr [di].13,bl
mov byte ptr [di].15,dl
pop bx
pop dx
pop cx
pop ax
ret
;
;--------------------------------------------------------
- 200 -
;
; Процедуры ввода/вывода с диска
;
; Вход:
; al = Номер дисковода
; ah = Описатель диска
; cx = Счетчик секторов
; dx = Первый сектор
; ds = cs
; es:di = Буфер обмена с диском
; Выход:
; При успешном завершении флаг переноса сброшен.
; Иначе CF=1 и AL содержит код ошибки (MS-DOS);
; В СХ количество НЕпереданных секторов
;
drv$read:
assume ds:code
jcxz dskok
call setup
jc dsk$io
call dskrd
jmp short dsk$io
drv$writ:
assume ds:code
jcxz dskok
call setup
jc dsk$io
call dskwrt
assume ds:nothing
dsk$io: jnc dskok
jmp err$cnt
dskok: jmp exit
setup:
assume ds:code
; Вход такой же, как показано выше
; На выходе:
; es:di = Буфер обмена
; ds:bx = Адрес БПБ
; В случае ошибки установлен CF (в AL код ошибки)
; В противном случае:
; [drive] = Номер дисковода (0-3)
; [seccnt] = Секторов для передачи
; [cursec] = Номер начального сектора
; [curhd] = Номер начальной головки
; [curtrk] = Номер начальной дорожки
; Задействованы все регистры
;
xchg bx,di
call buildbp
mov si,cx
add si,dx
cmp si,word ptr [di].drvlim ; Сравнить с
; макс. дисководом
jbe inrange
mov al,8
stc
ret
inrange:
mov [drive],al
mov [seccnt,cx ; Сохранить счетчик сект.
- 201 -
xchg ax,dx ; Уст. логического сект.
; для деления
xor dx,dx
div word ptr [di].seclim ; Разделить на Секторов
; в дорожке
inc dl ; Сохранить текущий сектор
mov [cursec],dl ; и получить кол-во головок
mov cx,word ptr [di].hdlim
xor dx,dx ; Разделить дорожки на
; головок в цилиндре
div cx
mov [curhd],dl ; Сохранить тек. головку
mov [curtrk],ax ; и текущую дорожку
seek:
push bx ; Адрес буфера
push di ; Адрес БПБ
call chknew ; Сброс коловки при смене
; дисковода
call drivesel
mov bl,[drive]
xor bh,bh ; bx - индекс дисковода
add bx,offset trktab ; Получить тек. дорожку
mov ax,[curtrk] ; Сохранить нужную
; дорожку
xchg al,ds:[bx] ; Сделать ее текущей
out disk+1,al ; Сообщить об этом
; контроллеру
cmp al,dl ; На правильной дорожке?
jz seekret ; Если да, то все
mov bh,2 ; Счетчик повторов поиска
cmp al,-1 ; Позиционирована?
jnz nohome ; Если нет, то позициони-
; ровать
trysk:
call home
jc seekerr
nohome: mov al,dl
out disk+3,al ; Нужная дорожка
mov al,1CH+stpspd ; Поиск
call dcom
and al,98H ; Ошибки готовности,
; поиска и циклического
; кода
jz seekret
js seekerr ; Если не готово - без
; повтора
dec bh
jnz trysk
seekerr:
mov bl,[drive]
xor bh,bh ; Индекс дисковода
add bx,offset trktab ; Текущую дорожку
mov byte ptr ds:[bx],-1 ; Сделать ее неопр.
call geterrcd
mov cx,[seccnt] ; Ничего не передано
pop bx ; Указатель БПБ
pop di ; Адрес буфера обмена
ret
seekret:
pop bx ; Указатель БПБ
- 202 -
pop di ; Адрес Буфера обмена
clc
ret
;
;--------------------------------------------------------
; Чтение
;
diskrd:
assume ds:code
mov cx,[seccnt]
rdlp:
call preset
push bx
mov bl,10 ; Счетчик попыток
mov dx,disk+3 ; Порт данных
rdagn:
mov al,80H ; Операция чтения
cli
out disk,al
mov bp,di ; Сохранить адрес для
; повторной попытки
jmp short rloopentry
rloop:
stosb
rloopentry:
in al,disk+5 ; Ожидание DRQ или INTRQ
shr al,1
in al,dx ; Считать данные
jnc rloop
sti ; Восстановить флаг
call getstat
and al,9CH
jz rdpop
mov di,bp ; Восстановить адрес буфера
dec bl
jnz rdagn
cmp al,10H ; Запись не найдена?
jnz got-code ; Нет
mov al,1
got-code:
call geterrcd
pop bx
ret
rdpop:
pop bx
loop rdlp
clc
ret
;--------------------------------------------------------
;
; Запись
;
diskwrt:
assume ds:code
mov cx,[seccnt]
mov si,di
push es
pop ds
assume ds:nothing
wrlp:
- 203 -
call preset
push bx
mov bl,10 ; Счетчик повторов
mov dx,disk+3 ; Порт данных
wragn:
mov al,0A0H ; Команда записи
cli
out disk,al
mov bp,si ; Сохранить адрес для
; повторов
wrloop:
in al,disk+5
shr al,1
lodsb ; Получить данные
out dx,al ; Записать
jnc wrloop
sti ; Восстановить флаг
dec si
call getstat
and al,0FCH
jz wrpop
mov si,bp ; Вернуть адрес буфера
dec bl
jnz wragn
call geterrcd
pop bx
ret
wrpop:
pop
loop wrlp
clc
ret
preset:
assume ds:nothing
mov al,[cursec]
cmp al,cs:[bx].seclim
jbe gotsec
mov dh,[curhd]
inc dh
cmp dh,cs:[bx].hdlim
jb sethead ; Выбрать новую головку
call step ; Перейти на след. дорожку
xor dh,dh ; Выбрать головку 0
sethead:
mov [curhd],dh
call,drivesel
mov al,1 ; Первый сектор
mov [cursec],al ; Установить cursec
gotsec:
out disk+2,al ; Сообщить контроллеру
; какой сектор
inc [cursec] ; На следующий сектор
ret
step:
assume ds:nothing
mov al,58H+stpspd
call dcom
push bx
mov [bl],drive
xor bh,bh ; ВХ - индекс дисковода
- 204 -
add bx,offset trktab ; Получить тек. дорожку
inc byte ptr cs:[bx] ; Следующая дорожка
pop bx
ret
home:
assume ds:nothing
mov bl,3
tryhom:
mov al,0CH+stpspd ; Восстановить
call,dcom
and al,98H
jz ret3
js homerr ; Если не готово, то
; без повторов
push ax ; Сохранить код ошибки
mov al,58H+stpspd
call dcom
dec bl
pop ax ; Вернуть код ошибки
jnz tryhom
homerr:
stc
ret3: ret
;
chknew:
assume ds:nothing
mov al,[drive] ; Получить номер дисковода
mov ah,al
xchg al,[curdrv] ; Сделать текущим
cmp al,ah ; Смена дисководов?
jz ret1 ; Нет
; При смене дисковода сбрасывайте головку
in al,disc+1 ; Получить номер
; текущей дорожки
out disc+3,al ; Выдать ее для поиска
mov al,10H ; Поиск и сброс головки
dcom:
assume ds:nothing
out disk,al
push ax
aam ; Задержка 10 мкс
pop ax
getstat:
in al,disk+4
test al,donebit
jz getstat
in al,disk
ret1: ret
;
drivesel:
assume ds:nothing
; Выбор дисковода по текущей информации
; Только AL меняется
mov al,[drive]
or al,smalbit+ddbit ; Диски 5 1/4" IBM PC
cmp [curhd],0
jz gothead
or al,backbit ; Выбор стороны 1
gothead:
out disk+4,al ; Выбор дисковода и
- 205 -
; стороны
ret
geterrcd:
assume ds:nothing
push cx
push es
push di
push cs
pop es ; ES - локальный сегмент
mov cs:[lsterr],al
mov cx,numerr ; Количество ошибочных
; ситуаций
mov di,offset errin ; Указатель на них
repne scasb
mov al,nuerr-1[di] ; Перевести
stc ; Установить флаг для
; индикации ошибки и
pop di
pop es
pop cx
ret ;вернуться
;
;--------------------------------------------------------
;
; БПБ для гибкого диска IBM. Многие параметры заполняются
; функцией Построить БПБ.
; Это БПБ для двустороннего, 9-секторного диска
drvbpb:
dw 512 ; Формат БПБ см. Разделе 2.9
db 1
dw 1
db 2
dw 64
dw 9*40
db 11111100B
dw 2
dw 9
dw 1
initab: ; До четырех устройств
dw drvbpb
dw drvbpb
dw drvbpb
dw drvbpb
errin: ; ошибки диска, возвращаемые контроллером
db 80H ; Нет ответа
db 40H ; Защита по записи
db 20H ; Ошибка записи
db 10H ; Ошибка поиска
db 8 ; Ошибка циклического кода
db 1 ; 10Н (Запись не найдена)
; при чтении
lsterr: db 0 ; Все другие ошибки
errout: ; Коды ошибок, соответствующие указанным выше
db 2 ; Нет ответа
db 0 ; Защита по записи
db 0AH ; Ошибка записи
db 6 ; Ошибка поиска
db 4 ; Ошибка циклического кода
db 8 ; Сектор не найден
db 12 ; Общая ошибка
- 206 -
drv$init:
;
; Определить количество физических дисководов чтением
; config.sys
;
assume ds:code
push ds
lds si,[ptrsav] ; DS:SI адресуют config.sys
assume ds;nothing
lds si,dword ptr [si.count]
scan-loop:
call scan-switch
mov al,cl
or al,al
jz scan4
cmp al,"s"
jz scan4
werror: pop ds
assume ds:code
mov dx,offset errmsg2
werror2:
mov ah,9
int 21H
xor ax,ax
push ax ; Нет устройств
jmp short abort
badndrv:
pop ds
mov dx,offset errmsg1
jmp werror2
scan4:
assume ds:nothing
; в ВХ количество флоппи-дисков
or bx,bx
jz badndrv ; Ошибка пользователя
cmp bx,4
ja badndrv ; Ошибка пользователя
pop ds
assume ds:code
push bx ; Сохранить кол-во устройств
abort: lds bx,[ptrsav]
assume ds;nothing
pop ax
mov byte ptr [bx].media,al
mov [drvmax],al
mov word ptr [bx].trans,offset drv$init ;
; Установить адрес
; Инициализации
mov [bx].trans+2,cs
mov word ptr [bx].count,offset initab ;
; Установить указатель
; на массив БПБ
mov [bx].count+2,cs
jmp exit
;
; Переключатель в CL, значение в ВХ
;
scan-switch:
xor bx,bx
mov cx,bx
- 207 -
lodsb
cmp al,10
jz numret
cmp al,"-"
jz got-switch
cmp al,"/"
jnz scan-switch
got-switch:
cmp byte ptr [si+1],":"
jnz terror
lodsb
or al,20H ; Преобразовать по нижнему
; регистру
mov cl,al ; Получить переключатель
lodsb ; Пропустить ":"
;
; Получить номер, адресуемый [si]
;
; Стирает только AX,DX BX возвращает номер
;
getnum1:
lodsb
sub al,"0"
jb chkret
cmp al,9
ja chkret
cbw
xchg ax,bx
mov dx,10
mul dx
add bx,ax
jmp getnum1
chkret:
add al,"0"
cmp al," "
jbe numret
cmp al,"-"
jz numret
cmp al,"/"
jz numret
terror:
pop ds ; Избавиться от адреса
; возврата
jmp werror
numret:
dec si
ret
errmsg1 db "smldrv: Bad number of drives",13,10,"$"
errmsg2 db "smldrv: Invalid parameter",13,10,"$"
code ends
end
- 208 -
_________________________________________________________
Драйвер символьного устройства
_________________________________________________________
; Адреса для ввода/вывода (IBM)
;
cr=13 ; ВК
backsp=8 ; Пробел
esc=1BH
brkadr=6CH ; Адрес вектора BREAK
asnmax=200 ; Размер буфера
code segment byte
assume cs:code,ds:nothing,es:nothing
;--------------------------------------------------------
; CON - драйвер устройства консоль
;
condev: ; Заголовок устройства CON
dw -1,-1
dw 1000000000010011B
dw strategy
dw entry
db 'con
;--------------------------------------------------------
; Таблица переходов по операциям
;
contbl:
dw con$init
dw exit
dw exit
dw cmderr
dw con$read
dw con$rdnd
dw exit
dw con$flsh
dw con$writ
dw con$writ
dw exit
dw exit
cmdtbl:
db 'A'
dw cuu ; курсор вверх
db 'B'
dw cud ; курсор вниз
db 'C'
dw cuf ; курсор вперед
db 'D'
dw cub ; курсор назад
db 'H'
dw cuh ; позиция курсора
db 'J'
dw ed ; очистить экран
db 'K'
dw el ; очистить строку
db 'Y'
dw cup ; позиция курсора
db 'j'
- 209 -
dw pscp ; сохранить ее
db 'k'
dw prcp ; восстановить ее
db 'y'
dw rm ; режим сброс
db 'x'
dw sm ; режим установка
db 0
page
;--------------------------------------------------------
; Точка входа устройства
;
cmdlen = 0 ; Длина этой команды
unit = 1 ; Указанное устройство
cmd = 2 ; Код операции
status = 3 ; Состояние
media = 13 ; Описатель диска
trans = 14 ; Буфер обмена с диском
count = 18 ; Счетчик блоков/символов
start = 20 ; Первый передаваемый блок
ptrsav dd 0
stratp proc far
strategy:
mov word ptr cs:[ptrsav],bx
mov word ptr cs:[ptrsav+2],es
ret
stratp endp
entry:
push si
push ax
push cx
push dx
push di
push bp
push ds
push es
push bx
lds bx,cs:[ptrsav]
mov cx,word ptr ds:[bx].count
mov al,byte ptr ds:[bx].cmd
cbw
mov si,offset contbl
add si,ax
add si,ax
cmp al,11
ja cmderr
les di,dword ptr ds:[bx].trans
push cs
pop ds
assume ds:code
jmp word ptr [si] ; Выполнить команду
page
;--------------------------------------------------------
; Общие процедуры для устройств
;--------------------------------------------------------
; EXIT - все процедуры выходят через эту точку
;
bus$exit:
mov ah,00000011B
jmp short err1
- 210 -
cmderr:
mov al,3
err$exit:
mov ah,10000001B
jmp short err1
exitp proc far
exit: mov ah,00000001B
err1: lds bx,cs:[ptrsav]
mov word ptr [bx].status,ax
pop bx
pop es
pop ds
pop bp
pop di
pop dx
pop cx
pop ax
pop si
ret
exitp endp
;---------------------------------------------------------
; Обработка нажатия клавиши break
;
break:
mov cs:altah,3
intret: iret
page
;
; Переменные строго привязаны к своим позициям,
; поэтому будьте внимательны при введении новых.
;
wrap db 0 ; 0=есть, 1=нет
state dw s1
mode db 3
maxol db 79
col db 0
row db 0
savcr dw 0
altah db 0 ; Обслуживание спец. клавиш
;---------------------------------------------------------
; chrout - запись символа из AL, используя текущий атрибут
;
attrw label word
attr db 00000111B ; Символьный атрибут
bpage db 0 ; Базовая страница
base dw 0B800H
chrout:
cmp al,13
jnz trylf
mov [col],0
jmp short setit
trylf:
cmp al,10
jz lf
cmp al,7
jnz tryback
torom:
mov bx,[attrw]
and bl,7
mov ah,14
- 211 -
int 10H
ret5: ret
tryback:
cmp al,8
jnz outchr
cmp [col],0
jz ret5
dec [col]
jmp short setit
outchr:
mov bx,[attrw]
mov cx,1
mov ah,9
int 10H
inc [col]
mov al,[col]
cmp al,[maxcol]
jbe setit
cmp [wrap],0
jz outchr1
dec [col]
ret
outchr1:
mov [col],0
lf: inc [row]
cmp [row],24
jb setit
mov [row],23
call scroll
setit:
mov dh,row
mov dl,col
xor bh,bh
mov ah,2
int 10H
ret
scroll:
call getmod
cmp al,2
jz myscroll
cmp al,3
jz myscroll
mov al,10
jmp torom
myscroll:
mov bh,[attr]
mov bl,' '
mov bp,80
mov ax.[base]
mov es,ax
mov ds,ax
xor di,di
mov si,160
mov cx,23*80
cld
cmp ax,0b800h
jz colorcard
rep movsw
mov ax,bx
- 212 -
mov cx,bp
rep stosw
sret: push cs
pop ds
ret
colorcard:
mov dx,3dah
wait2: in al,dx
test al,8
jz wait2
mov al,25h
mov dx,3d8h
out dx,al ; выключить видео
rep movsw
mov ax,dx
mov cx,dp
rep stosw
mov al,29h
mov dx,3d8h
out dx,al ; включить видео
jmp sret
getmod: mov ah,15
int 16 ; получить колонку
mov brage,bh
dec ah
mov word ptr mode,ax
ret
;-------------------------------------------------------------
;
; Чтение консоли
;
con$read:
jcxz con$exit
con$loop:
push cx ; Сохранить счетчик
call chrin ; Получить символ в AL
pop cx
stosb ; Поместить его по es:di
loop con$loop
con$exit:
jmp exit
;------------------------------------------------------------
; Ввести один символ в AL
;
;chrin: xor ax,ax
xchg al,altah ; Получить символ и нулевой
; altah
or al,al
jnz keyret
inagn: xor an,an
int 22
alt10:
or ax,ax
jz inagn
or al,al ; Специальный?
jnz keyret
mov altan,ah ; Сохранить спец. клавишу
- 213 -
keyret: ret
;------------------------------------------------------------
; Небуферизированное чтение
;
;
con$rdnd:
mov al,[altah]
or al,al
jnz rdexit
rd1: mov ah,1
int 22
jz conbus
or ax,ax
jnz rdexit
mov ah,0
int 22
jmp con$rdnd
rdexit: lds bx,[ptrsav]
mov [bx].media,al
exvec: jmp exit
conbus: jmp bus$exit
;------------------------------------------------------------
;
; Процедура сброса
;
con$flsh:
mov [altah],0 ; Очистить буфер
push ds
xor bp,bp
mov ds,bp ; Выбрать сегмент 0
mov ds:byte ptr 41AH,1EH ; Выставить указатели
mov ds:byte ptr 41CH,1EH ; головы и хвоста
pop ds
jmp exvec
;---------------------------------------------------------
; Запись на консоль
;
con$writ:
jcxz exvec
push cx
mov ah,3 ; Установить текущую
; позицию курсора
xor bx,bx
int 16
mov word ptr [col],dx
pop cx
con$lp:
mov al,es:[di] ; Получить символ
inc di
call outc ; Вывести символ
loop con$lp ; Повторять пока не конец
jmp exvec
cout:
sti
push ds
push cs
pop ds
call outc
- 214 -
pop ds
iret
outc:
push ax
push cx
push dx
push si
push di
push es
push bp
call video
pop bp
pop es
pop di
pop si
pop dx
pop cx
pop ax
ret
;--------------------------------------------------------
;
; Вывести один символ из AL на видеоустройство
;
video:
mov si,offset state
jmp [si]
s1: cmp al,esc ; Это управляющая последовательность?
jnz s1b
mov word ptr [si],offset s2
ret
s1b: call chrout
s1a: mov word ptr [si],offset s1
ret
s2:
push ax
call getmod
pop ax
mov bx,offset cmdtabl-3
s7a:
add bx,3
cmp byte ptr [bx],0
jz s1a
cmp byte ptr [bx],al
jnz s7a
jmp word ptr [bx+1]
movcur:
cmp byte ptr [bx],ah
jz setcur
add byte ptr [bx],al
setcur:
mov dx,word ptr col
xor bx,bx
mov ah,2
int 16
jmp s1a
cup:
mov word ptr [si],offset cup1
ret
cup1:
sub al,32
- 215 -
mov byte ptr [row],al
mov word ptr [si],offset cup2
ret
cup2:
sub al,32
mov byte ptr [col],al
jmp setcur
sm:
mov word ptr [si],offset s1a
ret
cuh:
mov word ptr col,1
jmp setcur
cuf:
mov ah,maxcol
mov al,1
cuf1: mov bx,offset col
jmp movcur
cub:
mov ax,00FFH
jmp cuf1
cuu:
mov ax,00FFH
cuu1: mov bx,offset row
jmp movcur
cud:
mov ax,23*256+1
jmp cuu1
pscp:
mov ax,word ptr col
mov savcr,ax
jmp setcur
prcp:
mov ax,savcr
mov word ptr col,ax
jmp setcur
ed:
cmp byte ptr [row],24
jae el1
mov cx,word ptr col
mov dh,24
jmp erase
el:
mov byte ptr [col],0
el: mov cx,word ptr [col]
el2: mov dh,ch
erase: mov dl,maxcol
mov bh,attr
mov ax,0600H
int 16
ed3: jmp setcur
rm:
mov word ptr [si],offset rm1
ret
rm1: xor cx,cx
mov ch,24
jmp el2
con$init:
int 11H
and al,00110000B
- 216 -
cmp al,00110000B
jnz iscolor
mov [base],0B00H
iscolor:
cmp al,00010000B
ja setbrk
mov [mode],0
mov [maxcol],39
setbrk:
xor bx,bx
mov ds,bx
mov bx,brkadr
mov word ptr [bx],offset break
mov word ptr [bx+2],cs
mov bx,29*4
mov word ptr [bx],offset cout
mov word ptr [bx+2],cs
lds bx,cs:[ptrsav]
mov word ptr [bx].trans,offset con$init
mov [bx].trans+2,cs
jmp exit
code ends
end
©
KOAP Open Portal 2000
|
|