Операционная система MS-DOS© Александр Фролов, Григорий ФроловТом 1, книга 3, М.: Диалог-МИФИ, 1992. 4.2. Общее управление вводом/выводомПодфункция 0Dh функции 44h прерывания INT 21h обеспечивает механизм взаимодействия между прикладным программным обеспечением и драйверами блочных устройств. Эта подфункция позволяет программам читать и изменять параметры устройств, предоставляет возможность выполнять аппаратно-независимое чтение, запись, форматирование и проверку дорожек диска. Эта подфункция была уже нами описана в разделе, посвященном драйверам. Для удобства приведем формат вызова этй подфункции еще раз: 0Dh Общее управление вводом/выводом GENERIC IOCTLВызов:
Возврат без ошибки:
Возврат с ошибкой:
Формат блока параметров зависит от выполняемой операции: CL = 40h/60h (получить/установить параметры устройства)
Биты специальных функций
Таблица разметки дорожки начинается с двухбайтового слова, содержащего общее количество секторов на дорожке. Затем для каждого сектора в таблице находится по два двухбайтовых слова, содержащих номер сектора (1, 2 и т.д.) и размер сектора. То есть для каждого сектора в таблице содержится два слова. Если в поле "специальные функции" бит 2 установлен в 1, размеры всех секторов должны быть одинаковыми. CL = 41h/61h (записать/прочитать дорожку)
CL = 42h/62h (форматировать/проверить дорожку)
Перед началом выполнения операции программа должна получить и созранить текущие параметры устройства. Для получения текущих параметров устройства необходимо выполнить операцию с кодом 60h. Затем программа должна установить новые параметры устройства, которые будут использованы в операциях чтения/записи, проверки или форматирования. Для установки параметров программа должна выполнить операцию с кодом 40h. После выполнения операции программа должна восстановить первоначальные параметры устройства, выполнив операцию с кодом 40h. Приведем пример программы, иллюстрирующей применение функции общего управления вводом/выводом для блочных устройств. Эта программа выполняет стандартное форматирование двадцатой дорожки диска А:. Для работы с блоками параметров файл sysp.h содержит определения специальных типов данных, которые будут использованы в программе форматирования: #pragma pack(1) /* Формат дорожки для GENERIC IOCTL */ typedef struct _TRK_LY_ { unsigned no; unsigned size; } TRK_LY; /* Параметры устройства для GENERIC IOCTL */ typedef struct _DPB_ { char spec; char devtype; unsigned devattr; unsigned numofcyl; char media_type; EBPB bpb; char reserved[6]; unsigned trkcnt; TRK_LY trk[100]; } DPB; /* Параметры для форматирования функцией GENERIC IOCTL */ typedef struct _DPB_FORMAT_ { char spec; unsigned head; unsigned track; } DPB_FORMAT; #pragma pack() Программа форматирования читает текущие параметры для диска А:, формирует структуру дорожки и устанавливает параметры для выполнения операции форматирования. Затем программа проверяет возможность использования указанной структуры дорожки и выполняет форматирование. #include <dos.h> #include <stdio.h> #include <malloc.h> #include <errno.h> #include "sysp.h" void main(void); void main(void) { union REGS reg; struct SREGS segreg; DPB _far *dbp; DPB_FORMAT _far *dbp_f; int sectors, i; printf("\nПрограмма уничтожит содержимое" "\n20-й дорожки диска А:." "\nЖелаете продолжить? (Y,N)\n"); // Ожидаем ответ оператора и анализируем его i = getch(); if((i != 'y') && (i != 'Y')) exit(-1); // Заказываем память для блока параметров устройства dbp = _fmalloc(sizeof(DPB)); // Заказываем память для блока параметров устройства, // который будет использован для форматирования dbp_f = _fmalloc(sizeof(DPB_FORMAT)); if(dbp == NULL || dbp_f == NULL) { printf("\nМало оперативной памяти!"); exit(-1); } // Получаем текущие параметры диска А: dbp->spec = 0; // Вызываем подфункцию 0Dh для выполнения // операции чтения текущих параметров диска А: reg.x.ax = 0x440d; reg.h.bl = 1; reg.x.cx = 0x0860; reg.x.dx = FP_OFF(dbp); segreg.ds = FP_SEG(dbp); intdosx(®, ®, &segreg); // Проверяем флаг переноса if(reg.x.cflag != 0) { printf("\nОшибка: %d",reg.x.ax); exit(-1); } // Заполняем блок параметров для форматирования. // Байт специальных функций содержит значение, // равное 5. Это означает, что: // - используется текущий блок параметров BIOS BPB; // - используются все поля в блоке параметров устройства; // - все сектора на дорожке имеют одинаковый размер dbp->spec = 5; // Считываем из BPB количество секторов на дорожке sectors = dbp->bpb.seccnt; // Подготавливаем таблицу, описывающую формат дорожки // Записываем количество секторов на дорожке dbp->trkcnt = sectors; // Для каждого сектора на дорожке в таблицу // записываем его номер и размер. // Заметьте, что записывается размер сектора // в байтах, а не код размера, как это делается // при форматировании с помощью функции 05h прерывания INT13h for(i = 0; i < sectors; i++) { dbp->trk[i].no = i+1; dbp->trk[i].size = 512; } // Устанавливаем новые параметры для диска А: reg.x.ax = 0x440d; reg.h.bl = 1; reg.x.cx = 0x0840; reg.x.dx = FP_OFF(dbp); segreg.ds = FP_SEG(dbp); intdosx(®, ®, &segreg); // Проверяем флаг переноса if(reg.x.cflag != 0) { printf("\nОшибка: %d",reg.x.ax); exit(-1); } // Подготавливаем блок параметров устройства, // который будет использован при вызове // операции проверки возможности форматирования // дорожки // В поле специальных функций записываем 1, // это означает, что будет выполняться проверка // возможности использования указанного формата дорожки dbp_f->spec = 1; dbp_f->head = 0; dbp_f->track = 20; reg.x.ax = 0x440d; reg.h.bl = 1; reg.x.cx = 0x0842; reg.x.dx = FP_OFF(dbp_f); segreg.ds = FP_SEG(dbp_f); intdosx(®, ®, &segreg); // Проверяем флаг переноса if(reg.x.cflag != 0) { printf("\nОшибка: %d",reg.x.ax); exit(-1); } // Если указанный формат дорожки поддерживается, // поле специальных функций будет содержать 0. // Проверяем это. if(dbp_f->spec != 0) { printf("\nФормат дорожки не поддерживается!"); exit(-1); } // Заполняем блок параметров для выполнения // операции форматирования dbp_f->spec = 0; dbp_f->head = 0; dbp_f->track = 20; // Форматируем дорожку с номером 20, головка 0 reg.x.ax = 0x440d; reg.h.bl = 1; reg.x.cx = 0x0842; reg.x.dx = FP_OFF(dbp_f); segreg.ds = FP_SEG(dbp_f); intdosx(®, ®, &segreg); // Проверяем флаг переноса if(reg.x.cflag != 0) { printf("\nОшибка: %d",reg.x.ax); exit(-1); } // Освобождаем буфера _ffree(dbp); _ffree(dbp_f); exit(0); } Теперь приведем программу, копирующую содержимое двух первых секторов нулевой дорожки (головка 0) в первые два сектора двадцатой дорожки. Эта программа использует тип данных, используемый в операциях чтения/записи: #pragma pack(1) /* Параметры для чтения/записи функцией GENERIC IOCTL */ typedef struct _DPB_WR_ { char spec; unsigned head; unsigned track; unsigned sector; unsigned sectcnt; void _far *buffer; } DPB_WR; #pragma pack() Программа пользуется текущими параметрами диска А:, поэтому операции чтения текущих параметров и записи новых параметров не используются. Обратите внимание на то, что эта и предыдущая программа разрушают содержимое двадцатой дорожки дискеты, поэтому для экспериментов с этими программами надо подготовить чистую отформатированную дискету. #include <dos.h> #include <stdio.h> #include <malloc.h> #include <errno.h> #include "sysp.h" void main(void); void main(void) { union REGS reg; struct SREGS segreg; DPB_WR _far *dbp_wr; char buf[2000]; int sectors, i; printf("\nПрограмма уничтожит содержимое" "\n20-й дорожки диска А:." "\nЖелаете продолжить? (Y,N)\n"); // Ожидаем ответ оператора и анализируем его i = getch(); if((i != 'y') && (i != 'Y')) exit(-1); // Заказываем память для блока параметров устройства, // который будет использован для чтения/записи dbp_wr = malloc(sizeof(DPB_WR)); if(dbp_wr == NULL) { printf("\nМало оперативной памяти!"); exit(-1); } // Заполняем блок параметров для выполнения // операции чтения. // Мы будем читать первые два сектора // на нулевой дорожке, головка 0. dbp_wr->spec = 0; dbp_wr->head = 0; dbp_wr->track = 0; dbp_wr->sector = 0; dbp_wr->sectcnt = 2; dbp_wr->buffer = buf; // Выполняем операцию чтения дорожки reg.x.ax = 0x440d; reg.h.bl = 1; reg.x.cx = 0x0861; reg.x.dx = FP_OFF(dbp_wr); segreg.ds = FP_SEG(dbp_wr); intdosx(®, ®, &segreg); // Проверяем флаг переноса if(reg.x.cflag != 0) { printf("\nОшибка: %d",reg.x.ax); exit(-1); } // Заполняем блок параметров для выполнения // операции записи. // Только что прочитанные два сектора нулевой // дорожки будут записаны на 20-ю дорожку. dbp_wr->spec = 0; dbp_wr->head = 0; dbp_wr->track = 20; dbp_wr->sector = 0; dbp_wr->sectcnt = 2; dbp_wr->buffer = buf; // Выполняем операцию записи reg.x.ax = 0x440d; reg.h.bl = 1; reg.x.cx = 0x0841; reg.x.dx = FP_OFF(dbp_wr); segreg.ds = FP_SEG(dbp_wr); intdosx(®, ®, &segreg); // Проверяем флаг переноса if(reg.x.cflag != 0) { printf("\nОшибка: %d",reg.x.ax); exit(-1); } // Освобождаем буфер free(dbp_wr); exit(0); } |