|
Глава 6. УСТАНАВЛИВАЕМЫЕ ДРАЙВЕРЫ
УСТРОЙСТВ
Зачем нужны драйверы устройств?
Установка драйверов устройств
Работа с драйвером в среде MS-DOS
Создание драйверов устройств
Пример драйвера виртуального диска
Заключение
Основное требование, предъявляемое к любой вычислительной сис-
теме, заключается не только в способности вычислять, но и в спо-
собности взаимодействовать с внешним миром через периферийные ус-
тройства. Без таковой способности компьютер становится не более
чем бесполезной "железякой". Задача любой операционной системы
состоит в обеспечении средств взаимодействия для прикладных прог-
рамм и для нужд самой операционной системы.
Для того, чтобы прикладная программа могла взаимодействовать с
внешним устройством, операционная система должна удовлетворять
двум основным требованиям. Во-первых, должен существовать опреде-
ленный интерфейс между прикладной программой и операционной сис-
темой. Этот интерфейс должен быть достаточно гибким, чтобы при-
кладная программа могла точно определить свои действия при работе
с требуемым устройством. Во-вторых, операционная система обязана
уметь передавать и принимать данные от устройства и управлять его
работой. Такой интерфейс в MS-DOS обеспечивается так называемыми
драйверами устройств.
В то время как операционные системы больших ЭВМ и миникомпь-
ютеров традиционно обладают широкими возможностями по поддержке
устройств, микрокомпьютеры довольно бедны в этой области. Обычно
они имеют средства поддержки основных дисковых накопителей, сис-
темного терминала, печатающего устройства и, возможно, какого-ли-
бо дополнительного устройства. Все что поддерживается сверх этого
уровня можно рассматривать как приятную неожиданность. В старых
операционных системах, включая MS-DOS версии 1.0, обеспечивать
поддержку дополнительных устройств после покупки ОС было довольно
затруднительно. Операционная система не содержала функциональных
запросов прикладного уровня для нестандартных устройств и сами
драйверы были глубоко запрятаны в BIOS (базовая система ввода-вы-
вода). Добавление или изменение драйвера устройства требовало
корректировки исходных кодов BIOS (при их наличии, разумеется),
повторного ассемблирования и копирования полученных кодов на за-
грузочную дорожку системного диска. Очень часто для выполнения
указанных операций не было даже соответствующих утилит. Более то-
го, такие компьютеры как IBM PC не позволяли и этого, т.к. их
BIOS записана в ПЗУ (постоянном запоминающем устройстве). Измене-
ние содержимого ПЗУ требует наличия специального программатора
(устройства, которое записывает информацию в программируемое
ПЗУ), а он имеется далеко не у каждого. И даже после всех этих
усилий прикладная программа не имела никаких средств для общения
с драйвером с помощью ОС.
Все изменилось с выходом MS-DOS версии 2.0. Вероятно, самым
значительным нововведением в операционных системах микрокомпьюте-
ров с тех пор как появилась CP/M стало то, что MS-DOS версии 2.0
и выше обеспечивают не только возможность установки драйверов без
- 6-2 -
каких-либо мучений, но и стандартный расширяемый интерфейс, кото-
рый дает программам возможность взаимодействовать с драйверами. В
результате громадно возросло количество устройств, поддерживаемых
MS-DOS и появились драйверы псевдоустройств, обеспечивающие
MS-DOS системы такими средствами как RAM-диски, высокоуровневые
графические интерфейсы и т.п.
Драйвер устройства в MS-DOS - это подпрограмма, которая вызы-
вается MS-DOS, с одной стороны, и взаимодействует с конкретным
устройством, с другой. Как посредник между системой и аппарату-
рой, драйвер устройства передает данные между программой и уст-
ройством.
Зачем нужны драйверы устройств?
Драйверы устройств решают две основные задачи. Первая заключа-
ется в обеспечении стандартного интерфейса со всеми программами,
желающими использовать определенное устройство, независимого от
конкретных особенностей устройства. Программа, выполняющая обра-
ботку текста, или электронная таблица, производящая вычисления,
может не заботиться о типе терминала, подключенного к системе,
выдавая простые команды типа "Отобразить символ" и "Получить сим-
вол". Все технические детали по пересылке символов берет на себя
драйвер, обеспечивая тем самым желанный для прикладной программы
высокоуровневый интерфейс. Замена терминала может вызвать замену
драйвера, но при этом в прикладной программе не потребуется де-
лать никаких изменений. Драйверы дисководов должны обеспечивать
стандартный интерфейс для всех используемых типов дисков, при
этом программа, осуществляющая ввод/вывод с диска, будет работать
с дискетой любого формата, с жестким диском, и даже с псевдодис-
ком в ОЗУ, не замечая никаких различий. Одним словом, первая за-
дача драйвера состоит в обеспечении независимого от устройства
унифицированного интерфейса.
Второе целевое назначение драйверов устройств заключается в
том, что они для всех прикладных программ обеспечивают сервис,
подобный библиотекам функций времени выполнения. Любая программа
освобождена не только от необходимости поддержки множества разно-
форматных устройств, но и от необходимости поддерживать вообще
какие-либо форматы. Все заботы по поддержке устройств возложены
на драйверы устройств. В связи с тем, что все драйверы собраны в
операционной системе, требуется лишь одна копия каждого драйвера.
В результате этого программы, написанные с использованием интер-
фейса, предоставляемого MS-DOS, вообще не содержат в себе драйве-
ров.
В операционной системе MS-DOS версии 2.0 и выше драйверы могут
быть добавлены для того, чтобы заменить встроенные драйверы сис-
темы. Если Вам не нравится как работает системный драйвер с конк-
ретным устройством, Вы можете написать свой собственный драйвер.
Как подчеркивалось выше, прикладные программы при этом ничего не
заметят. Конечно создание драйвера - не самое простое занятие,
но, по крайней мере, такая возможность у Вас есть.
Имея такое мощное средство обеспечения работы MS-DOS с различ-
ными устройствами, недолго представить себе драйверы, не поддер-
живающие реальных устройств! Другими словами, можно написать
драйвер,который поддерживает несуществующее устройство, например
драйвер-эмулятор диска в ОЗУ. Такие устройства получили название
"виртуальные устройства", а драйверы таких устройств, соответс-
твенно, "драйверы виртуальных устройств" или просто "виртуальные
- 6-3 -
драйверы".
Реальные или виртуальные устройства не ограничены, по сути де-
ла, только операциями ввода/вывода. На драйвер может быть возло-
жена любая функция по преобразованию данных. Высокоскоростные
процессоры для выполнения больших объемов вычислений с плавающей
точкой - это только один из примеров устройства преобразования
информации. Кроме того, драйверы могут программно эмулировать ре-
альные устройства, которые отсутствуют в конкретной системе, та-
кие как часы или сопроцессор с плавающей точкой.
Когда использовать драйверы устройств?
При каких условиях некоторую функцию следует удалить из прог-
раммы и перенести в драйвер? Основное правило состоит в том, что
если какая-либо функция выполняет ввод/вывод на на физическом
уровне (т.е. работая непосредственно с аппаратурой), то эта функ-
ция - прекрасный кандидат для переноса в драйвер. По самой приро-
де семейства микропроцессоров 80x86 такие функции обычно содержат
команды IN и/или OUT (включая INS или OUTS). Если система поддер-
живает ввод/вывод, отображенный на память, доступ к абсолютным
адресам памяти также может служить индикатором ввода/вывода на
физическом уровне (чтение и запись векторов прерываний тоже явля-
ется доступом к абсолютным адресам, но, конечно, предпочтительнее
использовать функции MS-DOS "Получить вектор прерывания" и "Уста-
новить вектор прерывания", чем использовать для этих же целей
драйвер).
Выделение программ-обработчиков операций ввода/вывода в драй-
вер устройства порождает четыре следствия : это делает программы
более переместимыми, делает обработчики операций ввода/вывода
доступными для других программ, желающих работать с этим устройс-
твом, несколько увеличивает в размерах систему и замедляет время
доступа к аппаратуре. Некоторое увеличение размера памяти, зани-
маемой системой, не имеет большого значения, а вот увеличение
времени доступа может быть критическим фактором для некоторых
приложений. Когда принимается решение о написании драйвера, необ-
ходимо тщательно взвесить скоростные характеристики программы, с
одной стороны, и повышение совместимости программ и доступность
драйвера, с другой стороны. Увеличение времени доступа за счет
накладных расходов при каждом обращении к драйверу более заметно
для устройств, которые передают за один раз слово или байт дан-
ных. В драйверах, передающих за одно обращение целый блок данных,
накладные расходы заметно уменьшаются.
MS-DOS - нереентерабельная система
В связи с тем, что обращения к драйверам осуществляет MS-DOS,
на них накладываются такие же ограничения, как и на резидентные в
памяти программы. Так, например, драйверы не могут пользоваться
функциями MS-DOS (за исключением некоторых функций, которые могут
использоваться при инициализации драйвера). Это серьезно ограни-
чивает свободу драйверов виртуальных устройств, созданных для до-
полнительной обработки информации, предназначенной для стандарт-
ных драйверов.
Так, например, драйвер виртуального принтера, предназначенный
для поддержки графических примитивов на игольчатом принтере не
может использовать стандартные функции MS-DOS для вывода симво-
лов. Драйвер виртуального принтера должен обеспечивать полную
- 6-4 -
программную поддержку для осуществления физического вывода на
принтер. Заметим, что драйвер, описанный в этом примере, именует-
ся виртуальным, несмотря на то, что он работает с физическим уст-
ройством. Это объясняется тем, что драйвер предоставляет возмож-
ности, не поддерживаемые реальным устройством, такие как
выполнение графических операций на простом принтере.
В связи с тем, что MS-DOS нереентерабельна, нельзя использо-
вать программу DEBUG для отладки установленного драйвера. Для вы-
полнения собственных операций ввода/вывода DEBUG использует
MS-DOS и если DEBUG использовать для отладки драйвера, он испор-
тит переданную драйверу информацию, делая невозможным возврат
корректной информации в MS-DOS. Один из способов обхода этого
препятствия заключается в использовании любых имеющихся встроен-
ных функций ввода/вывода (например, функций BIOS) для вывода от-
ладочной информации. Более предпочтительный способ заключается в
создании небольшой тестовой программы для проверки работы драйве-
ра, которая передает драйверу тестовые данные и проверяет возвра-
щаемую информацию. Такая программа запускается под управлением
отладчика обычным образом. Конечно, если устройство критично ко
времени, необходимо принять соответствующие меры, чтобы избежать
какого-либо влияния на работу драйвера.
Установка драйверов устройств
Как упоминалось ранее, во времена, предшествующие MS-DOS вер-
сии 2.0, установка драйвера устройства означала изменение BIOS.
Начиная с версии 2.0 появилась возможность устанавливать и заме-
нять драйверы в процессе начальной загрузки системы.
Процесс начальной загрузки MS-DOS начинается со сброса систе-
мы. Аппаратура Вашей системы устанавливается в состояние сброса
при включении питания компьютера. Сразу после сброса процессор
начинает выполнять команды, находящиеся в самом конце его адрес-
ного пространства. Для процессора 80386 это команды, находящиеся
по шестнадцатиричному адресу FFFFFFF0, для процессора 80286 по
адресу FFFFF0, для процессора 8086 по адресу FFFF0. В любом слу-
чае по этим адресам находится ПЗУ, содержащее начальный загруз-
чик, задача которого заключается в загрузке системной области
диска в память. Интересно отметить, что возможности начального
загрузчика постоянно росли. Первый персональный компьютер фирмы
IBM (IBM PC) мог загружаться только с дисковода "A". Вместе с
компьютером IBM PC XT появилась возможность загрузки с жесткого
диска и, видимо, недалек тот час, когда появится возможность се-
тевой загрузки.
Системная область диска, загружаемая в память начальным заг-
рузчиком, называется вторичным загрузчиком. В случае MS-DOS, ра-
ботающей на IBM - совместимом компьютере, это самый первый сектор
диска длиной 512 байт. Такой маленький размер объясняется тем
фактом, что BIOS находится в ПЗУ. Вторичному загрузчику, в этом
случае, для загрузки остальной части системы достаточно обратить-
ся к BIOS, которая всегда находится в ПЗУ. В системах, не содер-
жащих BIOS в ПЗУ, начальный загрузчик должен считывать с диска
программу, способную обеспечить возможность вторичному загрузчику
считать остальную часть системы. В таких системах начальный за-
грузчик должен считывать довольно большую часть диска.
Сама MS-DOS загружается только после того, как будет считан в
память вторичный загрузчик. Именно по этой причине возможен за-
пуск игр, не требующих для своей работы MS-DOS, или возможна заг-
- 6-5 -
рузка других операционных систем. Собственно, тип загружаемой
системы зависит от того, что именно считывается с загрузочного
диска. При загрузке MS-DOS вторичный загрузчик предполагает нали-
чие на диске корневого директория и, как минимум, двух системных
файлов. В связи с тем, что эти файлы скрытые, они не отображаются
при выводе содержимого корневого директория (однако, их можно
увидеть при помощи таких утилит, как XTREE, Norton Utilities или
SDIR). Функции этих файлов одинаковы у всех поставщиков, хотя
имена могут различаться. Первый файл содержит ядро MS-DOS и обыч-
но называется MSDOS.SYS или IBMDOS.COM на системах фирмы IBM.
Другой файл содержит интерфейс между MS-DOS и подсистемой вво-
да-вывода и называется IO.SYS (Microsoft), IBMBIO.COM (IBM) или
еще как-нибудь у других поставщиков. Вместе эти два файла состав-
ляют операционную систему MS-DOS. После того, как вторичный за-
грузчик находит и загружает эти файлы, начинается процесс инициа-
лизации MS-DOS. Заметим, что на IBM-совместимых системах
вторичный загрузчик считывает только файл IBMBIO.COM, который, в
свою очередь, загружает IBMDOS.COM.
Как только загружен интерфейсный файл (IO.SYS или его эквива-
лент), вторичный загрузчик передает управление процедуре инициа-
лизации, содержащейся в интерфейсном файле. Кроме этой процедуры
интерфейсный файл содержит стандартные драйверы, которые будут
использоваться при инициализации и работе MS-DOS.
Сама процедура инициализации заключается в распределении час-
тей MS-DOS в памяти, создании всех внутренних таблиц, рабочих об-
ластей и т.п., и, наконец, инициализации всех устройств, связан-
ных с системой. Инициализация устройств заключается в посылке
команды INIT каждому из драйверов, содержащихся в интерфейсном
файле (мы обсудим команду INIT позже, совместно с другими коман-
дами для драйверов устройств). После инициализации устройств про-
цедура инициализации заканчивает создание внутренних таблиц и
система к этому моменту готова к работе. До окончательного завер-
шения, однако, остается еще один шаг.
В этой точке процедура инициализации проверяет наличие файла
CONFIG.SYS. Если указанный файл отсутствует, то MS-DOS загружает
стандартный интерпретатор команд и передает ему управление. Если
же файл CONFIG.SYS найден, то выполняется еще один шаг инициали-
зации. На этом этапе Вам предоставляется возможность подключить к
MS-DOS Ваши собственные драйверы устройств.
Файл CONFIG.SYS
Файл CONFIG.SYS это обычный текстовый файл, который должен
быть расположен в корневом директории диска, с которого происхо-
дит загрузка системы (если этот файл находится не в корневом ди-
ректории, то процедура инициализации предполагает, что он совсем
отсутствует). Файл CONFIG.SYS содержит команды, руководствуясь
которыми процедура инициализации изменяет и/или дополняет стан-
дартную конфигурацию MS-DOS. Если этот файл доступен, процедура
инициализации (но не COMMAND.COM - он еще не загружен) считывает
его в память и обрабатывает строка за строкой. Каждая строка со-
держит одну команду конфигурации. На диаграмме 6-1 показана обра-
ботка некоторых команд. Наиболее важна для нас команда DEVICE,
которая имеет следующий формат:
DEVICE=[d:][path]filename[.ext][ parameters]
- 6-6 -
где (заключенные в квадратные скобки элементы не являются обя-
зательными):
d: - идентификатор дисковода,
path - путь к драйверу,
filename - имя файла, содержащего драйвер,
ext - расширение имени файла,
parameters - параметры для драйвера.
Эта команда задает необходимость установки нового драйвера.
Программа драйвера, содержащаяся в заданном драйвере, похожа на
обычную .COM программу, но имеет некоторые специфические особен-
ности, описываемые далее, в разделе, посвященном написанию драй-
веров.
В общем случае, драйвер представляет собой особую форму рези-
дентной программы. Когда в файле CONFIG.SYS встречается команда
DEVICE, соответствующий драйвер загружается в память и анализиру-
ется. Заголовок драйвера содержит информацию о типе, имени, атри-
бутах устройства и определяет точки входа в программу. После заг-
рузки драйвера MS-DOS обращается к драйверу с командой INIT.
Драйвер выполняет инициализацию и возвращает управление MS-DOS,
указывая адрес конца драйвера, т.е. адрес первого свободного бай-
та памяти, непосредственно следующего за драйвером. На этом уста-
новка драйвера заканчивается.
Указание адреса конца драйвера при возвращении управления
MS-DOS после выполнения команды INIT подобно указанию размера па-
мяти, занимаемой программой, при вызове функции MS-DOS "Остаться
резидентом". По возвращаемому адресу MS-DOS определяет расположе-
ние свободной памяти. Если файл CONFIG.SYS содержит другие коман-
ды DEVICE, следующий драйвер загружается непосредственно после
предыдущего. После того, как обработка файла CONFIG.SYS законче-
на, загружается еще один драйвер - драйвер фиктивного устройства
(NUL-драйвер). Затем MS-DOS завершает инициализацию загрузкой
постоянной части COMMAND.COM или другой, определяемой пользовате-
лем оболочки.
При загрузке драйверов MS-DOS связывает их в цепочку, так что-
бы каждый драйвер содержал ссылку на ранее загруженный драйвер.
Цепочка драйверов начинается, таким образом, с последнего загру-
женного драйвера (NUL-драйвер) и заканчивается самым первым заг-
руженным драйвером (обычно стандартный драйвер устройства COM2).
Такая цепочка строится, используя первые два слова заголовка каж-
дого драйвера. Эти два слова содержат сегмент и смещение следую-
щего в цепочке драйвера или, в случае последнего драйвера число -
1 (шестнадцатиричное значение FFFF). Пример цепочки драйверов по-
казан в листинге 6-6, приведенном в конце этой главы.
Когда MS-DOS требуется обратиться к определенному драйверу,
она начинает поиск по цепочке драйверов (начиная с NUL-драйвера)
в порядке, обратном тому, в котором драйверы были загружены. Пос-
ле того, как требуемый драйвер найден, MS-DOS обращается к нему с
соответствующей командой. Последовательность поиска в цепочке при
этом такова, что если загружен пользовательский драйвер, имя ко-
торого совпадает с именем какого-либо стандартного драйвера (та-
кого как CON, AUX или PRN), драйвер пользователя будет найден
первым. Это позволяет пользователю заменять стандартные драйверы
(например, заменить стандартный CON-драйвер на ANSI.SYS CON-драй-
вер).
Стандартные драйверы в действительности загружаются и инициа-
лизируются до того как файл CONFIG.SYS будет считан и обработан.
- 6-7 -
ЪДДДї ЪДДДї
і 1 і і 2 і
АДВДЩ АДВДЩ
АДДДВДДДЩ
ЪДДДї
і 3 і
АДВДЩ
/ \ Да
< 4 >ДДДДДДДД>В<ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
\ / і
іНет / \ Да і
і < 5 >ДДДДДДДДДДДДДДДДДДДДДДДДДДДї і
і \ / і
і<ДДДДДДДДДДДЩНет ЪДДДї і
і 7 і і
ЪДДДї АДВДЩ і
і 6 і Да / \ і
АДВДЩ ЪДДДДДДД< 8 > і
і \ / і
і ЪДДДї іНет і
/ \ Да і 9 і і
< 12 >ДДДДДДДДДї АДВДЩ ЪДДДї і
\ / і 10і і
іНет ЪДДДї ЪДДДї АДВДЩ і
і 13і і 11і і і
ЪДДДї АДВДЩ АДВДЩ і
і 14і і АДДДДДДДДДДДДДДДДДДДЩ
АДВДЩ і
і і
і<ДДДДДДДДДДДЩ
і
ЪДДДї
і 15і
АДДДЩ
Блок-схема 6-1. Процесс инициализации MS-DOS.
1 - Теплая загрузка (при нажатии клавиш Ctrl+Alt+Del)
2 - Холодная загрузка (кнопка "СБРОС" или включение питания)
3 - Загрузка системы
4 - Файл CONFIG.SYS существует ?
5 - Есть еще строки в CONFIG.SYS ?
6 - Загрузка и запуск требуемого командного процессора (по
умолчанию это COMMAND.COM)
7 - Чтение строки из файла CONFIG.SYS
8 - Это команда "DEVICE=" ?
9 - Загрузка указанного в команде "DEVICE=" файла и подключение
его к цепочке драйверов
10 - Обработка какой-либо из команд "BREAK=","BUFFERS=","FILES="
или "SHELL="
11 - Обращение к драйверу с командой "INIT="
12 - Файл AUTOEXEC.BAT существует ?
13 - Выполнение всех обнаруженных в AUTOEXEC.BAT команд
14 - Выполнение программ DATE и TIME
15 - Выдача системного приглашения "A:>"
- 6-8 -
Это позволяет процедуре инициализации драйвера использовать неко-
торые функции MS-DOS для вывода сообщений или настройке драйвера
на конкретную версию операционной системы. Без всякой опаски мо-
гут быть использованы функции MS-DOS с 01H по 0CH, которые обес-
печивают работу с устройствами CON, PRN и AUX, а также функция
30H ("Получить версию MS-DOS"). Вызовов, относящихся к работе с
файлами или управлением памятью, следует избегать, так как рас-
пределение памяти полностью еще не завершено.
После того, как файл CONFIG.SYS обработан и драйверы проиници-
ализированы, стандартные драйверы устройств CON, PRN и AUX закры-
ваются и заново открываются операционной системой для того, чтобы
могла произойти замена (если таковая предусмотрена) указанных
драйверов. Начиная с этого момента используются только новые
драйверы.
Определенные драйверы не могут быть заменены пользователем.
Один из них - это драйвер пустого (фиктивного) устройства NUL.
Это объясняется тем фактом, что MS-DOS использует NUL-драйвер в
качестве начала цепочки драйверов. Так как встроенный NUL-драйвер
всегда определяет начало цепочки драйверов, то первым всегда бу-
дет найден встроенный NUL-драйвер. Схематический пример цепочки
драйверов показан на рисунке 6-1. Подробно назначение каждого из
указанных полей будет объяснено позже. Драйвер, помеченный как
последний, в действительности был первым устанавливаемым драйве-
ром, а драйвер, находящийся сразу после NUL-драйвера (в цепочке)
устанавливался самым последним.
ЪДДДДДДДДДДДД· ЪДДДДДДДДДДДД· ЪДДДДДДДДДДДД·
і Указатель є і Указатель є і Маркер є
і на первый ЗДДДДДДДД>і на ЗДДДДДДДД>і последнего є
і драйвер є і следующий є і драйвера є
і є і драйвер є і ( -1 ) є
ГДДДДДДДДДДДД¶ ГДДДДДДДДДДДД¶ ГДДДДДДДДДДДД¶
і Атрибуты є і Атрибуты є і Атрибуты є
ГДДДДДДДДДДДД¶ ГДДДДДДДДДДДД¶ ГДДДДДДДДДДДД¶
і Указатель є і Указатель є і Указатель є
ЪДДДДДґ на є ЪДДДДДґ на є ЪДДДДДґ на є
і і СТРАТЕГИЙ є і і СТРАТЕГИЙ є і і СТРАТЕГИЙ є
і ГДДДДДДДДДДДД¶ і ГДДДДДДДДДДДД¶ і ГДДДДДДДДДДДД¶
і і Указатель є і і Указатель є і і Указатель є
і ЪДДґ на є і ЪДДґ на є і ЪДДґ на є
і і і ПРЕРЫВАНИЙ є і і і ПРЕРЫВАНИЙ є і і і ПРЕРЫВАНИЙ є
і і ГДДДДДДДДДДДД¶ і і ГДДДДДДДДДДДД¶ і і ГДДДДДДДДДДДД¶
і і і Устройство є і і і Имя или є і і і Имя или є
і і і NUL є і і і число є і і і число є
і і і є і і і устройств є і і і устройств є
АДДДД>ГДДДДДДДДДДДД¶ АДДДД>ГДДДДДДДДДДДД¶ АДДДД>ГДДДДДДДДДДДД¶
і і Программа є і і Программа є і і Программа є
і і СТРАТЕГИЙ є і і СТРАТЕГИЙ є і і СТРАТЕГИЙ є
і \/\/\/\/\/\/ і \/\/\/\/\/\/ і \/\/\/\/\/\/
і /\/\/\/\/\/\/\ і /\/\/\/\/\/\/\ і /\/\/\/\/\/\/\
АД>ГДДДДДДДДДДДД¶ АД>ГДДДДДДДДДДДД¶ АД>ГДДДДДДДДДДДД¶
і Программа є і Программа є і Программа є
і ПРЕРЫВАНИЙ є і ПРЕРЫВАНИЙ є і ПРЕРЫВАНИЙ є
\/\/\/\/\/\/ \/\/\/\/\/\/ \/\/\/\/\/\/
/\/\/\/\/\/\/\ /\/\/\/\/\/\/\ /\/\/\/\/\/\/\
ФННННННННННННј ФННННННННННННј ФННННННННННННј
Рисунок 6-1. Цепочка драйверов устройств.
Не только NUL-драйвер не может быть заменен. Драйверы, работа-
- 6-9 -
ющие с устройствами массовой памяти (например с дисками), также
не могут быть заменены. Вы можете добавить драйверы для новых
дисков, но не удалить или заменить уже существующие. Это ограни-
чение возникает по той причине, что имена драйверам дисковых уст-
ройств (A,B,C и т.д.) назначает MS-DOS при загрузке. Невозможно
присвоить конкретному дисководу уникальное имя, соответственно
нельзя и заменить его.
Использование команды ASSIGN для замены
драйверов дисковых устройств
Тем не менее не расстраивайтесь, если Вас не удовлетворяет ра-
бота существующих дисковых драйверов. Хотя их нельзя удалить, они
могут быть "нейтрализованы". После того, как Вы написали (и прове-
рили) новый драйвер,добавьте его в файл CONFIG.SYS. После переза-
грузки системы он будет включен в цепочку драйверов устройств. На-
пример, если Вы имеете три дисковода, новый драйвер получит имя
"D". Теперь используйте команду ASSIGN для переназначения любых
обращений к старому драйверу на новый. Допустим, мы хотим заменить
драйвер дисковода "A". Команда ASSIGN, при этом, будет иметь вид
ASSIGN A = D
MS-DOS переназначит все обращения к драйверу "A" на драйвер
"D", включая абсолютный доступ к диску по прерываниям 25H и 26H.
Если Вы написали новый драйвер для работы с тем же физическим
дисководом, с которым работал старый драйвер, то описанной проце-
дурой Вы довольно эффективно заменили его на новый. Если же Вам
покажется, что старый драйвер все-таки лучше, Вы можете восстано-
вить первоначальную конфигурацию, введя команду ASSIGN без пара-
метров.
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і ПРЕДУПРЕЖДЕНИЕ : Когда НЕЛЬЗЯ использовать команду ASSIGN і
і і
і Хотя команда ASSIGN позволяет Вам заменять существующие і
і драйверы дисков на новые, это не всегда разумно. Некоторые і
і команды, такие как BACKUP и PRINT, или программы, подобные і
і Lotus 1-2-3 будут весьма удивлены, если их попросят работать с і
і переопределенными дисками. Другие команды, такие как FORMAT, і
і DISKCOPY или DISKCOMP, вообще игнорируют такие диски и работают і
і с настоящими логическими дисками. і
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
Типы драйверов устройств
Существует два типа драйверов устройств, именованные и неиме-
нованные, называемые соответственно драйверами символьных уст-
ройств и драйверами блоковых устройств. Различие между ними го-
раздо глубже, чем способность иметь имя или заменяемость. Кроме
того, что блоковые драйверы предназначены для поддержки дисковых
устройств, предполагается,что один блоковый драйвер может поддер-
живать более одного дисковода. Команды ввода/вывода для таких
драйверов обеспечивают возможность доступа к отдельным секторам
и, если не задан атрибут NONIBM (также известный как NONFAT),
предполагается, что драйвер должен поддерживать стандартную для
MS-DOS структуру диска, включая FAT (таблицу распределения диска)
- 6-10 -
и директории.
Откровенно говоря, названия "символьный" и "блоковый" не сов-
сем точны, так как символьный драйвер тоже может поддерживать
блоковый режим передачи данных. Более того, нельзя сказать, что
символьные драйверы обеспечивают последовательный доступ, а блоч-
ные драйверы обеспечивают прямой доступ, так как можно спроекти-
ровать символьный драйвер так, чтобы он поддерживал прямой доступ
к устройству (если, конечно, он может работать в таком режиме.
Оставив пока вопрос о том, что же такое символьный драйвер и
что такое блоковый драйвер, обсудим некоторые способы работы с
драйверами устройств через MS-DOS. Это даст нам некоторые сообра-
жения о том, какой тип следует выбрать, если Вы желаете написать
драйвер для какого-либо приложения.
Работа с драйверами устройств в среде MS-DOS
Для прикладных программ MS-DOS обеспечивает четыре основных
метода доступа к внешним устройствам. Каждый из них удобен для
соответствующих приложений и мы обсудим достоинства и недостатки
каждого метода для того, чтобы Вы могли выбрать метод, наиболее
удобный для Вашего приложения. Мы не будем описывать детали каж-
дого из функциональных вызовов, так как эту информацию можно най-
ти в "MS-DOS Programmer's Reference Manual" ("MS-DOS. Руководство
программиста.") фирмы Microsoft или другом аналогичном руководс-
тве. Следующий ниже список классифицирует эти четыре метода.
* CP/M-ориентированные функции для работы с такими устройствами,
как консоль, принтер или вспомогательное устройство. Это истин-
но символьные устройства. Функции, входящие в эту группу :
CON: Функции 01H, 02H, и с 06H по 0CH
PRN: Функция 05H
AUX: Функции 03H и 04H
* CP/M-ориентированные функции для работы с файлами с использова-
нием FCB (блока управления файлами). Этот метод также может
быть использован для доступа к символьным устройствам. В эту
группу входят функции :
Открыть/Закрыть: Функции 0FH и 10H
Читать/Писать Устройство/Файл: Функции 14H и 15H
Читать/Писать Файл: Функции 21H, 22H, 27H и 28H
* Функции MS-DOS-стиля для работы с файлами с использованием
описателей. Этот метод (аналогично FCB-методу) тоже можно ис-
пользовать для работы с символьными устройствами. Функции, ра-
ботающие с использованием описателей файлов :
Открыть/Закрыть: Функции 3DH и 3EH
Читать/Писать Устройство/Файл: Функции 3FH и 40H
Управление Устройством: Функция 44H
* Функции прямого доступа к диску, выполняющие чтение и запись по
абсолютным адресам. Эти функции обеспечиваются отдельными пре-
рываниями INT 25H (абсолютное чтение) и INT 26H (абсолютная за-
пись).
- 6-11 -
Функции CP/M-стиля для работы с символьными устройствами
CP/M-ориентированные функции предназначены, в основном, для
работы со стандартным устройством CON и предлагают возможности для
буферизации, эхо-отображения, ожидания символов и проверки состоя-
ния. Поддержка устройств PRN и AUX более ограниченная, но вполне
достаточна для многих приложений. Для нестандартных устройств, од-
нако, необходимо использовать либо метод, использующий FCB (блоки
управления файлами), либо метод на основе описателей файлов.
Работа с устройством с использованием блоков управления файлами
FCB-метод работы с устройствами имеет и достоинства и недос-
татки. С одной стороны, FCB сложнее создавать и использовать, чем
работать с описателями файлов, хотя использование макросредств и
директив STRUC может весьма облегчить задачу построения блока уп-
равления файлом. С другой стороны, FCB-метод позволяет програм-
мисту непосредственно указывать номер записи в файле, делая воз-
можным прямой доступ к файлам. Функции 3FH ("Читать") и 40H
("Писать"), работающие с описателями, позволяют осуществлять толь-
ко последовательный доступ к файлам. Для выполнения прямого досту-
па к файлам, используя функции описателей , прикладная программа
должна обращаться к функции 42H ("Передвинуть указатель файла").
FCB-метод работы таких дополнительных действий не требует.
Работа с устройствами на основе описателей файлов
Хотя прямой доступ очень нужен при работе с файлами, он не
имеет большого значения при работе с не дисковыми устройствами.
При работе с такими устройствами метод доступа, использующий
описатели, намного проще в использовании и не требует от програм-
миста создания FCB. Кроме того, описатель-ориентированный метод
доступа (ДОМД) поддерживает IOCTL (управление вводом/выводом)
функцию 44H. Как мы вскоре увидим, IOCTL-функция может быть исклю-
чительно полезна для управления устройством.
При использовании ДОМД (описатель-ориентированного метода
доступа) для работы с не дисковыми устройствами, программист не
ограничен пересылкой одного байта за один раз. За одно обращение к
функциям ввода/вывода может быть переслано с устройства или на
устройство до 64 Kбайт. Как и при работе с дисками, использование
этих функций для не дисковых устройств приводит к выполнению
последовательной передачи данных. Используя, однако, IOCTL-функцию
прямого управления, можно задать устройству дополнительные пара-
метры. Так, например, если и устройство и его драйвер установлены
в режим прямого доступа, можно использовать IOCTL-функцию для уп-
равления точками отправления и назначения при пересылке данных в
устройстве.
Этот пример может помочь при иллюстрации потенциала прямого
управления вводом/выводом с устройством. Предположим, что некото-
рая система имеет отображаемую на адресное пространство графичес-
кую подсистему. Данные из системной памяти в графическую пересы-
лаются с использованием драйвера графического адаптера. По той
причине, что этот адаптер не является устройством массовой памя-
ти, драйвер для него должен быть символьным. Если ввод/вывод про-
изводится с использованием только ДОМД, нет никакого способа оп-
ределить место в видео-памяти, куда должны быть посланы данные.
- 6-12 -
Если же драйвер поддерживает IOCTL-функцию, место в графической
памяти можно определить через канал управления.
Функция 44H - управление вводом/выводом для устройств (IOCTL)
Как мы упоминали, не все устройства поддерживают вызов
IOCTL-функции. Те драйверы, которые обеспечивают управление вво-
дом/выводом, не обязательно поддерживают все возможности
IOCTL-функции. Тем не менее, IOCTL является настолько мощным
средством управления работой устройств, что понуждает многих
программистов поближе познакомиться с его возможностями. Знание
того, что можно сделать с помощью IOCTL, несомненно определяет
решение программиста о том, какими функциональными особенностями
наделить драйвер устройства.
Функция управления вводом/выводом имеет три основных режима,
которые определяются передаваемым в регистре AL кодом функции :
- Конфигурация устройства (коды 0, 1 и в последних версиях
MS-DOS, коды 8, 0BH, 0EH и 0FH);
- Управление каналом ввода/вывода (коды с 2 по 5 и в MS-DOS
версии 3.2, коды 0CH и 0DH);
- Запрос статуса устройства (коды 6 и 7).
Список кодов функций, поддерживаемых IOCTL, показан в таблице 6-1.
Запрос статуса устройства возвращает либо индикатор готовности
(0FFH) либо не готовности (0). В руководстве программиста фирма
Microsoft предупреждает о том, что код статуса может быть некор-
ректным на момент возвращения управления вызывающей программе.
Вероятно, в руководстве имеется в виду будущая возможность муль-
тизадачности MS-DOS. Можно только надеяться, что когда появятся
будущие версии, Microsoft найдет способ возвращать корректную ин-
формацию. Как бы то ни было, до тех пор пока MS-DOS не стала мно-
гозадачной, проблемы неточности статуса не должно существовать.
Мы уже упоминали возможности канала управления устройством
IOCTL. Попросту говоря, это средство пересылки буфера данных по
вспомогательному каналу. Механизм этого вызова идентичен вызову
функций ввода/вывода на основе ДОМД (функции 3FH и 40H), за иск-
лючением кодов функций, определяемых содержимым регистра AX.
Предназначены ли данные, передаваемые по дополнительному каналу,
для устройства или для самого драйвера - это дело разработчика.
Не будьте, однако, ослеплены простотой этой функции и не восп-
ринимайте ее как всего-лишь еще одну функцию ввода/вывода. В со-
ответствующем приложении, IOCTL может блестяще выступать в роли
вторичного канала для взаимодействия с драйвером. Фирма Microsoft
обеспечила "запасную дверь" для решения непредвиденных проблем.
Они говорят - "Вам кажется, что наш интерфейс с драйверами слиш-
ком ограничен ? Должен быть более гибким ? Что же, попробуйте вот
это." Такой подход является огромным шагом вперед по сравнению с
подходом "У нас нет этого, значит Вам это не нужно !", который не
так давно был весьма распространен в среде разработчиков систем.
- 6-13 -
Таблица 6-1
Функции управления вводом/выводом (IOCTL)
ДДДДДДВДДДДДДДДВДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Код і Версия іПримечаниеі Назначение
(AL=)і MS-DOS і і
ДДДДДДЕДДДДДДДДЕДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
0: і 2.0+ і #1,#2 іПолучить информацию устройства
1: і 2.0+ і іУстановить информацию устройства
2: і 2.0+ і #3,#6 іЧитать из управляющего канала СУ
3: і 2.0+ і #3,#6 іПисать в управляющий канал СУ
4: і 2.0+ і #3,#7 іЧитать из управляющего канала БУ
5: і 2.0+ і #3,#7 іПисать в управляющий канал БУ
6: і 2.0+ і #1 іПолучить входную информацию
7: і 2.0+ і #1 іПолучить выходную информацию
8: і 3.0+ і #2 іБУ поддерживает смену носителя ?
9: і 3.2+ і іБУ локальное или удаленное ?
A: і 3.2+ і іОписатель локальный или удаленный ?
B: і 3.0+ і #4 іИзменить счетчик попыток
C: і 3.3+ і #5 іЗапрос на переключение кодовых страниц
D: і 3.3+ і #5 іЗапрос IOCTL для блоковых устройств
E: і 3.3+ і #5 іПолучить имя логического диска
F: і 3.3+ і #5 іУстановить имя логического диска
ДДДДДДБДДДДДДДДБДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Примечание #1: Функция поддерживает как файлы, так и устройства.
Примечание #2: Функция не поддерживает сетевую работу.
Примечание #3: Функция разрешается битом 14 словом атрибутов
драйвера и поддержка определяется битом 14 слова
конфигурации.
Примечание #4: Функция требует загрузки команды SHARE.
Примечание #5: Функция разрешена битом 6 слова атрибутов драйвера.
Примечание #6: СУ - символьное устройство.
Примечание #7: БУ - блоковое устройство.
Конфигурация с помощью команд управления вводом/выводом
MS-DOS обеспечивает выполнение команд конфигурации ("Получить
или Установить информацию устройства"), поддерживаемых
IOCTL-функцией. На рисунке 6-2 показано 16-битовое слово конфигу-
рации, используемое функциями "Получить/Установить информацию ус-
тройства" (коды 0 и 1). В текущих версиях MS-DOS могут быть опре-
делены только младшие 8 бит этого слова. Ниже описано назначение
тех битов слова конфигурации, которые имеют значение для драйве-
ров устройств или влияют на способ обработки драйвером данных.
IOCTL БИТ 14: CTRL
Бит CTRL устанавливается в 1 если драйвер может обрабатывать
управляющие последовательности. Этот бит точно отражает состояние
IOCTL бита в слове атрибутов драйвера устройства. IOCTL-бит ис-
пользуется драйвером для оповещения MS-DOS о том, что драйвер бу-
дет принимать управляющие последовательности. Этот бит применим
как к файлам, так и к устройствам.
- 6-14 -
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
ЙНННСНННСНННСНННСНННСНННСНННСНННСНННСНННСНННСНННСНННСНННСНННСННН»
є R і C і і і і і і і I і E і B і S і I і I і I і I є
є E і T і і і і і і і S і O і I і P і S і S і S і S є
є S і R і R E S E R V E D і D і F і N і E і C і N і C і C є
є і L і і і і і і і E і і і C і L і U і O і I є
є і і і і і і і і V і і і L і K і L і T і N є
ИНННПНННПНННПНННПНННПНННПНННПНННПНННПНННПНННПНННПНННПНННПНННПНННј
ЗНАЧЕНИЯ БИТОВ УСТРОЙСТВО
CTRL =1 : Поддержка управляющего EOF =0 : Конец файла на входе
канала BIN =1 : Работа в двоичном
ISDEV=1 : Канал - это устройство режиме
=0 : Канал - это файл SPECL=1 : Специальное устрой-
ство
ISCLK=1 : Устройство "ЧАСЫ"
ФАЙЛ ISNUL=1 : Устройство NUL
После записи в канал биты с 0 по ISCOT=1 : Консоль вывода
5 - это номер блокового устр-ва ISCIN=1 : Консоль ввода
Рисунок 6-2. Слово конфигурации устройства.
IOCTL БИТ 7: ISDEV
Бит ISDEV равен 1 если канал (или описатель) открыт к уст-
ройству. Если канал открыт к файлу, то этот бит сбрасывается в 0.
IOCTL БИТ 5: BIN
Пятый бит конфигурации (BIN) определяет подготовленный или не-
подготовленный режим работы драйвера. Другими словами, этот бит
определяет будут ли данные проходить дополнительную обработку при
передаче или MS-DOS будет просто передавать "сырую" двоичную ин-
формацию между устройством и прикладной программой. Под дополни-
тельной обработкой подразумевается обработка определенных управ-
ляющих символов, расширение символов табуляции, проверка на
нажатие клавиш CTRL-BREAK и т.п.
Более традиционными для этих функций являются термины "двоич-
ный режим" и "ASCII режим", соответствующие неподготовленному и
подготовленному режимам. В руководстве программиста для MS-DOS
приводятся более детальные инструкции о том, как проверить и ус-
тановить пятый бит. Мы, в свою очередь, обсудим влияние этого би-
та на работу символьных драйверов. (Заметьте, что, как показано
на рис.6-2, этот бит не используется для блоковых драйверов).
Если символьный драйвер находится в подготовленном режиме (по
умолчанию), данные передаются побайтно. Другими словами, одно об-
ращение к драйверу приводит к передаче одного символа. Это проис-
ходит вне зависимости от того, какое количество байт затребовано
прикладной программой при обращении к MS-DOS. Например, если
прикладной программе требуется вывести 128 байт на символьное ус-
тройство, а драйвер работает в подготовленном режиме, то MS-DOS
сделает 128 обращений к драйверу с функцией "ВЫВОД" или "ВЫВОД С
ПРОВЕРКОЙ", передавая за один вызов один байт.
Посимвольного ввода/вывода можно избежать, переведя драйвер в
неподготовленный режим. Последний может быть установлен только с
помощью IOCTL функции. В неподготовленном режиме количество пере-
даваемых байт, заданное прикладной программой, используется также
при обращении к драйверу. Пользуясь тем же самым примером, если
прикладная программа требует вывода 128 байт на символьное уст-
- 6-15 -
ройство, и драйвер работает в неподготовленном режиме, то MS-DOS
сделает единственное обращение к драйверу с функцией "ВЫВОД" или
"ВЫВОД С ПРОВЕРКОЙ", задавая количество передаваемых байт равным
128.
IOCTL БИТ 4: SPECL
Подобно биту CTRL, бит SPECL в слове конфигурации точно отра-
жает состояние бита SPECL в слове атрибутов. Будучи установлен-
ным, этот бит означает, что данный драйвер (который почти всегда
является драйвером консоли) способен выполнять высокоскоростной
вывод в двоичном режиме, используя прерывание INT 29H.
Бит BIN, определяющий неподготовленный режим, также требует
разрешения высокоскоростного режима вывода, определяемого атрибу-
том SPECL. Если установлены как бит слова конфигурации BIN, так и
бит слова атрибутов SPECL, значит драйвер будет работать в режиме
высокоскоростного вывода. Этот режим и бит атрибутов SPECL обсуж-
даются более глубоко в разделе "Слове атрибутов заголовка драйве-
ра".
Группа команд управления вводом/выводом
Четыре IOCTL команды, появившиеся в MS-DOS версии 3.3 - коман-
ды C, D, E и F - являются необязательными и разрешены только при
установленном бите 6 слова атрибутов драйвера. Группа подфункций,
обеспечиваемых командами C и D, представляет собой довольно "раз-
ношерстное" собрание весьма специфических функций. Эта группа,
как правило, используется для поддержки определенных, заданных
изготовителем устройства функциональных особенностей, таких как
переключение фонтов в принтере, форматирование диска и т.д. Если
Вам кажется, что у Вас есть необходимость использовать эти коман-
ды, следует обратиться к руководству программиста, где представ-
лена более подробная информация.
Команды E и F позволяют прикладному программисту управлять
назначением и освобождением логических дисков, например так, как
это делается командой SUBST. Команда E ("Получить имя логического
диска") возвращает назначение, использованное при последнем обра-
щении к реальному устройству, а команда F ("Установить имя логи-
ческого диска") используется для изменения назначенных имен логи-
ческих дисков.
Прямой доступ к диску через прерывания INT 25H и INT 25H
С другой стороны спектра от доступа к устройству с помощью
описателей файлов (ДОМД) лежат прерывания прямого доступа к диску
: "Чтение по абсолютному адресу" (INT 25H) и "Запись по абсолют-
ному адресу" (INT 26H). Согласно названию, прерывания прямого
доступа к диску работают исключительно с блоковыми устройствами,
например с дисками. Задача этих прерываний заключается в обеспе-
чении работы с дисками напрямую, не используя файловую структуру
MS-DOS. Это может быть полезно в двух случаях.
В первом случае, программисты могут считывать или записывать
отдельные части стандартного диска MS-DOS, содержащие файл или
структуру директория. Это часто требуется, когда часть диска ста-
новится плохой и невозможно, поэтому, использовать FCB-метод или
ДОМД. В этом случае можно использовать функции прямого доступа к
диску для того, чтобы попробовать восстановить все, что может
быть восстановлено. Кроме того, программы могут считывать и запи-
сывать таблицу распределения (FAT) или директории диска, недос-
тупные другим методам. Такая способность требуется утилитам,
- 6-16 -
сортирующим директории, изменяющим атрибуты файлов и т.п.
Во втором случае, использование этих функций может потребо-
ваться в случае, если диск вообще не содержит таблицы распределе-
ния файлов или директориев. Такой диск может быть использован
только как диск данных. Такая же ситуация может встретиться при
чтении дисков, записанных в другой операционной среде, такой как
CP/M или UCSD-p система. Во всех этих случаях параметры диска,
возвращаемые системе драйвером, делают невозможным доступ к диску
любым другим методом. Любая попытка выполнения файловых операций
ввода/вывода, включая чтение директория, возвратит мусор или со-
общение об ошибке ("Non-DOS Disk"). Если Вы желаете получить под-
робную информацию о том, как MS-DOS определяет формат диска,
просмотрите описание команды драйверу "Построить блок параметров
BIOS" в руководстве программиста или ином, аналогичном документе.
Возвращаясь к обеспечению прямого доступа к диску, следует за-
метить, что INT 25H и INT26H не выполняют блокирование и деблоки-
рование данных. Блокирование и деблокирование требуются, когда
размер физического сектора на диске отличается от размера логи-
ческой записи, используемого системой. При блокировании данных
система собирает вместе достаточное количество записей для запол-
нения физического сектора перед сохранением его на диске. Дебло-
кирование используется при чтении с диска, т.к. один физический
сектор может содержать несколько записей. В последнем случае сис-
тема считывает целый сектор и, затем, выбирает оттуда требуемые
программе записи. Функции доступа к диску по абсолютным адресам
считывают и записывают только целые секторы, так что программист
обязан знать размер сектора диска для того, чтобы определить ко-
личество считанных или записанных байтов.
В связи с тем, что параметры, используемые этими прерываниями,
передаются драйверу без какого-либо преобразования, операции чте-
ния и записи передают блоки данных размером, кратным длине секто-
ра диска. Это отличает данный метод доступа от FCB-метода или
описатель-ориентированного метода доступа, где ввод/вывод опре-
деляется в терминах логических блоков и записей, а MS-DOS осу-
ществляет преобразование логических блоков в физические секторы.
Последняя особенность функций прямого доступа к диску заключа-
ется в том, что они возвращаются из прерываний INT 25H и INT 26H
при помощи команды RETF, а не IRET, оставляя при этом флаги на
стеке. Поэтому, после проверки корректности выполнения функции,
Вы должны убрать флаги со стека.
Опция "Ввод/вывод с проверкой"
При выполнении операций ввода/вывода следует учитывать одну
особенность, влияющее на работу драйвера устройства. Эта особен-
ность вызывается использованием опции "Ввод/вывод с проверкой",
при помощи которой можно заставить драйвер проверять выполнение
команд вывода, т.е. осуществлять считывание после записи. Эта оп-
ция может устанавливаться или отменяться тремя способами :
1.С командной строки MS-DOS пользователь может выполнить
команды "VERIFY ON" или "VERIFY OFF" для того, чтобы соот-
ветственно включить или выключить эту опцию.
2.Для некоторых команд MS-DOS, таких как COPY, можно за-
дать ключ /V, который включает опцию проверки на время вы-
полнения команды.
- 6-17 -
3.Опция проверки может быть включена и выключена любой
программой, используя функцию MS-DOS 2H ("Включить или
выключить опцию проверки").
Выводы
В этом разделе мы обсудили основные типы операций, которые мо-
гут потребоваться от драйвера; мы вплотную подошли к вопросам,
связанным с разработкой драйверов.
Обобщая все вышесказанное, можно отметить следующее. Выполне-
ние основных операций ввода/вывода всегда производится через
драйверы устройств. Драйверы могут также поддерживать дополни-
тельный канал ввода/вывода для управления устройством. Символьные
драйверы могут передавать от 1 до 64 Kбайт за одно обращение к
драйверу. Блоковые драйверы могут передавать данные только по
секторам, т.к. преобразование секторов в записи и обратно выпол-
няет MS-DOS. Как мы вкратце упоминали, блоковые драйверы могут
возвращать информацию об используемом ими в настоящий момент дис-
ке.
Создание драйверов устройств
Создание драйверов в любой операционной системе имеет много
преимуществ перед написанием обычных программ. Драйверы устройств
должны следовать строго определенной структуре, а если структура
понятна, то остальное приложится.
Базовая структура драйвера устройства показана на рис.6-3.
Обязательно должны присутствовать три раздела драйвера -- ЗАГОЛО-
ВОК ДРАЙВЕРА, ПРОГРАММА СТРАТЕГИЙ и ПРОГРАММА ПРЕРЫВАНИЙ. Прог-
рамма ПРЕРЫВАНИЙ это не тоже самое, что программа обработки пре-
рываний, которая может присутствовать в качестве необязательной
части работающего по прерываниям драйвера. На самом деле, прог-
рамма ПРЕРЫВАНИЙ - это точка входа в драйвер для обработки полу-
чаемых от MS-DOS команд.
ЪДДДДДДДДДДДДДДДДДДДДДДДДД·
і Заголовок драйвера є
ГДДДДДДДДДДДДДДДДДДДДДДДДД¶
і Область данных драйвера є
ГДДДДДДДДДДДДДДДДДДДДДДДДД¶
і Программа СТРАТЕГИЙ є
ГДДДДДДДДДДДДДДДДДДДДДДДДД¶
і Вход в є
і программу ПРЕРЫВАНИЙ є
ГДДДДДДДДДДДДДДДДДДДДДДДДД¶
і Обработчик команд є
ГДДДДДДДДДДДДДДДДДДДДДДДДД¶
і Программа обработки є
і прерываний є
ГДДДДДДДДДДДДДДДДДДДДДДДДД¶
і Процедура инициализации є
ФНННННННННННННННННННННННННј
Рисунок 6-3. Структура драйвера в MS-DOS
- 6-18 -
В программе 6-1 представлен скелет драйвера устройства. Хотя
структура драйвера похожа на структуру .COM программы, важно от-
метить следующие отличия :
1. Программа начинается с нулевого смещения, а не 100H.
2. Образ программы начинается с директив определения данных
для заголовка драйвера.
3. Программа не содержит директивы ASSUME для стекового
сегмента.
4. Программа не содержит директивы END START.
Листинг 6-1. Заголовок драйвера, программы СТРАТЕГИЙ и ПРЕРЫВАНИЙ
------------------------------------------------------------------
DRIVER SEGMENT PARA
ASSUME CS:DRIVER,DS:NOTHING,ES:NOTHING
ORG 0
START EQU $ ; Начало драйвера
;
;******* ЗАГОЛОВОК ДРАЙВЕРА *******************************************
;
dw -1,-1 ; Указатель на следующий драйвер
dw ATTRIBUTE ; Слово атрибутов
dw offset STRATEGY ; Точка входа в программу STRATEGY
dw offset INTERRUPT ; Точка входа в программу INTERRUPT
db 8 dup (?) ; Количество устройств/поле имени
;
;******* РЕЗИДЕНТНАЯ ЧАСТЬ ДРАЙВЕРА ***********************************
;
req_ptr dd ? ; Указатель на заголовок запроса
.
.
.
;
;******* ПРОГРАММА СТРАТЕГИИ ******************************************
;
; Сохранить адрес заголовка запроса для программы СТРАТЕГИЙ в REQ_PTR.
; На входе адрес заголовка запроса находится в регистрах ES:BX.
;
STRATEGY PROC FAR
mov cs:word ptr [req_ptr],bx
mov cs:word ptr [req_ptr + 2],bx
ret
STRATEGY ENDP
;
;******* ПРОГРАММА ПРЕРЫВАНИЙ *****************************************
;
; Обработать команду, находящуюся в заголовке запроса. Адрес заголовка
; запроса содержится в REQ_PTR в форме СМЕЩЕНИЕ:СЕГМЕНТ.
;
INTERRUPT PROC FAR
pusha ; Сохранить все регистры
- 6-19 -
lds bx,cs:[req_ptr] ; Получить адрес заголовка запроса
.
.
.
INTERRUPT ENDP
.
.
.
DRIVER ENDS
END
---------------------------------------------------------------------
Заголовок драйвера
Заголовок драйвера -- это блок данных длиной 18 байт, которым
должен начинаться любой драйвер. Заголовок драйвера всегда должен
располагаться начиная с нулевого смещения в сегменте драйвера.
При загрузке драйвера MS-DOS считывает заголовок для того, чтобы
определить тип драйвера и точки входа в драйвер. В заголовке
драйвера содержится четыре типа сведений, критичных для использо-
вания драйвера системой : ПОЛЕ СВЯЗИ, СЛОВО АТРИБУТОВ, ВЕКТОРА
ТОЧЕК ВХОДА и ПОЛЕ ИМЕНИ/КОЛИЧЕСТВА.
Поле связи
Первые четыре байта заголовка драйвера это FAR указатель (сме-
щение:сегмент) на следующий драйвер в цепочке (списке) драйверов.
При создании драйвера эти байты устанавливаются равными FFFF:FFFF
(-1). При загрузке нового драйвера его адрес помещается в поле
связи предыдущего драйвера. Исключением являются файлы, содержа-
щие несколько драйверов одновременно. В этом случае первые два
байта поля связи должны содержать смещение заголовка следующего
драйвера.
Слово атрибутов
Следующее слово заголовка драйвера называется словом атрибу-
тов. Оно содержит ряд однобитовых полей, которые характеризуют
тип и возможности драйвера. На рис.6-4 показано расположение и
значение битов в слове атрибутов. Слово атрибутов для разных
драйверов может иметь, например, следующее значение :
Драйвер диска формата IBM - 0000H
Стандартный драйвер консоли - 8003H
Драйвер стандартного устройства (напр. PRN) - 8000H
БИТ15: CHR. Бит CHR должен быть сброшен в 0, если драйвер пред-
назначен для блоковых устройств, и должен быть установлен в 1,
если драйвер будет обслуживать символьное устройство (см. раздел
"Типы драйверов устройств").
БИТ14: IOCTL. Бит IOCTL является необязательным. Его установка
информирует MS-DOS о том, что драйвер поддерживает средства кана-
ла прямого управления. Если IOCTL бит установлен, то драйвер ОБЯ-
ЗАН поддерживать команды 3 и 12 (IOCTL ввод и вывод), в противном
- 6-20 -
случае бит 14 должен быть сброшен. Указанные команды доступны при
помощи подфункций 2 и 3 (для символьных устройств) или 4 и 5 (для
блоковых устройств) функции MS-DOS 44H.
БИТ13: NONIBM/OTB. Для блоковых драйверов этот бит называется
также NONFAT бит. Будучи установленным, этот бит указывает на то,
что блоковое устройство может не поддерживать стандартной для IBM
/MS-DOS структуры диска. В этом случае обработка драйвером команд
INIT и BUILD BPB будет происходить особым образом. Для символьных
драйверов в MS-DOS версий 3.2 и более поздних, этот бит носит
название OTB (Output Until Busy) -- "Вывод пока не занято", и
указывает на то, что драйвер поддерживает дополнительную команду
9 (Output Until Busy). Эта команда полезна для символьных уст-
ройств, имеющих буфер большой емкости, таких как некоторые прин-
теры. Символьные драйверы, используемые с MS-DOS версий 3.1 и ни-
же, должны иметь этот бит сброшенным в 0.
БИТ12: NETWORK. Этот бит является необязательным атрибутом, впер-
вые определенный в MS-DOS версии 3.10. Интересно, что бит NETWORK
не упоминался в последующей документации по MS-DOS версий 3.2 или
3.3, так что использование его в настоящее время оставляет неко-
торые вопросы. Это бит предназначен для информирования MS-DOS о
том, что драйвер обслуживает сетевое устройство. Сетевые устройс-
тва помечаются как блоковые устройства в слове атрибутов; при
этом делается допущение, что обслуживаемое сетевое устройство яв-
ляется "окном" в сеть, позволяя, таким образом, целиком перенап-
равлять на обработку удаленному устройству системные вызовы. Ко-
нечно, для того, чтобы воспользоваться услугами сети для
указанного перенаправления, необходима поддержка соответствующего
средства, такого как MS-NET.
БИТ11: OCRM. Атрибут OCRM (Open/Close/Removable Media) появляется
начиная с MS-DOS версии 3.0. Он может использоваться как для сим-
вольных, так и для блоковых драйверов. Этот бит является не обя-
зательным, хотя Microsoft рекомендует устанавливать его для всех
новых драйверов. Поняв назначение этого атрибута, программист не-
сомненно сможет определиться в его использовании (или не исполь-
зовании).
Как для символьных, так и для блоковых драйверов установка
этого бита означает поддержку драйвером команд DEVICE OPEN и
DEVICE CLOSE (команды 13 "Открыть устройство" и 14 "Закрыть уст-
ройство"). Блоковые драйверы с установленным битом OCRM должны
также поддерживать команду CHECK FOR REMOVABLE MEDIA (команда 15,
"Проверка замены носителя").
Для блоковых устройств команды DEVICE OPEN и DEVICE CLOSE вы-
даются только в режиме совместного использования файлов (file
sharing). Этот режим включается после запуска команды SHARE.EXE.
При установленном режиме совместного использования файлов, коман-
да DEVICE OPEN выдается драйверу при вызове функций MS-DOS 0FH
("Открыть файл, используя FCB") или 3DH ("Открыть файл при помощи
вызова функций 10H ("Закрыть файл, используя FCB") или 3H ("Зак-
рыть файл при помощи описателя"). Для дисковых устройств коман-
ды DEVICE OPEN и DEVICE CLOSE можно использовать для подсчета
числа открытий определенного устройства, например, числа открытых
файлов на диске. Это может быть полезно при определении недопус-
тимости смены дискеты в дисководе, если на момент замены носителя
- 6-21 -
оставались открытые файлы.
Для символьных устройств команды DEVICE OPEN и DEVICE CLOSE
выдаются всегда, когда соответствующее устройство открывается и
закрывается, независимо от режима совместного использования фай-
лов, так что загрузка команды SHARE.EXE не требуется. При работе
с устройствами могут быть использованы только функции MS-DOS 3DH
("Открыть файл при помощи описателя") и 3H ("Закрыть файл при по-
мощи описателя"), так как FCB-метод не работает с устройствами.
Для символьных устройств команды DEVICE OPEN и DEVICE CLOSE могут
быть использованы для предотвращения одновременного доступа к та-
ким устройствам, как принтер или модем, а также для вызова проце-
дур пред- и после обработки, таких как процедуры настройки прин-
тера или завершение сеанса связи для модема.
Заметим, что устройства CON, AUX и PRN открыты всегда, так как
связаны с описателями 0, 1, и 2 (STDIN, STDOUT и STDERR -- все
отображаются на устройство CON), описателем 3 (STDAUX, отображае-
мый на устройство AUX) и описателем 4 (STDPRN, отображаемый на
устройство PRN).
Команда CHECK FOR REMOVABLE MEDIA выдается при вызове пользо-
вателем функции MS-DOS 44H ("Управление работой устройств") с
подкомандой номер 8. Драйвер должен вернуть информацию о наличии
сменного либо несменного носителя.
Атрибут OCRM (Open/Close/Removable Media) также учитывается
при обработке драйвером команды BUILD BPB ("Построить блок пара-
метров BIOS"). Сменный носитель может содержать "идентификатор
тома", одиннадцатисимвольное имя диска. Если устройство поддержи-
вает сменный носитель, имя тома должно быть определено и обрабо-
тано драйвером. Подробнее об этом можно найти при описании коман-
ды BUILD BIOS PARAMETER BLOCK.
БИТЫ с 10 по 7 : Зарезервированы.
---------------------------------
БИТ6: GIOCTL. В MS-DOS версии 3.3 бит GIOCTL ("Группа команд уп-
равления") устанавливается в 1 для индикации того, что блоковый
или символьный драйвер поддерживает дополнительные подкоманды ко-
мандой 19 (GENERIC I/O CONTROL REQUEST). Если этот бит разрешает
использование команды 19, драйвер должен также поддерживать ко-
манды 23 и 24 (GET/SET LOGICAL DRIVE -- Получить/Установить имя
логического диска).
При поддержке драйвером указанных команд, программа пользова-
теля может выдать команду GENERIC I/O CONTROL REQUEST с помощью
функции 44H MS-DOS (подфункции 0CH и 0DH). Для блоковых драйверов
команды GET/SET LOGICAL DRIVE могут быть выполнены вызовом под-
функций 0H (GET LOGICAL DRIVE) и 0FH (SET LOGICAL DRIVE) функции
MS-DOS 44H. Для получения более подробной информации обратитесь к
описанию функции 44H и описанию команд драйвера GENERIC IOCTL и
GET/SET LOGICAL DRIVE.
БИТ 5 : Зарезервирован.
-----------------------
БИТ4: SPECL. Бит SPECL является необязательным атрибутом, исполь-
зуемым только драйвером консоли, и информирующим MS -DOS о том,
что драйвер установил специальный обработчик INT 29H для выполне-
ния высокоскоростного вывода на консоль (устройство CON). Если
этот бит установлен, то при необходимости быстрого вывода на кон-
- 6-22 -
соль MS-DOS выдает программное прерывание INT 29H, передавая вы-
водимый символ в регистр AL. Режим быстрого вывода управляется и
индицируется битом 5 (режим двоичного вывода) в слове конфигура-
ции. При выдаче прерывания INT 29H ожидается, что драйвер выведет
переданный в регистре AL символ и вернет управление. Обычные про-
цедуры ввода/вывода пропускаются. Как стандартный драйвер консоли
MS-DOS, так и заменяющий его драйвер ANSI.SYS поддерживают эту
особенность. Если используемый драйвер консоли поддерживает пре-
рывание INT 29H (что определяется чтением слова конфигурации
драйвера), то прикладная программа также может осуществлять быст-
рый вывод на консоль, используя INT 29H.
Заметим, что этот бит объявлен резервным в документации IBM и
вообще игнорируется в последней документации фирмы Microsoft. Оба
этих факта говорят о том, что поддержка бита SPECL в будущем не
гарантируется.
БИТ3: CLOCK. Бит CLOCK устанавливается на драйвере символьного
устройства, имеющего имя "CLOCK$", для обозначения этого устройс-
тва, как устройства системного времени. Так как драйвер устройс-
тва "Часы" практически всегда обеспечивается системой, необходи-
мость использования этого бита возникает довольно редко.
Драйвер устройства "Часы" обычно является обычным драйвером
символьного устройства без каких-либо дополнительных атрибутов
(слово атрибутов 8008H). Время считывается командой INPUT (ввод)
и устанавливается командой OUTPUT (вывод). По любой из этих ко-
манд всегда передается ровно 6 байт, имеющих следующее значение :
# БАЙТА РАЗМЕР ЗНАЧЕНИЕ
0, 1 16 бит Количество дней с 1.1.1980г.
2 8 бит Минуты
3 8 бит Часы
4 8 бит Сотые доли секунды
5 8 бит Секунды
БИТ2: NUL. Бит NUL означает, что данный драйвер является драйве-
ром устройства NUL. В связи с тем, что NUL-драйвер не может быть
заменен, нет никакой необходимости создавать драйвер устройства
NUL.
БИТЫ1и0: STDIN и STDOUT. Биты STDIN и STDOUT означают, что данный
драйвер является соответственно драйвером стандартного устройства
ввода и вывода. Для устройства CON, обслуживающего системную кла-
виатуру и монитор, эти биты почти всегда определяются вместе. Ес-
ли устанавливается новый драйвер консоли (такой как ANSI.SYS) для
того, чтобы добавить какие-либо новые возможности, то оба этих
бита должны быть установленными. Атрибуты STDIN и STDOUT могут
быть установлены только на одном драйвере из всех активных (дру-
гие копии CON-драйвера тоже могут иметь эти атрибуты, однако ак-
тивным будет только последний установленный CON-драйвер).
Вектора точек входа программ СТРАТЕГИЙ и ПРЕРЫВАНИЙ
Следующие два слова заголовка драйвера содержат смещения прог-
рамм СТРАТЕГИЙ и ПРЕРЫВАНИЙ, соответственно. MS-DOS использует
эту информацию совместно с сегментным адресом драйвера для опре-
деления точек входа в указанные программы. Сегментный адрес драй-
вера система, конечно же, узнает при его загрузке.
- 6-23 -
Поле имени/количества устройств
Последние восемь байт заголовка драйвера служат двум целям.
Для символьных драйверов это поле содержит ASCII имя устройства,
дополненных справа пробелами. Например, для драйвера принтера это
поле может содержать строку 'PRN '.
Для блоковых устройств имеет значение только первый байт. Он
показывает MS-DOS сколько отдельных устройств поддерживается дан-
ным драйвером. Такая возможность необходима потому, что многие
контроллеры поддерживают более одного физического дисковода. Так
как остальные семь байт поля в этом случае не используются, там
можно хранить имя устройства для поиска драйвера в памяти или для
идентификации драйвера. Например, поле количества устройств драй-
вера RAM-диска, называемого RDISK (см. листинг 6-10), может быть
определено как :
UNIT_FIELD DB 1, 'RDISK '
Программа СТРАТЕГИЙ
Следующий раздел драйвера устройства - это программа СТРАТЕ-
ГИЙ. В листинге 6-1 она занимает только три строки выполняемых
кодов. Единственное назначение программы СТРАТЕГИЙ заключается в
сохранении адреса блока запроса для последующего его использова-
ния программой ПРЕРЫВАНИЙ.
Что представляет собой блок запроса? Листинг 6-2 представляет
структуру заголовка запроса. С него начинается любой блок запроса
ввода/вывода к драйверу. Для блока запроса может иногда требо-
ваться больше информации, чем содержится в в заголовке запроса,
поэтому заголовок содержит поле длины информации. К заголовку
запроса мы еще вернемся, а сейчас продолжим обсуждение программы
СТРАТЕГИЙ.
Листинг 6-2. Структура заголовка запроса
-----------------------------------------------------------------
request equ ds:[bx] ; базовый адрес заголовка
reqhdr struc ; запроса.
length db ? ; длина блока запроса (байт).
unit db ? ; количество устройств.
command db ? ; код команды для драйвера.
status dw ? ; возвращаемое состояние.
db 8 dup (?) ; резерв.
reqhdr ends
-----------------------------------------------------------------
Причина того, что программа СТРАТЕГИЙ обязана сохранять адрес
заголовка запроса заключается в том, что MS-DOS выполняет не
единственное обращение к драйверу для выполнения определенной ко-
манды. На самом деле, система сначала делает предварительное об-
ращение к драйверу для того, чтобы информировать драйвер о том,
что он должен сделать и затем делает повторное обращение для вы-
полнения требуемых действий.
Такое двухэтапное обращение к драйверу имеет смысл при работе
в MS-DOS какой-либо многозадачной системы. В этом случае запросы
к драйверу от разных задач могут выдаваться в любой момент време-
ни. Путем выделения в драйвере самостоятельных частей анализа
- 6-24 -
запроса и выполнения запроса драйвер может принимать множество
запросов, одновременно удовлетворяя полученный ранее запрос.
MS-DOS передает программе СТРАТЕГИЙ адрес блока запроса в ре-
гистрах ES:BX. Хотя программа СТРАТЕГИЙ должна сохранять сам блок
запроса, большинство драйверов ограничивается сохранением его ад-
реса. Это возможно из-за того, что MS-DOS в настоящее время вызы-
вает программу ПРЕРЫВАНИЙ непосредственно после возврата управле-
ния от программы СТРАТЕГИЙ, не изменяя информации в блоке
запроса. Следующий пример демонстрирует фрагмент кода, который
сохраняет блок запроса, используя описанную методику :
mov cs:word ptr [req_ptr],bx
mov cs:word ptr [req_ptr + 2],es
Однако, как только MS-DOS станет многозадачной, сохранение
только указателя на блок запроса будет уже недопустимо. В этом
случае программа СТРАТЕГИЙ должна будет не только сохранять сам
блок запроса но и, возможно, помещать блоки запросов в очередь
(если, конечно, эту функцию не возьмет на себя MS-DOS). Впрочем,
до тех пока этого не случилось, мы можем пользоваться более прос-
тым способом сохранения адреса блока.
Как программа ПРЕРЫВАНИЙ так и программа СТРАТЕГИЙ должны быть
определены в драйвере как FAR процедуры, возвращая управление
MS-DOS, соответственно, командой RETF. В связи с тем, что MS-DOS
вызывает эти подпрограммы с помощью команды CALL типа FAR, любая
иная команда возврата приведет либо к передаче управления по не-
верному адресу (RETN) либо к порче стека (IRET).
Программа ПРЕРЫВАНИЙ
После того, как программа СТРАТЕГИЙ сохраняет указатель на
блок запроса и возвращает управление, MS-DOS вызывает программу
ПРЕРЫВАНИЙ (называемую также точкой входа запроса в документации
фирмы IBM по PC DOS). Собственно запрос к драйверу обрабатывается
именно этой программой.
Самое первое действие, которое должна выполнить программа ПРЕ-
РЫВАНИЙ - это сохранить все регистры. На момент обращения к драй-
веру устройства стек имеет емкость примерно в 20 слов. Сохранение
всех регистров, включая флаги, требует 14 слов. Если программе
ПРЕРЫВАНИЙ требуется для работы более чем 6 слов стека, она долж-
на установить свой собственный локальный стек.
После сохранения текущего состояния процессора, программа ПРЕ-
РЫВАНИЙ должна получить блок запроса, сохраненный программой
СТРАТЕГИЙ. Если адрес этого блока был сохранен с помощью приве-
денных выше команд, то получить адрес блока параметров можно ко-
мандой LDS
lds bx,cs:[req_ptr] ; получить адрес блока запроса
Теперь, получив доступ к заголовку блока запроса, можно начи-
нать его обработку. Первый шаг заключается в анализе запроса.
Доступ к нужным полям блока запроса будет значительно облегчен,
если описана структура заголовка. Структура, которую мы использу-
ем в драйвере RDISK и которая определяет формат заголовка запро-
са, показана в листинге 6-2.
Если драйвер должен обслуживать блоковое устройство, то первый
элемент заголовка запроса, который должен быть проверен, это поле
- 6-25 -
количества устройств (request.unit). После проверки корректности
поля request.unit, программа ПРЕРЫВАНИЙ должна получить из блока
запроса код команды (request.command), которую требуется выпол-
нить. Символьные драйверы могут обращаться сразу к коду команды,
т.к. каждый символьный драйвер поддерживает только одно устройс-
тво.
Определив код команды, программа ПРЕРЫВАНИЙ должна передать
управление соответствующему обработчику. В листинге 6-3, содержа-
щем пример программы ПРЕРЫВАНИЙ, показан один из способов переда-
чи управления требуемому обработчику, основанный на использовании
таблицы переходов. Таблица переходов представляет собой последо-
вательность смещений программ-обработчиков команд. Для передачи
управления определенному обработчику необходимо указать индекс
требуемой подпрограммы, заданной своим смещением в таблице пере-
ходов. Этот индекс (в нашем случае это код команды) преобразуется
в смещение в таблице, после чего выполняется косвенный вызов
подпрограммы или переход на нее через таблицу переходов
call word ptr cs:jumptab[bx] ; обработать команду
В связи с тем, что индекс (т.е. код команды) может быть боль-
ше, чем максимальный из используемых кодов команд, программа ПРЕ-
РЫВАНИЙ должна выполнять проверку индекса для того, чтобы убе-
диться в его правильности. При этом, вместо сравнения индекса с
каким-либо заранее фиксированным значением, программа ПРЕРЫВАНИЙ
сравнивает код команды с максимально допустимым значением, храня-
щимся в поле max_cmd :
cmp bl,[max_cmd] ; команда допустима ?
Для того, чтобы понять пользу хранения максимально допустимого
значения в памяти, взгляните на таблицу 6-2. В этой таблице
представлены команды, поддерживаемые различными версиями MS-DOS.
Максимальный код команды, обеспечиваемый MS-DOS версий до 3.0,
имеет значение 0CH. Однако, учитывая тот факт, что max_cmd распо-
лагается в памяти, драйвер может модифицировать это значение во
время инициализации, позволяя, таким образом, использовать новые
команды, если драйвер загружен под управлением новой версии
MS-DOS.
- 6-26 -
Таблица 6-2
Команды для драйверов устройств
ДДДДДДДДВДДДДДДДВДДДДДДДДДВДДДДДДДДДВДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДД
Команда і Версияі Блоковыеі Симв-ныеі Атрибут і Название команды
і DOS і устр-ваі устр-ваі і
ДДДДДДДДЕДДДДДДДЕДДДДДДДДДЕДДДДДДДДДЕДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДД
0: і 2.0 і + і + і і INIT
1: і 2.0 і + і - і і MEDIA CHECK
2: і 2.0 і + і - і і BUILD BPB
3: і 2.0 і + і + і 14:IOCTLі INPUT IOCTL
4: і 2.0 і + і + і і INPUT
5: і 2.0 і - і + і і Nondestructive INPUT
6: і 2.0 і - і + і і INPUT STATUS
7: і 2.0 і - і + і і INPUT FLUSH
8: і 2.0 і + і + і і OUTPUT
9: і 2.0 і + і + і і OUTPUT with VERIFY
10: і 2.0 і - і + і і OUTPUT STATUS
11: і 2.0 і - і + і і OUTPUT FLUSH
12: і 2.0 і + і + і 14:IOCTLі OUTPUT IOCTL
13: і 3.0 і + і + і 11:OCRM і DEVICE OPEN
14: і 3.0 і + і + і 11:OCRM і DEVICE CLOSE
15: і 3.0 і + і - і 11:OCRM і REMOVABLE MEDIA
16: і 3.1 і - і + і 13:OTB і OUTPUT until busy
19: і 3.2 і + і + і 6:GIOCTLі Generic IOCTL Request
23: і 3.2 і + і - і 6:GIOCTLі Get Logical Device
24: і 3.2 і + і - і 6:GIOCTLі Set Logical Device
ДДДДДДДБДДДДДДДБДДДДДДДДДБДДДДДДДДДБДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДД
Примечание 1. В колонке "Версия DOS" указана самая ранняя версия
MS-DOS, начиная с которой поддерживается эта команда.
Примечание 2. В колонке "Атрибут" указаны бит слова атрибутов
драйвера, разрешающий использование данной команды.
ННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН
Последняя задача программы ПРЕРЫВАНИЙ после обработки требуе-
мой команды заключается в установке статуса возврата в блоке зап-
роса. В листинге 6-3 ожидается, что обработчик каждой команды
возвращает статус завершения в регистре AX. После возврата управ-
ления от обработчика, программа ПРЕРЫВАНИЙ записывает статус в
поле слова состояния заголовка запроса (поле request.status). За-
тем программа ПРЕРЫВАНИЙ устанавливает бит DONE ("выполнено") в
слове состояния и возвращает управление MS-DOS. Так как возврат
управления должен быть выполнен командой RETF, программа ПРЕРЫВА-
НИЙ определяется как процедура типа FAR.
Листинг 6-3. Пример программы ПРЕРЫВАНИЙ.
-----------------------------------------------------------------
;
; Определение битов слова состояния драйвера устройства
;
ST_ERROR equ 1000000000000000b ; была ошибка
ST_BUSY equ 0000001000000000b ; устройство занято
ST_DONE equ 0000000100000000b ; команда выполнена
;
; Определение кодов ошибки при обработке команд
;
WRITE_PROTECT equ 0 ; защита от записи
UNKNOWN_UNIT equ 1 ; неопознано устройство
NOT_READY equ 2 ; устройство не готово
- 6-27 -
UNKNOWN_COMMAND equ 3 ; команда не опознана
.
.
;
;********** Точка входа в программу ПРЕРЫВАНИЙ ************************
;
INTERRUPT proc far
pusha ; сохраним все рабочие
push ds ; регистры
push es
push cs ; установим локальный
pop ds ; сегмент данных
les di,[req_ptr] ; получим адрес блока
mov bl,es:[di].command ; запроса и код
; команды
;
; Установим заранее флаг ошибки (на случай, если команда будет
; неопознана)
;
mov ax,(ST_ERROR or UNKNOWN_COMMAND)
cmp bl,[max_cmd] ; эта команда
ja exit ; поддерживается ?
;
; Передадим управление соответствующему обработчику. На входе каждый
; обработчик получает регистры CS и DS установленными на сегмент
; DRIVER и регистры ES:DI указывающими на блок запроса. Свой статус
; обработчик должен вернуть в регистре AX.
;
xor bh,bh ; превратим команду
shl bx,1 ; в индекс
call word ptr cs:jumptab[bx] ; обработаем команду
;
; Запишем статус в слово состояния блока запроса
;
exit: push cs
pop ds
les di,[req_ptr] ; получим адрес блока
or ax,ST_DONE ; запроса, установим
mov es:[di].status,ax ; бит DONE и сохраним
pop es ; статус
pop ds ; восстановим контекст
popa
ret ; RETF
INTERRUPT endp
.
.
.
;
;********** Таблица переходов на обработку команд *******************
;
JUMPTAB label word
dw offset INIT ; 0 - Инициализация
dw offset MEDIA_CHECK ; 1 - Проверка носителя
dw offset BUILD_BPB ; 2 - Построить BPB
.
.
.
- 6-28 -
dw offset NO_COMMAND ; 16
dw offset GET_LOGICAL ; 17 - Получить имя ЛУ
dw offset SET_LOGICAL ; 18 - Установить ЛУ
.
.
.
---------------------------------------------------------------------
Слово состояния, показанное на рис.6-5, используется для инди-
кации ошибок, случившихся при выполнении какой-либо команды (бит
ERROR -- ошибка) и для отображения состояния устройства по коман-
дам опроса статуса и проверки смены носителя (бит BUSY -- заня-
то).
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
ЪДДДВДДДВДДДВДДДВДДДВДДДВДДДВДДДВДДДВДДДВДДДВДДДВДДДВДДДВДДДВДДД·
і E і і і і і і B і D і і і і і і і і є
і R і і і і і і U і O і і і КОД ОШИБКИ і і є
і R і ЗАРЕЗЕРВИРОВАНО і S і N і і ЕСЛИ БИТ 15 РАВЕН 1 і є
і O і і і і і і Y і E і і і і і і і і є
і R і і і і і і і і і і і і і і і є
ФНННПНННПНННПНННПНННПНННПНННПНННПНННПНННПНННПНННПНННПНННПНННПНННј
Значение битов :
ERROR = 1 : При обработке команды случилась ошибка.
Код ошибки находится в битах с 0 по 7.
BUSY = 1 : Устанавливается командами опроса состояния
и проверки смены носителя.
DONE = 1 : Команда выполнена. Устанавливается на выходе.
Рисунок 6-5. Слово состояния драйвера устройства
Бит ERROR устанавливается, если возникла ошибка при выполнении
какой-либо команды или если команда является недопустимой для
данного драйвера. При установленном бите ошибки драйвер обязан
поместить соответствующий код ошибки в биты с 0 по 7 слова состо-
яния. Возможные ошибки и их коды перечислены в таблице 6-3. Бит
DONE должен всегда устанавливаться драйвером перед возвратом уп-
равления к MS-DOS.
Таблица 6-3
Коды ошибок драйверов устройств
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Код Ошибка іКод Ошибка
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДД
0 Запись на устройство запрещена і 8 Сектор не обнаружен
1 Неопознанное устройство і 9 Нет бумаги в принтере
2 Устройство не готово і A Ошибка при записи
3 Команда не опознана і B Ошибка при чтении
4 Неверно переданы данные і C Общая ошибка
5 Неверна длина заголовка запросаі D Зарезервировано
6 Ошибка при установке головки і E Зарезервировано
7 Неопознанный носитель данных і F Недопустимая смена диска
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДД
Примечание 1. Все коды ошибок представлены в виде шестнадцати-
ричных значений.
Примечание 2. Код ошибки 0FH поддерживается только в MS-DOS вер-
сии 3.0 и более поздних.
- 6-29 -
Команды драйверов устройств
Заголовок запроса, как правило, содержит не всю информацию,
которая требуется для большинства команд. Команд, которые не тре-
буют дополнительной информации, довольно мало -- это команды
INPUN/OUTPUT STATUS , FLUSH OUTPUT, OPEN/CLOSE DEVICE и REMOVABLE
MEDIA. Все остальные команды требуют гораздо больше информации,
чем содержится в заголовке запроса. Для каждой из этих команд к
заголовку запроса добавляется дополнительная информация. Поле
request.length заголовка запроса содержит при этом общий размер
блока запроса (в байтах).
Для облегчения доступа к различным элементам блока запроса,
опять-таки, могут быть использованы структуры. В листинге 6-10
(листинге драйвера RDISK, приведенного в конце главы) показано
определение структур для тех команд, которые обрабатываются этим
драйвером. Заметьте, что нам не нужно определять все поля в каж-
дом блоке, т.к. различные запросы часто используют похожие блоки
запросов. Это обстоятельство довольно удобно, т.к. MASM не позво-
ляет использовать одно и тоже имя более одного раза, даже для
различных структур.
Команда INIT
ЙНННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН»
є є
є Команда INIT (0) є
є є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї є
є +00 : 23 Длина і X і Блок. драйверы є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ є
є +01 : Устройство ЪДДДї є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і X і Симв. драйверы є
є +02 : 00 Команда АДДДЩ є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД є
є +03 : Статус є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЧТЕНИЕ ЗАПИСЬ є
є Зарезервировано є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї ДДДДД ЪДДДї ДДД є
є +13 : Количество устройств і і і X і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДД є
є +14 : Адрес конца і і і X і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДД є
є +18 : Команда/Адрес BPB і X і і X і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДД є
є +22 : Номер устройства і X і і і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ ДДДДД АДДДЩ ДДД є
є є
є Адрес таблицы BPB возвращается только блоковыми драйверами. є
є Номер устройства поддерживается начиная с DOS 3.10. є
є є
ИННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННј
Команда INIT (инициализация) всегда является самой первой вы-
зываемой командой и обрабатывается на этапе установки драйвера.
- 6-30 -
MS-DOS выдает эту команду для каждого драйвера только один раз.
На команду INIT возложена ответственность за информирование
MS-DOS об особых характеристиках драйвера и за выполнение необхо-
димых действий по инициализации драйвера. Последние зависят от
типа устройства, управляемого драйвером. Возвращаемые драйвером
характеристики также зависят от типа драйвера.
Все драйверы должны возвращать адрес последнего байта памяти,
занимаемой драйвером и количество устройств, управляемых драйве-
ром. Драйверы символьных устройств могут поддерживать не более
одного устройства. Блоковые драйверы могут поддерживать несколько
устройств (например, если в одном устройстве содержится несколько
дисководов). Кроме того, драйвер может вернуть ноль в качестве
параметра количества поддерживаемых устройств, для прекращения
процесса инициализации. Это может потребоваться, к примеру, при
обнаружении отсутствия устройства. В такой ситуации драйвер дол-
жен также установить адрес последнего используемого байта равным
CS:0 (текущий кодовый сегмент, нулевое смещение) для того, чтобы
MS-DOS могла использовать всю занимаемую драйвером память. В нор-
мальной ситуации адрес завершения представляет собой адрес (сег-
мент и смещение) первого свободного после драйвера байта памяти.
MS-DOS продолжает загрузку системы начиная со следующего после
адреса завершения параграфа памяти (или начиная с адреса заверше-
ния, если он приходится на границу параграфа).
Третий параметр, определяемый командой INIT - это адрес табли-
цы BPB. Этот указатель, возвращаемый MS-DOS командой INIT, предс-
тавляет собой адрес таблицы, которая сама представляет собой со-
вокупность указателей на блоки параметров BIOS. Таблица BPB
содержит по одному указателю на каждое устройство, поддерживаемое
драйвером. Блок параметров BIOS (или, короче, BPB) это структура,
которая определяет формат блокового устройства (см. рис.6-6). Так
как этот параметр имеет смысл только для блоковых устройств, он
не возвращается символьными драйверами. Однако поле указателя
таблицы BPB в блоке запроса несет еще одну полезную нагрузку, ко-
торая может быть использована обоими типами драйверов - это поле
содержит адрес командной строки драйвера. У нас еще будет возмож-
ность подробнее обсудить назначение этого поля.
СМЕЩЕНИЕ СОДЕРЖАНИЕ РАЗМЕР
(hex)
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД·
+0 і Размер сектора в байтах є Слово
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
+2 і Количество секторов в кластере є Байт
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
+3 і Количество зарезервированных секторов є Слово
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
+5 і Количество таблиц FAT є Байт
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
+6 і Количество элементов директория є Слово
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
+8 і Количество логических секторов є Слово
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
+A і Описатель носителя є Байт
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
+B і Количество секторов в одной FAT є Слово
ФНННННННННННННННННННННННННННННННННННННННј
Рисунок 6-6. Блок параметров BIOS
- 6-31 -
Последний параметр, уникальный для команды INIT, это номер ус-
тройства. Этот параметр, который поддерживается только в MS-DOS
версии 3.10 и более поздних, используется для задания начального
номера устройства. К примеру, если драйвер должен управлять дис-
ками C: и D:, содержимое этого поля будет равно 2 и количество
устройств будет равным двум. Если драйвер должен управлять только
дисководом A:, то номер устройства будет равен 0, а количество
устройств 1. Эта возможность очень важна, так как она позволяет в
конце концов заменять стандартные блоковые драйверы на драйверы,
устанавливаемые пользователем.
Команда INIT является уникальной, так как из всех команд драй-
вера, она выполняется в среде, близкой к той, в которой выполня-
ются обычные программы. В отличие от остальных команд, команда
INIT может использовать функции MS-DOS с 01H по 0CH и 30H. Ука-
занные функции позволяют драйверу выдать идентифицирующее сообще-
ние во время установки и, если нужно, отобразить состояние конфи-
гурации драйвера. Функция 30H ("Получить версию DOS") позволяет
драйверу настроиться на определенную версию MS-DOS, что дает воз-
можность разработчику писать драйверы, работающие с любой версией
операционной системы.
Другое сходство команды INIT с обычными программами MS-DOS
заключается в том, что INIT может прочитать командную строку
драйвера и использовать ее для конфигурации драйвера. Как уже
указывалось, команда DEVICE в файле CONFIG.SYS имеет следующий
формат :
DEVICE=[d:][path]filename[.ext][ parameters]
При обращении к драйверу с командой INIT драйверу передается
адрес буфера, содержащего текст командной строки. Этот адрес пе-
редается в поле указателя таблицы BPB блока заголовка и указывает
на первый после знака "=" символ командной строки. Для получения
необходимой информации процедура инициализации должна просмотреть
командную строку, пропустив спецификации файла, и обработать пе-
реданные параметры. Однако, в отличие от стандартных программ,
команде INIT передается только адрес командной строки, а не сама
строка. Командную строку при этом можно только читать (и ни в ко-
ем случае не модифицировать). Для блоковых драйверов это адрес,
конечно же, должен будет перекрыт адресом таблицы BPB.
MS-DOS обращается к драйверу с командой INIT только единожды
во время загрузки системы, поэтому код, реализующий обработку
этой команды после завершения последней, будет бесполезно зани-
мать память. Для того, чтобы минимизировать использование памяти
драйвером, можно располагать код команды INIT после предполагае-
мого адреса завершения или отводить место, занимаемое процедурой
инициализации, для внутренних буферов драйвера (драйвер RDISK ис-
пользует пространство, занимаемое командой INIT, как часть буфера
памяти). В любом случае память будет заново использована либо
MS-DOS либо драйвером. Все остальные процедуры, реализующие ос-
тальные команды, должны располагаться до адреса завершения.
- 6-32 -
Команда MEDIA CHECK
~~~~~~~~~~~~~~~~~~~~~
ЙНННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН»
є є
є Команда MEDIA CHECK (1) є
є є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї є
є +00 : 19 Длина і X і Блок. драйверы є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ є
є +01 : номер Устройство ЪДДДї є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і і Симв. драйверы є
є +02 : 01 Команда АДДДЩ є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД є
є +03 : Статус є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЧТЕНИЕ ЗАПИСЬ є
є Зарезервировано є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї ДДДДД ЪДДДї ДДДД є
є +13 : Описатель носителя і X і і і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДД є
є +14 : Состояние носителя і і і X і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДД є
є +15 : Адрес имени тома і і і X і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ ДДДДД АДДДЩ ДДДД є
є є
є Состояние носителя : (-1) - носитель заменен, 0 - носитель неоп- є
є ределен, 1 - носитель не изменялся. є
є Имя тома возвращается только,если : (a) DOS версии не ниже 3.00, є
є (b) установлен атрибут OCRM и (c) возвращаемый статус носителя є
є равен (-1). є
є є
ИННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННј
Команда MEDIA CHECK (Проверить носитель) всегда выполняется
блоковыми драйверами и никогда не используется для драйверов сим-
вольных устройств. Эта команда используется MS-DOS для разрешения
проблемы, которая может возникнуть при работе с устройствами, ис-
пользующими сменный носитель информации : носитель (например,
гибкий диск) может быть заменен. При замене дискеты или ее экви-
валента формат новой дискеты может отличаться от предыдущего, а
уж содержимое новой дискеты несомненно будет другим.
При замене дискеты MS-DOS должна настроиться на новую структу-
ру диска : размер сектора, количество секторов и т.п. MS-DOS хра-
нит формат текущего диска в BPB и при смене носителя MS-DOS по-
требуется копия нового BPB.
Даже если дискета заменена на имеющую тот же формат, MS-DOS
должна знать о том, что замена диска произошла. Каждый раз при
смене носителя директории и файлы новой дискеты наверняка будут
отличаться от содержимого предыдущей дискеты, и MS-DOS должна бу-
дет решать: что делать с теми данными, которые хранятся в буфе-
рах, подготовленных для записи на предыдущий носитель.
Для разрешения всех этих вопросов MS-DOS выдает драйверу ко-
манду MEDIA CHECK, спрашивая его о том, был ли заменен носитель.
Драйвер должен вернуть на этот вопрос один из трех ответов: "Да"
(состояние носителя -1), "Нет" (состояние носителя 1) или "Не
знаю" (состояние носителя 0).
Важность этого вопроса отражается в том действии, которое
MS-DOS предпринимает при получении ответа на него. Если драйвер
- 6-33 -
отвечает "Нет, носитель НЕ БЫЛ заменен", MS-DOS продолжает рабо-
тать так, как и планировала, не проверяя, изменилось содержимое
дискеты или нет. Если драйвер отвечает "Да, носитель БЫЛ изме-
нен", MS-DOS "выбрасывает" все хранящиеся в буферах данные и за-
прашивает у драйвера параметры нового носителя. Наконец, если
драйвер отвечает что он сам не знает - была замена или нет,
MS-DOS берет решение на себя. Если есть какие-либо данные, подго-
товленные для записи на диск, MS-DOS делает предположение о том,
что это тот же самый диск. В противном случае она делает предпо-
ложение о том, что произошла смена диска и продолжает работать
так, как если бы драйвер вернул ответ "Носитель БЫЛ изменен".
Для оказания помощи драйверу в решении вопроса о смене носите-
ля MS-DOS передает драйверу текущий Media Descriptor Byte (байт
описателя носителя), сокращенно MDB. Этот байт входит в группу
параметров, называемую BPB (блок параметров BIOS), которая возв-
ращается MS-DOS командами драйвера INIT и BUILD BPB. Каждому уни-
кальному формату диска должен соответствовать свой описатель, хо-
тя это и не всегда возможно (в разделе, описывающем команду BUILD
BPB, этот вопрос обсуждается более подробно).
Описатель носителя хранится в первом байте, находящемся на
диске FAT (таблицы размещения файлов). Кроме того, младший байт
значения типа диска (см. табл.11.5) представляет собой не что
иное, как MDB. Подробнее о FAT и типах дисков Вы можете узнать,
прочитав 11 главу.
При решении вопроса о том, была ли замена носителя, драйвер
может использовать следующую логику :
1. Если устройство не поддерживает возможность смены носителя
(например, если это жесткий диск или RAM-диск), то драйвер
должен ответить "Нет, замены носителя не было". В противном
случае переход к шагу 2.
2. Фирма Microsoft утверждает, что на замену дискеты требуется
не менее двух секунд. Принимая этот факт во внимание, драй-
вер должен проверить системные часы и, если с момента преды-
дущего обращения к диску прошло менее двух секунд, вернуть
ответ "Нет, замены носителя не было". Конечно, этот метод
требует,чтобы драйвер всегда сохранял время обращения к дис-
ку. Если прошло более двух секунд, то переход к шагу 3. Оче-
видно, что если нет возможности считывать системное время,
то данный шаг можно опустить.
3. Иногда сам дисковод может иметь возможность информирования
драйвера о происшедшей замене носителя. Некоторые дисководы
оборудованы электронной схемой, подающей сигнал, если дверца
дисковода открывалась с момента последнего обращения к дис-
ку. Если драйвер обслуживает именно такой дисковод и послед-
ний сообщает, что дверца не открывалась, то драйвер должен
ответить "Нет, замены носителя не было". Если дверца была
открыта, то переход к шагу 4.
Бывают дисководы, в которых двигатели включаются только
при обращении к дискете и выключаются, выдержав некоторый
временной интервал. Если такой дисковод позволяет считывать
состояние двигателя и двигатель еще работает с момента пос-
леднего обращения, то это позволяет сделать вывод о том, что
дискета не заменялась и драйвер должен ответить "Нет, замены
носителя не было". Однако, встречаются дисководы, двигатели
которых включаются в тот момент, когда вставляется дискета,
что может сделать результаты данной проверки некорректными.
- 6-34 -
4. Драйвер должен прочесть с диска описатель носителя. Если
этот MDB отличается от переданного драйверу при вызове ко-
манды MEDIA CHECK описателя, то драйвер должен ответить
"Да, была замена носителя". В противном случае переход к ша-
гу 5.
5. Драйвер должен прочесть с диска идентификатор тома. Если он
отличается от того, который хранится драйвером с момента
последней команды BUILD BPB, то драйвер должен ответить "Да,
была замена носителя". Иначе переход к шагу 6.
6. Драйвер должен ответить "Не знаю, была ли замена носителя".
Может случиться так, что невозможно реализовать некоторые эта-
пы описанного алгоритма. Если по каким-либо причинам Вы не можете
определить, произошла ли замена дискеты, то лучшим ответом будет
"Не знаю, была ли замена носителя". Конкретный метод определения
замены носителя будет зависеть как от особенностей дисковода, так
и от квалификации программиста.
Если драйвер работает с MS-DOS версии 3.0 или выше, то команда
MEDIA CHECK может вернуть еще некоторую информацию. В том случае,
когда драйвер поддерживает команды OPEN/CLOSE/REMOVABLE MEDIA
(установлен бит 11 в слове атрибутов драйвера) и команда MEDIA
CHECK собирается ответить "Да, была замена носителя" (состояние
носителя : -1), тогда драйвер обязан вернуть указатель на имя то-
ма предыдущего диска (см. главу 11 для получения сведений о фор-
мате и расположении имени тома). Если драйвер не знает имя тома
предыдущего диска (например, если обращение к команде MEDIA CHECK
Команда BUILD BPB
ЙНННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН»
є Команда BUILD BIOS PARAMETER BLOCK (2) є
є є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї є
є +00 : 22 Длина і X і Блок. драйверы є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ є
є +01 : номер Устройство ЪДДДї є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і і Симв. драйверы є
є +02 : 02 Команда АДДДЩ є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД є
є +03 : Статус є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЧТЕНИЕ ЗАПИСЬ є
є Зарезервировано є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї ДДДДД ЪДДДї ДДДД є
є +13 : Описатель носителя і X і і і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДД є
є +14 : Указатель на FAT і X і і і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДД є
є +18 : Указатель на BPB і і і X і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ ДДДДД АДДДЩ ДДДД є
є є
є Поле по смещению 14 от начала блока запроса содержит указатель нає
є FAT для IBM-стандартных устройств (бит 13 в слове атрибутов равенє
є нулю) или указатель на "мусор" для NONIBM/NONFAT устройств (битє
є 13 слова атрибутов равен 1). є
ИННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННј
- 6-35 -
происходит впервые), то драйвер должен вернуть указатель на стро-
ку "NO NAME" оканчивающуюся нулевым байтом (т.е. "NO", пробел,
"NAME", четыре пробела, ноль).
Команда BUILD BPB (построить блок параметров BIOS) всегда вы-
полняется блоковыми драйверами и никогда не используется для
драйверов символьных устройств. Во всех случаях, когда MS-DOS
проинформирована или решила сама, что носитель заменен, она долж-
на получить параметры нового носителя. Выдавая команду BUILD BPB,
MS-DOS просит драйвер вернуть указатель на блок параметров BIOS,
содержащий новые значения (содержимое полей BPB показано на
рис.6-6).
Существует важное различие между адресом BPB, возвращаемым ко-
мандой BUILD BPB и указателем таблицы BPB, возвращаемым командой
INIT. В то время, как команда BUILD BPB возвращает указатель на
сам блок параметров BIOS, команда INIT возвращает адрес таблицы
указателей на BPB. Хотя различие между указателем и указателем на
указатели очевидно, оно может быть источником ошибок.
Подобно команде MEDIA CHECK, команда BUILD BPB может иметь де-
ло с идентификатором тома. В MS-DOS версии 3.0 и выше драйверы,
поддерживающие возможность замены носителя и имеющие атрибут OCRM
(бит 11 слова атрибутов равен 1), должны считывать и сохранять
имя тома. Это имя позже будет возвращаться последующими обращени-
ями к команде MEDIA CHECK.
Получение команды BUILD BPB может восприниматься драйвером как
заявление системы о том, что по ее мнению произошла замена носи-
теля. Если драйвер поддерживает счетчик количества "открываний" и
"закрываний", выполненных для устройства командами OPEN DEVICE и
CLOSE DEVICE, то пришла пора обнулить его.
Получение блока параметров BIOS
Не рассматривая механизма возврата BPB, мы должны решить за-
дачу определения содержимого блока параметров BIOS. Описываемые
методы применимы не только к команде BUILD BPB, но и к команде
INIT. В простейшем случае драйвера устройства, поддерживающего
только один тип носителя (например драйвер RAM-диска), содержимое
BPB может быть закодировано в теле самого драйвера. К несчастью,
при работе с реальными дисками, включая жесткие диски, не все так
просто и драйвер обязан определять содержимое BPB.
Как правило, BPB является частью блока начальной загрузки, как
показано на рис.6-7. В этом случае драйвер должен найти и прочи-
тать этот блок, выбрать оттуда блок параметров BIOS и возвратить
адрес последнего. Практически во всех случаях блок начальной заг-
рузки располагается в самом первом логическом секторе диска (т.е.
сектора, имеющего номер 0). Преобразование номера логического
сектора в координаты физического сектора зависит от характеристик
устройства и должно быть описано в документации по этому устройс-
тву. Драйвер должен проверить структуру этого сектора, чтобы убе-
диться, что он действительно содержит блок начальной загрузки.
Если первый логический сектор не содержит корректного блока
начальной загрузки, например, как в дисках, отформатированных в
MS-DOS версий до 2.0,то драйвер должен считать первый сектор таб-
лицы размещения файлов (FAT). К счастью, MS-DOS версий до 2.0
поддерживали только несколько форматов, каждый из которых опреде-
лялся в первом секторе FAT второго логического сектора диска. Са-
мый первый байт первого сектора FAT содержит байт описателя но-
- 6-36 -
СМЕЩЕНИЕ СОДЕРЖАНИЕ РАЗМЕР
(hex)
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД·
+00 і Команда перехода на код загрузчика є 3 байта
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
+03 і Имя и версия изготовителя є 8 байт
ЦД ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
є +0B і Размер сектора в байтах є Слово
є ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
є +0D і Количество секторов в кластере є Байт
є ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
є +0E і Количество зарезервированных секторов є Слово
БЛОК є ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
є +10 і Количество таблиц FAT є Байт
ПАРАМЕТРОВ Д¶ ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
є +11 і Количество элементов директория є Слово
BIOS є ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
є +13 і Количество логических секторов є Слово
є ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
є +15 і Описатель носителя є Байт
є ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
є +16 і Количество секторов в одной FAT є Слово
УД ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
+18 і Количество секторов на дорожке є Слово
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
+1A і Количество головок чтения/записи є Слово
ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¶
+1C і Количество скрытых секторов є Слово
ФНННННННННННННННННННННННННННННННННННННННј
Рисунок 6-7. Содержимое первых 30 байт блока начальной загрузки
сителя, который можно использовать для определения соответству-
ющего содержимого BPB, возвращаемого к MS-DOS. Версии MS-DOS
до 2.0 используют описатели 0FEH и 0FFH. В главе 11 представлен
список различных значений типов дисков, из которых берется MDB.
Выполняя этот процесс, Вам следует помнить, что просто чтение
диска не может гарантировать правильных результатов. Если уст-
ройство и драйвер поддерживают несколько форматов (например, с
различными размерами сектора), то драйверу может потребоваться
несколько попыток чтения с разными форматами для того, чтобы об-
наружить корректный формат. После того, как сформирован BPB и оп-
ределен формат данного диска драйвер, поддерживающий устройство
со сменным носителем (имеющий атрибут OCRM), обязан получить
идентификатор тома данного диска. Найти его можно, обратившись к
корневому директорию, как описано в главе 11.
Вкратце, последовательность обработки команды BUILD BPB следу-
ющая :
1. Драйвер должен прочитать блок начальной загрузки (обычно на-
ходящийся в первом логическом секторе диска - сектор #0) и
проверить его на наличие блока параметров BIOS. Если BPB об-
наружен, то переход к шагу 3, иначе переход к шагу 2.
2. Драйвер должен прочитать первый сектор FAT для того, чтобы
получить байт описателя носителя. Полагаясь на этот MDB,
- 6-37 -
драйвер должен сконструировать соответствующий BPB (см. гла-
ву 11 о соответствии между MDB и BPB).
3. Если устройство поддерживает замену носителя (установлен бит
11 слова атрибутов), драйвер должен получить из корневого
директория идентификатор тома и сохранить его.
Для выполнения этого алгоритма, драйвер должен иметь буфера
для хранения копии BPB и имени тома, а также буфер, предназначен-
ный для считывания туда сектора с диска.
Мы опустили из рассмотрения параметры, которые передаются
драйверу при обращении к нему с командой BUILD BPB. Игнорируйте
их. Один из этих параметров - это описанный ранее описатель носи-
теля, который в данной ситуации не имеет никакого значения, так
как данная команда возвращает MS-DOS новое его значение. Второй
параметр - это адрес буфера, который либо не содержит ничего су-
щественного (если бит 13, NONIBM атрибут, равен 1), либо содержит
копию первого сектора FAT (если бит 13 сброшен). В последнем слу-
чае, т.е. если там содержится FAT, этот буфер никоим образом не
должен быть модифицирован, а так как драйвер обязан иметь свой
буфер, куда будет считываться блок начальной загрузки, то на бу-
фер, передаваемый при вызове команды BUILD BPB можно не обращать
внимания.
Напоследок представляется важным отметить, что в отличие от
BPB описатель носителя не обеспечивает однозначного определения
формата диска. Однако, MS-DOS версии 3.0 и выше не будут обнов-
лять свои внутренние структуры, ассоциированные с данным дисково-
дом, до тех пор, пока байт описателя носителя не станет отличным
от предыдущего MDB. Даже несмотря на то, что MS-DOS версии 3.0 и
выше не обращают внимание на действительное значение MDB, драйвер
должен вернуть новый MDB при смене формата дискеты.
Команды INPUT, OUTPUT и OUTPUT & VERIFY (команды 4, 8 и 9 -
"Ввод", "Вывод" и "Вывод с проверкой", соответственно) всегда
требуются для всех драйверов. При помощи этих команд выполняется
передача данных между MS-DOS и устройством.
Команды IOCTL INPUT и IOCTL OUTPUT (коды 3 и 12 - "Ввод команд
управления" и "Вывод команд управления", соответственно) являются
дополнительными, требующимися только при установленном IOCTL ат-
рибуте (бит 14 слова атрибутов драйвера). Эти команды применяются
как с блоковыми так и с символьными драйверами и обеспечивают пе-
редачу данных между MS-DOS и драйвером.
Команда OUTPUT UNTIL BUSY (код 16 - "Вывод пока не занято")
является необязательной командой и используется исключительно для
символьных драйверов, имеющих атрибут NONIBM/OTB (бит 13). Эта
команда обеспечивает передачу данных от MS-DOS к устройству. За-
метьте также, что эта команда не документирована в IBM Technical
Reference Manual для PC-DOS версии 3.30.
Команды OUTPUT и OUTPUT & VERIFY устанавливаются комбинацией
пятого бита IOCTL (бит 5 - подготовленный/неподготовленный режим)
и опцией VERIFY. Если установлен режим проверки, то весь вывод
данных обеспечивается командой OUTPUT & VERIFY. Если режим провер-
ки не установлен, то используется обычная команда OUTPUT. Перевод
драйвера в неподготовленный режим (при установке IOCTL бита 5)
позволяет осуществлять многобайтные передачи.
Существует комбинация режимов, которая должна была бы вызвать
использование команды OUTPUT UNTIL BUSY, но не делает этого. Эта
комбинация включает режим без проверки (так что команда OUTPUT &
- 6-38 -
Команды INPUT и OUTPUT
~~~~~~~~~~~~~~~~~~~~~~~~
ЙНННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН»
є є
є Команды INPUT и OUTPUT (3,4,8,9,12,16) є
є є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї є
є +00 : 22 Длина і X і Блок. драйверы є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ є
є +01 : номер Устройство ЪДДДї є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і X і Симв. драйверы є
є +02 : команда Команда АДДДЩ є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД є
є +03 : Статус ЪДДДДДДДДДДДДДДДДДДДДДДДДДДїє
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і Команды : іє
є Зарезервировано і іє
є і 03 : IOCTL INPUT іє
є і 04 : INPUT іє
є і 08 : OUTPUT іє
є і 09 : OUTPUT & VERIFY іє
є і 12 : IOCTL OUTPUT іє
є і 16 : OUTPUT UNTIL BUSY іє
є АДДДДДДДДДДДДДДДДДДДДДДДДДДЩє
є є
є ЧТЕНИЕ ЗАПИСЬ є
є є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї ДДДДД ЪДДДї ДДДДДє
є +13 : Описатель носителя і X і і і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДДДє
є +14 : Адрес буфера і X і і і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДДДє
є +18 : Количество байтов/секторов і X і і X і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДДДє
є +20 : Начальный сектор і X і і і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДДДє
є +22 : Указатель на имя тома і і і X і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ ДДДДД АДДДЩ ДДДДДє
є є
є Поле по смещению 18 от начала блока запроса содержит на входеє
є требуемое количество байтов/секторов. Драйвер должен поместить вє
є это поле фактическое количество переданных секторов или байтов. є
є Указатель на имя тома возвращается только в MS-DOS версии 3.00 иє
є выше при условии, что возвращается ошибка 0FH -- "Недопустимаяє
є замена диска". є
є є
ИННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННј
VERIFY не будет использоваться), неподготовленный режим (позволя-
ющий многобайтные передачи) и устройство, поддерживающее команду
OUTPUT UNTIL BUSY. Однако, при тестировании этого режима обнару-
жилось, что команда OUTPUT UNTIL BUSY не выдается никогда, чем и
объясняется, наверное, почему IBM опустила эту команду в своей
документации.
Все эти команды имеют общую структуру блока запроса, но отли-
чаются типом запрашиваемой операции ввода/вывода и типом драйвера
устройства. Ниже перечислены основные параметры, используемые при
вызове команд ввода/вывода :
- 6-39 -
* Сама команда определяет источник и получатель при передаче
данных. Важно отметить, что операции управления вводом/выво-
дом предназначены для передачи драйверу различных директив и
управляющей информации, а не для передачи данных непосредс-
твенно на устройство. Приведем возможные комбинации источни-
ка и получателя данных :
КОМАНДЫ ИСТОЧНИК ПОЛУЧАТЕЛЬ
INPUT Устройство Буфер
OUTPUT Буфер Устройство
OUTPUT VERIFY Буфер Устройство
OUTPUT UNTIL BUSY Буфер Устройство
IOCTL INPUT Драйвер Буфер
IOCTL OUTPUT Буфер Драйвер
* Адрес источника или получателя со стороны MS-DOS представля-
ет собой адрес буфера, который либо содержит данные для вы-
вода (команды OUTPUT), либо будет заполнен данными (команды
INPUT).
* "Количество байт/секторов" определяет сколько байт (для сим-
вольных устройств и в командах IOCTL) или секторов (команды
INPUT, OUTPUT и OUTPUT&VERIFY) будет (или было) передано.
* Только для блоковых драйверов задаются параметры "Устройс-
тво" и "Начальный сектор", уточняющие местонахождение источ-
ника (для INPUT) или получателя (для OUTPUT).
* Параметр "Байт описателя носителя" (только для блоковых ус-
тройств) может быть использован для определения формата дис-
ка или того факта, что носитель был заменен.
Как только драйвер определил источника и получателя, он выпол-
няет передачу данных. После выполнения передачи драйвер должен
вернуть фактическое количество переданных байтов или секторов.
Даже если возникла ошибка и установлен индикатор ошибки в возвра-
щаемом слове состояния, MS-DOS считает, что возвращаемое значение
параметра "Количество байтов/секторов" корректно. Если драйверу
не удалось обновить этот параметр, то возвращаемое значение будет
таким же как и переданное драйверу на входе. Вы должны также
знать, что даже если передача прошла успешно, счетчик все-таки
может иметь неверное значение. Это происходит при возникновении
т.н. "перекрытия".
Перекрытие (для блоковых драйверов) возникает в том случае,
если передается большее количество байт, чем то которое можно ад-
ресовать с помощью сегментного адреса буфера. Приведем следующий
пример. Пусть драйвер пересылает 64 сектора по 512 байт каждый из
буфера начиная со смещения 8000H. Таким образом, общее количество
байт, которые требуется передать, составит 32768 (8000H). Так как
начальное смещение в буфере равно 8002H, то смещение последнего
байта будет иметь заведомо некорректное значение 10002H. В подоб-
ных случаях, т.е. при возникновении перекрытий, драйвер не должен
пытаться передавать недостижимую порцию данных.
Каждая команда имеет свои особенные требования для выполнения
передачи и отличаются возвращаемым значением статуса и счетчика.
Эти требования описаны ниже для каждой из команд.
- 6-40 -
КОМАНДЫ CTL INPUT и CTL OUTPUT (3 и 12).
Это простейшие команды, обычно требуемые только для передачи
данных самому драйверу (не устройству) или получения данных от
него. Для MS-DOS эти данные не имеют никакого значения, и, более
того, могут быть проигнорированы самим драйвером, если ему так
захочется. Ответственность за обработку переданных таким образом
данных лежит только на драйвере и прикладной программе. Как пра-
вило, используются для изменения режимов работы драйвера и/или
устройства, хотя возможны и другие варианты. Важно только, чтобы
драйвер не забывал правильно устанавливать возвращаемое значение
счетчика переданных байтов.
КОМАНДЫ INPUT OUTPUT (4 и 8).
Для большинства символьных драйверов логика обработки команд
INPUT и OUTPUT весьма незамысловата. Если передача прошла успеш-
но, то устанавливается бит DONE в слове состояния драйвера и
драйвер возвращает управление. Если возникла какая-либо проблема,
то в слово состояния записывается код соответствующей ошибки
(см.табл.6-3), устанавливается счетчик и возвращается управление.
Если символьное устройство не имеет готовых данных на момент
выдачи команды INPUT, драйвер может либо подождать или вернуть
ошибку "Устройство не готово". При выводе данных, если устройство
не может их принять, драйвер также может вернуть эту ошибку. Од-
нако ошибка "Устройство не готово" обычно используется для указа-
ния того, что устройство выключено или по каким-либо причинам не-
доступно. Использование этой ошибки всего лишь для индикации
неготовности данных является не слишком хорошим решением, так как
получив ошибку "Устройство не готово", MS-DOS запросто может вы-
дать оператору запрос на вмешательство.
Логика работы блоковых драйверов при выполнении операций
ввода/вывода более сложная. Как правило, драйвер должен выполнять
преобразование номера начального сектора в координаты физического
сектора, обычно состоящие из номера цилиндра (дорожки), номера
головки и номера физического сектора на дорожке. Возможно, что
драйверу придется выполнить операцию перевода головки чтения/за-
писи на соответствующую дорожку перед началом передачи и, может
быть, в процессе самой передачи секторов. Более подробно устройс-
тво диска описано в главе 11.
Более того, устройства, подобные дисководам, являются источни-
ком множества ошибок (см.табл.6-3), таких как "Запись на устройс-
тво запрещена", "Неверно переданы данные (ошибка CRC)", "Ошибка
при установке головки", "Ошибка при чтении", "Ошибка при записи",
и даже такая звучная как "Общая ошибка". Обычно при возникновении
ошибки драйвер фиксирует код ошибки в слове состояния, устанавли-
вает счетчик успешно переданных секторов и возвращает управление.
Однако одна ошибка требует дальнейшего анализа и обработки - это
"Недопустимая смена диска".
Ошибка "Недопустимая смена диска" воспринимается MS-DOS версии
3.0 и выше и только в том случае, когда MS-DOS знает что она име-
ет дело с устройством, поддерживающем замену носителя (установлен
атрибут OCRM в слове атрибутов драйвера). Отличие этой ошибки от
остальных заключается в том, что если драйвер информирует MS-DOS
о недопустимой замене носителя, MS-DOS должна знать с каким,
собственно, диском намеревался работать драйвер. Эта информация
определяется именем тома ожидаемого диска, указатель на которое
- 6-41 -
должен вернуть драйвер. Как и в команде MEDIA CHECK, если соот-
ветствующее имя драйверу не известно, он должен вернуть адрес
строки "NO NAME".
Как узнает драйвер о недопустимой замене носителя? Если драй-
вер ведет счетчик количества открытий и закрытий, выполненных на
устройстве (командами 13 и 14) и диск заменяется пользователем
(что определяется другим форматом, другим описателем носителя и
т.п.) при количестве открытий превышающем количество закрытий, то
делается вывод о том, что замена носителя была недопустимой и
формируется ошибка "Недопустимая смена диска".
КОМАНДА OUTPUT & VERIFY (9).
Команда OUTPUT & VERIFY(вывод с проверкой) применяется только для
тех устройств, в которых возможно считывание данных после их за-
писи на устройство для того, чтобы убедиться в корректности вы-
полненной операции. Для таких устройств (например для дисков)
драйвер должен выводить данные (также как и по команде OUTPUT),
считывать их обратно (так же как по INPUT) и сравнить считанные
данные с теми, которые были записаны. Если обнаружена ошибка, то
драйверу следует не пытаться повторить неудавшуюся операцию, а
сообщить об этой ситуации MS-DOS, вернув соответствующий код
ошибки (см.табл.6-3) и количество успешно переданных байтов/сек-
торов.
Как и в случае команды BUILD BPB, обработка команды
OUTPUT & VERIFY требует наличия у драйвера внутреннего буфера для
считывания проверяемых данных. Если устройство не позволяет счи-
тывать данные обратно, то данная команда должна обрабатываться
также как и команда OUTPUT (команда 8).
КОМАНДА OUTPUT UNTIL BUSY (16).
Команда OUTPUT UNTIL BUSY представляет еще одну разновидность
команды OUTPUT. Эта команда, которая используется только с сим-
вольными устройствами, драйверы которых имеют атрибут OTB (бит 13
слова атрибутов), позволяет программам передавать большие порции
данных устройствам, которые имеют внутренние буфера (таких как
принтеры). Драйвер такого устройства должен посылать данные либо
до тех пор пока они не кончатся, либо пока устройство в состоянии
их принять. Очень важно, чтобы такой драйвер корректно устанавли-
вал счетчик переданных байтов, так чтобы MS-DOS знала какое коли-
чество данных уже передано. Обратите внимание, что для этой ко-
манды не является ошибочной ситуация, когда передано меньше
данных, чем было запрошено.
Команда NONDESTRUCTIVE INPUT WITHOUT WAIT (неразрушающее счи-
тывание без ожидания) требуется только для драйверов символьных
устройств и не используется для блоковых драйверов. Хотя эта ко-
манда похожа на обычную символьную команду INPUT, она все же име-
ет несколько заметных отличий :
* Отсутствует буфер данных и счетчик количества переданных
данных. При вызове этой команды требуемое количество байт
всегда равно 1 и если устройство готово предоставить байт
данных, он возвращается в поле "Считанный из устройства
байт" блока запроса.
* Нет ожидания. Если устройство не готово предоставить очеред-
- 6-42 -
Команда NONDESTRUCTIVE INPUT WITHOUT WAIT
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ЙННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН»
є є
є Команда NONDESTRUCTIVE INPUT WITHOUT WAIT (5) є
є є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї є
є +00 : 14 Длина і і Блок. драйверы є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ є
є +01 : Устройство ЪДДДї є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і X і Симв. драйверы є
є +02 : 05 Команда АДДДЩ є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД є
є +03 : Статус є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЧТЕНИЕ ЗАПИСЬ є
є Зарезервировано є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї ДДДДД ЪДДДї ДДДДє
є +13 : Считанный из устр-ва байт і і і X і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ ДДДДД АДДДЩ ДДДДє
є є
ИНННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННј
ной символ, то драйвер должен установить бит BUSY в дополне-
ние к биту DONE в слове состояния и незамедлительно вернуть
управление.
* Чтение неразрушающее. Если устройство готово выдать байт
данных, то драйвер обязан не только возвратить этот байт, но
и сохранить его для чтения последующей командой INPUT. Если
вводимые данные помещаются драйвером в очередь (как в управ-
ляемых прерываниями драйверах), то возвращаемый этой коман-
дой байт должен остаться в очереди.
Эта команда предназначена для того, чтобы MS-DOS могла,
во-первых, определить наличие данных, не используя команду INPUT,
которая может привести к длительному ожиданию данных, и, во-вто-
Команды STATUS и FLUSH INPUT/OUTPUT
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ЙНННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН»
єКоманды STATUS и FLUSH INPUT/OUTPUT (6,7,10,11) є
є є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї є
є+00 : 13 Длина і і Блок. драйверы є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ є
є+01 : номер Устройство ЪДДДї є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і X і Симв. драйверы є
є+02 : команда Команда АДДДЩ є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД є
є+03 : Статус ЪДДДДДДДДДДДДДДДДДДДДї є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і КОМАНДЫ : і є
є Зарезервировано і і є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і 6 : INPUT STATUS і є
є і 7 : INPUT FLUSH і є
є і 10 : OUTPUT STATUS і є
є і 11 : OUTPUT FLUSH і є
є АДДДДДДДДДДДДДДДДДДДДЩ є
ИННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННј
- 6-43 -
рых, анализировать следующий символ в буфере без изъятия его от-
туда.
Команды I/O STATUS и I/O FLUSH (команды 6,10 и 7,11, соответс-
твенно) требуются только для символьных устройств и не использу-
ются блоковыми.
Команды INPUT STATUS и INPUT FLUSH имеют смысл только для тех
драйверов символьных устройств, которые поддерживают управляемые
прерываниями очереди вводимых данных, хотя эти команды могут вы-
зываться для любого символьного драйвера.Команда INPUT STATUS ис-
пользуется для индикации состояния очереди следующим образом:
* Если очередь есть, но она пуста, то драйвер должен устано-
вить биты DONE и BUSY в слове состояния и вернуть управле-
ние.
* Если в очереди есть символы, доступные для чтения, то драй-
вер должен установить бит DONE, сбросить бит BUSY и вернуть
управление.
* Если очередь не поддерживается, то драйвер должен установить
бит DONE, сбросить бит BUSY в слове состояния и вернуть уп-
равление. Это выглядит странным - уведомлять MS-DOS о нали-
чии символа, когда даже очереди нет.Объяснение заключается в
том, что после такого ответа MS-DOS выдаст команду INPUT для
считывания символа. Если же этого не сделать, то MS-DOS бу-
дет продолжать опрашивать статус ввода бесконечно, так как
из-за отсутствия очереди статус всегда будет одним и тем же.
Команда INPUT FLUSH применяется для уведомления драйвера о не-
обходимости удаления всех находящихся в данный момент во входной
очереди символов. После очистки очереди (если таковая имеется)
драйвер должен установить бит DONE и вернуть управление. При об-
работке этой команды не должно возникать никаких ошибок, по край-
ней мере MS-DOS предполагает, что эта команда всегда завершается
успешно.
Команда OUTPUT STATUS используется для проверки состояния вы-
ходной очереди или устройства. Если драйвер не поддерживает вы-
ходную очередь, то следует, по возможности, вернуть состояние са-
мого устройства. Состояние определяется битом BUSY ("занято")
слова состояния (состояние "занято" означает что вывод задержива-
ется). Установив состояние, драйвер должен установить бит DONE и
вернуть управление.
Команда OUTPUT FLUSH предназначена для указания драйверу необ-
ходимости удалить все находящиеся в выходной очереди символы (ес-
ли очередь поддерживается) и, если это возможно, немедленно прек-
ратить любые операции вывода. После выполнения этих действий
драйвер должен установить бит DONE в слове состояния драйвера и
вернуть управление MS-DOS.
Команды DEVICE OPEN и DEVICE CLOSE (команды 13 и 14) являются
необязательными командами, поддерживаемые MS-DOS версий 3.0 и вы-
ше, и используются только если драйвер имеет атрибут OCRM (бит 11
слова атрибутов драйвера равен 1). Однако Microsoft рекомендует
использовать эти команды во всех новых создаваемых драйверах.
- 6-44 -
Команды DEVICE OPEN/CLOSE и REMOVABLE MEDIA
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ЙНННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН»
є є
єКоманды DEVICE OPEN/CLOSE и REMOVABLE MEDIA (13,14,15) є
є є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї є
є+00 : 13 Длина і X і Блок. драйверы є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ є
є+01 : номер Устройство ЪДДДї є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і і Симв. драйверы є
є+02 : команда Команда АДДДЩ є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД є
є+03 : Статус ЪДДДДДДДДДДДДДДДДДДДДї є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і КОМАНДЫ : і є
є Зарезервировано і і є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і 13 : DEVICE OPEN і є
є і 14 : DEVICE CLOSE і є
є і 15 : REMOVABLE і є
є і MEDIA CHECK і є
є АДДДДДДДДДДДДДДДДДДДДЩ є
ИННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННј
Команда REMOVABLE MEDIA (15) является дополнительной командой
для блоковых драйверов в MS-DOS 3.0 и выше и используется только
при наличии у драйвера атрибута OCRM (бит 11 слова атрибутов). Эта
команда также рекомендуется к использованию фирмой Microsoft во
всех новых драйверах.
Условия, при которых происходит обращение к командам
DEVICEOPEN и DEVICECLOSE, описаны выше в подразделе "Слово атри-
бутов", подзаголовок "БИТ 11 : OCRM".
Для блоковых устройств со сменным носителем информации эти ко-
манды могут использоваться для отслеживания количества открытых
на устройстве файлов, позволяя, таким образом, обнаруживать ситу-
ацию недопустимой замены носителя (которая возникает при замене
диска, на котором еще имеются открытые файлы).
Для символьных устройств эти команды могут использоваться для
предотвращения одновременного доступа различных программ к одному
устройству (такому как принтер) или для обеспечения возможностей
перед и после обработки устройства (например, операций загрузки и
сброса принтера).
Команда REMOVABLEMEDIA может быть выдана прикладной програм-
мой, используя подфункцию "Проверка заменяемости носителя" функ-
ции IOCTL (подфункция 08H функции 44H). При вызове этой функции
прикладная программа должна задать номер интересующего ее диско-
вода. Получив команду REMOVABLEMEDIA, драйвер должен определить
имеет ли упомянутое устройство возможность замены носителя и вер-
нуть статус битом BUSY слова состояния драйвера. Если устройство
не поддерживает смены носителя, то драйвер должен установить бит
BUSY, в противном случае сбросить его.
Команда GENERIC IOCTL (19) является дополнительной командой,
поддерживаемой MS-DOS начиная с версии 3.20. Использование этой
команды разрешается установленным в 1 атрибутом GIOCTL (бит 6)
слова состояния.
- 6-45 -
Команда GENERIC IOCTL
~~~~~~~~~~~~~~~~~~~~~~~
ЙНННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН»
є є
є Команда GENERIC IOCTL (19) є
є є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї є
є +00 : 23 Длина і X і Блок. драйверы є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ є
є +01 : номер Устройство ЪДДДї є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і і Симв. драйверы є
є +02 : 19 Команда АДДДЩ є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД є
є +03 : Статус є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЧТЕНИЕ ЗАПИСЬ є
є Зарезервировано є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї ДДДДД ЪДДДї ДДДДД є
є +13 : Номер функции (старший) і X і і і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДДД є
є +14 : Номер функции (младший) і X і і і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДДД є
є +15 : Содержимое регистра SI і X і і і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДДД є
є +17 : Содержимое регистра DI і X і і і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДДД є
є +19 : Адрес блока IOCTL запроса і X і і і є
є ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ ДДДДД АДДДЩ ДДДДД є
є є
ИННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННј
Название "Группа команд управления вводом/выводом" не совсем
точно, так как эта команда используется при поддержке драйвером
дополнительных возможностей. Одна группа дополнительных функций
(доступ к которой обеспечивается IOCTL подфункцией 0CH) поддержи-
вает возможность переключения кодовых страниц (code page
switching), средства для оперативной реконфигурации драйвера.
Другая большая группа функций (доступ к которой обеспечивается
IOCTL подфункцией 0DH) обеспечивает стандартный интерфейс для ап-
паратурозависимых операций блоковых драйверов. Операции, входящие
в данную группу, включают чтение, запись, верификацию, форматиро-
вание целых дорожек, чтение и модификацию блока параметров BIOS
(BPB).
Расширенные возможности команды GENERIC IOCTL хорошо описаны в
"MS-DOS Technical Reference Manual" ("MS-DOS. Техническое описа-
ние") в разделе, описывающем функцию 44H MS-DOS. В связи с тем,
что эти функции предназначены в основном для поддержки оборудова-
ния производителей, мы отсылаем читателей к упомянутому руководс-
тву для получения более подробной информации.
Команды GETLOGICALDEVICE и SETLOGICALDEVICE (23 и 24) являются
дополнительными командами для блоковых драйверов и поддерживаются
в MS-DOS начиная с версии 3.20. Использование этих команд разре-
шается при наличии у драйвера атрибута GIOCTL (бит 6 слова атри-
бутов) равного 1.
- 6-46 -
Команды GET & SET LOGICAL DEVICE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ЙНННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН»
є є
єКоманда GET & SET LOGICAL DEVICE (23,24) є
є є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї є
є+00 : 21 Длина і X і Блок. драйверы є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ є
є+01 : номер Устройство ЪДДДї є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і і Симв. драйверы є
є+02 : команда Команда АДДДЩ є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД є
є+03 : Статус ЪДДДДДДДДДДДДДДДДДДДДДДДДДїє
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД і КОМАНДЫ : іє
є Зарезервировано і іє
є і 23 : GET LOGICAL DEVICE іє
є і 24 : SET LOGICAL DEVICE іє
є АДДДДДДДДДДДДДДДДДДДДДДДДДЩє
є є
є ЧТЕНИЕ ЗАПИСЬ є
є є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ЪДДДї ДДДДД ЪДДДї ДДДДє
є+13 : Ввод (код устройства) і X і і і є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДДє
є+14 : Код команды і X і і і є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДДє
є+15 : Статус і X і і і є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД ГДДДґ ДДДДД ГДДДґ ДДДДє
є+17 : Зарезервировано і і і X і є
єДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД АДДДЩ ДДДДД АДДДЩ ДДДДє
є є
ИННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННј
Эти команды используются для отслеживания имени текущего
диска для устройств, имеющих несколько логических дисков. Подобно
команде GENERICIOCTL, команды GET/SET LOGICAL DEVICE доступны че-
рез функцию 44H MS-DOS. Подфункция 0H применяется для получения
текущего имени логического диска, а функция 0FH для присвоения
имени нового логического диска. Так же как и команда
GENERICIOCTL, команды GET/SET LOGICAL DEVICE предназначены, в ос-
новном, для поддержки устройств производителя (например, в случае
драйвера DRIVER.SYS, для поддержки 3.5-дюймовых гибких дисков).
Полное описание этих команд можно найти в "MS-DOS Technical
Reference Manual" в разделе, описывающем функцию MS-DOS 44H, куда
мы Вас и отсылаем.
Создание загрузочного файла драйвера устройства
Выше уже упоминалось, что программа драйвера устройства похожа
на обычную .COM программу. Это утверждение тем более истинно при
использовании описываемого метода создания .SYS файла драйвера.
Заметьте, что нет никаких причин, кроме соглашений, для использо-
вания расширения .SYS в файлах драйверов - допустимы любые рас-
ширения. В листинге 6-4 представлен диалог с системой при созда-
нии драйвера "DRIVER". Этот файл ассемблируется и линкуется как
обычная программа, после чего преобразуется в двоичный .SYS файл.
Отметим,что отсутствие стека для драйвера является нормальным яв-
- 6-47 -
лением, так как драйвер при работе использует собственный стек
MS-DOS.
В примере, приведенном в листинге 6-4, создается также выход-
ной .LST файл ассемблера и выходной .MAP файл редактора связей
(линкера). Конечно же, .OBJ и .EXE файлы могут быть удалены после
создания .SYS файла.
Листинг 6-4. Процесс создания простого драйвера
-----------------------------------------------------------------
C> masm driver,driver,driver;
Microsoft Macro Assembler Version 4.00
Copyright Microsoft Corp 1981, 1983, 1984, 1985.
All rights reserved.
45976 Bytes symbol space free
0 Warning Errors
0 severe Errors
C> link driver,driver,driver;
Microsoft 8086 Object linker
Version 3.00 Copyright Microsoft Corp 1983, 1984, 1985
Warning: no stack segment
C> exe2bin driver driver.sys
-----------------------------------------------------------------
Отладка драйверов устройств
После того, как драйвер установлен в системе, он уже не может
быть отлажен с помощью MS-DOS (из-за проблемы реентерабельности).
Однако отлаживать драйверы необходимо, так как подобно практичес-
ки всем программам трудно ожидать от драйвера правильной работы
после первого запуска. К решению задачи отладки драйверов можно
подойти с трех сторон.
Во-первых, разрабатывайте драйвер по технологии "сверху вниз"
- заставьте работать основную часть программы, а затем добавляй-
те более сложные блоки. Не пытайтесь сделать в первую очередь об-
работчики IOCTL. Процедурами, правильной работы которых Вы должны
добиться в первую очередь, являются программы СТРАТЕГИЙ и ПРЕРЫ-
ВАНИЙ, а также процедура инициализации INIT. В блоковых драйверах
Вы должны также добиться правильной работы команды MEDIACHECK и,
если только Вы не установили NONIBM бит в слове атрибутов, коман-
ды BUILDBPB. С помощью такого набора функций Вы, конечно, не смо-
жете выполнять операции ввода/вывода, однако MS-DOS сможет по
крайней мере успешно загрузить этот драйвер.
Другой подход, который может помочь в отладке драйверов, зак-
лючается в использовании функций BIOS для вывода информации, оп-
ределяющей текущее состояние драйвера. Знание места, до которого
дошел драйвер, прежде чем аварийно завершиться очень помогает при
отладке. Если у Вас нет ROM-BIOS, на который можно положиться, Вы
можете встроить в драйвер различные подпрограммы вывода. Напри-
- 6-48 -
мер, отлаживая драйвер RDISK (приведенный в конце этой главы),
авторы встроили в драйвер средства вывода на дисплей идентифици-
рующего символа для каждой обрабатываемой команды ("I" для ПРЕРЫ-
ВАНИЙ, "S" для СТРАТЕГИЙ, "i" для INIT и т.д.). Это представляло
действительную помощь когда драйвер загружался и был доступен с
помощью прерываний прямого доступа к диску, но "сваливался" при
попытке чтения директория диска. Взаимодействие между драйвером и
системой может быть одной из самых сложных проблем и, к не-
счастью, обычно может быть отлажено только после загрузки драйве-
ра.
Если Вы решили добавить отладочные команды к Вашему драйверу,
знайте, что это вероятнее всего увеличит требуемую глубину стека
и Вам, возможно, придется использовать в драйвере локальный стек
(если, конечно, Вы еще не сделали этого).
При тестировании отдельных частей драйвера нет никакой необхо-
димости отлаживать их после его загрузки. Если Вам не жалко вре-
мени, потраченного на написание простой тестовой программы, соз-
дающей блоки запросов и передающей их драйверу для обработки, то
Вы сможете использовать обычную программу DEBUG для отладки тес-
товой программы и самого драйвера. Это позволит Вам довести драй-
вер до состояния, при котором он уже может быть загружен, после
чего использовать другие способы отладки для исправления остав-
шихся ошибок.
При разработке драйверов всегда пользуйтесь копией системного
диска. Ошибка в драйвере может привести к тому, что система не
будет загружаться или к разрушению каких-либо значимых данных на
диске. По этим причинам Вам следует всегда иметь копию системного
диска.
Отображение списка загруженных в системе драйверов
Очень часто при отладке драйверов полезно знать какие конкрет-
но драйверы загружены в данный момент. На этот случай мы приводим
текст небольшой программы, названной SD (SHOW DRIVERS - показать
драйверы). Примерный вид выводимой этой программой информации по-
казан в листинге 6-5.
Большинство отображаемых драйверов являются стандартными драй-
верами MS-DOS, эа исключением верхнего драйвера CON-устройства
(драйвера консоли), который является драйвером ANSYI.SYS, и верх-
него блокового драйвера, который является Bernulli Box драйвером.
Нижний блоковый драйвер является стандартным MS-DOS драйвером,
поддерживающем одновременно один жесткий диск и два гибких.
Колонка Attrib содержит слова атрибутов драйверов, колонка
Address содержит начальный адрес каждого драйвера (взятый из поля
связи предыдущего в списке драйвера) и колонки STRAT и INTRP со-
держат смещения программ СТРАТЕГИЙ и ПРЕРЫВАНИЙ от начала драйве-
ра. Исходный текст программы SD на языке ассемблера приведен в
листинге 6-6. Заметьте, что в программе SD используются файлы
DRIVER.INC (листинг 6-7), STDMAC.INC (листинг A-7, приложение A)
и программа BIN2HEX файла STDLIB.LIB (листинг A-8, приложение A).
- 6-49 -
Листинг 6-5. Пример цепочки драйверов, выводимый программой SD
--------------------------------------------------------------------
SD-ShowDriv, Version 1.00, Copyright 1988 Kevin Jaeger
Device Type Units Attrib Address STRAT INTRP
-------------------------------------------------------------------
NUL Char 01 8004 0000:1898 1418 141E
CON Char 01 8013 08A9:0000 00A2 00AD
-------- Block 02 0000 083D:0000 00A7 00B2
CON Char 01 8013 0070:0160 00A7 00B2
AUX Char 01 8000 0070:01F1 00A7 00B8
PRN Char 01 A000 0070:02A0 00A7 00C7
CLOCK$ Char 01 8008 0070:034A 00A7 00DC
-------- Block 03 0800 0870:0416 00A7 00E2
COM1 Char 01 8000 0070:0203 00A7 00B8
LPT1 Char 01 A000 0070:02B2 00A7 00C7
LPT2 Char 01 A000 0070:0B13 00A7 00CD
LPT3 Char 01 A000 0070:0B25 00A7 00D3
COM2 Char 01 8000 0070:0B37 00A7 00BE
<<< ------------------ End Of Driver List --------------------- >>>
--------------------------------------------------------------------
Листинг 6-6. Исходный текст программы SHOWDRIV.ASM
---------------------------------------------------------------------
PAGE 60,132
; ************ SHOWDRIV *********************************************
;
; SHOWDRIV - Отображение списка загруженных драйверов MS-DOS
;
; ************ INCLUDES *********************************************
;
INCLUDE stdmac.inc
INCLUDE driver.inc
;
; ************ DGROUP (DATA) COMPONENT SEGMENTS *********************
;
_DATA SEGMENT BYTE PUBLIC 'DATA'
_DATA ENDS
;
STACK SEGMENT PARA STACK
dw 1024 dup (?)
STACK ENDS
;
DGROUP GROUP _DATA, STACK
;
; ************ DATA STORAGE & TEMPLATES *****************************
;
_DATA SEGMENT
;
; параметры для поиска
;
nuldev db 'NUL ' ; Имя NUL драйвера
nulattr dw AT_CHR OR AT_NUL ; Слово атрибутов
;
; Текстовые сообщения для вывода на дисплей. Формат :
;
; "Device Type Units Attrib Address STRAT INTRP"
; "-----------------------------------------------------------------"
; "xxxxxxxx xxxx xx xxxx xxxx:xxxx xxxx xxxx"
- 6-50 -
; "<<< ------------------ End Of Driver List ------------------- >>>"
;
$title db CR,LF
db 'SD-ShowDriv, Version 1.00, Copyright 1988'
db CR,LF,CR,LF
db 'Device Type Units Attrib Address'
db ' STRAT INTRP'
db CR,LF
db '-----------------------------------------------'
db '--------------------'
db CR,LF,'$'
$space db ' $'
$block db '-------- Block $'
$char db 'Char$'
$colon db ':'
$end db CR,LF
db '<<< ------------------ End Of Driver List -----'
db '---------------- >>>'
$crlf db CR,LF,'$'
;
; Шаблон структуры
;
devhead STRUC ; Структура заголовка драйвера
next dd ? ; Указатель на следующего...
attrib dw ? ; Слово атрибутов
strat dw ? ; Смещение программы СТРАТЕГИЙ
intrp dw ? ; Смещение программы ПРЕРЫВАНИЙ
dname db 8 dup (?) ; Имя/количество устройств
term db ? ; Конец заголовка драйвера
devhead ENDS
;
_DATA ENDS
;
; ************ ПРОГРАММА НАЧИНАЕТСЯ ЗДЕСЬ ***************************
;
_TEXT SEGMENT BYTE PUBLIC 'CODE'
ASSUME cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP
;
EXTRN bin2hex:near ; Шестнадцатиричный вывод
main PROC FAR
mov ax,DGROUP ; Установка сегмента данных
mov ds,ax
;
; Найдем NUL-драйвер с помощью поиска имени "NUL"
;
cld
mov cx,0FFFEh ; Счетчик для поиска
xor ax,ax ;
mov es,ax ; Начало поиска после таблицы
mov di,0400Hh ; прерываний
mov al,nuldev ; Начинаем с поиска этой буквы
search:
repne scasb ; Ищем пока не найдем
jne exit ; Не нашли...
;
push cx ; Возможно нашли...
push di ; Сохраним текущую позицию
- 6-51 -
mov si,offset nuldev+1 ; Остаток строки "NUL "
mov cx,7 ; Длина остатка
repe cmpsb ; Сравним остаток строки
jne not_it ; Не совпадают...
;
sub di,(offset term - offset attrib) ; Выровняем указатель
cmpsw ; Это атрибут NUL-драйвера ?
jne not_it ; Нет...
add sp,4 ; Удаляем сохраненные DI и CX
sub di,(offset strat - offset next) ; Выравниваем указатель
jmp found_nul ; Нашли заголовок NUL-драйвера!
;
not_it: ; Восстанавливаем позицию
pop di ; и счетчик
pop cx
jmp short search
;
; Нашли заголовок NUL-драйвера. Теперь выводим всю цепочку
;
found_nul:
@DisStr $title ; Выводим название (титул)
show_driver:
call ShowDeviceInfo ; Отобразим заголовок драйвера
cmp word ptr es:[di],-1 ; Проверим на конец цепочки
jne done ; Если (-1) то на выход
les di,es:[di].next ; Если не (-1) то на следующий
jmp short show_driver ; заголовок
done:
@DisStr $end ; Завершающее сообщение
@DisStr $crlf
;
exit: mov al,0 ; Нормальное завершение
@ExitToDOS ; Завершение программы
main ENDP
;
; ************ ShowDeviceInfo ****************************************
; Подпрограмма ShowDeviceInfo отображает блок, адресуемый по ES:DI,
; предполагая что это заголовок драйвера. Формат выводимой информации
; показан выше.
;
ShowDeviceInfo PROC NEAR
test es,[di].attrib,AT_CHR ; Драйвер символьный или
jnz is_char ; блоковый ?
@DisStr $block ; Блоковый (без имени)
xor ah,ah
mov al,es:[di].dname ; Количество устройств
jmp short dis_units
is_char:
push ds ; Сохраним DS
push es ; Выровняем сегменты
pop ds
lea si,es:[di].dname ; SI = смещение имени
mov cx,8 ; Длина имени
show_name:
lodsb ; Выводим по одному символу
@DisChr al ; за раз
loop show_name
- 6-52 -
pop ds ; Восстанавливаем DS
@DisStr @space
@DisStr @char ; Выводим тип драйвера
@DisStr @space
mov ax,1 ; Только одно устройство
;
dis_units:
mov ch,02 ; Выводим количество устройств
call bin2hex
@DisStr @space
mov ch,04 ; Вывод числовых данных
mov ax,es:[di].attrib
call bin2hex ; Выводим слово атрибутов
@DisStr @space
;
mov ax,es
call bin2hex ; Выводим сегментный адрес
@DisChr $colon
mov ax,di
call bin2hex ; Выводим смещение
@DisStr @space
;
mov ax,es:[di].strat
call bin2hex ; Выводим адрес СТРАТЕГИЙ
@DisStr @space
;
mov ax,es:[di].intrp
call bin2hex ; Выводим адрес ПРЕРЫВАНИЙ
@DisStr @crlf
;
ret
ShowDeviceInfo ENDP
;
; ************ КОНЕЦ ПРОГРАММЫ, КОНЕЦ ФАЙЛА ************************
;
_TEXT ENDS
END main
---------------------------------------------------------------------
Листинг 6-7. Файл DRIVER.INC
---------------------------------------------------------------------
; ************ DRIVER.INC *******************************************
;
; Driver.Inc : Содержит определения и константы для использования при
; ассемблировании драйверов MS-DOS.
;
; ************ ОПРЕДЕЛЕНИЕ КОНСТАНТ, ИСПОЛЬЗУЕМЫХ В ДРАЙВЕРАХ *******
;
; Определение битов слова атрибутов драйвера :
AT_CHR EQU 1000000000000000b ; Символьное устройство
AT_IOCTL EQU 0100000000000000b ; Поддержка IOCTL
AT_BUSY EQU 0010000000000000b ; Поддержка OTB
AT_NOIBM EQU 0010000000000000b ; Не IBM устройство
AT_NET EQU 0001000000000000b ; Сетевое устройство
AT_OCRM EQU 0000100000000000b ; Поддержка OCRM
- 6-53 -
AT_GIOCTL EQU 0000000001000000b ; Поддержка GIOCTL
AT_LOGICL EQU 0000000001000000b ; Get/Set Logical Dev
AT_SPECL EQU 0000000000010000b ; Специальное устр-во
AT_CLOCK EQU 0000000000001000b ; Устройство "ЧАСЫ"
AT_NUL EQU 0000000000000100b ; Устройство NUL
AT_STDOUT EQU 0000000000000010b ; Стандартные устр-ва
AT_STDIN EQU 0000000000000001b ; ввода и вывода
;
; Определение кодов ошибок драйверов устройств :
WRITE_PROTECT EQU 0
UNKNOWN_UNIT EQU 1
NOT_READY EQU 2
UNKNOWN_UNIT EQU 3
CRC_ERROR EQU 4
BAD_REQUEST EQU 5
SEEK_ERROR EQU 6
UNKNOWN_MEDIA EQU 7
SECTOR_NOT_FOUND EQU 8
OUT_OF_PAPER EQU 9
WRITE_FAULT EQU 0Ah
READ_FAULT EQU 0Bh
GENERAL_FAILURE EQU 0Ch
INVALID_DISK_CHANGE EQU 0Fh
;
; Статус, возвращаемый командой MEDIA CHECK :
IsChanged EQU -1 ; носитель был заменен
DontKnow EQU 0 ; не известно была ли замена
NotChanged EQU 1 ; носитель был заменен
;
; ************ КОНЕЦ ФАЙЛА : DRIVER.INC *****************************
---------------------------------------------------------------------
Пример драйвера виртуального диска
В конце этой главы, в листинге 6-10, мы приводим пример весьма
упрощенного драйвера RAM-диска (т.е. драйвера виртуального диска,
размещаемого в ОЗУ). Несмотря на свою простоту, драйвер на 100%
работоспособен и может быть использован на любой MS-DOS системе
начиная с версии 2.0 и выше. Драйвер RAM-диска, показанный в лис-
тинге 6-10, использует 360 Kбайт системной памяти для эмуляции
стандартного пятидюймового дисковода. Если Вы намерены использо-
вать этот драйвер, то Ваша система должна иметь по крайней мере
512 Kбайт памяти. Если Вы имеете меньше памяти или просто желаете
иметь виртуальный диск меньших размеров, то Вы можете изменить
принимаемые по умолчанию параметры, которые описаны в секции
драйвера, помеченной как "Описание RAM-диска".
Более элегантным решением изменения размеров RAM-диска являет-
ся использование параметров командной строки. Вспомните, что при
входе в обработчик команды INIT параметры request.bpbtabo и
request.bpbtabs содержат длинный указатель на командную строку
драйвера. Эта строка может быть проверена на наличие переключате-
лей и опций, которые могут быть использованы для конфигурации
драйвера. При использовании этого метода процедура INIT должна
выполнить проверку, скорректировать параметры в BPB и сегментный
адрес завершения драйвера.
- 6-54 -
После того, как программа была обработана ассемблером и редак-
тором связей, переименуйте ее в RDISK.SYS. Теперь создайте файл
CONFIG.SYS (если, конечно, он еже не создан) и добавьте в него
командную строку :
DEVICE=RDISK.SYS
При первой же перезагрузке драйвер будет установлен как драй-
вер следующего по порядку дисковода (вероятно как драйвер диско-
вода C:, если у Вас нет жесткого диска). Ничего более для уста-
новки драйвера RDISK не требуется.
Доступ к RAM-диску возможен с помощью любых функций MS-DOS или
программ, за исключением команд DISKCOPY и DISKCOMP. Обе эти
программы ожидают определенные типы дисков и не работают с
RAM-дисками.
Драйвер RDISK, приведенный в листинге 6-10, содержит простой
код, который может быть использован для отладки или исследования
драйверов. Он написан с использованием функций ввода/вывода уров-
ня BIOS, приведенных в листинге 6-8. Для того, чтобы отладочный
код располагался до адреса завершения драйвера, RDISK включает в
себя исходный текст файла BIOSIO.ASM (см.листинг 6-9). Так как
библиотечные процедуры обычно добавляются редактором связей в ко-
нец программы, их использование в драйверах устройств представля-
ется проблематичным.
Отладочный код может быть задействован путем включения в файл
RDISK оператора DEBUG EQU 1 или, при использовании Microsoft MASM
версии 4 или более поздней, указанием в командной строке опции
/DDEBUG.
Во время выполнения отладочный код использует ряд команд драй-
вера в качестве индекса в таблице message_table. Элементами таб-
лицы message_table являются адреса строк, представляющих имена
команд, находящихся в области данных, предшествующей таблице
message_table.Эти текстовые строки отображаются с помощью аппара-
турозависимой процедуры _biosprt. В драйвере RDISK процедура
_biosprt использует адаптер EGA с цветным монитором, что позволя-
ет легко отличать отладочный текст от обычных сообщений MS-DOS.
Листинг 6-8. Файл BIOSIO.INC
----------------------------------------------------------------------
; ************ BIOSIO.INC ********************************************
;
; BiosIO.Inc содержит константы для использования процедур BIOS уровня
; находящихся в файле STDLIB.LIB
;
; Макрокоманда @Video для использования с видеопроцедурами
;
@Video MACRO function
mov ah,function
int 10h
ENDM
;
; ************ BIOS I/O Equates **************************************
;
; Эти определения поддерживают использование ввода/вывода уровня BIOS.
;
; Определения функций видеосервиса BIOS (INT 10H)
- 6-55 -
SET_CURSOR_POS EQU 02H ;; BH = страница, DH = строка, DL = колонка
GET_CURSOR_POS EQU 03H ;; BH = страница; строка => DH, колонка => DL
SET_PAGE EQU 05H ;; AL => страница
SCROLL_UP EQU 06H ;; AL = #строк, BH => атрибут, C(x) = верхняя
SCROLL_DOWN EQU 07H ;; левая, D(x) = нижняя правая,
;; (x)H = строка, (x)L = колонка
READ_CHR_ATR EQU 08H ;; BH = страница; атр. => AH, симв. => AL
WRITE_CHR_ATR EQU 09H ;; BH = страница, CX = 1, AL = симв., BL = атр.
WRITE_CHAR EQU 0AH ;; BH = страница, CX = 1, AL = симв., без атр.
WRITE_TEXT EQU 0EH ;; BH = страница, AL = символ
GET_MODE EQU 0FH ;; режим => AL, #колонок => AH, страница => BH
;
; Атрибуты символов при использовании адаптера EGA
BLINK EQU 10000000b
BRIGHT EQU 00001000b
BLACK_F EQU 00h
BLUE_F EQU 01h
GREEN_F EQU 02h
CYAN_F EQU 03h
RED_F EQU 04h
MAGENTA_F EQU 05h
YELLOW_F EQU 06h
WHITE_F EQU 07h
BLACK_B EQU 10h
BLUE_B EQU 10h
GREEN_B EQU 20h
CYAN_B EQU 30h
RED_B EQU 40h
MAGENTA_B EQU 50h
YELLOW_B EQU 60h
WHITE_B EQU 70h
;
; ************ КОНЕЦ ФАЙЛА BIOSIO.INC ********************************
Листинг 6-9. Файл BIOSIO.ASM
----------------------------------------------------------------------
PAGE 60,132
PUBLIC _biosprt
; ************ BIOSIO.ASM ********************************************
; BIOSIO: Содержит процедуры для выполнения ввода/вывода на
; уровне BIOS, используя стандартные вызовы BIOS. Эти процедуры
; предназначены для целей отладки.
;
IFNDEF DEBUG ; если не часть DEBUG, то должна быть часть
; от LIBRARY, и должна включать наши
; собственные определения
; ************ INCLUDES **********************************************
;
INCLUD biosio.inc ; BIOS I/O difinition
;
; ************ DGROUP (DATA) COMPONENT SEGMENTS **********************
_DATA SEGMENT BYTE PUBLIC 'DATA'
_DATA ENDS
;
DGROUP GROUP _DATA
;
- 6-56 -
;************* PROGRAM CODE STARTS HERE ******************************
;
_TEXT SEGMENT BYTE PUBLIC 'CODE'
ASSUME cs:_TEXT, ds:DGROUP, es:DGROUP, ss:DGROUP
ENDIF
;
; Шаблон структуры, описывающей состояние стека для _BIODPRT
bpframe STRUC
dw ? ; Старый BP
dw ? ; адрес возврата
p1 dw ? ; параметр #1
p2 dw ? ; параметр #2
p3 dw ? ; параметр #3
p4 dw ? ; параметр #4
bpframe ENDS
prtbase EQU [bp]
;
; _BIOSPRT
; Эта подпрограмма выполняет вывод на экран на уровне BIOS и
; используется для отладки драйвера. Подпрограмма использует
; видеорежим 03h : 80*25 цветной текст
;
; Эквивалентный языку Си синтаксис вызова : biosprt(string,color)
;
_biosprt PROC NEAR
push bp
mov bp,sp
push si
push cx
push bx
;
@Video GET_MODE ; Получить номер тек.страницы
mov si,word prt [prtbase.p1] ; адрес строки
mov bl,byte prt [prtbase.p2] ; атрибут
mov cx,1
;
biosprtloop:
lodsb ; Берем очередной символ
or al,al ; Строка завершается нулем
jz biosprtdone
cmp al,'$' ; или завершается "$"
jz biosprtdone
push ax
mov al,020h
@Video WRITE_CHR_ATR ; Пробел с атрибутом
pop ax
@Video WRITE_TEXT ; Символ в режиме TTY
jmp biosprtloop ; Следующий символ
;
biosprtdone
pop bx
pop cx
pop si
pop bp
ret
_boisprt ENDP
;
- 6-57 -
IFNDEF DEBUG ; если не включено как часть
_TEXT ENDS ; DEBUG, то потребуются наши
ENDIF ; собственные ENDS
;
; ************ КОНЕЦ ФАЙЛА BIOSIO.ASM ********************************
; END ; При использовании в библиотеке, удалите ";"
----------------------------------------------------------------------
Листинг 6-10. Исходный текст драйвера RAM-диска
----------------------------------------------------------------------
PAGE 60,132
; ************ RDISK.ASM : MS-DOS ДРАЙВЕР RAM-ДИСКА ******************
;
; Этот файл содержит исходный текст простого MS-DOS драйвера RAM-диска
; эмулирующего 360K флоппи-диск.
;
; В этом примере демонстрируются основные принципы построения драйвера
; устройств, включая один из методов, который можно использовать для
; отладки драйверов. Для установки этого драйвера включите в файл
; CONFIG.SYS строку "DEVICE=RDISK.SYS"
;
; ============ ВСПОМОГАТЕЛЬНЫЕ ФАЙЛЫ ДЛЯ ДРАЙВЕРА ====================
;
INCLUDE driver.inc ; Константы для MS-DOS драйвера
IFDEF DEBUG
INCLUDE biosio.inc ; Определения для отладки
ENDIF
;
; ============ КОНСТАНТЫ =============================================
;
; Ограничения,накладываемые версией MS-DOS на максимальный код команды
;
CMD_PRE_30 EQU 00Ch ; до MS-DOS версии 3.00
CMD_PRE_32 EQU 00Fh ; до MS-DOS версии 3.20
CMD_32 EQU 018h ; начиная с версии 3.20
;
IFDEF DEBUG
CR EQU 0Ah ; используются в отладочных
LF EQU 0Dh ; сообщениях
ENDIF
;
PAGE
;
; ============ ШАБЛОНЫ СТРУКТУР ======================================
;
request EQU es:[di] ; указатель на блок запроса
;
; Структура заголовка запроса
;
reqhdr STRUC
rlength db ? ; размер блока запроса
unit db ? ; номер устройства
command db ? ; код команды
status dw ? ; возвращаемый статус
db 8 DUP (?) ; зарезервировано
reghdr ENDS
- 6-58 -
;
; Структура блока запроса для команды INIT
;
inithdr STRUC
db (type reqhdr) DUP (?)
units db ? ; количество устройств
endadro dw ? ; смещение и сегмент
endadrs dw ? ; адреса завершения
bpbtabo dw ? ; смещение и сегмент
bpbtabs dw ? ; таблицы BPB
devnum db ? ; номер устройства
inithdr ENDS
;
; Структура блока запроса для команды MEDIA CHECK
;
mchkhdr STRUC
db (type reqhdr) DUP (?)
mbd db ? ; описатель носителя
chande dw ? ; статус замены
volume dd ? ; указатель на имя тома
mchkhdr ENDS
;
; Структура блока запроса для команды BUILD BPB
;
bpbhdr STRUC
db (type reqhdr) DUP (?)
db ? ; описатель носителя
dd ? ; указатель на FAT
bpbptro dw ? ; смещение BPB
bpbptrs dw ? ; сегмент BPB
bpbhdr ENDS
;
; Структура блока запроса для команд чтения/записи
;
iohdr STRUC
db (type reqhdr) DUP(?)
db ? ; описатель носителя
bufprt dd ? ; адрес буфера
count dw ? ; кол-во байт/секторов
start dw ? ; # начального сектора
nuvol dd ? ; адрес нов. имени тома
iohdr ENDS
;
; Структура блока параметров BIOS (BPB)
;
bpbstrc STRUC
bps dw ? ; количество байтов в секторе
spau db ? ; кол-во секторов в кластере
nrs dw ? ; кол-во зарезервир. секторов
nft db ? ; количество копий FAT
nde dw ? ; кол-во элементов директория
nls dw ? ; кол-во логических секторов
md db ? ; байт описателя носителя
nfs dw ? ; размер FAT в секторах
bpbstrc ENDS
;
- 6-59 -
PAGE
;
; ============= НАЧАЛО КОДА ДРАЙВЕРА =================================
;
_TEXT SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:_TEXT, DS:_TEXT, ES:NOTHING
ORG 0
ORIGIN EQU $
;
; ============= ЗАГОЛОВОК ДРАЙВЕРА ===================================
;
dw -1,-1 ; указатель на след. драйвер
dw AT_IOCTL OR AT_OCRM OR AT_NET
dw offset STRATEGRY ; смещение СТРАТЕГИЙ
dw offset ПРЕРЫВАНИЙ ; смещение ПРЕРЫВАНИЙ
db 1,'CDEVICE' ; кол-во устройств/имя
;
; ============= ТАБЛИЦА АДРЕСОВ ОБРАБОТЧИКОВ КОМАНД ==================
;
JUMPTAB LABEL WORD
dw offset INIT ; 0 - инициализация
dw offset MEDIA_CHECK ; 1 - проверка носителя
dw offset BUILD_BPB ; 2 - построить BPB
dw offset IOCTL_INPUT ; 3 - IOCTL ввод
dw offset READ ; 4 - ввод из устр-ва
dw offset READ_NOWAIT ; 5 - неразруш. ввод
dw offset INPUT_STATUS ; 6 - ввод статуса
dw offset INPUT_FLUSH ; 7 - сбросить ввод
dw offset WRITE ; 8 - вывод на устр-во
dw offset WRITE_VERIFY ; 9 - вывод с проверкой
dw offset OUTPUT_STATUS ; A - вывод статуса
dw offset OUTPUT_FLUSH ; B - сбросить вывод
dw offset IOCTL_OUTPUT ; C - вывод IOCTL
dw offset DEVICE_OPEN ; D - открыть устр-во
dw offset DEVICE_CLOSE ; E - закрыть устр-во
dw offset REMOVABLE ; F - носитель сменный?
dw offset NO_COMMAND ; 10
dw offset NO_COMMAND ; 11
dw offset NO_COMMAND ; 12
dw offset GENERIC_IOCTL ; 13 - Generic IOCTL
dw offset NO_COMMAND ; 14
dw offset NO_COMMAND ; 15
dw offset NO_COMMAND ; 16
dw offset GET_LOGICAL ; 17 - получить/устано-
dw offset SET_LOGICAL ; 18 - вить лог.устр-во
;
; ============ ОБЛАСТЬ ДАННЫХ ДРАЙВЕРА ===============================
;
reg_ptr dd ? ; адрес блока запроса
max_cmd db CMD_PRE_30 ; максимально допустимый код
; ; команды
save_ss dw ? ; значение SS на входе
save_sp dw ? ; значение SP на входе
;
- 6-60 -
PAGE
;
; ============ ПРОГРАММА СТРАТЕГИЙ ====================================
;
STRATEGY PROC FAR
mov cs:word ptr [reg_ptr],bx
mov cs:word ptr [reg_ptr+2],es
ret
strategy ENDP
;
; ============ ПРОГРАММА ПРЕРЫВАНИЙ ===================================
;
INTERRUPT PROC FAR
push ax ; сохранить все рабочие
push cx ; регистры
push dx
push bx
push bp
push si
push di
push ds
push es
;
push cs ; определим локальный сегмент
pop ds ; данных
;
mov word ptr save_ss,ss ; сохраним входное
mov word ptr save_sp,sp ; значение SS и SP
;
mov bx,cs ; установим локальный
mov ax,offset local_stack - 2 ; стек
mov ss,bx
mov sp,ax
;
les di,[req_ptr] ; получить адрес блока
mov bl,request.command ; запроса и команду
;
; установим заранее код ошибки на случай если команда неверная
;
mov ax,(ST_ERROR OR UNKNOWN_COMMAND)
cmp bl,[max_cmd] ; команда поддерживается ?
ja exit ; нет - отвергаем ее
;
; Выдаем указанную команду на выполнение соответствующему обработчику.
; Каждый обработчик получает управление с CS и DS установленными на
; сегмент драйвера и ES:DI указывающем на блок запроса. Свой статус
; обработчики возвращают в регистре AX.
;
xor bh,bh ; BX - индекс в таблице
shl bx,1 ; команд
IFDEF DEBUG
call print_command ; выдаем имя обрабатываемой
ENDIF ; команды
call word ptr jumptab[bx] ; вызываем обработчик
;
; Перешлем статус из регистра AX в слово состояния блока запроса
;
exit: push cs ; установка локального
- 6-61 -
pop ds ; сегмента данных
;
les di,[req_ptr] ; получим адрес блока запроса
or ax,ST_DONE ; установим бит DONE
mov request.status,ax ; сохраним статус
;
mov ss,word ptr save_ss ; восстановим значение
mov sp,word ptr save_sp ; регистров SS:SP
;
pop es ; восстановим содержимое
pop ds ; регистров
pop di
pop si
pop bp
pop bx
pop dx
pop cx
pop ax
ret
interrupt ENDP
;
PAGE
;
; ============ ОБРАБОТЧИКИ КОМАНД ====================================
;
NO_COMAND PROC NEAR ; неподдерживаемая команда
ret ; возврат с ошибкой
NO_COMMAND ENDP
;
MEDIA_CHECK PROC NEAR ; 1 - проверка носителя
mov request.change,NotChanged
xor ax,ax
ret
MEDIA_CHECK ENDP
;
BUILD_BPB PROC NEAR ; 2 - построить BPB
mov request.bpbptro,offset bpb
mov request.bpbptrs,cs
xor ax,ax
ret
BUILD_BPB ENDP
;
IOCTL_INPUT PROC NEAR ; 3 - ввод IOCTL
xor ax,ax
ret
IOCTL_INPUT ENDP
;
READ PROC NEAR ; 4 - ввод из устройства
call verify ; проверка и установка параметров
jc rd_err ; выход по ошибке
les di,request.bufptr ; считываем в буфер
rep movsw ; передача
xor ax,ax ; нет ошибок
rd_err:
ret
READ ENDP
;
- 6-62 -
READ_NOWAIT PROC NEAR ; 5 - неразрушающий ввод
xor ax,ax ; без ожидания
ret
READ_NOWAIT ENDP
;
INPUT_STATUS PROC NEAR ; 6 - ввод статуса
xor ax,ax
ret
INPUT_STATUS ENDP
;
INPUT_FLUSH PROC NEAR ; 7 - сбросить входную очередь
xor ax,ax
ret
INPUT_FLUSH ENDP
;
WRITE PROC NEAR ; 8 - вывод на устройство
call verify ; проверка и установка параметров
jc wr_err ; выход при ошибке
push ds ; сохраним сегмент "сектора"
lds si,request.bufptr ; записываем из буфера
pop es ; на диск
xor di,di ; с нулевым смещением
rep movsw ; передача
xor ax,ax ; нет ошибок
wr_err:
ret
WRITE ENDP
;
WRITE_VERIFY PROC NEAR ; 9 - вывод с проверкой
call write
ret
WRITE_VERIFY ENDP
;
OUTPUT_STATUS PROC NEAR ; A - вывод статуса
xor ax,ax
ret
OUTPUT_STATUS ENDP
;
OUTPUT_FLUSH PROC NEAR ; B - сбросить выходную очередь
xor ax,ax
ret
OUTPUT_FLUSH ENDP
;
IOCTL_OUTPUT PROC NEAR ; C - вывод IOCTL
xor ax,ax
ret
IOCTL_OUTPUT
;
DEVICE_OPEN PROC NEAR ; D - открыть устройство
xor ax,ax
ret
DEVICE_OPEN ENDP
;
DEVICE_CLOSE PROC NEAR ; E - закрыть устройство
xor ax,ax
ret
DEVICE_CLOSE ENDP
- 6-63 -
;
REMOVABLE PROC NEAR ; F - носитель сменный ?
mov ax,ST_BUSY ; нет !
ret
REMOVABLE ENDP
;
GENERIC_IOCTL PROC NEAR ; 13 - групповой IOCTL запрос
xor ax,ax
ret
GENERIC_IOCTL ENDP
;
GET_LOGICAL PROC NEAR ; 17 - получить имя логического
xor ax,ax ; диска
ret
GET_LOGICAL ENDP
;
SET_LOGICAL PROC NEAR ; 18 - установить имя логического
xor ax,ax ; диска
ret
SET_LOGICAL ENDP
;
PAGE
; ------------ Подпрограммы обработки запросов -----------------------
; Эти подпрограммы вызываются для обработки параметров любого запроса
; на ввод/вывод.
; На входе :
; ES:DI - содержит адрес блока запроса
; Действия :
; Проверка параметра "номер сектора" на допустимость.
; Преобразование этого параметра в "сегмент:смещение".
; Выровнять счетчик для предотвращения "перекрытия".
; На выходе :
; DS:SI - содержит адрес "сектора" в RAM-диске
; ES:DI - содержит адрес блока запроса
; CX - содержит количество передаваемых слов.
;
verify PROC NEAR
; проверим,что номера начального и конечного секторов лежат в пределах
; от 0 до N.
mov cx,request.start ; сравним номер начального
cmp cx,bpb.nls ; сектора с количеством
jae out_of_range ; логических секторов
add cx,request.count ; найдем номер конечного
dec cx ; сектора и тоже сравним
cmp cx,bpb.nls ; если номера секторов
jb in_range ; нормальные то продолжим
; заданные секторы не содержатся на диске
out_of_range:
mov ax,ST_ERROR OR SECTOR_NOT_FOUND
mov request.count,0 ; ничего не было передано
stc ; возвращаемся с ошибкой
ret
; вычислим сегментный адрес начального сектора
in_range:
mov ax,bpb.bps ; количество байт в секторе
mov cl,4 ; разделим на 16 для получения
shr ax,cl ; размера в параграфах
- 6-64 -
mul request.start ; смещение параграфа относи-
; тельно начала диска
add ax,RPARA ; смещение параграфа относи-
mov dx,cs ; тельно CS
add ax,dx ; абсолютное смещ. параграфа
mov si,ax ; сохраним сегмент в SI
; вычислим и проверим счетчик передаваемых данных
mov ax,bpb.bps ; размер сектора в байтах
mul request.count ; счетчик передачи в байтах
cmp dx,0 ; проверим на корректность
jne out_of_range
; выровняем счетчик в AX для предотвращения перекрытия
mov cx,word ptr request.bufptr
cmp ax,0 ; смещение = 0
je set_size
neg cx ; остаток = 64K - смещение
cmp cx,ax ; буфера
jae set_size ; если остаток меньше счетчика,
mov ax,cx ; то передаем только остаток
; установим количество передаваемых секторов и счетчик передачи
set_size:
mov cx,ax ; счетчик передачи в байтах
shr cx,1 ; преобразуем в счетчик слов
div bpb.bps ; (DX был 0) кол-во секторов
mov request.count,ax ; сохраним счетчик передачи
; загрузим в DS:SI адрес блока в памяти
mov ds,si
xor si,si
; установим направление передачи и вернемся без ошибок
cld
clc
ret
verify ENDP
;
IFDEF DEBUG
INCLUDE biosio.asm
PAGE
;
; ************ КОД И ДАННЫЕ ДЛЯ ОТЛАДКИ ******************************
;
; Отладочные сообщения
;
NO_COMMAND_msg db 'NO COMMAND',CR,LF,'$'
INIT_msg db 'INITialization',CR,LF,'$'
MEDIA_CHECK_msg db 'MEDIA Check',CR,LF,'$'
BUILD_BPB_msg db 'Build BIOS Parameter Block',CR,LF,'$'
IOCTL_INPUT_msg db 'IO Control Input',CR,LF,'$'
READ_msg db 'Input from Device',CR,LF,'$'
READ_NOWAIT_msg db 'Nondestructive Input no-wait',CR,LF,'$'
INPUT_STATUS_msg db 'Input Status',CR,LF,'$'
INPUT_FLUSH_msg db 'Flush Input Queue',CR,LF,'$'
WRITE_msg db 'Output to Device',CR,LF,'$'
WRITE_VERIFY_msg db 'Output with Verify',CR,LF,'$'
OUTPUT_STATUS_msg db 'Output Status',CR,LF,'$'
OUTPUT_FLUSH_msg db 'Flush Output Queue',CR,LF,'$'
IOCTL_OUTPUT_msg db 'IO Control Output',CR,LF,'$'
DEVICE_OPEN_msg db 'Open a Device',CR,LF,'$'
- 6-65 -
DEVICE_CLOSE_msg db 'Close a Device',CR,LF,'$'
REMOVABLE_msg db 'Is Media Removable',CR,LF,'$'
GENERIC_IOCTL_msg db 'Generic IOCTL Request',CR,LF,'$'
GET_LOGICAL_msg db 'Get Logical Device',CR,LF,'$'
SET_LOGICAL_msg db 'Set Logical Device',CR,LF,'$'
;
PAGE
;
; ============= ТАБЛИЦА АДРЕСОВ ОТЛАДОЧНЫХ СООБЩЕНИЙ =================
;
message_table LABEL WORD
dw offset INIT_msg ; 01 - инициализация
dw offset MEDIA_CHECK_msg ; 02 - проверка носителя
dw offset BUILD_BPB_msg ; 03 - построить BPB
dw offset IOCTL_INPUT_msg ; 04 - ввод IOCTL
dw offset READ_msg ; 05 - ввод из устройства
dw offset READ_NOWAIT_msg ; 06 - неразруш. ввод без ожид.
dw offset INPUT_STATUS_msg ; 07 - ввод статуса
dw offset INPUT_FLUSH_msg ; 08 - сброс входной очереди
dw offset WRITE_msg ; 09 - вывод на устройство
dw offset WRITE_VERIFY_msg ; 10 - вывод с проверкой
dw offset OUTPUT_STATUS_msg ; 11 - вывод статуса
dw offset OUTPUT_FLUSH_msg ; 12 - сброс выходной очереди
dw offset IOCTL_OUTPUT_msg ; 13 - вывод IOCTL
dw offset DEVICE_OPEN_msg ; 14 - открыть устройство
dw offset DEVICE_CLOSE_msg ; 15 - закрыть устройство
dw offset REMOVABLE_msg ; 16 - носитель сменный ?
dw offset NO_COMMAND_msg ; 17 -
dw offset NO_COMMAND_msg ; 18 -
dw offset NO_COMMAND_msg ; 19 -
dw offset GENERIC_IOCTL_msg ; 20 - групповой IOCTL запрос
dw offset NO_COMMAND_msg ; 21 -
dw offset NO_COMMAND_msg ; 22 -
dw offset NO_COMMAND_msg ; 23 -
dw offset GET_LOGICAL_msg ; 24 - получить имя диска
dw offset SET_LOGICAL_msg ; 25 - установить имя диска
;
PAGE
; PRINT_COMMAND
;
; Эта процедура вызывает функцию BIOS для печати (_biosprt), передавая
; ей адрес строки, содержащей имя только что вызванной команды. При
; вызове этой процедуры удвоенный код команды передается в регистре BX.
; Все используемые регистры сохраняются.
;
print_command PROC NEAR
push ax ; сохраним содержимое рег. AX
mov ax, BLUE_F OR BRIGHT OR BLACK_B ; установим цвет
push ax
mov ax,word ptr message_table[bx] ; адрес строки
push ax
call _biosprt ; вызываем процедуру BIOS
add sp,4 ; очищаем стек от параметров
pop ax ; восстанавливаем AX и выходим
ret
print_command ENDP
ENDIF
- 6-66 -
;
PAGE
;
; ******* ВНУТРЕННИЙ СТЕК И КОНЕЦ ОПЕРАЦИОННОЙ ЧАСТИ ДРАЙВЕРА ********
;
db 32 DUP ('stack ') ; внутренний стек глубиной
local_stack EQU $ ; 256 байт
;
bpb_tab dw offset bpb ; указатель на BPB
;
LAST_USED EQU $ ; адрес завершения
;
; ******* ХАРАКТЕРИСТИКИ RAM-ДИСКА, ПРИНИМАЕМЫЕ ПО УМОЛЧАНИЮ **********
;
; Параметры для 5-1/4" двустороннего двойной плотности диска с девятью
; секторами на дорожке.
;
MTYPE EQU 0FDh ; байт описателя носителя
TRACKS EQU 40 ; 40 дорожек
SECTORS EQU 9 ; 9 секторов на дорожке
DSIZE EQU 512 ; 512 байт в секторе
SIDES EQU 2 ; 2 стороны на диске
;
FSECS EQU 2 ; количество секторов в FAT
DIREN EQU 112 ; количество элементов директория
DSECS EQU 7 ; 7 секторов в директории
CLSIZ EQU 2 ; 2 сектора в кластере
;
STOTAL EQU TRACKS*SECTORS*SIDES ; всего секторов
PTOTAL EQU (DSIZE/16)*STOTAL ; всего параграфов
;
; ************ НАЧАЛО ОБЛАСТИ ДАННЫХ RAM-ДИСКА ***********************
;
; RAM-диск д.б. выровнен на границу параграфа
;
IF ($-ORIGIN) mod 16
ORG ($-ORIGIN) + 16 - (($-ORIGIN) mod 16)
ENDIF
RDISK LABEL BYTE ; начало RAM-диска
RPARA EQU ($-ORIGIN)/16 ; размер кода в параграфах
;
; ------------ Блок параметров BIOS ----------------------------------
;
jmp short boot ; короткий JMP (2 байта)
nop ; требуется для boot_record
db 'IBM 3.1' ; 8 байт имя и версия
;
bpb bpbstrc
dw SECTORS ; количество секторов на дорожке
dw SIDES ; количество головок чтения/записи
dw 0 ; количество скрытых секторов
boot:
db (DSIZE-30) DUP (?) ; остаток boot_sector
;
; ------------ Таблицы размещения файлов (FAT) -----------------------
; ; первые два элемента FAT
FAT_1 db MTYPE,0FFh,0FFh ; нулевой остаток FAT
- 6-67 -
db (DSIZE-3) DUP (0)
db ((FSECS-1) * DSIZE) DUP (0)
FAT_2 db MTYPE,0FFh,0FFh ; первые два элемента FAT
db (DSIZE-3) DUP (0) ; нулевой остаток FAT
db ((FSECS-1) * DSIZE) DUP (0)
;
; ------------ Сектора директория ------------------------------------
;
DIREC db 'RAM_DISK ' ; имя тома (11 байт)
db 08h ; VID
db 10 DUP (?) ; зарезервировано
dw 0600h ; время 12:00:00 (полдень)
dw 021h ; дата 1 января 1980 года
dw 0 ; начальный кластер 0
dd 0 ; размер файла 0
db (DSIZE-32) DUP (0) ; нулевой остаток директория
db ((DSECS-1) * DSIZE) DUP (0)
BUFFER LABEL BYTE ; начало области данных
;
; ************ ПРОЦЕДУРА ИНИЦИАЛИЗАЦИИ *******************************
;
INCLUDE stdmac.inc
;
; ============ Область данных инициализации ==========================
;
$signon db 'RAM DISK Driver Version 1.00 Installed: Drive'
$desig db 'A'
$crlf db 0Dh,0Ah,'$'
;
; ============ Начало процедуры инициализации ========================
;
INIT PROC NEAR ; 00 - инициализация
;
; установим адрес завершения, количество устройств и указатель на
; таблицу BPB
;
mov request.endadro,0 ; адрес конца драйвера
mov request.endadrs,cs
add request.endadrs,(RPARA+PTOTAL) ; последний параграф
mov request.units,1
mov request.bpbtabo,offset bpb_tab
mov request.bpbtabs,cs
mov al,$desig ; скорректируем имя диска
add al,request.devnum
mov $desig,al
;
; вывод на экран идентификационной строки
@DisStr $signon
;
; скорректируем значение "max_cmd" исходя из версии MS-DOS
@GetDOSVersion ; получим номер версии MS-DOS
cmp al,3 ; MS-DOS версии 3.00 и выше ?
jb init_done ; нет - прекращаем инициализацию
mov [max_cmd],CMD_PRE_32 ; команды для MS-DOS 3.00
cmp ah,2 ; MS-DOS версии 3.20 и выше ?
jb init_done ; нет - прекращаем инициализацию
mov [max_cmd],CMD_32 ; команды для MS-DOS 3.20
- 6-68 -
;
init_done:
xor ax,ax ; нет проблем !
ret
INIT ENDP
;
; ************ КОНЕЦ ДРАЙВЕРА. КОНЕЦ ФАЙЛА ***************************
;
_TEXT ENDS
END
---------------------------------------------------------------------
Заключение
Теперь Вы готовы писать и устанавливать свои собственные драй-
веры устройств. Руководствуйтесь нашими замечаниями и "MS-DOS
Programmers Reference Manual" при возникновении каких-либо техни-
ческих вопросов.
ЙННННННННННН»
є Вывод ЗДї
є программы є і
ИНСНННННННННј і
АДДДєДДДДДДДЩ
ЙННННННННННННННННННОНННННННННННННННННН»
є є є
ЙННННННvНННННН» ЙННННННvНННННН» ЙННННННvНННННН»
є Виртуальный ЗДї є Виртуальный ЗДї є Виртуальный ЗДї
є дисплей #0 є і є дисплей #1 є і є дисплей #2 є і
ИНСНННННННННННј і ИНСНННННННННННј і ИНСНННННННННННј і
АДДДДєДДДДДДДДЩ АДДДДєДДДДДДДДЩ АДДДДєДДДДДДДДЩ
ИННННННННННННННННН>є<НННННННННННННННННј
є
ЙНННННvННННН»
є Монитор ЗДї
є Дисплей є і
ИНСНННННННННј і
АДДДДДДДДДДДЩ
Рисунок 6-8. Драйвер виртуальных экранов
Полезными драйверами были бы, например, драйвер матричного
принтера, поддерживающий графические команды (такие как "нарисо-
вать линию") и преобразующий их к требуемому принтером формату,
или драйвер терминала, поддерживающий виртуальные экраны (см.рис.
6-8). Такой драйвер терминала может иметь несколько буферов в па-
мяти, хранящих копии экранной информации. Посылая команды драйве-
ру по IOCTL-каналу, можно указать драйверу какой виртуальный эк-
ран должен быть обновлен и какой виртуальный экран должен быть
отображен на реальном экране. Если Вы успешно написали такой
драйвер, то Вы можете заменить им существующий драйвер консоли.
Список идей, которые можно было бы реализовать в драйверах,
практически бесконечен. Вероятно, у Вас уже появилось несколько
своих, которые Вы хотели бы реализовать. Если у Вас хватает спо-
койствия и терпения то ничто не может помешать Вам в этом, так
что дерзайте!
© KOAP
Open Portal 2000
|
|