#include <stdio.h>
#include <dos.h>

typedef struct _DISK_CONFIG_
{
  int  n_floppy;
  int  n_hard;
  int  t_floppy1;
  int  t_floppy2;
  int  t_hard1;
  int  t_hard2;
} DISK_CONFIG;

typedef struct _DPT_
{
  unsigned char srt_hut;
  unsigned char dma_hlt;
  unsigned char motor_w;
  unsigned char sec_size;
  unsigned char eot;
  unsigned char gap_rw;
  unsigned char dtl;
  unsigned char gap_f;
  unsigned char fill_char;
 unsigned char hst;
 unsigned char mot_start;
} DPT;

typedef struct _HDPT_
{
  unsigned max_cyl;
  unsigned char max_head;
  unsigned srwcc;
  unsigned swpc;
  unsigned char max_ecc;
  unsigned char dstopt;
  unsigned char st_del;
  unsigned char fm_del;
  unsigned char chk_del;
  char reserve[4];
} HDPT;

void disk_cfg(DISK_CONFIG* cfg);
DPT far *get_dpt(void);
HDPT far *get_hdp1(void);
HDPT far *get_hdp2(void);

void main(void)
{
  DISK_CONFIG cfg;
  DPT  far *dpt_ptr;
  HDPT far *hdpt1_ptr;
  HDPT far *hdpt2_ptr;

  printf("\n"
    "\nКонфигурация дисковой подсистемы"
    "\n  (C)Фролов А., 1995\n");

  // Определяем конфигурацию дисковой подсистемы
  disk_cfg(&cfg);

  printf("\nУстановлено:"
    "\n   НГМД: %d"
    "\n   НМД:  %d",
    cfg.n_floppy, cfg.n_hard);

  printf("\nТип НГМД:  A: - %d, B: - %d"
         "\nТип НМД:   C: - %d, D: - %d",
    cfg.t_floppy1, cfg.t_floppy2,
    cfg.t_hard1,   cfg.t_hard2);

  // Получаем адрес таблицы параметров дискеты
  dpt_ptr = get_dpt();

  printf("\n"
    "\nКод размера сектора дискеты:           %d"
    "\nЗаполняющий символ для форматирования: %2.2X",
    dpt_ptr->sec_size, dpt_ptr->fill_char);

  // Получаем адреса первой и второй таблицы
  // параметров жесткого диска
  hdpt1_ptr = get_hdp1();
  hdpt2_ptr = get_hdp2();

  printf("\n"
    "\nПараметры первого НМД:"
    "\n   Количество дорожек:       %d"
    "\n   Количество головок:       %d"
    "\n"
    "\nПараметры второго диска:"
    "\n   Количество дорожек:       %d"
    "\n   Количество головок:       %d",
    hdpt1_ptr->max_cyl,  hdpt1_ptr->max_head,
    hdpt2_ptr->max_cyl,  hdpt2_ptr->max_head);
}

/**
* disk_cfg
*
* Определить конфигурацию дисковой подсистемы
*
* Функция заполняет структуру, описывающую
* конфигурацию дисковой подсистемы:
*
* typedef struct _DISK_CONFIG_
* {
*   int  n_floppy;
*   int  n_hard;
*   int  t_floppy1;
*   int  t_floppy2;
*   int  t_hard1;
*   int  t_hard2;
* } DISK_CONFIG;
*
**/

