Операционная система MS-DOS© Александр Фролов, Григорий ФроловТом 1, книги 1-2, М.: Диалог-МИФИ, 1991. 6.6. Функции управления устройствами ввода/вывода IOCTLВ этом разделе мы рассмотрим средства управления устройствами ввода/вывода IOCTL (сокращение от Input/Output Control). Использование IOCTL - обычный метод организации связи с устройствами или получения информации об открытых файлах. Описания будут приводиться в порядке номеров подфункций функции 44h прерывания 21h. Для версии DOS 2.1 и более поздних версий поддерживаются подфункции с номерами от 0 до 7, для версии 3.0 дополнительно могут использоваться подфункции 8, 0Bh, для 3.1 - 9 и 0Ah, для 3.2 и более поздних версий добавляются подфункции 0Dh, 0Eh, 0Fh. Версия DOS 3.3 и более поздние версии поддерживают также подфункцию 0Ch. 00h Получить информацию об устройстве 01h Установить информацию об устройстве 02h/03h Чтение/запись управляющей информации для символьных устройств 04h/05h Чтение/запись управляющей информации для блочных устройств 06h/07h Получить состояние ввода/вывода 08h Проверить возможность замены носителя данных для блочного устройства 09h Локальное или удаленное устройство 0Ah Проверить индекс на локальный/удаленный 0Bh Установка количества повторов при обращении к файлу 0Ch Переключение кодовых страниц 0Dh Общее управление вводом/выводом (GENERIC IOCTL) 0Eh Получение информации о логическом дисководе 0Fh Установка текущего логического дисковода # 00h Получить информацию об устройствеВызов:
Возврат без ошибки:
Возврат с ошибкой:
Функция возвращает в регистре DX информацию об устройстве, которая имеет следующий формат (для устройства):
Если при вызове этой подфункции регистр BX содержал индекс файла, формат получаемой в регистре DX информации будет следующий:
Особое внимание следует обратить на бит 5 слова информации об устройстве. Этот бит определяет режим обмена данными DOS и драйвера - двоичный или ASCII. В двоичном режиме управляющие символы CTRL-C, CTRL-P, CTRL-S, CTRL-Z интерпретируются как обычные данные. # 01h Установить информацию об устройствеВызов:
Возврат без ошибки:
Возврат с ошибкой:
Эта подфункция позволяет устанавливать некоторые биты в слове информации об устройстве. В зависимости от установки бита 5 (двоичный/ASCII) драйвер по-разному выполняет команды ввода-вывода. В режиме ASCII обмен с драйвером символьного устройства выполняется по байтам (содержимое поля count в запросе всегда равно 1). Если Вам надо обслуживать быстродействующее устройство ввода/вывода, такой посимвольный обмен может оказаться слишком медленным. В этом случае Вы можете установить бит 5 в единицу и выполнять обмен в двоичном режиме. Разумеется, Вам придется самостоятельно отслеживать управляющие символы. Ниже мы приведем пример программы, которая сначала устанавливает ASCII-режим для драйвера, описанного выше, выводит на него 8 символов, затем выполняет аналогичную операцию в двоичном режиме. Драйвер при каждом обращении к нему для ввода или вывода выдает сообщение на экран. Запустив программу (и не забыв подключить драйвер), Вы увидите, что в ASCII-режиме для записи или чтения восьми символов драйвер вызывается восемь раз, а в двоичном режиме - только один раз. #include <io.h> #include <conio.h> #include <stdio.h> #include <fcntl.h> #include <sys\types.h> #include <sys\stat.h> #include <malloc.h> #include <errno.h> #include <dos.h> int main(void); union REGS inregs, outregs; struct SREGS segregs; int main(void) { char buf[100]; int io_handle; unsigned count; // Открываем устройство с именем IODRIVER if( (io_handle = open("IODRIVER", O_RDWR)) == - 1 ) { // Если открыть не удалось, выводим // код ошибки printf("Ошибка при открытии устройства %d",errno); return errno; } // Читаем 8 байт из устройства в буфер buf if( (count = read(io_handle, buf, 8)) == -1 ) { // Если при чтении произошла ошибка, // выводим ее код printf("Ошибка чтения %d",errno); return errno; } // Закрываем прочитанную строку нулем // для последующего вывода функцией printf buf[8]=0; printf("\n___ Введена строка: %s ___",buf); // Выводим только что прочитанные данные // обратно на то же устройство if( (count = write(io_handle, buf, 8)) == -1 ) { // Если при записи произошла ошибка, // выводим ее код printf("Ошибка записи %d",errno); return errno; } // Получаем информацию об устройстве inregs.h.ah = 0x44; inregs.h.al = 0; inregs.x.bx = io_handle; intdos( &inregs, &outregs ); if(outregs.x.cflag == 1) { // При ошибке выводим ее код printf("IOCTL error %x\n",&outregs.x.ax); exit(-1); } // Выводим слово информации об устройстве на экран printf("\nDevice Information: %04X\n", outregs.x.dx); // Устанавливаем в 1 бит 5 (переключаем драйвер // в двоичный режим обмена данными inregs.x.dx = (outregs.x.dx | 0x0020) & 0x00ff; // Устанавливаем слово информации об устройстве inregs.h.ah = 0x44; inregs.h.al = 1; inregs.x.bx = io_handle; intdos( &inregs, &outregs ); if(outregs.x.cflag == 1) { // При ошибке выводим код ошибки printf("IOCTL error %x\n",&outregs.x.ax); exit(-1); } // Выводим слово информации об устройстве на экран printf("\nDevice Information: %04X\n", outregs.x.dx); // Читаем 8 байт из устройства в буфер buf // Обмен теперь производится в двоичном режиме if( (count = read(io_handle, buf, 8)) == -1 ) { // Если при чтении произошла ошибка, // выводим ее код printf("Ошибка чтения %d",errno); return errno; } // Закрываем прочитанную строку нулем // для последующего вывода функцией printf buf[8]=0; printf("\n___ Введена строка: %s ___",buf); // Выводим только что прочитанные данные // обратно на то же устройство if( (count = write(io_handle, buf, 8)) == -1 ) { // Если при записи произошла ошибка, // выводим ее код printf("Ошибка записи %d",errno); return errno; } // Закрываем устройство close(io_handle); exit(0); } # 02h/03h Чтение/запись управляющей информации для символьных устройствВызов:
Возврат без ошибки:
Возврат с ошибкой:
Эти подфункции позволяют прикладной программе обмениваться произвольной управляющей информацией с драйвером устройства. Они инициируют вызов драйвера с командами 3 и 12 соответственно для операций чтения и записи управляющей информации. Для использования этих подфункций драйвер должен поддерживать интерфейс IOCTL. Для проверки можно использвать подфункцию 0 (чтение информации устройства). Если бит 14 установлен, драйвер поддерживает IOCTL. # 04h/05h Чтение/запись управляющей информации для блочных устройствВызов:
Возврат без ошибки:
Возврат с ошибкой:
Для использования этих подфункций драйвер должен поддерживать интерфейс IOCTL. Для проверки можно использовать подфункцию 0 (чтение информации устройства). Если бит 14 установлен, драйвер поддерживает IOCTL. # 06h/07h Получить состояние ввода/выводаВызов:
Возврат без ошибки:
Возврат с ошибкой:
Эти подфункции предназначены для проверки готовности устройства к вводу/выводу данных или для проверки на достижение конца файла. # 08h Проверить возможность замены носителя данных для блочного устройстваВызов:
Возврат без ошибки:
Возврат с ошибкой:
Эта подфункция проверяет возможность замены носителя данных. Дискета - заменяемый носитель данных, а жесткий диск или электронный (RAM) диск - нет. # 09h Получить информацию о том, является ли устройство локальным или удаленным (при работе в сети)Вызов:
Возврат без ошибки:
Возврат с ошибкой:
Ошибка 01h может возникнуть, если не загружена команда SHARE. Используя эту подфункцию, программы могут определить принадлежность дисковода локальной станции или серверу. Однако обычно работа программы не должна зависеть от расположения дисковода. # 0Ah Проверить индекс на локальный/удаленныйВызов:
Возврат без ошибки:
Возврат с ошибкой:
Ошибка 01h может возникнуть, если не загружена команда SHARE. Данная подфункция позволяет проверить, является ли открытое устройство или файл локальным или удаленным. Справедливы замечания к предыдущей подфункции о том, что работа программы не всегда должна зависеть от расположения файла или устройства. # 0Bh Установка количества повторов при обращении к файлуВызов:
Возврат без ошибки:
Возврат с ошибкой:
Код ошибки 01h появляется, если задан недопустимый номер подфункции или не загружена команда SHARE. Операции, которые могут привести к возникновению конфликтных ситуаций, автоматически повторяются несколько раз до выдачи сообщения об ошибке. Можно задавать количество повторений операций и пауз между ними. Пауза формируется при выполнении пустого цикла, и ее длительность зависит от тактовой частоты процессора на машине: mov cx,pause loop $ # 0Ch Переключение кодовых страницВызов:
Возврат без ошибки:
Возврат с ошибкой:
Для подготовки кодовой страницы сначала вызывают эту подфункцию с кодом операции CL=4Ch, затем должна идти серия вызовов подфункции 03h функции 44h прерывания INT 21h - запись IOCTL на символьное устройство. Формат записываемых данных зависит от типа устройства. Драйверы DISPLAY.SYS и PRINTER.SYS, входящие в состав дистрибутива DOS, получают эти данные из файлов с расширением имени .CPI, таких как EGA.CPI, LCD.CPI, 4201.CPI и т.д. Блок параметров имеет различный формат для разных кодов операций:
# 0Dh Общее управление вводом/выводом (GENERIC IOCTL)Вызов:
Возврат без ошибки:
Возврат с ошибкой:
Общая схема использования этой подфункции:
Формат блока параметров зависит от выполняемой операции: CL = 40h/60h (получить/установить параметры устройства)
Биты байта специальных функций имеют следующее значение:
В операции 60h значение этого бита, равное 1, используется для извлечения текущего BPB, как если бы он был получен по команде драйвера с кодом 2 (построить BPB). Значение этого бита, равное 0, говорит о том, что надо извлечь BPB, используемый по умолчанию. Для операции с кодом 40h значение бита, равное 1, используется для извлечения текущего BPB, значение 0 приводит к использованию BPB, подготовленного в данном блоке параметров.
Значение этого бита, равное 1, - это указание игнорировать все поля в блоке параметров, кроме поля описания физической структуры дорожки на данном устройстве.
Значение этого бита, равное 1, говорит о том, что все сектора на этой дорожке имеют одинаковый размер. Таблица разметки дорожки начинается с двухбайтового слова, содержащего общее количество секторов на дорожке. Затем для каждого сектора в таблице находится по два двухбайтовых слова, содержащих номер сектора (1, 2 и т.д.) и размер сектора. То есть для каждого сектора в таблице содержится два слова. Если в поле "специальные функции" бит 2 установлен в 1, размеры всех секторов должны быть одинаковыми. CL = 41h/61h (записать/прочитать дорожку)
CL = 42h/62h (форматировать/проверить дорожку)
# 0Eh Получение информации о логическом дисководеВызов:
Возврат без ошибки:
Возврат с ошибкой:
# 0Fh Установка текущего логического дисководаВызов:
Возврат без ошибки:
Возврат с ошибкой:
Последние две команды предназначены для работы с логическими дисководами. На одном физическом дисководе DOS может образовать несколько логических дисков. Эти команды могут использоваться программами, например, для выдачи сообщения о необходимости заменить дискету при переходе от одного логического устройства к другому, если эти устройства расположены на одном физическом накопителе. |