ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.


Самая свежая информация бумага офисная а4 здесь.
ГЛАВА 2   MS-DOS ДРАЙВЕРЫ УСТРОЙСТВ
      _________________________________________________________



     2.1    Введение
     2.2    Формат драйвера устройства
     2.3    Как написать дравер устройства
     2.3.1    Программа стратегии драйвера
     2.3.2    Программа прерывания
     2.4    Загрузка драйвера
     2.5    Заголовок устройства
     2.5.1    Указатель на следующий драйвер
     2.5.2    Поле атрибута
     2.5.3    Программы стратегии и прерывания
     2.5.4    Поле имени
     2.6    Заголовок запроса
     2.6.1    Поле длины запроса
     2.6.2    Поле кода устройства
     2.6.3    Поле кода команды
     2.6.4    Поле состояния
     2.7    Функции драйвера устройства
     2.7.1    Инициализация
     2.7.2    Проверка диска
     2.7.3    Построение BPB ( Блок Параметров БСВВ )
     2.7.4    Запись или чтение
     2.7.5    Небуферизированное чтение
     2.7.6    Открытие или закрытие
     2.7.7    Сменяемый диск
     2.7.8    Проверка состояния
     2.7.9    Снос
     2.7.10   Общее УВВ ( Управление вводом/выводом )
     2.7.11   Получение/установка карты логического дисковода
     2.8    Байт описатель диска
     2.9    Формат таблицы описания диска
     2.10   Устройство ЧАСЫ
     2.11   Порядок обращения к устройству
     2.12   Два примера драйверов устройств


                             - 178 -



     2.1  Введение

     Файл  io.sys  включает  резидентные  драйверы  устройств,
формирующие базовую систему ввода/вывода  (БСВВ)  MS-DOS.  Эти
драйверы вызываются системой для обработки запросов прикладных
     программ  на  ввод/вывод.  Возможности  MS-DOS  позволяют
вводить новые устройства, например, принтеры, плоттеры и  мыши
без  модификации  БСВВ. Нерезидентные или загружаемые драйверы
могут  быть  легко  включены  во  время   начальной   загрузки
командной строкой DEVICE в файле config.sys.
     Во  время  начальной  загрузки  должны присутствовать как
минимум  пять  резидентных  драйверов.  Все  они  находятся  в
связном списке - заголовок каждого содержит DWORD указатель на
следующий.  Заголовок  последнего содержит маркер конца списка
-1,-1 (все биты установлены).
     Каждый драйвер в  этой  цепи  имеет  две  точки  входа  -
указатели  на  программу  стратегии  и  программу  прерывания.
MS-DOS сразу  после  программы  стратегии  вызывает  программу
прерывания.
     Такое  двухвходовое  построение  обеспечит работу будущих
мультипрограммных  версий  MS-DOS.  В   многозадачном   режиме
ввод/вывод   должен  быть  асинхронным.  Для  этого  программа
стратегии должна выстраивать  очередь  из  запросов  и  быстро
возвращать   управление.   Дальше   вся   ответственность   за
выполнение поступивших запросов лежит на программе прерывания,
которая считывает запросы из очереди. После выполнения запроса
программа прерывания  флажирует  его  как  "выполнен".  MS-DOS
периодически   сканирует   список  запросов  в  поисках  таких
запросов, а затем "будит" соответствующую программу, ожидающую
выполнения этого запроса.
     Запросы различаются размером и форматом и состоят из двух
секций:

     1. Заголовок запроса, имеющий стандартный формат для
        всех запросов
     2. Конкретная информация к запросу

     Драйвер  вызывается  с  указателем   на   этот   "пакет".
Программа  стратегии  должна  сохранить  адрес  этого пакета в
фиксированном месте, после  чего  сразу  вызывается  программа
прерывания,   обрабатывающая   этот  пакет.  Запрос  считается
выполненным по возвращении из программы прерывания.
     Файл драйвера должен иметь формат .bin или .exe и иметь в
своем начале заголовок устройства.
     Загружаемые  драйверы  с   форматом   .exe   могут   быть
использованы   в   не-IBM   версиях  MS-DOS.  На  персональных
компьютерах IBM загрузчик .exe файлов находится в command.com,
который  не  присутствует  во   время   загрузки   загружаемых
драйверов.
     2.2 Формат драйвера устройства

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

                             - 179 -



     _________________________________________________________
     Примечание
               Файл драйвера не должен использовать ORG 100H,
               т.к. он не использует Префикс сегмента кодов
               (PSP). Файл должен начинаться с нуля (ORG 0 или
               отсутствие директивы ORG).
     _________________________________________________________

     Существует два типа драйверов:

     - Драйвер символьного устройства
     - Драйвер блокового устройства

     Символьные   устройства   осуществляют   последовательный
символьный ввод/вывод. Такими устройствами  являются  консоль,
последовательный порт и принтер (CON, AUX, CLOCK и т.д.).
     Блоковые устройства включают все дисководы в системе. Они
могут осуществлять выборочный ввод/вывод блоков данных (обычно
равных физическому размеру сектора). Все они имеют свои номера
и идентифицируются буквами A, B, C и т.д.
     Один  драйвер блокового устройства может отвечать за один
или несколько логически связных дисководов. Например,  драйвер
ALPHA  может  отвечать за дисководы A,B,C и D. Это значит, что
для него определено четыре номера (0-3),  а  сам  он  занимает
четыре  буквы.  Положение  драйвера в списке определяет, каким
буквам соответствуют его номера. Если  в  нашем  примере  BETA
является  вторым  драйвером в списке и для него определено три
номера (0-2), то этим номерам уже будут соответствовать  буквы
E,F  и G. Теоретическая граница - 63, однако нужно учесть, что
загрузка драйвера не будет  выполнена,  если  получится  буква
больше  Z(5АН).  Все  резидентные  драйверы помещаются впереди
загружаемых драйверов.

     _________________________________________________________
     Примечание
               Драйверы символьных устройств не могут отвечать
               за несколько устройств, т.к. имеют только одно
               имя.
     _________________________________________________________

     2.3 Как создать драйвер устройства

     Для  создания  загружаемого  драйвера   вам   необходимо
програмный файл (формат .com или .exe) с заголовком в начале.
Не  забудьте,  что  код должен начинаться не с 100Н, а с 00Н.
Указатель на следующий драйвер должен быть  выставлен  в  -1,
если  файл  содержит  только  один  драйвер.  Соответствующим
образом устанавливаются поля атрибута и точек входа.
     В случае с символьным устройством поле имени содержит имя
символьного   устройства.   Если  длина  имени  меньше  восьми
символов,  то  оно  дополняется  пробелами   (20Н).   Обратите
внимание, что имена устройств не включают двоеточие (:).
     MS-DOS  всегда  обрабатывает в первую очередь загружаемые
драйверы перед  резидентными.  Поэтому  для  установки  нового
драйвера  устройства  CON  нужно  просто  указать  имя CON. Не
забудьте установить  биты  стандартного  ввода/вывода в  слове
атрибута  нового  драйвера.  Сканирование  по списку драйверов
останавливается  на  первом  подходящем,  поэтому  загружаемые
драйверы имеют преимущество.

                             - 180 -


     Не  разрешается  заменять  резидентные  драйверы блоковых
устройств, как, например, вы  это  можете  сделать  с  другими
драйверами   БСВВ.  Драйверы  блоковых  устройств  могут  быть
использованы только для устройств, не поддерживаемых  напрямую
резидентными драйверами из файла io.sys.

     2.3.1 Программа стратегии

     Эта  программа отвечает за помещение поступающих запросов