void disk_cfg(DISK_CONFIG* cfg)
{
  char unsigned far *modptr;
  char unsigned pc_type;
  char cfg_byte;
  int  cfg_word;

  union REGS inregs, outregs;

  // Определяем тип компьютера
  modptr = (char unsigned far*)MK_FP(0xf000, 0xfffe);
  pc_type = *modptr;

  // В зависимости от типа компьютера выбираем
  // способ определения конфигурации дисковой
  // подсистемы
  switch (pc_type)
  {
    case 0xfc:

      // Для IBM AT считываем конфигурацию дисковой
      // подсистемы из КМОП-памяти

      // Считываем байт конфигурации
      outp(0x70, 0x14);
      cfg_byte = inp(0x71);

      // Определяем количество установленных НГМД
      if((cfg_byte & 1) == 0)
      {
        // Если младший бит байта конфигурации равен 0,
        // НГМД отсутствуют
        cfg->n_floppy  = 0;
        cfg->t_floppy1 = 0;
        cfg->t_floppy2 = 0;
      }
      else
      {
        // Определяем количество установленных НГМД
	cfg->n_floppy = ((cfg_byte >> 6) & 3) + 1;

        // Определяем типы НГМД
        outp(0x70, 0x10);
        cfg_byte = inp(0x71);

        cfg->t_floppy2 = cfg_byte & 0xf;
        cfg->t_floppy1 = (cfg_byte >> 4) & 0xf;
      }

      // Определяем конфигурацию НМД
      outp(0x70, 0x12);
      cfg_byte = inp(0x71);

      if(cfg_byte == 0)
      {
        // Если обе тетрады равны нулю, система
        // не содержит НМД
	cfg->n_hard  = 0;
	cfg->t_hard1 = 0;
	cfg->t_hard2 = 0;
      }
      else
      {
        // Определяем тип первого диска - диска C:
	if((cfg_byte & 0xf) != 0xf)
	  cfg->t_hard1 = cfg_byte & 0xf;
	else
        {
	  outp(0x70, 0x19);
	  cfg->t_hard1 = inp(0x71);
	}

        // Определяем тип второго диска - диска D:
	if((cfg_byte & 0xf0) != 0xf0)
	  cfg->t_hard2 = (cfg_byte >> 4) & 0xf;
        else
        {
	  outp(0x70, 0x1a);
	  cfg->t_hard2 = inp(0x71);
	}
      }

      // Вычисляем количество НМД, установленных
      // в системе
      cfg->n_hard = 0;
      if(cfg->t_hard1 != 0) cfg->n_hard++;
      if(cfg->t_hard2 != 0) cfg->n_hard++;

      // Для некоторых совместимых с IBM AT машин невозможно
      // определить тип диска, так как в КМОП-памяти для
      // типа диска установлено значение 0, несмотря на то,
      // что диск имеется. В таких случаях можно определить
      // наличие жесткого диска, используя слово
      // конфигурации, возвращаемое прерыванием INT 11h.

      if(cfg->n_hard == 0)
      {
        int86(0x11, &inregs, &outregs);
	cfg_word = outregs.x.ax;

        // Проверяем, есть ли НМД
	if((cfg_word & 1) != 0)
        {
	  cfg->n_hard =  1;

          // Считаем, что тип используемого жесткого
          // диска неопределен
	  cfg->t_hard1 = 0;
	  cfg->t_hard2 = 0;
	}
      }
      break;

    default:

      // Для остальных типов компьютеров вызываем
      // прерывание INT 11h, используем возвращаемый
      // этим прерыванием байт конфигурации
      int86(0x11, &inregs, &outregs);
      cfg_word = outregs.x.ax;

      // Определяем количество установленных
      // НГМД
      cfg->n_floppy = ((cfg_word >> 6) & 3) + 1;

      // Считаем, что тип используемого НГМД
      // неопределен
      cfg->t_floppy1 = 0;
      cfg->t_floppy2 = 0;

      // Определяем наличие НМД
      if((cfg_word & 1) != 0)
      {
        cfg->n_hard =  1;

        // Считаем, что тип используемого НМД
        // неопределен
        cfg->t_hard1 = 0;
        cfg->t_hard2 = 0;
      }
      break;
  }
}

/**
* get_dpt
*
* Вычислить адрес таблицы параметров дискеты
*
* Функция возвращает указатель на таблицу
* параметров дискеты
*
**/

DPT far *get_dpt(void)
{
  void far * far *ptr;

  ptr = (void far * far *)MK_FP(0x0, 0x78);
  return(DPT far*)(*ptr);
}

/**
* get_hdp1
*
* Вычислить адрес первой таблицы параметров диска
*
* Функция возвращает указатель на первую таблицу
* параметров диска
*
**/

HDPT far *get_hdp1(void)
{
  void far * far *ptr;

  ptr = (void far * far *)MK_FP(0x0, 0x104);
  return(HDPT far*)(*ptr);
}

/**
* get_hdp2
*
* Вычислить адрес первой таблицы параметров диска
*
* Функция возвращает указатель на первую таблицу
* параметров диска
*
**/

HDPT far *get_hdp2(void)
{
  void far * far *ptr;

  ptr = (void far * far *)MK_FP(0x0, 0x118);
  return(HDPT far*)(*ptr);
}
