Операционная система 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);
}
|