в  очередь.  Она  вызывается  системой  и  предназначена   для
применения в будущих мультипрограммных версиях MS-DOS. Текущая
версия  не поддерживает этих возможностей и обслуживает только
один  запрос  в  каждый  момент  времени,  поэтому   программа
стратегии   максимально   проста   -   каждый   запрос  просто
сохраняется в одной области ( см.  Раздел  2.12  "Два  примера
драйверов устройств").

     2.3.2 Программа прерывания

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

     2.4 Загрузка драйверов устройств

     Загрузка  новых  драйверов  происходит во время начальной
загрузки системы.  Загрузка  выполняется  кодом инициализации,
находящимся в файле io.sys, и обрабатывающем файл config.sys.
     MS-DOS вызывает драйверы устройств следующим образом:

     1. MS-DOS делает дальний вызов программы стратегии.
     2. MS-DOS  передает  информацию  из  заголовка  запроса
        программе стратегии.
     3. MS-DOS делает дальний вызов программы прерывания.

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


     2.5 Заголовок устройства

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

     DWORD   Указатель на следующий драйвер
             (Обычно равен -1, если драйвер последний или един-
             ственный в файле)
     WORD    Атрибуты
     WORD    Указатель на программу стратегии
     WORD    Указатель на программу прерывания
     8-BYTE  Поле имени символьного устройства
             (Для  блоковых  устройств  первый  байт  содержит
             количество устройств).

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

                             - 181 -



     2.5.1 Поле указателя на следующий драйвер

     Содержит  адрес  (смещение:сегмент) следующего драйвера в
файле. Если драйвер  является  единственным  или  последним  в
списке, то это поле должно быть выставлено в -1.

     2.5.2 Поле атрибута

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

     Таблица 2.1
     Для символьных устройств:
     __________________________________________________________
     Бит  Сост.  Значение
     __________________________________________________________
     0    1      Консоль ввода
     1    1      Консоль вывода
     2    1      Нулевое устройство
     3    1      Часы
     4-5         Зарезервировано (должны быть нулями)
     6    1      Поддерживает функции 3.2
     7-10        Зарезервировано (должны быть нулями)
     11   1      Понимает Открыть/закрыть
     12          Зарезервирован  (должен быть нулем)
     13   1      Поддерживает режим OUB (вывод пока не занят)
     14   1      Поддерживает управляющие последовательности
     15   1      Символьное устройство
     __________________________________________________________

     Таблица 2.2
     Для блоковых устройств:
     __________________________________________________________
     Бит  Сост.  Значение
     __________________________________________________________
     0           Зарезервирован (должен быть нулем)
     1    1      Поддерживает 32-битную адресацию сектора
     2-5         Зарезервировано (должны быть нулями)
     6    1      Поддерживает функции 3.2 и функции общего УВВ
     7-10        Зарезервировано (должны быть нулями)
     11   1      Понимает Открыть/закрыть/сменный
     12          Зарезервирован (должен быть нулем)
     13   1      Определяет диск проверкой байта FAT ID
     14   1      Поддерживает управляющие последовательности УВВ
     15   0      Блоковое устройство
     __________________________________________________________

     Допустим,   вы   хотите   иметь   новый  драйвер,  вместо
стандартных ввода/вывода. Для этого вам необходимо  установить
биты  0  и 1 равными 1. Хотя предусмотрен бит признак нулевого
устройства, этот  бит  применяется   MS-DOS  для  определения,
используется  ли  нулевое  устройство.  Нулевое  устройство не
может быть переназначено.
     Бит 13 в блоковых  устройствах  имеет  дело  с  операцией
Построить  БПБ (Блок параметров Базовой Системы Ввода/Вывода).
При  его  установке  первый  сектор  FAT  (Таблица  размещения
файлов)  должен  всегда  начинаться  с одного и того же места.

                             - 182 -


Этот бит имеет другое значение на символьных  устройствах.  Он
показывает,  может  ли  устройство выполнить запрос на вывод в
режиме OUB (Вывод пока не занято).
     Бит 14 сообщает MS-DOS может ли  устройство  обрабатывать
управляющие последовательности функции 44Н (УВВ).
     Если    драйвер   не   может   обрабатывать   управляющие
последовательности, то этот бит должен быть равен нулю. В этом
случае  MS-DOS  возвращает   ошибку   при   попытке   передать
или получить управляющие последовательности с помощью функциии
44Н.
     Бит  11  сообщает  MS-DOS  3.X  и  более  поздних версий,
поддерживает ли устройство дополнительные функции MS-DOS  3.X.
В  MS-DOS  2.X  этот  бит был зарезервирован и равен нулю. Все
новые     драйверы      должны      поддерживать      операции
Открыть/Закрыть/Сменный-диск  и  установить  этот бит в 1. Так
как MS-DOS 2.X никогда не использует этот бит,  новый  драйвер
будет совместим со старыми версиями системы.
     Бит   6  сообщает  системе,  поддерживает  ли  устройство
функции 440СН, 440DH, 440EH и 440FH.
     Бит  1  в  блоковых  устройствах  индицирует   32-битовую
адресацию  сектора. Если он установлен, то поле номера сектора
всех запросов является двойным словом (DWORD),  добавляемым  в
конец  заголовка  запроса.  Старое  WORD номера сектора должно
быть равно -1.
     Если бит 1 равен 0, то используется 16-битовая  адресация
сектора.

     Слово атрибута символьного устройства:
t1
  15  14  13  12  11  10   9   8   7   6  5  4   3   2   1   0
_______________________________________________________________
і С і У і   і   і О і   і   і   і   і 3 і  і  і Ч і Н і С і С і
і И і В і   і   і Т і   і   і   і   і . і  і  і А і У і В і В і
і М і В і   і   і К і   і   і   і   і 2 і  і  і С і Л і В і Ы і
_______________________________________________________________

     Слово атрибута блокового устройства:

  15  14  13  12  11  10   9   8   7   6  5  4   3   2   1   0
_______________________________________________________________
і   і У і Т і   і О і   і   і   і   і 3 і  і  і   і   і > і   і
і   і В і Р і   і Т і   і   і   і   і . і  і  і   і   і 3 і   і
і   і В і Ф і   і К і   і   і   і   і 2 і  і  і   і   і 2 і   і
_______________________________________________________________
t0
     2.5.3 Программы стратегии и прерывания

     Эти  поля  содержат  указатели  на  программы стратегии и
прерывания.  Сегментный  адрес  тот  же,  что  и  у  заголовка
устройства.

     2.5.4 Поле имени

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


                             - 183 -



     2.6 Заголовок запроса

     Когда  MS-DOS  вызывает драйвер устройства для выполнения
какой-либо  функции,  программе  стратегии  передается   адрес
заголовка запроса в ES:BX. Это область фиксированной длины, за
которой  следуют данные, необходимые для выполняемой операции.
Не забудьте,  что  на  драйвере   лежит   ответственность   за
сохранение   регистров  и  флагов.  Для  этого,  как  правило,
требуется не более 20 команд POP-PUSH. Если  требуется  больше
места, то драйвер может создать свой собственный стэк.

t1     Заголовок запроса:
     _______________________________________________________
    і BYTE    Длина в байтах заголовка запроса              і
    і BYTE    Код устройства, к которому обращается операцияі
    і BYTE    Код операции                                  і
    і WORD    Слово состояния                               і
    і 8 БАЙТ  Зарезервировано                               і
     _______________________________________________________
t0
     2.6.1 Длина заголовка запроса

     Это поле содержит длину в байтах заголовка запроса.

     2.6.2 Код устройства

     Код устройства, к которому обращается операция. Например,
если  за  драйвером  закреплено  три  устройства  (буквы),  то
возможными значениями этого поля будут 0, 1 и 2.

     2.6.3 Код операции

     Код  Операция
     __________________________________________________________
     0    Инициализация
     1    Проверка диска (только для блоковых устройств)
     2    Построить БПБ  (только для блоковых устройств)
     3    УВВ Ввод  (если устройство имеет УВВ)
     4    Ввод  (чтение)
     5    Небуферизированное чтение
     6    Состояние ввода (только для символьных устройств)
     7    Сброс (ввод)    (только для символьных устройств)
     8    Вывод (запись)
     9    Вывод (запись) с проверкой
     10   Состояние вывода (только для символьных устройств)
     11   Сброс (вывод)    (только для символьных устройств)
     12   УВВ Вывод  (если устройство имеет УВВ)
     13   Открыть (если установлен бит 11 слова атрибута)
     14   Закрыть (если установлен бит 11 слова атрибута)
     15   Сменный диск (если установлен бит 11 слова атрибута
                       на блоковом устройстве)
     16   Вывод пока не занято (если установлен бит 13 на
                               символьном устройстве)
     19   Общее УВВ
     23   Получить карту логического дисковода
     24   Установить карту логического дисковода
     __________________________________________________________

                             - 184 -



     2.6.4 Слово состояния

t1     15  14 13 12 11 10  9   8  7  6  5  4  3  2  1  0
     ___________________________________________________
     і О і              і З і В і                      і
     і Ш і Зарезервиро- і А і Ы і Код ошибки           і
     і Б і вано         і Н і П і (если бит 15 = 1)    і
     ___________________________________________________
t0
     На  входе  слово  состояния  равно  нулю  и   заполняется
программой прерывания драйвера по возвращении.
     После выполнения операции драйвер устанавливает бит 8.
     Бит  9   (Занято)   устанавливается   только   операциями
Состояние и Сменный диск.
     Если  по  возвращении  установлен бит 15, то младший байт
слова состояния содержит код ошибки:

     Код  Значение
     __________________________________________________________
     0    Защищено по записи
     1    Неизвестное устройство
     2    Дисковод не готов
     3    Неизвестная операция
     4    Ошибка циклического кода проверки
     5    Неразрешенная длина запроса
     6    Ошибка поиска
     7    Неизвестный диск
     8    Сектор не найден
     9    Нет бумаги в принтере
     А    Ошибка записи
     В    Ошибка чтения
     С    Общий сбой
     D    Зарезервировано
     Е    Зарезервировано
     F    Неразрешенная смена диска
     __________________________________________________________


     2.7 Функции драйвера устройства

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

     - Инициализация
     - Проверка диска
     - Построить БПБ
     - Чтение, Запись, Вывод пока не занято, Запись с проверкой
       УВВ чтение, УВВ запись
     - Небуферизированное чтение
     - Открыть или Закрыть (3.Х)
     - Сменный диск (3.Х)
     - Проверка состояния
     - Сброс
     - Общее УВВ
     - Получить/установить карту логического дисковода

                             - 185 -



     Все программы стратегии вызываются при ES:BX  содержащими
указатель  на заголовок запроса. Программа прерывания получает
указатели  на  заголовки  запросов  из  очереди,   создаваемой
программой   стратегии.   Код  операции  в  заголовке  запроса
сообщает драйверу, какую функцию выполнить и какая  информация
содержится в хвосте заголовка запроса.
     __________________________________________________________
     Примечание
               Все двусловные (DWORD) указатели содержат первым
               смещение, а потом сегмент.
     __________________________________________________________


     2.7.1 Функция инициализации

t1     Код операции - 0
             ___________________________________________________
     ES:BX - і 13 БАЙТ  Заголовок запроса                      і
             і BYTE     Количество устройств                   і
             і DWORD    Конечный адрес                         і
             і DWORD    Указатель на массив БПБ (не устанавливаі
             і          ется символьными устройствами)         і
             і BYTE     Номер блокового устройства             і
             ___________________________________________________
t0
     Одной  из  функций,  определенных  для  каждого  драйвера
является функция Инициализации.  Этот  код  вызывается  только
однажды  при загрузке драйвера. Программа инициализации должна
возвращать конечный  адрес,  являющийся  DWORD  указателем  на
конец  той части драйвера, которая должна остаться резидентом.
Для экономии места вы можете использовать этот  указатель  для
удаления кода инициализации, который нужен только один раз.
     Поля  Количество устройств, Конечный адрес и Указатель на
массив БПБ устанавливаются драйвером. Однако на  входе,  DWORD
указатель   на   массив  БПБ  содержит  указатель  на  символ,
следующий  за  "="  в  командной  строке   файла   config.sys,
вызвавшей   загрузку   этого  файла.  Это  позволяет  драйверу
сканировать строку в поисках параметров, которые возможно были
переданы драйверу. Эта строка заканчивается ВК или ПС.  Данные
строки могут быть только прочитаны.
     Кроме  того,  для  блоковых  устройств  номер  дисковода,
назначенный первому устройству  драйвера  (А=0)  содержится  в
поле  номера  блокового устройства. Эти данные тоже только для
чтения.
     __________________________________________________________
     Примечание
               Программа Инициализации может работать только с
               функциями 01Н-0СН, 25Н, 30Н и 35Н.
     __________________________________________________________

     Загружаемые   драйверы   символьных   устройств    должны
возвращать  конечный  адрес.  Им  является указатель на первый
свободный байт памяти  после  кода  драйвера.  Он  может  быть
использован для удаления ставшего не нужным  кода инициализации.
     Драйверы  блоковых  устройств должны возвращать следующую
информацию:

     1. Количество устройств. Система использует это  значение
для  определения  логических  имен  устройств.  Если  на время

                             - 186 -


загрузки  драйвера  максимальной  текущей  буквой  логического
устройства  была  F,  а  программа инициализации вернула 4, то
логическими именами устройств загруженного драйвера будут  уже
G,  H,  I  и  J. Соответствие определяется позицией драйвера в
списке устройств и значением поля Имя устройства  в  заголовке
драйвера   (первый   байт   для  блоковых  устройств  содержит
количество устройств).
     2. DWORD указатель на массив WORD  смещений  (указателей)
на  БПБ  (Блоки  параметров  БСВВ). Передаваемые драйвером БПБ
используются системой для создания внутренних структур. В этом
массиве для каждого устройства должна быть своя  точка  входа.
Если  все устройства одинаковы, то все указатели адресуют один
и тот же БПБ. Формат БПБ описан в  Разделе  2.7.3  "Построение
БПБ".
     Обратите внимание на то, что массив указателей должен быть
защищен  (указатель массива указывает на первый свободный байт
после массива), т.к. структуры DOS  выстраиваются,  начиная  с
байта,  адресуемого указателем массива указателей. Указываемый
размер сектора должен  быть  меньше  или  равен  максимальному
размеру  сектора, определяемого резидентными драйверами (БСВВ)
во время инициализации. В противном случае,  инициализация  не
будет выполнена.
     3.  Байт описатель диска. Этот байт не имеет значения для
MS-DOS, однако передается устройствам, чтобы те  могли  знать,
какие   параметры   MS-DOS  в  данный  момент  использует  для
конкретного дисковода.
     __________________________________________________________
     Примечание
               Если в файле содержится несколько драйверов, то
               MS-DOS использует конечный адрес, возвращенный
               последней вызванной функцией инициализации. Все
               драйверы  в  одном  файле   должны   возвращать
               одинаковый  конечный  адрес.  Код инициализации
               для  всех  драйверов  должен  идти  после  этих
               драйверов .
     __________________________________________________________

     2.7.2  Функция проверки диска

     Код операции - 1
t1             ___________________________________________________
     ES:BX - і 13 БАЙТ  Заголовок запроса                      і
             і BYTE     Описатель диска из БПБ                 і
             і BYTE     Код возврата                           і
             і DWORD    Указатель на предыдущую метку тома     і
             і          (если установлен бит 11 слова атрибута і
             і          и код возврата равен  -1)              і
              __________________________________________________
t0
     Эта функция используется только с блоковыми устройствами.
Она вызывается, когда поступил запрос на доступ к диску не для
файловых  чтения  или записи, например, при открытии, закрытии
или переименования. Функция предназначена для определения, был
ли сменен диск в дисководе. Если драйвер подтвердит, что  диск
не  был  сменен (через механизм замка), то MS-DOS уже не нужно
будет повторять целый ряд операций - чтение FAT и  инвалидацию
буферов.
     При  вызове  функции DOS для доступа к диску (отличной от
чтения или записи) имеет место следующий порядок действий:


                             - 187 -


     1. DOS  преобразует  имя  дисковода  в  номер  устройства
конкретного блокового устройства.
     2.  После этого вызывается драйвер устройства с операцией
проверки диска на предмет смены. MS-DOS передает  старый  байт
описатель диска. Драйвер возвращает код возврата:

     Код        Значение
     __________________________________________________________
     1          Диск не был сменен
     0          Неизвестно
     -1         Диск был сменен
     Величина   Ошибка (Величина - стандартный код ошибки)
     __________________________________________________________

     Если  диск  не был сменен, то система продолжает работу с
диском.
     Если код возврата равен -1  и  остались  модифицированные
сектора, не записанные обратно на диск, то MS-DOS считает, что
диск не был сменен. MS-DOS делает недействительными все другие
буферы  для  этого  устройства  и  вызывает  функцию  драйвера
Построить БПБ.
     Если диск был сменен, то MS-DOS делает  недействительными
все  буферы,  соотнесенные  с  этим устройством и ждущие своей
записи на диск, а затем вызывает функцию Построить БПБ.
     3. По возвращении драйвером БПБ, MS-DOS корректирует свои
внутренние структуры для драйвера из нового БПБ и осуществляет
доступ после чтения каталога и FAT.
     Обратите  внимание  на  то,   что   драйверу   передается
предыдущий байт описатель диска.
     Если бит 11 слова атрибута равен 1, а драйвер вернул -1
(диск был сменен), то драйвер должен выставить DWORD указа-
тель на поле предыдущей метки тома. Если DOS определит, что
"диск был сменен" является ошибкой, связанной с состоянием
системного каше, то она сгенерирует код ошибки 0FH от имени
устройства. Если драйвер не применяет метку тома, а бит 11
установлен, то он должен установить фиксированный указатель
на строку "NO NAME",0 (Нет имени).
     Пользователь не может сменить диск за меньше чем две се-
кунды, поэтому если функция проверки диска вызвана в течение
первых двух секунд доступа, то драйвер возвращает (1). Это
значительно оптимизирует работу системы.
     _________________________________________________________
     Примечание
               Если байт-метка в возвращаемом БПБ равен пре-
               дыдущему байту-метке, то MS-DOS будет считать,
               что формат диска такой же (даже если диск был
               сменен) и не выполняет обновления внутренних
               структур. Поэтому все БПБ должны иметь уни-
               кальные байты-метки, независимо от байта FAT ID.
     _________________________________________________________


                             - 188 -



     2.7.3 Функция построения БПБ

     Код операции - 2
t1          _________________________________________________
     ES:BX - і 13 БАЙТ  Заголовок запроса                    і
             і BYTE     Описатель диска из БПБ               і
             і DWORD    Указатель на буфер обмена            і
             і          ( указывает на односекторный буфер   і
             і          или первый сектор FAT, в зависимости і
             і          от значения бита 13 слова атрибута)  і
             і DWORD    Указатель на БПБ                     і
             _________________________________________________
t0
     Эта функция используется только с блоковыми устройства-
ми. Она вызывается всякий раз, когда предыдущая функция про-
верки диска соосбщает о смене диска. Драйвер должен возвра-
щать указатель на БПБ.
     Функция построения БПБ возвращает DWORD указатель на од-
носекторный буфер. Содержимое буфера зависит от значения бита
13 в слове атрибута. Если бит равен нулю, то буфер содержит
первый сектор первой FAT. Его первым байтом является байт FAT
ID. В этом случае драйвер не должен изменять этот буфер. Об-
ратите внимание, что позиция   первой   FAT   должна быть оди-
наковой для всех возможных дисков, т.к. первый сектор FAT
должен быть прочитан до того, как возвращен дейсивительный БПБ.
Если бит равен 1, то указатель адресует один свободный сектор.
     MS-DOS включает дополнительную поддержку для устройств,
имеющих замки дисководов или другие средства сообщения
системе о смене диска. Существует ошибка, которая может быть
возвращена драйвером (ошибка 15). Эта ошибка означает, что
диск был сменен тогда, когда он не должен был быть смененным.
Драйвер может генерировать эту ошибку при чтении или при
записи.  DOS может генерировать эту ошибку при вызове функции
драйвера Проверка диска, когда  драйвер  сигнализирует  смену
диска,  а  в  буферах  системного  каше  осталась информация,
требующая своей записи на предыдущий диск.
     Для  драйверов,  поддерживающих  эту   ошибку,   функция
построения  БПБ  является своего рода триггером, инициирующим
считывание  с  диска  новой   метки   тома.   Эта   процедура
свидетельствует  о  том, что диск был сменен правильно. Метка
тома помещается на диск командой FORMAT в  корневой  каталог.
Она хранится драйвером как строка ASCIZ.
     Требования   к  возвращаемой  драйвером  метке  тома  не
исключают  использование  некоторых  других   идентификаторов
тома,  главное,  при этом должны использоваться строки ASCIZ.
По соглашениям, нулевая метка  тома (отсутствующая) является
строкой:
          db    "no name",0   ; "нет имени"


                             - 189 -



     2.7.4 Функции чтения и записи

     Коды операций - 3, 4, 8, 9, 12 и 16
t1          _________________________________________________
     ES:BX - і 13 БАЙТ  Заголовок запроса                     і
             і BYTE     Описатель диска из БПБ                і
             і DWORD    Указатель на буфер обмена             і
             і WORD     Счетчик байт/сектор                   і
             і WORD     Номер начального сектора              і
             і          (или -1, если драйвер поддерживает    і
             і          16-битовую адресацию сектора)         і
             і (игнорируется на символьных устройствах)       і
             і DWORD    Указатель на метку тома               і
             і DWORD    Номер начального сектора              і
             і      (если WORD поле с тем же именем равно -1) і
             і          (старшее  слово идет первым)          і
             і                  ИЛИ                           і
             і          Указатель на метку тома               і
             і           (в случае ошибки 0FH)                і
             __________________________________________________
t0
     Код   Операция
     _________________________________________________________
     3     УВВ чтение
     4     Чтение (для блоковых или символьных устройств)
     8     Запись (для блоковых или символьных устройств)
     9     Запись с проверкой
     12    УВВ запись
     16    Вывод пока не занято
           (только для символьных устройств)

     Драйвер  должен  выполнять чтение/запись в зависимости от
установленного кода операции.  Блоковые  устройства  читают  и
записывают  сектора; символьные устройства читают и записывают
байты.
     По  завершении  ввода/вывода  драйвер  устройства  должен
выставить   слово  состояния  и  сообщить  количество  успешно
переданных байт.  Это  должно  быть  сделано,  даже  в  случае
ошибки.  Установка  одного  лишь  бита ошибки и кода ошибки НЕ
достаточно.
     Кроме    того,    дравер    должен   установить   счетчик
ДЕЙСТВИТЕЛЬНО переданных секторов (байт).
     Если  установлен  режим  проверки,  то   драйвер   должен
вызываться с кодом операции 9. Ваш драйвер в этом случае берет
на себя всю работу по проверке записи.
     Если  драйвер  возвращает  код  ошибки 0FH (неразрешенная
смена диска), то он должен вернуть DWORD указатель  на  строку
ASCIZ  с  правильной меткой тома. Возвращаенный код заставляет
систему выдать запрос пользователю на установку нужного диска.
Драйвер читает метку тома как результат функции Построить БПБ.
     Драйверы  могут  вести   счет   открытых   файлов   путем
мониторинга  функций  Открыть  и  Закрыть.  Это  позволяет  им
в нужное время возвращать код ошибки 0FH. Действительно,  если
открытых  файлов  нет  (счетчик=0),  и  диск не был сменен, то
ввод/вывод будет выполнен успешно. Если  есть  открытые  файлы
при смене диска, то возможно будет выдан код ошибки 0FH.
     Обратите внимание на то , что возврат драйвером количес-
тва переданных байт меньшего запрошенного не является ошибкой.
     Режим OUB (Вывод пока не занято) позволяет программам

                             - 190 -


обслуживания спулеров использовать "взрывной" характер этих
принтеров. Многие принтеры имеют оперативную память, исполь-
зуемую в качестве буфера, который в свою очередь заполняется
свободно, т.е. принтер не дает состояния "занят" или дает на
короткие промежутки времени (менее десяти команд) между сим-
волами. Строка символов может быть быстро загружена в прин-
тер,  после  чего  принтер  долго занят распечаткой введенных
символов. При такой загрузке драйверу нет необходимости ждать
готовности устройства.
     _________________________________________________________
     Примечание для блоковых устройств

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

     Хотя   command.com  не  делает  автоматически  повторных
     попыток,  некоторые  прикладные  программы  имеют   свои
     процедуры  обслуживания  прерывания  24Н, которые делают
     повторные  попытки  при   определенных   ошибках   перед
     их сигнализацией.

     2.7.5 Небуферизированное чтение

     Код операции - 5
t1          _______________________________
     ES:BX - і 13 БАЙТ  Заголовок запроса  і
             і BYTE     Байт от устройства і
             _______________________________
t0
     Эта функция позволяет MS-DOS просматривать входной буфер
на  один символ вперед. Драйвер устанавливает бит "выполнено"
в слове состояния.
     Если  символьоне  устройство  возвращает  бит   "занято"
равным  нулю  (есть символы в буфере), то возвращен следующий
символ, который был бы прочитан. Этот символ не удаляется  из
входного  буфера.  Если  этот  бит  равен  1, то в буфере нет
символов.

     2.7.6 Функции открытия и закрытия

     Коды операций - 13 и 14
             ______________________________
     ES:BX - і 13 БАЙТ  Заголовок запроса і
             ------------------------------

     Функции открытия и закрытия  вызываются  MS-DOS  только,
если бит 11 в заголовке устройства равен 1. Они предназначены
для  того,  чтобы  информировать драйвер о текущей активности
файлов. Драйвер может вести счет  открытых  файлов  и  каждый
вызов  функции  драйвера  Открыть  производит инкремент этого
счетчика, а каждое Закрыть - декремент.  Если  счетчик  равен
нулю,  то  нет  открытых  файлов  на этом устройстве. Поэтому
драйвер должен сбросить все буферы, т.к. теперь  пользователь
может "легально" сменить диск в дисководе.
     Могут возникнуть сложности с этим механизмом на блоковых
устройствах,  т.к. программы использующие FCB могут открывать
файлы  без  их  закрытия.  Поэтому  рекомендуется  сбрасывать

                             - 191 -


счетчик  в  ноль  без  сброса буферов, когда ответ на "был ли
диск  сменен"  положительный  и  вызвана   функция   драйвера
Построить БПБ.
     Эти  функции  более  полезны  на символьных устройствах.
Например,  функция  Открыть  может  быть   использована   для
передачи   устройству   инициализирующей  последовательности.
Механизм счетчика  может  быть  использован  для  обнаружения
одновременного  доступа  к  устройству.  В этом случае второе
Открыть должно возвращать ошибку.
     Обратите внимание на то, что  раз  все  программы  имеют
доступ  к  стандартным  устройствам  (хендлы  0,1,2,3,4),  то
устройства CON, AUX и PRN всегда открыты.

     2.7.7 Сменный диск (функция проверки типа диска)

     Код операции - 15
t1          ______________________________
     ES:BX - і 13 БАЙТ  Заголовок запроса і
             ______________________________
t0
     Эта функция вызывается,  только  если  бит  11  в  слове
атрибута  заголовка  устройства  равен  1. Некоторым утилитам
иногда необходимо знать, с каким диском они имеют  дело  -  с
флоппи  диском  или жестким диском. Примером является команда
FORMAT, которая выводит различные варианты некоторых запросов.
     Информация возвращается в бите "занято" слова состояния.
Если этот бит равен 1, то диск жесткий. Если бит равен нулю,
то диск сменяемый (флоппи). Обратите внимание на то, что бит
ошибки не проверяется. Считается, что эта функция не дает
сбоев.

     2.7.8 Функция проверки состояния

     Код операции - 6 и 10
t1          ______________________________
     ES:BX - і 13 БАЙТ  Заголовок запроса і
             ______________________________
t0
     При   вызове   системой   этой  функции  драйвер  должен
выставить слово состояния следующим образом:

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

                             - 192 -



     2.7.9 Функция сброса

     Коды операций - 7 и 11
t1          ______________________________
     ES:BX - і 13 БАЙТ  Заголовок запроса і
             ______________________________
t0
     Функция сброса приказывает драйверу сбросить все текущие
запросы.  Эта функция используется для сброса входной очереди
на символьных устройствах.
     Дравер  устройства  выполняет  сброс,  выставляет  слово
состояния и возвращает управление.

     2.7.10 Функции общего УВВ

     Код операции - 19
t1          ___________________________________________
     ES:BX - і 13 БАЙТ  Заголовок запроса              і
             і BYTE     Код категории (главный)        і
             і BYTE     Код функции (вспомогательный)  і
             і WORD     Содержимое (SI)                і
             і WORD     Содержимое (DI)                і
             і DWORD    Указатель на буфер данных      і
             ___________________________________________
t0
     Функции  общего УВВ дают расширенное средство управления
вводом/выводом. Они заменяют и делают  функции  драйвера  УВВ
чтение/запись  абсолютными.  Функция  общего УВВ содержит код
категории и код функции. DOS считывает это поле для перехвата
и выполнения команд драйвера, которые обслуживаются кодом DOS.
Все остальные категории команд направляются для  обслуживания
драйверу.
     Более  подробно коды функций и категорий даны в описании
функций 440СН и 440DH в Главе 1, "Системные вызовы".

     2.7.11 Установить/получить карту логического дисковода

t1  Код операции - 23 (получить) и 24 (установить)
             _______________________________________________
     ES:BX - і 13 БАЙТ  Заголовок запроса                  і
             і BYTE     Ввод (код устройства)              і
             і BYTE     Вывод (текущий логический дисковод)і
             і BYTE     Код команды                        і
             і WORD     Состояние                          і
             і DWORD    Зарезервировано                    і
             _______________________________________________
t0
     Эта функция вызывается MS-DOS,  только  если  установлен
бит  6  в слове атрибута заголовка устройства. Активизируемый
логический  дисковод  передается  в   поле   Код   устройства
заголовка  запроса.  Драйвер  устройства  возвращает  текущий
логический   дисковод   ,   соответствующий    запрашиваемому
физическому.


                             - 193 -



     2.8 Байт описатель диска

     В MS-DOS байт описатель диска используется для сообщения
DOS  о  наличии  другого  типа  диска.  Этот байт может иметь
значение от 0 до FFH. Он  необязательно  должен  совпадать  с
байтом FAT ID (метка таблицы размещения файлов). Байт FAT ID,
являющийся  первым  байтом  FAT,  использовался в MS-DOS 1.00
для различения типов дисков может  использоваться  драйверами
версий  2.X  и  3.X.  Байт  FAT  ID имеет значение только для
блоковых устройств, где бит 13 слова атрибута равен нулю.
     Байт описатель диска и байт FAT ID не имеют значения для
MS-DOS. Они передаются драйверу так,  чтобы  программы  могли
определить тип диска.


     2.9 Формат таблицы описания диска

     Файловая   система   MS-DOS  использует  связный  список
указателей (один для каждого кластера),  называемый  Таблицей
размещения файлов (FAT). Неиспользуемые кластеры представлены
нулем,  а  конец  файла  FFFH  (или  FFFFH  на  устройствах с
16-битовыми  элемениами   таблицы).   Используемые   элементы
никогда  не  должны  адресовать нулевые элементы. Если все же
это происходит, то первый  элемент  FAT  (который  адресуется
нулевым элементом) зарезервирован и содержит "конец" цепочки.
Обычно   предусмотрено  несколько  признаков  конца  цепочки,
используемых для различения типов дисков ( [F]FF8H [F]FFFH ).
     Предпочтительнее писать полную таблицу описания диска  в
секторе    начальной   загрузки   и   использовать   ее   для
идентификации диска. Для обеспечения совместимости с  ранними
версиями  системы,  чьи  драйверы  не  устанавливают  бит 13,
необходимо также записывать байты FAT ID  во  время  процесса
форматирования.
     Для  большей  гибкости  в  поддержке  различных дисковых
форматов, рекомендуется хранить  информацию,  касающуюся  БПБ
для  конкретных  дисков, в секторе начальной загрузки. Формат
такого сектора показан ниже:
t1  __________________________________________________________
     і 3 БАЙТА  Близкий переход на код начальной загрузки     і
     і 8 БАЙТ   Имя и версия                                  і
  Б  і WORD     Байт в секторе                                і
  П  і BYTE     Секторов в кластере                           і
  Б  і WORD     Зарезервировано секторов                      і
  і  і BYTE     Количество FAT                                і
     і WORD     Количество входов  корневого каталога         і
  Б  і WORD     Количество секторов в логическом образе или 0 і
  П  і BYTE     Байт описатель диска                          і
  Б  і WORD     Количество секторов FAT                       і
     і WORD     Cекторов на дорожке                           і
     і WORD     Количество головок                            і
     і WORD     Количество скрытых секторов (младшее слово)   і
     і WORD     Количество скрытых секторов (старшее слово)   і
     і DWORD    Количество логических секоров                 і
     __________________________________________________________
t0
     Хотя MS-DOS не использует пять полей, следующих за  БПБ,
драйверы устройств могут использовать их для анализа диска.
     Поля  "количество  секторов  на  дорожке"  и "количество
головок" необходимы для  поддержки  различных  типов  дисков,

                             - 194 -


имеющих  одинаковую логическую разметку, но разную физическую
(например,   40   дорожек,   двусторонний   и   80   дорожек,
односторонний).
     Поле "количество логических секторов" сообщает драйверу,
сколько секторов резервировать, если поле "количество секто-
ров в логическом образе" равно нулю.
     Рекомендуется   следующая  процедура  определения  диска
драйверами, устанавливающими бит 13 слова атрибута:

     1. Считать сектор начальной загрузки в  область  памяти,
адресуемую DWORD указателем на буфер обмена.
     2. Определить, является ли первый байт сектора начальной
загрузки  Е9Н  или ЕВН (для определения длины кода перехода).
Если так, то БПБ имеет смещение 3. Вернуть указатель на него.
     3. Если сектор  начальной  загрузки  не  имеет  БПБ,  то
вероятно  диск  форматировался  1.Х версией MS-DOS и возможно
использует байт FAT ID для идентификации диска.
     Драйвер может прочитать первый сектор Таблицы размещения
файлов (FAT) в буфер обмена и  прочитать  первый  байт  этого
сектора, после чего вернуть указатель на "зашитый" БПБ.

     2.10 Устройство Часы

     MS-DOS  расчитана  также  на работу с системными часами.
Ими могут быть CMOS часы реального времени  или  интервальный
таймер,  инициализируемый  пользователем  во  время  загрузки
системы. Устройство Часы функционирует  также,  как  и  любое
другое  символьное  устройство,  за исключением того, что оно
идентифицируется битом 3 слова атрибута. DOS использует  этот
бит;  в последующем устройство Часы может иметь любое имя. На
IBM компьютерах используется имя  $CLOCK  для  предотвращения
конфликтов с существующими файлами, имеющими имя clock.
     Уникальность  этого устройства состоит в том, что MS-DOS
читает и записывает 6-байтную последовательность,  кодирующую
дату  и  время.  Запись  на это устройство означает установку
даты и времени; чтение - их вывод.
     Ниже приведен двоичный формат, используемый  устройством
часы:
t1
  байт 0    байт 1     байт 2   байт 3    байт 4    байт 5
_____________________________________________________________
і         і         і         і         і         і         і
і дней после 1.1.80 і  минуты і   часы  і сек/100 і секунды і
і младш.  і  старш. і         і         і         і         і
 ____________________________________________________________
t0

     2.11 Порядок обращения к устройству

     Нижеприведенные   пункты   иллюстрируют   цепь  событий,
происходящих при вызове MS-DOS драйвера блокового устройства
для выполнения операции Запись:

     1.  MS-DOS  заполняет  заголовок запроса в фиксированной
         области памяти.
     2.  MS-DOS   вызывает   программу   стратегии   драйвера
         блокового устройства.
     3.  Драйвер устройства сохраняет регистры ES и BX (ES:BX
         адресуют  заголовок  запроса)  и  выполняет  дальний
         возврат.

                             - 195 -


     4.  MS-DOS вызывает программу прерывания.
     5.  Драйвер  считывает из заголовка запроса код операции
         (смещение 2). Драйвер  преобразует  код  операции  в
         индекс   таблицы   адресов  процедур,  выполняющих
         соответствующие  операции  и   передает   управление
         процедуре с этим индексом.
     6.  Драйвер считывает код  устройства  (смещение 1)  для
         определения диска, на который выполняется запись.
     7.  Так как операцией является Запись на диск, то драйвер
         должен   получить   адрес  буфера  обмена  с  диском
         (смещение 14), количество секторов (смещение  18)  и
         начальный сектор (смещение 20) в заголовке запроса.
     8.  Драйвер   устройства   преобразует   номер  первого
         логического сектора  в  номера  дорожки,  головки  и
         сектора.
     9.  Драйвер  устройства  записывает указанное количество
         секторов на диск  из  буфера  обмена,  указанного  в
         запросе.   Обратите   внимание   на  то,  что  может
         понадобится несколько команд Записи.
     10. После завершения  записи,  драйвер  должен  сообщить
         MS-DOS результат установкой бита "выполнено" в слове
         состояния  (смещение  3  в заголовке запроса). Кроме
         того, он должен  сообщить  количество  действительно
         переданных байт в поле Счетчик сектор/байт.
     11. В случае ошибки драйвер устанавливает бит 8 и 15 в
         слове состояния и заполняет младший его  байт  кодом
         ошибки.  Количество  действительно  переданных  байт
         помещается в соответствующее поле заголовка запроса,
         т.к. недостаточно устанавливать один лишь бит ошибки.
     12. Драйвер устройства выполняет дальний возврат в MS-DOS.

     Драйверы  должны  сохранять  состояние   системы,   т.е.
сохранять все регистры, включая регистр флагов. Флаги DF и IF
наиболее  важны.  При  вызове  программы прерывания драйвера,
MS-DOS  содержит  40-50  байт  свободного   пространства   во
внутреннем   стэке.   Если   драйвер  выполняет  значительные
стэковые операции, то он должен переключиться на свой стэк.



     2.12  Два примера драйверов устройств

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

   ;  ********** Драйвер блокового устройства **********
   ;
   ;  Поддерживает  до  четырех  5.25-дюймовых  дисководов на
   ;  одном дисковом контроллере. Поддерживает все стандартные
   ;  форматы IBM PC.

     false  equ    0
     true   equ    not false

     ;Адрес порта ввода/вывода дискового контроллера
     disk   equ    0E0H
     ;disk+0
     ;      1793   Команда/состояние

                             - 196 -


     ;disk+1
     ;      1793   Дорожка
     ;disk+2
     ;      1793   Сектор
     ;disk+3
     ;      1793   Данные
     ;disk+4
     ;      AUX    Команда/состояние
     ;disk+5
     ;      Ожид. Синх.
     ;Бит выбора обратной стороны
     backbit  equ  04H
     ;Бит выбора 5 1/4"
     smalbit  equ  10H
     ;Бит двойной плотности
     ddbit    equ  08H

     ;Бит "выполнено"  в регистре состояния
     donebit  equ  01H

     ;Используйте  эту  таблицу  для  выбора  скорости   шага
     ;головки.   Значения  для  5"  дисководов  вдвое  больше
     ;указанных в таблице значений.

     ; Шаг   1771   1793
     ;
     ; 0      6ms    3ms
     ; 1      6ms    6ms
     ; 2     10ms   10ms
     ; 3     20ms   15ms

     stpspd  equ    1
     numerr  equ    errout-errin

     cr      equ    0DH
     lf      equ    0AH

     code    segment
     assume  cs:code,ds:nothing,es:nothing,ss:nothing
     ;--------------------------------------------------------
     ;
     ; Заголовок устройства
     ;
     drvdev  label  word
             dw     -1,-1
             dw     0000   ;  Блоковое, IBM формат
             dw     strategy
             dw     drv$in
     drvmax  db     4

     drvtbl  label  word
             dw     drv$init
             dw     media$chk
             dw     get$bpb
             dw     cmderr
             dw     drv$read
             dw     exit
             dw     exit
             dw     exit
             dw     drv$writ

                             - 197 -


             dw     drv$writ
             dw     exit
             dw     exit
             dw     exit

     ;--------------------------------------------------------
     ;
     ;       Программа стратегии
     ;
     ptrsav  dd     0
     stratp  proc   far
     strategy:
             mov    word ptr [ptrsav],bx
             mov    word ptr [ptrsav+2],es
             ret
     stratp  endp

     ;--------------------------------------------------------
     ;       Главный вход
     ;
     cmdlen = 0   ; Длина команды
     unit   = 1   ; Указанное устройство
     cmdc   = 2   ; Код операции
     status = 3   ; Состояние
     media  = 13  ; Описатель диска
     trans  = 14  ; Буфер обмена
     count  = 18  ; Счетчик блоков или символов
     start  = 20  ; Первый блок для передачи
     ;
     drv$in:
             push  si
             push  ax
             push  cx
             push  dx
             push  di
             push  bp
             push  ds
             push  es
             push  bx

             lds    bx,[ptrsav]           ; Получить указатель
                                          ; на заголовок
             mov al,byte ptr [bx].unit    ; al = код устройства
             mov ah,byte ptr [bx].media   ; ah = описатель дис-
                                          ; ка
             mov   cx,word ptr [bx].count ; cx = счетчик
             mov dx,word ptr [bx].start   ; dx = начальный сек-
                                          ; тор
             push  ax
             mov   al,byte ptr [bx].cmdc  ; Код операции
             cmp   al,15                  ;
             ja    cmderrp                ; Не тот код
             cbw
             shl   ax,1                   ; умноженный на 2 =
                                          ; индексу в таблице
                                          ; адресов
             mov   si,offset drvtbl       ; ES:DI = буфер
                                          ; обмена
             add   si,ax
             pop   ax

                             - 198 -


             les   di,dword ptr [bx].trans
             push  cs
             pop   ds

     assume  ds:code
             jmp word ptr [si]       ; переход на выполнение
                                     ; команды
     ;--------------------------------------------------------
     ;
     ;       EXIT (выход) - все программы выходят через эту
     ;                      процедуру
     ;
     assume  ds:nothing
     cmderrp:
             pop   ax                 ; Очистить стэк
     cmderr:
             mov   al,3               ; Неизвестная команда
             jmp   short   err$exit
     err$cnt:
             lds   bx,[ptrsav]
             sub   word ptr [bx].count,cx
     err$exit:                        ; В AL код ошибки
             mov   ah,10000001B       ; Возврат ошибки
             jmp   short err1

     exitp   proc  far

     exit:   mov   ah,00000001B
     err1:   lds   bx,[ptrsav]
             mov word ptr [bx].status,ax ; Отметить заверше-
                                         ; ние операции
             pop   bx
             pop   es
             pop   ds
             pop   bp
             pop   di
             pop   dx
             pop   cx
             pop   ax
             pop   si
             ret       ; Восстановление регистров и возврат
     exitp   endp
     ;--------------------------------------------------------
     curdrv  db    -1
     trktab  db    -1,-1,-1,-1
     seccnt  dw    0
     drvlim  =     8      ; Количество секторов на устройстве
     seclim  =     13     ; Максимальный сектор
     hdlim   =     15     ; Максимальная головка
     ;
     ; Предостережение:  сохраняйте порядок drive - curhd !
     ;
     drive   db    0      ; Код физического дисковода
     curhd   db    0      ; Текущая головка
     cursec  db    0      ; Текущий сектор
     curtrk  dw    0      ; Текущая дорожка
     ;
     media$chk:           ; Всегда показывает "не знаю"
     assume  ds:code
             test  ah,00000100B  ; Сменяемый ли диск?

                             - 199 -


             jz    media$ext
             xor   di,di         ; Я не знаю
     media$ext:
             lds   bx,[ptrsav]
             mov   word ptr [bx].trans,di
             jmp   exit
     build$bpb:
     assume  ds:code
             mov   ah,byte ptr es:[di]  ; Получить байт FAT ID
             call  buildbp              ; Перевести
     setbpb: lds   bx,[ptrsav]
             mov   [bx].media,ah
             mov   [bx].count,di
             mov   [bx].count+2,cs
             jmp   exit
     buildbp:
     assume  ds:nothing
     ; В АН байт FAT ID
     ; DI указывает на правильный БПБ по возвращении
             push  ax
             push  cx
             push  dx
             push  bx
             mov   cl,ah            ; Сравнить с правильным
             and   cl,0F8H          ; байтом FAT ID
             cmp   cl,0F8H
             jz    goodid
             mov   ah,0FEH          ; По умолчанию 8 секторов
     goodid:                        ; двусторонний
             mov   al,1             ; Количество секторов FAT
             mov   bx,64*256+8 ; Каталоговые входы и сект. макс.
             mov   cx,40*8          ; Размер диска
             mov   dx,01*256+1
             mov   di,offset drvbpb
             test  ah,00000010B     ; Проверка на 8 или 9 сект.
             jny   has8             ; has8 = имеет 8 секторов
             inc   al               ; Инкремент секторов FAT,
             inc   bl               ; максимума секторов и
             add   cx,40            ; размера диска
     has8:   test  ah,00000001B     ; Проверка кол-ва головок
             jz    has1             ; Z = 1 головка
             add   cx,cx            ; Удвоить размер диска
             mov   bh,112           ; Увел. кол-ва кат. входов
             inc   dh              ; Инкремент сект/все устр. и
             inc   dl              ; головок
     ;
     has1:   mov   byte ptr [di].2,dh
             mov   byte ptr [di].6,bh
             mov   word ptr [di].8,cx
             mov   byte ptr [di].10,ah
             mov   byte ptr [di].11,al
             mov   byte ptr [di].13,bl
             mov   byte ptr [di].15,dl
             pop   bx
             pop   dx
             pop   cx
             pop   ax
             ret
     ;
     ;--------------------------------------------------------

                             - 200 -


     ;
     ;       Процедуры ввода/вывода с диска
     ;
     ; Вход:
     ;       al    = Номер дисковода
     ;       ah    = Описатель диска
     ;       cx    = Счетчик секторов
     ;       dx    = Первый сектор
     ;       ds    = cs
     ;       es:di = Буфер обмена с диском
     ; Выход:
     ;       При успешном завершении флаг переноса сброшен.
     ;       Иначе CF=1 и AL содержит код ошибки (MS-DOS);
     ;       В СХ количество НЕпереданных секторов
     ;
     drv$read:
     assume  ds:code
             jcxz  dskok
             call  setup
             jc    dsk$io
             call  dskrd
             jmp   short dsk$io
     drv$writ:
     assume  ds:code
             jcxz  dskok
             call  setup
             jc    dsk$io
             call  dskwrt
     assume  ds:nothing
     dsk$io: jnc   dskok
             jmp   err$cnt
     dskok:  jmp   exit
     setup:
     assume  ds:code
     ; Вход такой же, как показано выше
     ; На выходе:
     ; es:di = Буфер обмена
     ; ds:bx = Адрес БПБ
     ; В случае ошибки установлен CF (в AL код ошибки)
     ; В противном случае:
     ;       [drive]  = Номер дисковода (0-3)
     ;       [seccnt] = Секторов для передачи
     ;       [cursec] = Номер начального сектора
     ;       [curhd]  = Номер начальной головки
     ;       [curtrk] = Номер начальной дорожки
     ; Задействованы все регистры
     ;
             xchg  bx,di
             call  buildbp
             mov   si,cx
             add   si,dx
             cmp   si,word ptr [di].drvlim ; Сравнить с
                                           ; макс. дисководом
             jbe   inrange
             mov   al,8
             stc
             ret
     inrange:
             mov   [drive],al
             mov   [seccnt,cx       ; Сохранить счетчик сект.

                             - 201 -


             xchg  ax,dx            ; Уст. логического сект.
                                    ; для деления
             xor   dx,dx
             div   word ptr [di].seclim ; Разделить на Секторов
                                        ; в дорожке
             inc   dl               ; Сохранить текущий сектор
             mov   [cursec],dl      ; и получить кол-во головок
             mov   cx,word ptr [di].hdlim
             xor   dx,dx            ; Разделить дорожки на
                                    ; головок в цилиндре
             div   cx
             mov   [curhd],dl       ; Сохранить тек. головку
             mov   [curtrk],ax      ; и текущую дорожку
     seek:
             push  bx               ; Адрес буфера
             push  di               ; Адрес БПБ
             call  chknew           ; Сброс коловки при смене
                                    ; дисковода
             call  drivesel
             mov   bl,[drive]
             xor   bh,bh            ; bx - индекс дисковода
             add   bx,offset trktab ; Получить тек. дорожку
             mov   ax,[curtrk]      ; Сохранить нужную
                                    ; дорожку
             xchg  al,ds:[bx]       ; Сделать ее текущей
             out   disk+1,al        ; Сообщить об этом
                                    ; контроллеру
             cmp   al,dl            ; На правильной дорожке?
             jz    seekret          ; Если да, то все
             mov   bh,2             ; Счетчик повторов поиска
             cmp   al,-1            ; Позиционирована?
             jnz   nohome           ; Если нет, то позициони-
                                    ; ровать
     trysk:
             call  home
             jc    seekerr
     nohome: mov   al,dl
             out   disk+3,al        ; Нужная дорожка
             mov   al,1CH+stpspd    ; Поиск
             call  dcom
             and   al,98H           ; Ошибки готовности,
                                    ; поиска и циклического
                                    ; кода
             jz    seekret
             js    seekerr          ; Если не готово - без
                                    ; повтора
             dec   bh
             jnz   trysk
     seekerr:
             mov   bl,[drive]
             xor   bh,bh            ; Индекс дисковода
             add   bx,offset trktab ; Текущую дорожку
             mov   byte ptr ds:[bx],-1 ; Сделать ее неопр.
             call  geterrcd
             mov   cx,[seccnt]      ; Ничего не передано
             pop   bx               ; Указатель БПБ
             pop   di               ; Адрес буфера обмена
             ret
     seekret:
             pop   bx               ; Указатель БПБ


                             - 202 -


             pop   di               ; Адрес Буфера обмена
             clc
             ret
     ;
     ;--------------------------------------------------------
     ;                       Чтение
     ;
     diskrd:
     assume  ds:code
             mov   cx,[seccnt]
     rdlp:
             call  preset
             push  bx
             mov   bl,10            ; Счетчик попыток
             mov   dx,disk+3        ; Порт данных
     rdagn:
             mov   al,80H           ; Операция чтения
             cli
             out   disk,al
             mov   bp,di            ; Сохранить адрес для
                                    ; повторной попытки
             jmp   short rloopentry
     rloop:
             stosb
     rloopentry:
             in    al,disk+5        ; Ожидание DRQ или INTRQ
             shr   al,1
             in    al,dx            ; Считать данные
             jnc   rloop
             sti                    ; Восстановить флаг
             call  getstat
             and   al,9CH
             jz    rdpop
             mov   di,bp            ; Восстановить адрес буфера
             dec   bl
             jnz   rdagn
             cmp   al,10H           ; Запись не найдена?
             jnz   got-code         ; Нет
             mov   al,1
     got-code:
             call  geterrcd
             pop   bx
             ret
     rdpop:
             pop   bx
             loop  rdlp
             clc
             ret
     ;--------------------------------------------------------
     ;
     ;                      Запись
     ;
     diskwrt:
     assume  ds:code
             mov   cx,[seccnt]
             mov   si,di
             push  es
             pop   ds
     assume  ds:nothing
     wrlp:

                             - 203 -


             call  preset
             push  bx
             mov   bl,10            ; Счетчик повторов
             mov   dx,disk+3        ; Порт данных
     wragn:
             mov   al,0A0H          ; Команда записи
             cli
             out   disk,al
             mov   bp,si            ; Сохранить адрес для
                                    ; повторов
     wrloop:
             in    al,disk+5
             shr   al,1
             lodsb                  ; Получить данные
             out   dx,al            ; Записать
             jnc   wrloop
             sti                    ; Восстановить флаг
             dec   si
             call  getstat
             and   al,0FCH
             jz    wrpop
             mov   si,bp            ; Вернуть адрес буфера
             dec   bl
             jnz   wragn
             call  geterrcd
             pop   bx
             ret
     wrpop:
             pop
             loop  wrlp
             clc
             ret
     preset:
     assume  ds:nothing
             mov   al,[cursec]
             cmp   al,cs:[bx].seclim
             jbe   gotsec
             mov   dh,[curhd]
             inc   dh
             cmp   dh,cs:[bx].hdlim
             jb    sethead          ; Выбрать новую головку
             call  step             ; Перейти на след. дорожку
             xor   dh,dh            ; Выбрать головку 0
     sethead:
             mov   [curhd],dh
             call,drivesel
             mov   al,1             ; Первый сектор
             mov   [cursec],al      ; Установить cursec
     gotsec:
             out   disk+2,al        ; Сообщить контроллеру
                                    ; какой сектор
             inc   [cursec]         ; На следующий сектор
             ret
     step:
     assume  ds:nothing
             mov   al,58H+stpspd
             call  dcom
             push  bx
             mov   [bl],drive
             xor   bh,bh            ; ВХ - индекс дисковода

                             - 204 -


             add   bx,offset trktab ; Получить тек. дорожку
             inc   byte ptr cs:[bx] ; Следующая дорожка
             pop   bx
             ret
     home:
     assume  ds:nothing
             mov   bl,3
     tryhom:
             mov   al,0CH+stpspd    ; Восстановить
             call,dcom
             and   al,98H
             jz    ret3
             js    homerr           ; Если не готово, то
                                    ; без повторов
             push  ax               ; Сохранить код ошибки
             mov   al,58H+stpspd
             call  dcom
             dec   bl
             pop   ax               ; Вернуть код ошибки
             jnz   tryhom
     homerr:
             stc
     ret3:   ret
     ;
     chknew:
     assume  ds:nothing
             mov   al,[drive]       ; Получить номер дисковода
             mov   ah,al
             xchg  al,[curdrv]      ; Сделать текущим
             cmp   al,ah            ; Смена дисководов?
             jz    ret1             ; Нет
     ; При смене дисковода сбрасывайте головку
             in    al,disc+1        ; Получить номер
                                    ; текущей дорожки
             out   disc+3,al        ; Выдать ее для поиска
             mov   al,10H           ; Поиск и сброс головки
     dcom:
     assume  ds:nothing
             out   disk,al
             push  ax
             aam                    ; Задержка 10 мкс
             pop   ax
     getstat:
             in    al,disk+4
             test  al,donebit
             jz    getstat
             in    al,disk
     ret1:   ret
     ;
     drivesel:
     assume  ds:nothing
     ; Выбор дисковода по текущей информации
     ; Только AL меняется
             mov   al,[drive]
             or    al,smalbit+ddbit ; Диски  5 1/4" IBM PC
             cmp   [curhd],0
             jz    gothead
             or    al,backbit       ; Выбор стороны 1
     gothead:
             out   disk+4,al        ; Выбор дисковода и

                             - 205 -


                                    ; стороны
             ret
     geterrcd:
     assume  ds:nothing
             push  cx
             push  es
             push  di
             push  cs
             pop   es               ; ES - локальный сегмент
             mov   cs:[lsterr],al
             mov   cx,numerr        ; Количество ошибочных
                                    ; ситуаций
             mov   di,offset errin  ; Указатель на них
             repne scasb
             mov   al,nuerr-1[di]   ; Перевести
             stc                    ; Установить флаг для
                                    ; индикации ошибки и
             pop   di
             pop   es
             pop   cx
             ret                    ;вернуться
     ;
     ;--------------------------------------------------------
     ;
     ; БПБ для гибкого диска IBM. Многие параметры заполняются
     ; функцией Построить БПБ.
     ; Это БПБ для двустороннего, 9-секторного диска
     drvbpb:
             dw    512         ; Формат БПБ см. Разделе 2.9
             db    1
             dw    1
             db    2
             dw    64
             dw    9*40
             db    11111100B
             dw    2
             dw    9
             dw    1
     initab:                        ; До четырех устройств
             dw    drvbpb
             dw    drvbpb
             dw    drvbpb
             dw    drvbpb
     errin:  ; ошибки диска, возвращаемые контроллером
             db    80H              ; Нет ответа
             db    40H              ; Защита по записи
             db    20H              ; Ошибка записи
             db    10H              ; Ошибка поиска
             db    8                ; Ошибка циклического кода
             db    1                ; 10Н (Запись не найдена)
                                    ; при чтении
     lsterr: db    0                ; Все другие ошибки
     errout: ; Коды ошибок, соответствующие указанным выше
             db    2                ; Нет ответа
             db    0                ; Защита по записи
             db    0AH              ; Ошибка записи
             db    6                ; Ошибка поиска
             db    4                ; Ошибка циклического кода
             db    8                ; Сектор не найден
             db    12               ; Общая ошибка

                             - 206 -


     drv$init:
     ;
     ; Определить количество физических дисководов чтением
     ; config.sys
     ;
     assume  ds:code
             push  ds
             lds   si,[ptrsav]      ; DS:SI адресуют config.sys
     assume ds;nothing
             lds   si,dword ptr [si.count]
     scan-loop:
             call  scan-switch
             mov   al,cl
             or    al,al
             jz    scan4
             cmp   al,"s"
             jz    scan4
     werror: pop   ds
     assume  ds:code
             mov   dx,offset errmsg2
     werror2:
             mov   ah,9
             int   21H
             xor   ax,ax
             push  ax               ; Нет устройств
             jmp   short abort
     badndrv:
             pop   ds
             mov   dx,offset errmsg1
             jmp   werror2
     scan4:
     assume  ds:nothing
     ; в ВХ количество флоппи-дисков
             or    bx,bx
             jz    badndrv          ; Ошибка пользователя
             cmp   bx,4
             ja    badndrv          ; Ошибка пользователя
             pop   ds
     assume  ds:code
             push bx         ; Сохранить кол-во устройств
     abort:  lds   bx,[ptrsav]
     assume  ds;nothing
             pop   ax
             mov   byte ptr [bx].media,al
             mov   [drvmax],al
             mov   word ptr [bx].trans,offset drv$init ;
                                    ; Установить адрес
                                    ; Инициализации
             mov   [bx].trans+2,cs
             mov   word ptr [bx].count,offset initab ;
                                    ; Установить указатель
                                    ; на массив БПБ
             mov   [bx].count+2,cs
             jmp   exit
     ;
     ; Переключатель в CL, значение в ВХ
     ;
     scan-switch:
             xor   bx,bx
             mov   cx,bx

                             - 207 -


             lodsb
             cmp   al,10
             jz    numret
             cmp   al,"-"
             jz    got-switch
             cmp   al,"/"
             jnz   scan-switch
     got-switch:
             cmp   byte ptr [si+1],":"
             jnz   terror
             lodsb
             or    al,20H           ; Преобразовать по нижнему
                                    ; регистру
             mov   cl,al            ; Получить переключатель
             lodsb                  ; Пропустить ":"
     ;
     ; Получить номер, адресуемый [si]
     ;
     ; Стирает только AX,DX          BX возвращает номер
     ;
     getnum1:
             lodsb
             sub   al,"0"
             jb    chkret
             cmp   al,9
             ja    chkret
             cbw
             xchg  ax,bx
             mov   dx,10
             mul   dx
             add   bx,ax
             jmp   getnum1
     chkret:
             add   al,"0"
             cmp   al," "
             jbe   numret
             cmp   al,"-"
             jz    numret
             cmp   al,"/"
             jz    numret
     terror:
             pop   ds               ; Избавиться от адреса
                                    ; возврата
             jmp   werror
     numret:
             dec   si
             ret
     errmsg1 db    "smldrv:  Bad number of drives",13,10,"$"
     errmsg2 db    "smldrv:  Invalid parameter",13,10,"$"
     code    ends
             end




                             - 208 -



     _________________________________________________________


                   Драйвер символьного устройства

     _________________________________________________________

     ;  Адреса для ввода/вывода (IBM)
     ;
             cr=13                  ; ВК
             backsp=8               ; Пробел
             esc=1BH
             brkadr=6CH             ; Адрес вектора BREAK
             asnmax=200             ; Размер буфера
     code    segment byte
     assume  cs:code,ds:nothing,es:nothing
     ;--------------------------------------------------------
     ;       CON - драйвер устройства консоль
     ;
     condev:                        ; Заголовок устройства CON
             dw    -1,-1
             dw    1000000000010011B
             dw    strategy
             dw    entry
             db    'con
     ;--------------------------------------------------------
     ;       Таблица переходов по операциям
     ;
     contbl:
             dw    con$init
             dw    exit
             dw    exit
             dw    cmderr
             dw    con$read
             dw    con$rdnd
             dw    exit
             dw    con$flsh
             dw    con$writ
             dw    con$writ
             dw    exit
             dw    exit
     cmdtbl:
             db    'A'
             dw    cuu              ; курсор вверх
             db    'B'
             dw    cud              ; курсор вниз
             db    'C'
             dw    cuf              ; курсор вперед
             db    'D'
             dw    cub              ; курсор назад
             db    'H'
             dw    cuh              ; позиция курсора
             db    'J'
             dw    ed               ; очистить экран
             db    'K'
             dw    el               ; очистить строку
             db    'Y'
             dw    cup              ; позиция курсора
             db    'j'

                             - 209 -


             dw    pscp             ; сохранить ее
             db    'k'
             dw    prcp             ; восстановить ее
             db    'y'
             dw    rm               ; режим сброс
             db    'x'
             dw    sm               ; режим установка
             db    0
     page
     ;--------------------------------------------------------
     ;       Точка входа устройства
     ;
     cmdlen  =     0                ; Длина этой команды
     unit    =     1                ; Указанное устройство
     cmd     =     2                ; Код операции
     status  =     3                ; Состояние
     media   =     13               ; Описатель диска
     trans   =     14               ; Буфер обмена с диском
     count   =     18               ; Счетчик блоков/символов
     start   =     20               ; Первый передаваемый блок
     ptrsav  dd    0
     stratp  proc  far
     strategy:
             mov   word ptr cs:[ptrsav],bx
             mov   word ptr cs:[ptrsav+2],es
             ret
     stratp  endp
     entry:
             push  si
             push  ax
             push  cx
             push  dx
             push  di
             push  bp
             push  ds
             push  es
             push  bx
             lds   bx,cs:[ptrsav]
             mov   cx,word ptr ds:[bx].count
             mov   al,byte ptr ds:[bx].cmd
             cbw
             mov   si,offset contbl
             add   si,ax
             add   si,ax
             cmp   al,11
             ja    cmderr
             les   di,dword ptr ds:[bx].trans
             push  cs
             pop   ds
     assume  ds:code
             jmp   word ptr [si]    ; Выполнить команду
     page
     ;--------------------------------------------------------
     ;       Общие процедуры для устройств
     ;--------------------------------------------------------
     ;       EXIT - все процедуры выходят через эту точку
     ;
     bus$exit:
             mov   ah,00000011B
             jmp   short err1

                             - 210 -


     cmderr:
             mov   al,3
     err$exit:
             mov   ah,10000001B
             jmp   short  err1
     exitp   proc  far
     exit:   mov   ah,00000001B
     err1:   lds   bx,cs:[ptrsav]
             mov   word ptr [bx].status,ax
             pop   bx
             pop   es
             pop   ds
             pop   bp
             pop   di
             pop   dx
             pop   cx
             pop   ax
             pop   si
             ret
     exitp   endp
     ;---------------------------------------------------------
     ;       Обработка нажатия клавиши break
     ;
     break:
             mov   cs:altah,3
     intret: iret
     page
     ;
     ; Переменные строго привязаны к своим позициям,
     ; поэтому будьте внимательны при введении новых.
     ;
     wrap    db    0              ; 0=есть, 1=нет
     state   dw    s1
     mode    db    3
     maxol   db    79
     col     db    0
     row     db    0
     savcr   dw    0
     altah   db    0              ; Обслуживание спец. клавиш
     ;---------------------------------------------------------
     ; chrout - запись символа из AL, используя текущий атрибут
     ;
     attrw   label word
     attr    db    00000111B      ; Символьный атрибут
     bpage   db    0              ; Базовая страница
     base    dw    0B800H
     chrout:
             cmp   al,13
             jnz   trylf
             mov   [col],0
             jmp   short setit
     trylf:
             cmp   al,10
             jz    lf
             cmp   al,7
             jnz   tryback
     torom:
             mov   bx,[attrw]
             and   bl,7
             mov   ah,14

                             - 211 -


             int   10H
     ret5:   ret
     tryback:
             cmp   al,8
             jnz   outchr
             cmp   [col],0
             jz    ret5
             dec   [col]
             jmp   short setit
     outchr:
             mov   bx,[attrw]
             mov   cx,1
             mov   ah,9
             int   10H
             inc   [col]
             mov   al,[col]
             cmp   al,[maxcol]
             jbe   setit
             cmp   [wrap],0
             jz    outchr1
             dec   [col]
             ret
     outchr1:
             mov   [col],0
     lf:     inc   [row]
             cmp   [row],24
             jb    setit
             mov   [row],23
             call  scroll
     setit:
             mov   dh,row
             mov   dl,col
             xor   bh,bh
             mov   ah,2
             int   10H
             ret
     scroll:
             call getmod
             cmp   al,2
             jz    myscroll
             cmp   al,3
             jz    myscroll
             mov   al,10
             jmp   torom
     myscroll:
             mov   bh,[attr]
             mov   bl,' '
             mov   bp,80
             mov   ax.[base]
             mov   es,ax
             mov   ds,ax
             xor   di,di
             mov   si,160
             mov   cx,23*80
             cld
             cmp   ax,0b800h
             jz    colorcard

             rep   movsw
             mov   ax,bx

                             - 212 -


             mov   cx,bp
             rep   stosw
     sret:   push  cs
             pop   ds
             ret

 colorcard:
             mov   dx,3dah
  wait2:     in    al,dx
             test  al,8
             jz    wait2
             mov   al,25h
             mov   dx,3d8h
             out   dx,al          ; выключить видео
             rep   movsw
             mov   ax,dx
             mov   cx,dp
             rep   stosw
             mov   al,29h
             mov   dx,3d8h
             out   dx,al          ; включить видео
             jmp   sret

 getmod:     mov   ah,15
             int   16             ; получить колонку
             mov   brage,bh
             dec   ah
             mov   word ptr mode,ax
             ret
  ;-------------------------------------------------------------
  ;
  ;          Чтение консоли
  ;
  con$read:
             jcxz  con$exit
  con$loop:
             push  cx             ; Сохранить счетчик
             call  chrin          ; Получить символ в AL
             pop   cx
             stosb                ; Поместить его по es:di
             loop  con$loop
  con$exit:
             jmp   exit
  ;------------------------------------------------------------
  ;          Ввести один символ в AL
  ;
  ;chrin:    xor   ax,ax
             xchg  al,altah       ; Получить символ и нулевой
                                  ; altah
             or    al,al
             jnz   keyret

  inagn:     xor   an,an
             int   22
  alt10:
             or    ax,ax
             jz    inagn
             or    al,al          ; Специальный?
             jnz   keyret
             mov   altan,ah       ; Сохранить спец. клавишу

                             - 213 -


  keyret:    ret
  ;------------------------------------------------------------
  ;          Небуферизированное чтение
  ;
  ;
  con$rdnd:
             mov   al,[altah]
             or    al,al
             jnz   rdexit

  rd1:       mov   ah,1
             int   22
             jz    conbus
             or    ax,ax
             jnz   rdexit
             mov   ah,0
             int   22
             jmp   con$rdnd

  rdexit:    lds   bx,[ptrsav]
             mov   [bx].media,al
  exvec:     jmp   exit
  conbus:    jmp   bus$exit
  ;------------------------------------------------------------
  ;
  ;          Процедура сброса
  ;
     con$flsh:
             mov   [altah],0      ; Очистить буфер
             push  ds
             xor   bp,bp
             mov   ds,bp          ; Выбрать сегмент 0
             mov   ds:byte ptr 41AH,1EH ; Выставить указатели
             mov   ds:byte ptr 41CH,1EH ; головы и хвоста
             pop   ds
             jmp   exvec
     ;---------------------------------------------------------
     ;       Запись на консоль
     ;
     con$writ:
             jcxz  exvec
             push  cx
             mov   ah,3           ; Установить текущую
                                  ; позицию курсора
             xor   bx,bx
             int   16
             mov   word ptr [col],dx
             pop   cx
     con$lp:
             mov   al,es:[di]     ; Получить символ
             inc   di
             call  outc           ; Вывести символ
             loop  con$lp         ; Повторять пока не конец
             jmp   exvec
     cout:
             sti
             push  ds
             push  cs
             pop   ds
             call  outc

                             - 214 -


             pop   ds
             iret
     outc:
             push  ax
             push  cx
             push  dx
             push  si
             push  di
             push  es
             push  bp
             call  video
             pop   bp
             pop   es
             pop   di
             pop   si
             pop   dx
             pop   cx
             pop   ax
             ret
     ;--------------------------------------------------------
     ;
     ;       Вывести один символ из AL на видеоустройство
     ;
     video:
             mov   si,offset state
             jmp   [si]
     s1:     cmp   al,esc ; Это управляющая последовательность?
             jnz   s1b
             mov   word ptr [si],offset s2
             ret
     s1b:    call  chrout
     s1a:    mov   word ptr [si],offset s1
             ret
     s2:
             push  ax
             call  getmod
             pop   ax
             mov   bx,offset cmdtabl-3
     s7a:
             add   bx,3
             cmp   byte ptr [bx],0
             jz    s1a
             cmp   byte ptr [bx],al
             jnz   s7a
             jmp   word ptr [bx+1]
     movcur:
             cmp   byte ptr [bx],ah
             jz    setcur
             add   byte ptr [bx],al
     setcur:
             mov   dx,word ptr col
             xor   bx,bx
             mov   ah,2
             int   16
             jmp   s1a
     cup:
             mov   word ptr [si],offset cup1
             ret
     cup1:
             sub   al,32

                             - 215 -


             mov   byte ptr [row],al
             mov   word ptr [si],offset cup2
             ret
     cup2:
             sub   al,32
             mov   byte ptr [col],al
             jmp   setcur
     sm:
             mov   word ptr [si],offset s1a
             ret
     cuh:
             mov   word ptr col,1
             jmp   setcur
     cuf:
             mov   ah,maxcol
             mov   al,1
     cuf1:   mov   bx,offset col
             jmp   movcur
     cub:
             mov   ax,00FFH
             jmp   cuf1
     cuu:
             mov   ax,00FFH
     cuu1:   mov   bx,offset row
             jmp   movcur
     cud:
             mov   ax,23*256+1
             jmp   cuu1
     pscp:
             mov   ax,word ptr col
             mov   savcr,ax
             jmp   setcur
     prcp:
             mov   ax,savcr
             mov   word ptr col,ax
             jmp   setcur
     ed:
             cmp byte ptr [row],24
             jae el1
             mov   cx,word ptr col
             mov   dh,24
             jmp   erase
     el:
             mov   byte ptr [col],0
     el:     mov   cx,word ptr [col]
     el2:    mov   dh,ch
     erase:  mov   dl,maxcol
             mov   bh,attr
             mov   ax,0600H
             int   16
     ed3:    jmp   setcur
     rm:
             mov   word ptr [si],offset rm1
             ret
     rm1:    xor   cx,cx
             mov   ch,24
             jmp   el2
     con$init:
             int   11H
             and   al,00110000B

                             - 216 -


             cmp   al,00110000B
             jnz   iscolor
             mov   [base],0B00H
     iscolor:
             cmp   al,00010000B
             ja    setbrk
             mov   [mode],0
             mov   [maxcol],39
     setbrk:
             xor   bx,bx
             mov   ds,bx
             mov   bx,brkadr
             mov   word ptr [bx],offset break
             mov   word ptr [bx+2],cs
             mov   bx,29*4
             mov   word ptr [bx],offset cout
             mov   word ptr [bx+2],cs
             lds   bx,cs:[ptrsav]
             mov   word ptr [bx].trans,offset con$init
             mov   [bx].trans+2,cs
             jmp   exit
     code    ends
             end




© KOAP Open Portal 2000


?????? ???????????