/*-------------------------------------------------------------------*/
/*                                                                   */
/*  ＦＤＵ  （Ｆｌｏｐｐｙ  Ｄｉｓｋ  Ｕｔｉｌｉｔｙ）  Ver. 0.92    */
/*                                                                   */
/*                                             for FM TOWNS or FMR   */
/*                                                                   */
/* Debug Date 940103-940219                                          */
/*                                                                   */
/* Free Ware Collection 8 Release Date      '92-02-19  By T.O6809    */
/*                                                                   */
/*-------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>
#include <jctype.h>
#include <conio.h>
#include <dos.h>
#include <limits.h>
#include <process.h>
#include <io.h>
#include <fcntl.h>

#define     VER              "0.92"
#define     CSL_OFF()        printf("\x1B[1v")
#define     CSL_ON()         printf("\x1B[0v")
#define     CSL_TOP()        printf("\x1B[80D")
#define     DEL_STR_END()    printf("\x1B[0K")
#define     DEL_STR_TOP()    printf("\x1B[1K")
#define     COLOR_RED()      printf("\x1B[31m")
#define     COLOR_WHITE()    printf("\x1B[37m")
#define     BEEP()           printf("\x7")
#define     LOCATE(x,y)      printf("\x1B[%d;%dH", y+1, x+1)
#define     CLS()            printf("\x1B[2J")

#define     MFM              0x00       /* 記録方式                  */
#define     FM               0x80
#define     HD2              0x00       /* FD Type                   */
#define     Hd2              0x50
#define     DD2              0x10
#define     D2               0x20
#define     L0128            0x00       /* Sector Length Type        */
#define     L0256            0x01
#define     L0512            0x02
#define     L1024            0x03
#define     F640             1
#define     F720             2
#define     F1200            3
#define     F1232            4
#define     F1440            5
#define     IBM2D8_0         6
#define     IBM2D8_1         7
#define     IBM2DD5_0        8
#define     IBM2DD5_1        9
#define     FRM              10
#define     FRM_FAT          20
#define     DCP              30
#define     DCP_EMS          31
#define     SDUMP            40

#define     TRUE             1              /* 真 */
#define     FALSE            0              /* 偽 */

#define     ASCII            0
#define     SJIS             1
#define     JIS              2
#define     NEC_JIS          3
#define     EUC              4
#define     EBCDIC           5
#define     EBCDIK           6
#define     UNICODE          7

#define     CTRL_A           0x01
#define     CTRL_B           0x02
#define     CTRL_K           0x0B
#define     CTRL_N           0x0E
#define     UP               0x1E
#define     DOWN             0x1F
#define     RLUP             0x16
#define     RLDN             0x17
#define     ESC              0x1B

#define     ON               1
#define     OFF              0

typedef unsigned long ulong;
typedef unsigned int  uint;
typedef unsigned char uchar;

int  drive_count = 0;                   /* Drive Count                           */
int  drive_media;                       /* 0:FD 1:? 2:HD 3:RAM Disk ff:?         */
int  o_drive_no[128];                   /* Drive Number                          */
uint o_fd_type   = 0xffff;              /* 1:640k 2:720k 3:1200k 4:1232k 5:1440k */
uint o_repeat    = 1;                   /* Repeat Count                          */
uint o_help      = 0;                   /* Help Messge                           */
uint o_debug     = 0;                   /*                                       */
uint o_beep      = 0;                   /* Beep                                  */
uint o_type      = 0;                   /* 10:Format 20:FAT  30:DiskCopy         */
uint o_cm_count  = 0;                   /*                                       */
uint o_cf_flag   = OFF;                 /*                                       */
uint fd_type;                           /* 1:640k 2:720k 3:1200k 4:1232k 5:1440k */
uint repeat_count;                      /*                                       */
uint old_mode1[4], old_mode2[4];        /*                                       */
uint fd_mode_sts;                       /*                                       */
uint fat_use_flag[256];                 /*                                       */

int  ems_handle;
int  ems_flag = OFF;

typedef struct {
    uchar   trackno;            /* トラック番号 */
    uchar   headno;             /* ヘッド番号   */
    uchar   secno;              /* セクタ番号   */
    uchar   seccnt;             /* セクタ長     */
    uchar   crc1;
    uchar   crc2;
} DKB_SEC;

uchar form_data[14500];

static int tr_sz[][23] = {                                                      /* FD Format Information      */
/*  0    1    2      3   4   5   6    7    8    9   10   11   12  13  14  15   16   17  18    19  20   21   22*/
/*            SLType Sec Trk Hed Scln Gap0 Sync Idx Gap1 Sync AM1 ID  CRC Gap2 Sync AM2 Data  CRC Gap3 Gap4   */
     D2, MFM, L0256, 16, 40, 2,  370, 80,  12,  4,  50,  12,  4,  4,  2,  22,  12,  4,   256, 2,   54, 152, 146,/* 320K 2D FM-7*/
    DD2, MFM, L0512,  8, 80, 2,  656, 80,  12,  4,  50,  12,  4,  4,  2,  22,  12,  4,   512, 2,   84, 310, 146,/* 640K 2DD    */
    DD2, MFM, L0512,  9, 80, 2,  656, 80,  12,  4,  50,  12,  4,  4,  2,  22,  12,  4,   512, 2,   84, 182, 146,/* 720K 2DD    */
    HD2, MFM, L0512, 15, 80, 2,  656, 80,  12,  4,  50,  12,  4,  4,  2,  22,  12,  4,   512, 2,   84, 400, 146,/*1200K 2HC    */
    HD2, MFM, L1024,  8, 77, 2, 1200, 80,  12,  4,  50,  12,  4,  4,  2,  22,  12,  4,  1024, 2,  116, 654, 146,/*1232K 2HD    */
    Hd2, MFM, L0512, 18, 80, 2,  680, 80,  12,  4,  50,  12,  4,  4,  2,  22,  12,  4,   512, 2,  108, 400, 146,/*1440K 2HD    */
    HD2,  FM, L0128, 26, 77, 2,  186, 40,   6,  1,  26,   6,  1,  4,  2,  11,   6,  1,   128, 2,   27, 247, 146,/*0    8'2D IBM*/
    HD2, MFM, L0256, 26, 77, 2,  370, 80,  12,  4,  50,  12,  4,  4,  2,  22,  12,  4,   256, 2,   54, 598, 146,/*1-77 8'2D IBM*/
    DD2,  FM, L0128, 16, 77, 2,  186, 40,   6,  1,  26,   6,  1,  4,  2,  11,   6,  1,   128, 2,   27,  44,  74,/*0    5'2DDIBM*/
    DD2, MFM, L0256, 16, 77, 2,  370, 80,  12,  4,  50,  12,  4,  4,  2,  22,  12,  4,   256, 2,   54, 152, 146,/*1-77 5'2DDIBM*/
};

uchar ipl_data[][19] = {                    /* FD IPL DATA               */
/*  0  1     2     3     4  5     6     7  8     9     10    11   12  13   14  15   16 17 18 */
    0, 0x00, 0x00, 0x00, 0, 0x00, 0x00, 0, 0x00, 0x00, 0x00, 0x00, 0, 0x00, 0, 0x00 ,0, 0, 0,
    0, 0x02, 0x02, 0x01, 0, 0x02, 0x70, 0, 0x00, 0x05, 0xFB, 0x02, 0, 0x08, 0, 0x02 ,0, 0, 0,
    0, 0x02, 0x02, 0x01, 0, 0x02, 0x70, 0, 0xA0, 0x05, 0xF9, 0x03, 0, 0x09, 0, 0x02 ,0, 0, 0,
    0, 0x02, 0x01, 0x01, 0, 0x02, 0xE0, 0, 0x60, 0x09, 0xF9, 0x07, 0, 0x0F, 0, 0x02 ,0, 0, 0,
    0, 0x04, 0x01, 0x01, 0, 0x02, 0xC0, 0, 0xD0, 0x04, 0xFE, 0x02, 0, 0x08, 0, 0x02 ,0, 0, 0,
    0, 0x02, 0x01, 0x01, 0, 0x02, 0xE0, 0, 0x40, 0x0b, 0xF0, 0x09, 0, 0x12, 0, 0x02 ,0, 0, 0,
    0, 0x00, 0x00, 0x00, 0, 0x00, 0x00, 0, 0x00, 0x00, 0x00, 0x00, 0, 0x00, 0, 0x00 ,0, 0, 0,
    0, 0x00, 0x00, 0x00, 0, 0x00, 0x00, 0, 0x00, 0x00, 0x00, 0x00, 0, 0x00, 0, 0x00 ,0, 0, 0,
    0, 0x00, 0x00, 0x00, 0, 0x00, 0x00, 0, 0x00, 0x00, 0x00, 0x00, 0, 0x00, 0, 0x00 ,0, 0, 0,
    0, 0x00, 0x00, 0x00, 0, 0x00, 0x00, 0, 0x00, 0x00, 0x00, 0x00, 0, 0x00, 0, 0x00 ,0, 0, 0,
};
char fd_type_msg[][32] = {
        "F-BASIC       [2D]",
        "MS-DOS(640k  80* 8) [2DD]",
        "MS-DOS(720k  80* 9) [2DD]",
        "MS-DOS(1200k 80*15) [2HC]",
        "MS-DOS(1232k 77* 8) [2HD]",
        "MS-DOS(1440k 80*18) [2HD]",
        "IBM(0)       77*26  [8'2D]",
        "IBM(1-77)    77*26  [8'2D]",
        "IBM(0)       77*16  [5'2DD]",
        "IBM(1-77)    77*16  [5'2DD]",
};
char code_str[][20] = {
        "ASIIC              ",
        "SJIS               ",
        "JIS                ",
        "NEC JIS(未サポート)",
        "EUC                ",
        "EBCDIC             ",
        "EBCDIK             ",
        "UNICODE(未サポート)",
};
int devno[4] = {0x20, 0x21, 0x22, 0x23};/* デバイス番号              */

int  chk_opt(int, char *[]);            /* Check Option              */
void err_msg(int, ...);                 /* Error Messge              */
int  old_fd_mode_get(uint [], uint []); /*                           */
void old_fd_mode_set(uint [], uint []); /*                           */
void make_form_data(void);              /* Make Format Data          */
void fd_form(void);                     /* FD Format                 */
void fd_form_sub(int);                  /* FD Format Subroutine      */
void init_ipl(int);                     /* FD Initialize IPL Data    */
void fd_form_fat(void);                 /* FD Sector 0 Initialize    */
void init_fat(int);                     /* FD Initialize FAT Data    */
void fd_copy(void);                     /* FD Copy                   */
void fat_flg_make(int);                 /*                           */
void fd_copy_sub(int, int);             /* FD Copy Subroutine        */
                                        /* FD_Copy (EMS)             */
void fd_copy_ems(int, int, int, int [], ulong, uchar huge *, int);
                                        /* FD_Copy (Standard Memory) */
void fd_copy_mem(int, int, int, int [], ulong, uchar huge *);

void fd_sdump(void);                    /* FD Sector Dump            */
int  fd_sdump_sub(int, int);            /*                           */
int  chk_fd_type(int, int, int *);      /*                           */
int  keyin_digit(int, int, char *, char *); /*                       */
void codecnv(int, uchar *, uchar *, int);/*                          */
void ibmcnv(int, uchar *, uchar *, int);/*                           */
int  sjistojis(uint, uint *);           /*                           */
int  jistosjis(uint, uint *);           /*                           */
int  uKYB_lock(int);                    /*                           */
int  getkey (void);                     /*                           */

int  ems_alloc(ulong *, int *);         /* EMS Memory Alloc          */
int  ems_chk(void);                     /* EMS Status Check          */
int  ems_map(int far *, int);           /* EMS Map Set               */
int  ems_free(int);                     /* EMS Memory Free           */

void fd_write_ready(int);               /* FD Ready    FMT or DCPdst */
void fd_read_ready(int);                /* FD Ready           DCPdst */
void get_fd_type(int);                  /* GET FD type FMT or DCPsrc */
int  fd_set_mode(int);                  /* Set Mode FD               */
int  fd_chk(int);                       /* Check FD                  */
void dump(uchar [], long, int, int);    /* Dump                      */
void time_get(int *, int *, int *);     /* Get Time                  */
void interrupt far ctrl_c(void);        /* CTRL+C Interrupt          */
void end_fdu(void);

                                        /* Call BIOS Function               */
int  uDKB_setmode(int, uint, uint);                            /* INT 93 00 */
int  uDKB_rdmode(int, uint *, uint *);                         /* INT 93 01 */
int  uDKB_rdstatus(int, uint *);                               /* INT 93 02 */
int  uDKB_restore(int);                                        /* INT 93 03 */
int  uDKB_read(int, int, int, int, int, uchar *,  int *);      /* INT 93 05 */
int  uDKB_read1(int, int, int, int, int, uchar huge *,  int *);/* INT 93 05 */
int  uDKB_write(int, int, int, int, int, uchar *, int *);      /* INT 93 06 */
int  uDKB_write1(int, int, int, int, int, uchar huge *, int *);/* INT 93 06 */
int  uDKB_chksec(int, int, int, int, int, int *);              /* INT 93 07 */
int  uDKB_rdsecid(int, int, int, DKB_SEC *);                   /* INT 93 09 */
int  uDKB_format(int, int, int, uchar *);                      /* INT 93 0A */
int  system_get(uchar *);                                      /* INT 8E 00 */

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
    int   ret;

    ret = chk_opt(argc, argv);
    if (ret == 1) {
        err_msg(1);
        exit(1);
    } else if (ret == 2) {
        err_msg(2);
        exit(1);
    }

    fd_mode_sts = old_fd_mode_get(&old_mode1[0], &old_mode2[0]);

    _dos_setvect(0x23, (void (interrupt far *)())ctrl_c);

    CSL_OFF();

    switch(o_type) {
        case FRM:                       /* format */
            make_form_data();
            for (repeat_count = 0; repeat_count < o_repeat; repeat_count++) {
                fd_form();
            }
            break;
        case FRM_FAT:                   /* format (FAT) */
            for (repeat_count = 0; repeat_count < o_repeat; repeat_count++) {
                fd_form_fat();
            }
            break;
        case DCP:                       /* Disk Copy */
        case DCP_EMS:
            for (repeat_count = 0; repeat_count < o_repeat; repeat_count++) {
                fd_copy();
            }
            if (o_type == DCP_EMS) {
                ems_free(ems_handle);
                ems_flag = OFF;
            }
            break;
        case SDUMP:                     /* Sctor Dump */
            fd_sdump();
            break;
        default:
            break;
    }

    old_fd_mode_set(&old_mode1[0], &old_mode2[0]);

    outp(0x208, 0x03);                  /* Motor OFF (bit4 0) */

    CSL_ON();

    return (0);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
int chk_opt(int ac, char *av[])
{
    int   i, tmp, f_cnt = 0, ret = 0;
    uint  c_cnt;
    long  wkl;
    uchar machine_sts[200];

    if (ac <= 1) {
        ret = 1;
    } else if ((av[1][0] == '-' || av[1][0] == '/') && av[1][1] == '?') {
        ret = 1;
        o_help = ON;
    } else {
        system_get(&machine_sts[0]);
        for (i = 1; i < ac; i++) {
            if ((av[i][0] >= 'A' && av[i][0] <= 'p' && av[i][1] == ':') ||
                (av[i][0] >= 'a' && av[i][0] <= 'p' && av[i][1] == ':')  ) {
                tmp = 0x30 + (toupper(av[i][0]) - 'A') * 2;
                if ((drive_media = machine_sts[tmp+0]) == 0) {
                    o_drive_no[drive_count++] = machine_sts[tmp+1];
                } else {
                    drive_count++;
                    ret = 2;
                }
            } else if (av[i][0] == '-' || av[i][0] == '/') {
                if (av[i][1] == 'c') {
                    c_cnt = 0;
                    f_cnt++;
                    o_type = DCP;
                    if (strchr(&av[i][2], (int)'f') != NULL) {
                        c_cnt++;
                        o_cf_flag = ON;
                    }
                    if (strchr(&av[i][2], (int)'m') != NULL) {
                        c_cnt++;
                        o_type = DCP_EMS;
                    }
                    if (strlen(&av[i][2]) != c_cnt) {
                        ret = 1;
                    }
                } else if (av[i][1] == 'B') {
                    o_beep = ON;
                } else if (av[i][1] == 'f') {
                    f_cnt++;
                    o_type = FRM;
                    if (av[i][2] == (char)NULL) { /* default */
                        o_fd_type = F1232;
                    } else if (av[i][3] == (char)NULL) {
                        o_fd_type = av[i][2] - '0';
                        if (!(o_fd_type >= F640 && o_fd_type <= F1440)) {
                            ret = 1;
                        }
                    } else if (strcmp("640", &av[i][2]) == 0) {
                        o_fd_type = F640;
                    } else if (strcmp("720", &av[i][2]) == 0) {
                        o_fd_type = F720;
                    } else if (strcmp("1200", &av[i][2]) == 0) {
                        o_fd_type = F1200;
                    } else if (strcmp("1232", &av[i][2]) == 0) {
                        o_fd_type = F1232;
                    } else if (strcmp("1440", &av[i][2]) == 0) {
                        o_fd_type = F1440;
                    } else {
                        ret = 1;
                    }
                } else if (av[i][1] == 'F' && av[i][2] == (char)NULL) {
                    f_cnt++;
                    o_type = FRM_FAT;
                } else if (av[i][1] == 'd' && av[i][2] == 's' &&
                           av[i][3] == (char)NULL                ) {
                    f_cnt++;
                    o_type = SDUMP;
                } else {
                    ret = 1;
                }
            } else if (av[i][0] == '+') {/* Set Repeat Count */
                if (isdigit(av[i][1])) {
                    wkl = atol(&av[i][1]);
                    if (wkl == 0 || wkl > UINT_MAX) {
                        ret = 1;
                    } else {
                        o_repeat = (uint)wkl;
                    }
                } else {
                    if (av[i][1] == '+' && av[i][2] == (char)NULL) {
                        o_repeat = UINT_MAX;
                    } else {
                        ret = 1;
                    }
                }
            } else {
                ret = 1;
            }
        }
    }
    if (o_type == DCP || o_type == DCP_EMS) {
        if (drive_count == 2) {             /* Disk Copy */
            drive_count = 1;
        } else {
            ret = 1;
        }
    } else if (o_type ==DCP_EMS && drive_count != 1) {
        ret = 1;
    }
    if (o_type == SDUMP) {
        if (drive_count != 1) {
            ret = 1;
        }
    } else if (drive_count == 0) {
        ret = 1;
    }
    if (f_cnt != 1) {
        ret = 1;
    }

    return (ret);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void err_msg(int msgno, int drv)
{
    if (msgno == 1) {
        if (o_help == OFF) {
            printf("fdu (Ver. %s)  for FM TOWNS%37cBy T.O6809\n" , VER, ' ');
            puts("Usage: fdu -? | -{f{1-5}|F|c[mf]|ds} [-B] [+{+|1-65535}] <Drive:>...");
        } else {
            printf("-- fdu (Ver. %s) -- for FM TOWNS -------"
                   "----------------------- By T.O6809 --\n" , VER);
            puts("Usage: fdu -? | -{f{1-5}|F|c[mf]|ds} [-B] [+{+|1-65535}] <Drive:>...");
            puts("----------------------------------------"
                 "---------------------------------------");
            puts("-?           Help");
            puts("-f1 | -f640  MS-DOS Format  640k[2DD] (80*2* 8* 512*2)");
            puts("-f2 | -f720  MS-DOS Format  720k[2DD] (80*2* 9* 512*2)");
            puts("-f3 | -f1200 MS-DOS Format 1200k[2HC] (80*2*15* 512*1)");
            puts("-f4 | -f1232 MS-DOS Format 1232k[2HD] (77*2* 8*1024*1)");
            puts("-f5 | -f1440 MS-DOS Format 1440k[2HD] (80*2*18* 512*1)");
            puts("-F           MS-DOS Format FAT Only");
            puts("-c           MS-DOS Disk Copy");
            puts("-cm          MS-DOS Disk Copy (Multiple Copy)");
            puts("-cf          MS-DOS Disk Copy (Copy is Use sector only)");
            puts("-ds          Sector Dump");
            puts("-B           BEEP ON");
            puts("+{+|1-65535} 65535 Repeat  or  1 - 65535 Repeat");
            puts("<Drive:>...  A: - P:");
            puts("");
            puts("Ex.)   fdu -f1232 +10 a: b: (format a: and format b:) * 10");
            puts("       fdu -F -5 a:         (format /C a:) * 5");
            puts("       fdu -c +100 a: b:    (diskcopy a: b:) * 100");
            puts("       fdu -cmf a: b:");
        }
    } else if (msgno == 2) {
        if (drive_media == 2) {
            puts("That is not FD. (Hard Disk)");
        } else if (drive_media == 3) {
            puts("That is not FD. (RAM Disk)");
        } else if (drive_media == 5) {
            puts("That is not FD. (ROM Dvice)");
        } else {
            puts("That is not FD. (Unknow Dvice)");
        }
    } else if (msgno == 3) {
        CSL_TOP();
        printf("%c: Can't format then change anther disk if ready, push any key.",
               'A'+drv);
        getch();
        DEL_STR_TOP();
    } else if (msgno == 4) {
        CSL_TOP();
        printf("%c: Unknow format.", 'A'+drv);
    }
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
int old_fd_mode_get(uint old_mode1[], uint old_mode2[])
{
    int  ret;

    ret = uDKB_rdmode(0x20, &old_mode1[0], &old_mode2[0]);
    ret = uDKB_rdmode(0x21, &old_mode1[1], &old_mode2[1]);
    ret = uDKB_rdmode(0x22, &old_mode1[2], &old_mode2[2]);
    ret = uDKB_rdmode(0x23, &old_mode1[3], &old_mode2[3]);

    return(1);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void old_fd_mode_set(uint old_mode1[], uint old_mode2[])
{
    int  ret;

    ret = uDKB_setmode(0x20, old_mode1[0], old_mode2[0]);
    ret = uDKB_setmode(0x21, old_mode1[1], old_mode2[1]);
    ret = uDKB_setmode(0x22, old_mode1[2], old_mode2[2]);
    ret = uDKB_setmode(0x23, old_mode1[3], old_mode2[3]);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void make_form_data(void)
{
    int   cnt, i, j, tmp, sec_len, pre_gap1;

    for (i = 0; i < tr_sz[o_fd_type][7]; i++) {             /* Gap0            */
        form_data[i] = 0x4E;
    }
    cnt = tr_sz[o_fd_type][7]+tr_sz[o_fd_type][8];          /* Gap0 + Sync     */
    for (i = tr_sz[o_fd_type][7]; i < cnt; i++) {           /* Sync            */
        form_data[i] = 0;
    }
    if (tr_sz[o_fd_type][1] == MFM) {
        form_data[cnt]   = 0xF6;                            /* Index Mark      */
        form_data[cnt+1] = 0xF6;
        form_data[cnt+2] = 0xF6;
        form_data[cnt+3] = 0xFC;
    } else {
        form_data[cnt]   = 0xFC;
    }
                                                            /* Gap0 + Sync + Idx + Gap1 */
    pre_gap1 = tr_sz[o_fd_type][22] = cnt+tr_sz[o_fd_type][9]+tr_sz[o_fd_type][10];
    for (i = pre_gap1-tr_sz[o_fd_type][10]; i < pre_gap1; i++) { /* Gap1       */
        form_data[i] = 0x4E;
    }

    for (i = 0; i < tr_sz[o_fd_type][3]; i++) {             /* loop Sctor      */
        sec_len = tr_sz[o_fd_type][6] * i;
        for (j = 0; j < tr_sz[o_fd_type][11]; j++) {        /* Sync            */
            form_data[sec_len+pre_gap1+j] = 0;
        }
        cnt = pre_gap1 + tr_sz[o_fd_type][11];              /* Gap0 + Sync + Idx + Gap1 + Sync */
        if (tr_sz[o_fd_type][1] == MFM) {
            form_data[sec_len+cnt++] = 0xF5;                /* ID Address Mark */
            form_data[sec_len+cnt++] = 0xF5;
            form_data[sec_len+cnt++] = 0xF5;
            form_data[sec_len+cnt++] = 0xFE;
        } else {
            form_data[sec_len+cnt++] = 0xFE;
        }
        form_data[sec_len+cnt++] = 0;                         /* Track   Number*/
        form_data[sec_len+cnt++] = 0;                         /* Cylnder Number*/
        form_data[sec_len+cnt++] = (uchar)(i+1);              /* Sector  Number*/
        form_data[sec_len+cnt++] = (uchar)tr_sz[o_fd_type][2];/* Sec Length    */
        form_data[sec_len+cnt++] = 0xF7;                      /* CRC           */

        for (j = 0; j < tr_sz[o_fd_type][15]; j++) {        /* Gap2            */
            form_data[sec_len+cnt+j] = 0x4E;
        }
        cnt += tr_sz[o_fd_type][15];
        for (j = 0; j < tr_sz[o_fd_type][16]; j++) {        /* Sync            */
            form_data[sec_len+cnt+j] = 0;
        }
        cnt += tr_sz[o_fd_type][16];
        if (tr_sz[o_fd_type][1] == MFM) {
            form_data[sec_len+cnt++] = 0xF5;                /* Data or         */
            form_data[sec_len+cnt++] = 0xF5;                /* Deleted DataMark*/
            form_data[sec_len+cnt++] = 0xF5;
            form_data[sec_len+cnt++] = 0xFB;
        } else {
            form_data[sec_len+cnt++] = 0xFB;
        }

        for (j = 0; j < tr_sz[o_fd_type][18]; j++) {        /* Data            */
            form_data[sec_len+cnt+j] = 0xE5;
        }
        cnt += tr_sz[o_fd_type][18];
        form_data[sec_len+cnt++] = 0xF7;                    /* CRC             */

        for (j = 0; j < tr_sz[o_fd_type][20]; j++) {        /* Gap3            */
            form_data[sec_len+cnt+j] = 0x4E;
        }
    }

    tmp = tr_sz[o_fd_type][6]*(tr_sz[o_fd_type][3]-1)+cnt+j;
    for (i = tmp; i < tmp + tr_sz[o_fd_type][21]*5; i++) {
        form_data[i] = 0x4E;
    }
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void fd_form(void)
{
    int ret, i, s_min, s_sec, s_hsec, e_min, e_sec, e_hsec;
    static int f_old = 0xffff;

    for (i = 0; i < drive_count; i++) {
        if (o_drive_no[i] == f_old) {
            CSL_TOP();
            printf("%c: Change disk. [Push Any Key]", 'A'+o_drive_no[i]);
            getch();
            DEL_STR_TOP();
        }
        f_old = o_drive_no[i];
        fd_write_ready(o_drive_no[i]);
        if (fd_set_mode(o_drive_no[i]) == 2) {
            printf("\"1440k FD\" can't support.");
            CSL_ON();
            exit(5);
        }

        CSL_TOP();
        printf("%s Format %c: [%ld/%ld]\n",
               fd_type_msg[o_fd_type], o_drive_no[i]+'A',
               (long)repeat_count*drive_count+i+1,(long)o_repeat*drive_count);

        while ((ret = fd_chk(o_drive_no[i])) != 0) {
            err_msg(3, o_drive_no[i]);
        }

        time_get(&s_min, &s_sec, &s_hsec);

        fd_form_sub(o_drive_no[i]);
        init_ipl(o_drive_no[i]);
        init_fat(o_drive_no[i]);

        time_get(&e_min, &e_sec, &e_hsec);
        if (s_min > e_min) e_min += 60;
        if (s_hsec > e_hsec) {
            e_hsec += 100;
            e_sec--;
        }
        CSL_TOP();
        printf("Finished (%3d.%02d sec)\n",
               (e_min*60 + e_sec) - (s_min*60 + s_sec), e_hsec - s_hsec);

        if (o_beep == ON) {
            BEEP();
        }
    }
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void fd_form_sub(int drv)
{
    int  i, j, ret, pre_gap1;

    ret = uDKB_restore(devno[drv]);     /* シリンダ０へのシーク      */

    CSL_TOP();
    printf("%02d/%02d Track Format", 0, tr_sz[o_fd_type][4]-1);
    pre_gap1 = tr_sz[o_fd_type][22];
    for (i = 0; i < tr_sz[o_fd_type][4]; i++) {
        for (j = 0; j < tr_sz[o_fd_type][3]; j++) { /* Face 0 */
            form_data[tr_sz[o_fd_type][6]*j+pre_gap1+16] = (uchar)i;
            form_data[tr_sz[o_fd_type][6]*j+pre_gap1+17] = 0;
        }
        ret = uDKB_format(devno[drv], i, 0, form_data);

        for (j = 0; j < tr_sz[o_fd_type][3]; j++) { /* Face 1 */
            form_data[tr_sz[o_fd_type][6]*j+pre_gap1+17] = 1;
        }
        ret = uDKB_format(devno[drv], i, 1, form_data);
        CSL_TOP();
        printf("%02d", i);
    }
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void init_ipl(int drv)
{
    int   ret, secnum;
    uchar *bf_p;

    if ((bf_p = calloc(tr_sz[o_fd_type][18]*tr_sz[o_fd_type][3], sizeof(uchar))) == NULL) {
        puts("Memory alloc error\n");
        CSL_ON();
        exit(3);
    }

    *(bf_p+ 0) = 0xEB;                            /* IPL near jump */
    *(bf_p+ 1) = 0x1C;
    *(bf_p+ 2) = 0x90;
    *(bf_p+ 3) = 0x46;                            /* F */
    *(bf_p+ 4) = 0x44;                            /* D */
    *(bf_p+ 5) = 0x55;                            /* U */
    *(bf_p+ 6) = 0x20;                            /*   */
    *(bf_p+ 7) = 0x30;                            /* 0 */
    *(bf_p+ 8) = 0x2E;                            /* . */
    *(bf_p+ 9) = 0x39;                            /* 9 */
    *(bf_p+10) = 0x32;                            /* 2 */

    *(bf_p+11) = ipl_data[o_fd_type][ 0];         /* Byte/Sector             */
    *(bf_p+12) = ipl_data[o_fd_type][ 1];
    *(bf_p+13) = ipl_data[o_fd_type][ 2];         /* Sector/Cluster          */
    *(bf_p+14) = ipl_data[o_fd_type][ 3];         /* Reserve Sector Number   */
    *(bf_p+15) = ipl_data[o_fd_type][ 4];
    *(bf_p+16) = ipl_data[o_fd_type][ 5];         /* FAT Number              */
    *(bf_p+17) = ipl_data[o_fd_type][ 6];         /* Root Directry Entry MAX */
    *(bf_p+18) = ipl_data[o_fd_type][ 7];
    *(bf_p+19) = ipl_data[o_fd_type][ 8];         /* Logical Sector Number   */
    *(bf_p+20) = ipl_data[o_fd_type][ 9];
    *(bf_p+21) = ipl_data[o_fd_type][10];         /* Media ID Byte           */
    *(bf_p+22) = ipl_data[o_fd_type][11];         /* Sector/FAT              */
    *(bf_p+23) = ipl_data[o_fd_type][12];
    *(bf_p+24) = ipl_data[o_fd_type][13];         /* Sector/Track            */
    *(bf_p+25) = ipl_data[o_fd_type][14];
    *(bf_p+26) = ipl_data[o_fd_type][15];         /* Head                    */
    *(bf_p+27) = ipl_data[o_fd_type][16];
    *(bf_p+28) = ipl_data[o_fd_type][17];         /* Hidden Sector           */
    *(bf_p+29) = ipl_data[o_fd_type][18];

    *(bf_p+30) = 0xEA;                            /* IPL Routine             */
    *(bf_p+31) = 0x00;
    *(bf_p+32) = 0x00;
    *(bf_p+33) = 0xFF;
    *(bf_p+34) = 0xFF;

    ret = uDKB_write(devno[drv], 0, 0, 1, tr_sz[o_fd_type][3], bf_p, &secnum);
    free(bf_p);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void fd_form_fat(void)
{
    int  i, s_min, s_sec, s_hsec, e_min, e_sec, e_hsec;
    static uint cnt;

    for (i = 0; i < drive_count; i++) {
        if (cnt++ != 0) {
            CSL_TOP();
            printf("%c: Change disk. [Push Any Key]", 'A'+o_drive_no[i]);
            getch();
            DEL_STR_TOP();
        }

        fd_write_ready(o_drive_no[i]);
        get_fd_type(o_drive_no[i]);
        if (o_fd_type == 0xffff) {
            err_msg(4, o_drive_no[i]);
            CSL_ON();
            exit(4);
        }

        if (fd_set_mode(o_drive_no[i]) == 2) {
            printf("\"1440k FD\" can't support.");
            CSL_ON();
            exit(5);
        }

        CSL_TOP();
        printf("%s Format (FAT) %c: [%ld/%ld]\n",
               fd_type_msg[o_fd_type], o_drive_no[i]+'A',
               (long)repeat_count*drive_count+i+1, (long)o_repeat*drive_count);

        time_get(&s_min, &s_sec, &s_hsec);

        init_fat(o_drive_no[i]);

        time_get(&e_min, &e_sec, &e_hsec);
        if (s_min > e_min) e_min += 60;
        if (s_hsec > e_hsec) {
            e_hsec += 100;
            e_sec--;
        }
        CSL_TOP();
        printf("Finished (%3d.%02d sec)\n",
               (e_min*60 + e_sec) - (s_min*60 + s_sec), e_hsec - s_hsec);

        if (o_beep == ON) {
            BEEP();
        }
    }
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void init_fat(int drv)
{
    int   i, ret, secnum, fat2_size, fcb_size, track_size;
    uchar *bf_p;

    ret = uDKB_restore(devno[drv]);     /* シリンダ０へのシーク      */

    bf_p = malloc(tr_sz[o_fd_type][18]*tr_sz[o_fd_type][3]*2);
    if (bf_p == NULL) {
        puts("Malloc error\n");
        CSL_ON();
        exit(3);
    }

    track_size = tr_sz[o_fd_type][18]*tr_sz[o_fd_type][3];
    ret = uDKB_read(devno[drv], 0, 0, 1, tr_sz[o_fd_type][3], bf_p, &secnum);
    ret = uDKB_read(devno[drv], 0, 1, 1, tr_sz[o_fd_type][3], bf_p+track_size, &secnum);

    fat2_size = tr_sz[o_fd_type][18]*ipl_data[o_fd_type][11]*ipl_data[o_fd_type][5]; /* Total FAT Size */
    fcb_size  = ipl_data[o_fd_type][6]*32;                                           /* FBC Size       */
    memset(bf_p+tr_sz[o_fd_type][18],              0, fat2_size);                    /* FAT Clear      */
    memset(bf_p+tr_sz[o_fd_type][18]+fat2_size, 0xF6, fcb_size);                     /* FCB Clear      */
                                                                                     /* FAT ID Set     */
    *(bf_p+tr_sz[o_fd_type][18]+0) = ipl_data[o_fd_type][10];
    *(bf_p+tr_sz[o_fd_type][18]+1) = 0xFF;
    *(bf_p+tr_sz[o_fd_type][18]+2) = 0xFF;
    *(bf_p+tr_sz[o_fd_type][18]+tr_sz[o_fd_type][18]*ipl_data[o_fd_type][11]+0) = ipl_data[o_fd_type][10];
    *(bf_p+tr_sz[o_fd_type][18]+tr_sz[o_fd_type][18]*ipl_data[o_fd_type][11]+1) = 0xFF;
    *(bf_p+tr_sz[o_fd_type][18]+tr_sz[o_fd_type][18]*ipl_data[o_fd_type][11]+2) = 0xFF;
                                                                                     /* FCB Set        */
    for (i = tr_sz[o_fd_type][18]+fat2_size; i < tr_sz[o_fd_type][18]+fat2_size+fcb_size; i += 32) {
        *(bf_p+i) = 0;
    }

    ret = uDKB_write(devno[drv], 0, 0, 1, tr_sz[o_fd_type][3], bf_p+0, &secnum);
    ret = uDKB_write(devno[drv], 0, 1, 1, tr_sz[o_fd_type][3], bf_p+track_size, &secnum);
    free(bf_p);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void fd_copy()
{
    int ret, s_min, s_sec, s_hsec, e_min, e_sec, e_hsec;

    if (o_type == DCP && o_cm_count++ != 0) {
        CSL_TOP();
        printf("Change disk. [Push Any Key]");
        getch();
        DEL_STR_TOP();
    }

    if (o_type == DCP || (o_type == DCP_EMS && o_cm_count == 0)) {
        get_fd_type(o_drive_no[0]);               /* Src         Drive */
        if (o_fd_type == 0xffff) {
            err_msg(4, o_drive_no[0]);
            CSL_ON();
            exit(4);
        }
    }
    if (o_type == DCP && o_drive_no[0] != o_drive_no[1]) {
        fd_write_ready(o_drive_no[1]);            /* Destination Drive */
    }

    if (fd_set_mode(o_drive_no[0]) == 2) {        /* Src         Drive */
        printf("\"1440k FD\" can't support.");
        CSL_ON();
        exit(5);
    }
    if (fd_set_mode(o_drive_no[1]) == 2) {        /* Destination Drive */
        printf("\"1440k FD\" can't support.");
        CSL_ON();
        exit(5);
    }

    if (o_type == DCP || (o_type == DCP_EMS && o_cm_count == 0)) {
        make_form_data();
        if (o_cf_flag == ON) {
            if (o_fd_type >= F640 && o_fd_type <= F1440) {
                fat_flg_make(o_drive_no[0]);
            }
        }
    }


    CSL_TOP();
    printf("%s Disk Copy %c: -> %c: [%ld/%ld]\n",
           fd_type_msg[o_fd_type], o_drive_no[0]+'A', o_drive_no[1]+'A',
           (long)repeat_count+1, (long)o_repeat*drive_count);

    if (o_type == DCP && o_drive_no[0] != o_drive_no[1]) {
        while ((ret = fd_chk(o_drive_no[1])) != 0) {
            err_msg(3, o_drive_no[1]);
        }
    }

    time_get(&s_min, &s_sec, &s_hsec);

    fd_copy_sub(o_drive_no[0], o_drive_no[1]);

    time_get(&e_min, &e_sec, &e_hsec);
    if (s_min > e_min) e_min += 60;
    if (s_hsec > e_hsec) {
        e_hsec += 100;
        e_sec--;
    }
    CSL_TOP();
    printf("Finished (%3d.%02d sec)\n",
           (e_min*60 + e_sec) - (s_min*60 + s_sec), e_hsec - s_hsec);

    if (o_beep == ON) {
        BEEP();
    }
    o_cm_count++;
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void fat_flg_make(int drv1)
{
    int   ret, secnum, i, j, tmp_fat_odd, tmp_fat_evn, count, fat_size, top_data, fat_count;
    uchar *bf_p, *flag_p, *flag_pm;

    if ((bf_p = malloc(tr_sz[o_fd_type][18]*tr_sz[o_fd_type][3])) == NULL) {
        puts("Memory alloc error\n");
        CSL_ON();
        exit(3);
    }
    if ((flag_p = calloc(tr_sz[o_fd_type][3]*tr_sz[o_fd_type][4]*2, sizeof(uchar))) == NULL) {
        puts("Memory alloc error\n");
        CSL_ON();
        exit(3);
    }

    ret = uDKB_read(devno[drv1], 0, 0, 1, tr_sz[o_fd_type][3], bf_p, &secnum);
    fat_size = tr_sz[o_fd_type][18]*ipl_data[o_fd_type][11]; /* 1 FAT Size */

    top_data = 1+ipl_data[o_fd_type][11]*ipl_data[o_fd_type][5]+(ipl_data[o_fd_type][6]*32)/tr_sz[o_fd_type][18];
    memset(flag_p, 1, top_data);
    flag_pm = flag_p;
    flag_p += (top_data/ipl_data[o_fd_type][2]);
    fat_count = tr_sz[o_fd_type][3]*tr_sz[o_fd_type][4]*tr_sz[o_fd_type][5]/ipl_data[o_fd_type][2]*12L/8;
    for (i = tr_sz[o_fd_type][18]+3, count = 0; i < tr_sz[o_fd_type][18]+fat_count; i+=3, count+=2) {
        tmp_fat_odd = (((int)(*(bf_p+i+1)) << 8) |  *(bf_p+i)        ) & 0x0FFF;
        tmp_fat_evn = (((int)(*(bf_p+i+2)) << 4) | (*(bf_p+i+1)) >> 4) & 0x0FFF;
        if (tmp_fat_odd != 0 && tmp_fat_odd != 0xff7) {
            *(flag_p+count) = ON;
        }
        if (tmp_fat_evn != 0 && tmp_fat_evn != 0xff7) {
            *(flag_p+count+1) = ON;
        }
    }
    if (o_fd_type == F640 || o_fd_type == F720) {
        for (i = tr_sz[o_fd_type][3]*tr_sz[o_fd_type][4]*2/ipl_data[o_fd_type][2]; i >= 0; i--) {
            if (*(flag_pm+i) == ON) {
                *(flag_pm+i*2)   = ON;
                *(flag_pm+i*2+1) = ON;
            } else {
                *(flag_pm+i*2)   = OFF;
                *(flag_pm+i*2+1) = OFF;
            }
        }
    }

    memset(&fat_use_flag[0], 0, 256);
    for (i = 0; i < tr_sz[o_fd_type][4]*2; i++) {   /* Loop Track Number */
        for (j = 0; j < tr_sz[o_fd_type][3]; j++) { /* Loop Sctor Number */
            if (*(flag_pm+i*tr_sz[o_fd_type][3]+j) == 1) {
                fat_use_flag[i] = ON;
                break;
            }
        }
    }
    free(flag_p);
    free(bf_p);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void fd_copy_sub(int drv1, int drv2)
{
    ulong  adr;
    int    i, ret, tmp;
    static ulong bf_max, trk_siz, fd_siz;
    static int   bf_siz[80], loop;
    static uchar huge *bf_p;

    trk_siz = tr_sz[o_fd_type][18] * tr_sz[o_fd_type][3];
    fd_siz  = trk_siz * tr_sz[o_fd_type][4] * 2;

    if ((o_type == DCP && drv1 == drv2) || (o_type == DCP_EMS && o_cm_count == 0)) {
        if (ems_chk() == 0) {
            if ((ems_alloc(&adr, &ems_handle)) == 0) {
                ems_flag = ON;
                bf_p = (uchar huge *)adr;
                bf_max = 16L*1024*4;              /* EMS Size */
            }
        }
    }
    if (o_type == DCP_EMS && ems_flag == OFF) {
        printf("No enough EMS, then option \"-cc\" can't use.");
        end_fdu();
        exit(3);
    }
    if (ems_flag == OFF) {
        for (bf_max = 0xA0000; bf_max > 0; bf_max -= trk_siz) {
            bf_p = (uchar huge *)halloc(bf_max, sizeof(char));
            if (bf_p != NULL) {
                break;
            }
        }
    }

    if (o_type == DCP || (o_type == DCP_EMS && o_cm_count == 0)) {
        tmp = (uint)(bf_max / (trk_siz*2));
        loop = tr_sz[o_fd_type][4] / tmp;
        for (i = 0; i < loop; i++) {
            bf_siz[i] = tmp;
        }
        if ((tr_sz[o_fd_type][4] % tmp) != 0) {
            bf_siz[loop++] = (tr_sz[o_fd_type][4] % tmp);
        }
    }
    ret = uDKB_restore(devno[drv1]);
    ret = uDKB_restore(devno[drv2]);

    if (ems_flag == ON) {
        fd_copy_ems(drv1, drv2, loop, bf_siz, trk_siz, bf_p, ems_handle);
    } else {
        fd_copy_mem(drv1, drv2, loop, bf_siz, trk_siz, bf_p);
    }

    if (ems_flag == ON) {
        if (o_type == DCP) {
            ems_free(ems_handle);
            ems_flag = OFF;
        }
    } else {
        hfree(bf_p);
    }
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void fd_copy_ems(int drv1, int drv2, int loop, int bf_siz[], 
                 ulong trk_siz, uchar huge *bf_p, int handle)
{
    int  i, j, k, l;
    int  ret, secnum, pre_gap1, track, page, rcnt = 0, tmp_fd_type;
    uint far *map_adr;
    uint map_data[4*2];

    if ((o_type == DCP && drv1 == drv2) || (o_type == DCP_EMS && o_cm_count == 0)) {
        for (i = 0, page = 0, track = 0; i < loop; i++) {
            for (j = 0; j < 4; j++) {
                map_data[j*2]   = page++;
                map_data[j*2+1] = j;
            }
            map_adr = map_data;
            ems_map(map_adr, handle);
            for (j = track, k = 0; j < track+bf_siz[i]; j++, k++) {
                while (TRUE) {
                    if (o_cf_flag == ON) {
                        if (fat_use_flag[j*2] == OFF) {
                            break;
                        }
                    }
                    CSL_TOP();
                    printf("%02d/%02d Track Read  ", j, tr_sz[o_fd_type][4]-1);
                    rcnt++;
                    ret = uDKB_read1(devno[drv1], j, 0, 1,tr_sz[o_fd_type][3],
                                     bf_p+k*trk_siz*2, &secnum);
                    if (ret == 0) {
                        rcnt = 0;
                        break;
                    } else if (rcnt >= 2) {
                        printf("Read error [%x]", ret);
                        end_fdu();
                        exit(2);
                    }
                }
                while (TRUE) {
                    if (o_cf_flag == ON) {
                        if (fat_use_flag[j*2+1] == OFF) {
                            break;
                        }
                    }
                    rcnt++;
                    ret = uDKB_read1(devno[drv1], j, 1, 1,tr_sz[o_fd_type][3],
                                     bf_p+k*trk_siz*2+trk_siz, &secnum);
                    if (ret == 0) {
                        rcnt = 0;
                        break;
                    } else if (rcnt >= 2) {
                        printf("Read error [%x]", ret);
                        end_fdu();
                        exit(2);
                    }
                }
            }
            track += bf_siz[i];
        }
    }

    if (drv1 == drv2 || (o_type == DCP_EMS && o_cm_count != 0)) {
        CSL_TOP();
        printf("%c:(dst) Change disk. [Push Any Key]", 'A'+drv2);
        getch();
        DEL_STR_TOP();
    }
    fd_write_ready(drv2);                         /* Destination Drive */
    while ((ret = fd_chk(drv2)) != 0) {
        err_msg(3, drv2);
        fd_write_ready(drv2);                     /* Destination Drive */
    }

    pre_gap1 = tr_sz[o_fd_type][22];
    for (i = 0, page = 0, track = 0; i < loop; i++) {
        for (j = 0; j < 4; j++) {
            map_data[j*2]   = page++;
            map_data[j*2+1] = j;
        }
        map_adr = map_data;
        ems_map(map_adr, handle);
        for (j = track, k = 0; j < track+bf_siz[i]; j++, k++) {
            tmp_fd_type = fd_type;
            rcnt = 0;
            while (TRUE) {
                rcnt++;
                if (o_fd_type != fd_type) {
                    CSL_TOP();
                    printf("%02d/%02d Track Format", j, tr_sz[o_fd_type][4]-1);
                    for (l = 0; l < tr_sz[o_fd_type][3]; l++) {  /* Face 0 */
                        form_data[tr_sz[o_fd_type][6]*l+pre_gap1+16] = (uchar)j;
                        form_data[tr_sz[o_fd_type][6]*l+pre_gap1+17] = 0;
                    }
                    ret = uDKB_format(devno[drv2], j, 0, form_data);
                }
                CSL_TOP();
                printf("%02d/%02d Track Write ", j, tr_sz[o_fd_type][4]-1);
                if (o_cf_flag == ON) {
                    if (fat_use_flag[j*2] == OFF) {
                        break;
                    }
                }
                ret = uDKB_write1(devno[drv2], j, 0, 1,tr_sz[o_fd_type][3],
                                  bf_p+k*trk_siz*2, &secnum);
                if (ret == 0) {
                    fd_type = tmp_fd_type;
                    break;
                } else if (rcnt >= 2) {
                    printf("Write error ");
                    end_fdu();
                    exit(2);
                } else {
                    fd_type = !o_fd_type;
                }
            }
            tmp_fd_type = fd_type;
            rcnt = 0;
            while (TRUE) {
                rcnt++;
                if (o_fd_type != fd_type) {
                    for (l = 0; l < tr_sz[o_fd_type][3]; l++) {  /* Face 1 */
                        form_data[tr_sz[o_fd_type][6]*l+pre_gap1+17] = 1;
                    }
                    ret = uDKB_format(devno[drv2], j, 1, form_data);
                }
                if (o_cf_flag == ON) {
                    if (fat_use_flag[j*2+1] == OFF) {
                        break;
                    }
                }
                ret = uDKB_write1(devno[drv2], j, 1, 1,tr_sz[o_fd_type][3],
                                  bf_p+k*trk_siz*2+trk_siz, &secnum);
                if (ret == 0) {
                    fd_type = tmp_fd_type;
                    break;
                } else if (rcnt >= 2) {
                    printf("Write error ");
                    end_fdu();
                    exit(2);
                } else {
                    fd_type = !o_fd_type;
                }
            }
        }
        track += bf_siz[i];
    }
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void fd_copy_mem(int drv1, int drv2, int loop, int *bf_siz,
                 ulong trk_siz, uchar huge *bf_p)
{
    int  i, j, k, l;
    int  ret, secnum, pre_gap1, track, rcnt = 0, tmp_fd_type;

    for (i = 0, track = 0; i < loop; i++) {
        if (drv1 == drv2 && i != 0) {
            CSL_TOP();
            printf("%c:(dst) Change disk. [Push Any Key]", 'A'+drv1);
            getch();
            DEL_STR_TOP();
            fd_read_ready(drv1);                  /* Destination or Src Drive */
        }
        for (j = track, k = 0; j < track+bf_siz[i]; j++, k++) {
            while (TRUE) {
                if (o_cf_flag == ON) {
                    if (fat_use_flag[j*2] == OFF) {
                        break;
                    }
                }
                CSL_TOP();
                printf("%02d/%02d Track Read  ", j, tr_sz[o_fd_type][4]-1);
                rcnt++;
                ret = uDKB_read1(devno[drv1], j, 0, 1,tr_sz[o_fd_type][3],
                                 bf_p+k*trk_siz*2, &secnum);
                if (ret == 0) {
                    rcnt = 0;
                    break;
                } else if (rcnt >= 2) {
                    printf("Read error [%x]", ret);
                    end_fdu();
                    exit(2);
                }
            }
            while (TRUE) {
                if (o_cf_flag == ON) {
                    if (fat_use_flag[j*2+1] == OFF) {
                        break;
                    }
                }
                rcnt++;
                ret = uDKB_read1(devno[drv1], j, 1, 1,tr_sz[o_fd_type][3],
                                 bf_p+k*trk_siz*2+trk_siz, &secnum);
                if (ret == 0) {
                    rcnt = 0;
                    break;
                } else if (rcnt >= 2) {
                    printf("Read error [%x]", ret);
                    end_fdu();
                    exit(2);
                }
            }
        }

        if (drv1 == drv2) {
            CSL_TOP();
            printf("%c:(dst) Change disk. [Push Any Key]", 'A'+drv2);
            getch();
            DEL_STR_TOP();
            fd_write_ready(drv2);                 /* Destination Drive */
            if (i == 0) {
                printf("");
                while ((ret = fd_chk(drv2)) != 0) {
                    err_msg(3, drv2);
                    fd_write_ready(drv2);         /* Destination Drive */
                }
            }
        } else if (i == 0 && o_type == DCP_EMS) {
            fd_type = o_fd_type;
        }
        pre_gap1 = tr_sz[o_fd_type][22];
        for (j = track, k = 0; j < track+bf_siz[i]; j++, k++) {
            tmp_fd_type = fd_type;
            rcnt = 0;
            while (TRUE) {
                rcnt++;
                if (o_fd_type != fd_type) {
                    CSL_TOP();
                    printf("%02d/%02d Track Format", j, tr_sz[o_fd_type][4]-1);
                    for (l = 0; l < tr_sz[o_fd_type][3]; l++) {  /* Face 0 */
                        form_data[tr_sz[o_fd_type][6]*l+pre_gap1+16] = (uchar)j;
                        form_data[tr_sz[o_fd_type][6]*l+pre_gap1+17] = 0;
                    }
                    ret = uDKB_format(devno[drv2], j, 0, form_data);
                }
                if (o_cf_flag == ON) {
                    if (fat_use_flag[j*2] == OFF) {
                        break;
                    }
                }
                CSL_TOP();
                printf("%02d/%02d Track Write ", j, tr_sz[o_fd_type][4]-1);
                ret = uDKB_write1(devno[drv2], j, 0, 1,tr_sz[o_fd_type][3],
                                  bf_p+k*trk_siz*2, &secnum);
                if (ret == 0) {
                    fd_type = tmp_fd_type;
                    break;
                } else if (rcnt >= 2) {
                    printf("Write error ");
                    end_fdu();
                    exit(2);
                } else {
                    fd_type = !o_fd_type;
                }
            }
            tmp_fd_type = fd_type;
            rcnt = 0;
            while (TRUE) {
                rcnt++;
                if (o_fd_type != fd_type) {
                    for (l = 0; l < tr_sz[o_fd_type][3]; l++) {  /* Face 1 */
                        form_data[tr_sz[o_fd_type][6]*l+pre_gap1+17] = 1;
                    }
                    ret = uDKB_format(devno[drv2], j, 1, form_data);
                }
                if (o_cf_flag == ON) {
                    if (fat_use_flag[j*2+1] == OFF) {
                        break;
                    }
                }
                ret = uDKB_write1(devno[drv2], j, 1, 1,tr_sz[o_fd_type][3],
                                  bf_p+k*trk_siz*2+trk_siz, &secnum);
                if (ret == 0) {
                    fd_type = tmp_fd_type;
                    break;
                } else if (rcnt >= 2) {
                    printf("Write error ");
                    end_fdu();
                    exit(2);
                } else {
                    fd_type = !o_fd_type;
                }
            }
        }
        track += bf_siz[i];
    }
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void fd_sdump()
{
    int  track, side, err = 0, ret = 1;

    CSL_ON();
    CLS();
    while (ret) {
        CLS();
        LOCATE(0, 21);
        track = keyin_digit(0, 79, "What Track [0 - 79] ? ", "Bad Track No.");
        CLS();
        LOCATE(0, 21);
        side  = keyin_digit(0, 1,  "What Side  [0 or 1] ? ", "Bad Side  No.");
        CSL_OFF();

        ret = fd_sdump_sub(track, side);
    }
}

/*---------------------------------------------------------------------*/
/*                                                                     */
/*---------------------------------------------------------------------*/
int fd_sdump_sub(int track, int side)
{
    int   ret, no, secnum, size, code = 0, sts;
    int   end_flag, index, read_flag, tmp_size, up_flag, top_flag;
    int   disp_flag;
    uint  status, mode1, mode2;
    uchar *bf_p;

    while (TRUE) {                                /* Drive Ready ? */
        ret = uDKB_rdstatus(devno[o_drive_no[0]], &status);
        if ((status & 0x01) != 0) {
            CSL_TOP();
            printf("%c: Drive ready? [Push Any Key]", 'A'+o_drive_no[0]);
            getch();
        } else {
            break;
        }
    }
                                                  /* Fd Tyep Check */
    ret = chk_fd_type(devno[o_drive_no[0]], status, &no);

    if ((bf_p = malloc(tr_sz[no][18]*tr_sz[no][3])) == NULL) {
        puts("Memory alloc error\n");
        CSL_ON();
        exit(3);
    }

    CLS();
    end_flag  = OFF;
    read_flag = ON;
    up_flag   = OFF;
    top_flag  = OFF;

    uKYB_lock(1);                                 /* key lock */

    do {
        if (read_flag == ON) {
            memset(bf_p, 0, tr_sz[no][18]*tr_sz[no][3]);
            ret = uDKB_read(devno[o_drive_no[0]], track, side, 1, tr_sz[no][3], bf_p, &secnum);
            if (ret == 0x8088) {
                CLS();
                if (no == IBM2D8_0 || no == IBM2DD5_0) {
                    no += 1;
                } else if (no == IBM2D8_1 || no == IBM2DD5_1) {
                    no -= 1;
                }
                mode1 = tr_sz[no][0] | tr_sz[no][1] | tr_sz[no][2];
                mode2 = (tr_sz[no][5] << 8) | tr_sz[no][3];
                ret = uDKB_setmode(devno[o_drive_no[0]], mode1, mode2);
                ret = uDKB_read(devno[o_drive_no[0]], track, side, 1, tr_sz[no][3], bf_p, &secnum);
            }
            if (ret != 0) {
                COLOR_RED();
                LOCATE(59, 0);
                printf("read status [%04x]", ret);
                COLOR_WHITE();
            } else {
                LOCATE(59, 0);
                DEL_STR_END();
            }
            tmp_size = tr_sz[no][18];
            if (tr_sz[no][18] > 256) {
                size = 256;
            } else {
                size = tr_sz[no][18];
            }
            if (up_flag == OFF) {
                index = 0;
            } else {
                if (top_flag == ON) {
                    top_flag = OFF;
                    index = 0;
                } else {
                    index = tr_sz[no][18]*tr_sz[no][3] - size;
                }
            }
            up_flag   = OFF;
            read_flag = OFF;
            disp_flag = ON;
        }

        if (disp_flag == ON) {                    /* Dump */
            disp_flag = OFF;
            LOCATE(0, 0);
            printf ("%s", fd_type_msg[no]);
            LOCATE(0, 2);
            printf ("Drive:%x  Track:%02d  Side:%d  ", o_drive_no[0], track, side);
            printf("Sector:%02d/%02d  Pege:%02d/%02d",
                   (index / tr_sz[no][18])+1, tr_sz[no][3],
                   ((index & (tr_sz[no][18]-size))+size) / size, tr_sz[no][18] / size);
            LOCATE(59, 2);
            printf("%s", code_str[code]);
            LOCATE(0, 4);
            dump(bf_p+index, (long)size, code, index);
            LOCATE(0, 21);
            printf("CTRL+A(Change Media) CTRL+K(Change Code) CTRL+N(Next Track) CTRL+B(Back Track)");
            LOCATE(0, 22);
            printf("↑(Back Page) ↓(Next Page)");
            LOCATE(0, 23);
            COLOR_RED();
            printf("ESC(END)");
            COLOR_WHITE();
        }
        switch (getkey()) {                       /* Inkey */
            case CTRL_K:
                code = (code+1) & 0x7;
                disp_flag = ON;
                break;
            case CTRL_A:
                end_flag = ON;
                sts = 1;
                CSL_ON();
                CLS();
                LOCATE(0, 21);
                uKYB_lock(0);                     /* key unlock */
                o_drive_no[0] = keyin_digit(0, 3,  "What Drive [0 - 3]  ? ", "Bad Drive No.");
                break;
            case UP:
            case RLUP:
                tmp_size += size;
                if (index > 0) {
                    index -= size;
                } else {
                    if (side == 1) {
                        side = 0;
                    } else if (track != 0) {
                        track--;
                        side = 1;
                    } else {
                        top_flag = ON;
                    }
                    up_flag = ON;
                    read_flag = ON;
                }
                disp_flag = ON;
                break;
            case DOWN:
            case RLDN:
                tmp_size -= size;
                if (index + size < tr_sz[no][18]*tr_sz[no][3]) {
                    index += size;
                } else {
                    if (side == 1) {
                        track++;
                        side = 0;
                    } else {
                        side = 1;
                    }
                    read_flag = ON;
                }
                disp_flag = ON;
                break;
            case CTRL_B:
                if (side == 1) {
                    side = 0;
                } else {
                    if (track != 0) {
                        track--;
                        side = 1;
                    }
                }
                read_flag = ON;
                disp_flag = ON;
                break;
            case CTRL_N:
                if (side == 1) {
                    track++;
                    side = 0;
                } else {
                    side = 1;
                }
                read_flag = ON;
                disp_flag = ON;
                break;
            case ESC:
                end_flag = ON;
                sts = 0;
                break;
            default:
                break;
        }
    } while(end_flag == OFF);

    uKYB_lock(0);                                 /* key unlock */
    free(bf_p);

    return(sts);
}

/*---------------------------------------------------------------------*/
/*                                                                     */
/*---------------------------------------------------------------------*/
int chk_fd_type(int drv, int status, int *no)
{
    int ret, ret1, secnum;
    DKB_SEC secid;
    uint mode1, mode2;
    uchar bf[1024];

    ret1 = uDKB_restore(drv);
    ret1 = uDKB_rdsecid(drv, 0, 0, &secid);

    ret = 0;
    for (*no = 0; *no < 11; (*no)++) {
        if ((tr_sz[*no][0] | tr_sz[*no][1] | tr_sz[*no][2]) ==
            ((status & 0x00F0) | secid.seccnt             )   ) {
            ret = 1;
            break;
        }
    }
    if (*no == F640) {
        ret = uDKB_read(drv, 0, 0, 1, 1, &bf[0], &secnum);
        if (bf[0x18] != 8) {
            *no = F720;
        }
    } else if (*no == F1200) {
        ret = uDKB_read(drv, 0, 0, 1, 1, &bf[0], &secnum);
        if (bf[0x18] == 0x12) {
            *no = F1440;
        }
    }
    mode1 = tr_sz[*no][0] | tr_sz[*no][1] | tr_sz[*no][2];
    mode2 = (tr_sz[*no][5] << 8) | tr_sz[*no][3];

    ret1 = uDKB_setmode(drv, mode1, mode2);

    return (ret);
}

/*---------------------------------------------------------------------*/
/*                                                                     */
/*---------------------------------------------------------------------*/
int keyin_digit(int min, int max, char *msg1, char *msg2)
{
    char tmp[130];
    int  i, err = OFF, data, length;

    while(TRUE) {
        printf("%s", msg1);
        gets(tmp);
        length = strlen(tmp);
        if (length <= 0) {
            err = ON;
        } else {
            for (i = 0; i < length; i++) {
                if (isdigit(tmp[i]) == 0) {
                    err = ON;
                    break;
                } else {
                    err = OFF;
                }
            }
        }
        if (err == OFF) {
            data = atoi(tmp);
            if (data >= min && data <= max) {
                break;
            }
        }
        printf("%s\n", msg2);
    }

    return(data);
}

/*---------------------------------------------------------------------*/
/*                                                                     */
/*---------------------------------------------------------------------*/
void codecnv(int code, uchar *in, uchar *out, int n)
{
    int   i, kana_flag, kanji_flag;
    uint  tmp_in, tmp_kanji1;
    uchar tmp_char;

    switch (code) {
        case ASCII:
            memcpy(out, in, n);
            break;
        case SJIS:
            memcpy(out, in, n);
            break;
        case JIS:
            for (i = 0; i < n; i+=2) {
                tmp_in = *(in+1);
                tmp_in = (tmp_in << 8) | *in;
                jistosjis(tmp_in, (uint *)out);
                tmp_char = *out;
                *out     = *(out+1);
                *(out+1) = tmp_char;
                in += 2;
                out+= 2;
            }
            break;
        case NEC_JIS:
            for (i = 0; i < n; i+=2) {
                tmp_in = *(in+1);
                tmp_in = (tmp_in << 8) | *in;
                /*nec_jistosjis(tmp_in, (uint *)out);*/
                jistosjis(tmp_in, (uint *)out);
                tmp_char = *out;
                *out     = *(out+1);
                *(out+1) = tmp_char;
                in += 2;
                out+= 2;
            }
            break;
        case EUC:
            kana_flag  = OFF;
            kanji_flag = OFF;
            for (i = 0; i < n; i++) {
                if (kana_flag == ON) {
                    kana_flag = OFF;
                    *(out+i) = *(in+i);
                } else if (kanji_flag == ON) {
                    kanji_flag = OFF;
                    tmp_in = *(in+i) - 0x80;
                    tmp_in = (tmp_in << 8) | tmp_kanji1;
                    jistosjis(tmp_in, (uint *)(out+i));
                    tmp_char   = *(out+i-1);
                    *(out+i-1) = *(out+i);
                    *(out+i)   = tmp_char;
                } else if (*(in+i) >= 0 && *(in+i) <= 0x7f) {
                    *(out+i)   = *(in+i);
                } else if (*(in+i) == 0x8e) {
                    kana_flag = ON;
                    *(out+i)   = 0x20;
                } else if ((*(in+i) >= 0xa1) && ((n > i+1) && (*(in+i+1) >= 0xa1))) {
                    kanji_flag = ON;
                    tmp_kanji1 = *(in+i) - 0x80;
                } else {
                    *(out+i)   = *(in+i);
                    *(out+i+1) = *(in+i+1);
                }
            }
            break;
        case EBCDIC:
            ibmcnv(2, in, out, n);
            break;
        case EBCDIK:
            ibmcnv(4, in, out, n);
            break;
        case UNICODE:
            memcpy(out, in, n);
            break;
        default:
            break;
    }
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/* ibmcnv  =  ebcdic <-> jis, ebcdik <-> jis    code converter       */
/*                                                                   */
/*   mode   1 -- jis    -> ebcdic     2 -- ebcdic -> jis             */
/*          3 -- jis    -> ebcdik     4 -- ebcdik -> jis             */
/*   *in    strings                                                  */
/*   *out   strings                                                  */
/*   n      data length                                              */
/*                                                                   */
/*-------------------------------------------------------------------*/
void ibmcnv(int mode, uchar *in, uchar *out, int n)
{
    static uchar jis2ebc[256] = { /* jis -> ebcdic */
        0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, /* 0x00 */
        0x16, 0x40, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08 */
        0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, /* 0x10 */
        0x18, 0x19, 0x40, 0x27, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18 */
        0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, /* 0x20 */
        0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61, /* 0x28 */
        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x30 */
        0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f, /* 0x38 */
        0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x40 */
        0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, /* 0x48 */
        0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, /* 0x50 */
        0xe7, 0xe8, 0xe9, 0xc0, 0xe0, 0xd0, 0x6a, 0x6d, /* 0x58 */
        0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x60 */
        0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, /* 0x68 */
        0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, /* 0x70 */
        0xa7, 0xa8, 0xa9, 0xa0, 0x4f, 0xb0, 0x5f, 0x07, /* 0x78 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0x80 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0x88 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0x90 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0x98 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xa0 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xa8 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xb0 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xb8 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xc0 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xc8 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xd0 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xd8 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xe0 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xe8 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xf0 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40  /* 0xf8 */
    };
    static uchar jis2ebk[256] = { /* jis -> ebcdik */
        0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, /* 0x00 */
        0x16, 0x40, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08 */
        0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, /* 0x10 */
        0x18, 0x19, 0x40, 0x27, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18 */
        0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, /* 0x20 */
        0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61, /* 0x28 */
        0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x30 */
        0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f, /* 0x38 */
        0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x40 */
        0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, /* 0x48 */
        0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, /* 0x50 */
        0xe7, 0xe8, 0xe9, 0xc0, 0xe0, 0xd0, 0x6a, 0x6d, /* 0x58 */
        0x79, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0x60 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0x68 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0x70 */
        0x40, 0x40, 0xa9, 0xa0, 0x4f, 0xb0, 0x5f, 0x07, /* 0x78 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0x80 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0x88 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0x90 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0x98 */
        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0xa0 */
        0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* 0xa8 */
        0x58, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0xb0 */
        0x88, 0x89, 0x8a, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, /* 0xb8 */
        0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, /* 0xc0 */
        0x99, 0x9a, 0x9d, 0x9e, 0x9f, 0xa2, 0xa3, 0xa4, /* 0xc8 */
        0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xac, 0xad, /* 0xd0 */
        0xae, 0xaf, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xd8 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xe0 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xe8 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* 0xf0 */
        0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40  /* 0xf8 */
    };
    static uchar ebc2jis[256] = { /* ebcdic -> jis */
        0x00, 0x01, 0x02, 0x03, 0x20, 0x09, 0x20, 0x7f, /* 0x00 */
        0x20, 0x20, 0x20, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08 */
        0x10, 0x11, 0x12, 0x13, 0x20, 0x20, 0x08, 0x20, /* 0x10 */
        0x18, 0x19, 0x20, 0x20, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18 */
        0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x17, 0x1b, /* 0x20 */
        0x20, 0x20, 0x20, 0x20, 0x20, 0x05, 0x06, 0x07, /* 0x28 */
        0x20, 0x20, 0x16, 0x20, 0x20, 0x20, 0x20, 0x04, /* 0x30 */
        0x20, 0x20, 0x20, 0x20, 0x14, 0x15, 0x20, 0x1a, /* 0x38 */
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0x40 */
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0x48 */
        0x26, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0x50 */
        0xb0, 0x20, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x7e, /* 0x58 */
        0x2d, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0x60 */
        0x20, 0x20, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f, /* 0x68 */
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0x70 */
        0x20, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, /* 0x78 */
        0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x80 */
        0x68, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0x88 */
        0x20, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, /* 0x90 */
        0x71, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0x98 */
        0x7b, 0x20, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, /* 0xa0 */
        0x79, 0x7a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0xa8 */
        0x7d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0xb0 */
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0xb8 */
        0x5b, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0xc0 */
        0x48, 0x49, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0xc8 */
        0x5d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* 0xd0 */
        0x51, 0x52, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0xd8 */
        0x5c, 0x20, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, /* 0xe0 */
        0x59, 0x5a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0xe8 */
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0xf0 */
        0x38, 0x39, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20  /* 0xf8 */
    };
    static uchar ebk2jis[256] = { /* ebcdik -> jis */
        0x00, 0x01, 0x02, 0x03, 0x20, 0x09, 0x20, 0x7f, /* 0x00 */
        0x20, 0x20, 0x20, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08 */
        0x10, 0x11, 0x12, 0x13, 0x20, 0x20, 0x08, 0x20, /* 0x10 */
        0x18, 0x19, 0x20, 0x20, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18 */
        0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x17, 0x1b, /* 0x20 */
        0x20, 0x20, 0x20, 0x20, 0x20, 0x05, 0x06, 0x07, /* 0x28 */
        0x20, 0x20, 0x16, 0x20, 0x20, 0x20, 0x20, 0x04, /* 0x30 */
        0x20, 0x20, 0x20, 0x20, 0x14, 0x15, 0x20, 0x1a, /* 0x38 */
        0x20, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x40 */
        0xa8, 0xa9, 0x20, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, /* 0x48 */
        0x26, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0x20, /* 0x50 */
        0xb0, 0x20, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x7e, /* 0x58 */
        0x2d, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0x60 */
        0x20, 0x20, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f, /* 0x68 */
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0x70 */
        0x20, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, /* 0x78 */
        0x20, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0x80 */
        0xb8, 0xb9, 0xba, 0x20, 0xbb, 0xbc, 0xbd, 0xbe, /* 0x88 */
        0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, /* 0x90 */
        0xc7, 0xc8, 0xc9, 0x20, 0x20, 0xca, 0xcb, 0xcc, /* 0x98 */
        0x7b, 0x20, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, /* 0xa0 */
        0xd3, 0xd4, 0xd5, 0x20, 0xd6, 0xd7, 0xd8, 0xd9, /* 0xa8 */
        0x7d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0xb0 */
        0x20, 0x20, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xb8 */
        0x5b, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0xc0 */
        0x48, 0x49, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0xc8 */
        0x5d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* 0xd0 */
        0x51, 0x52, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0xd8 */
        0x5c, 0x20, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, /* 0xe0 */
        0x59, 0x5a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /* 0xe8 */
        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0xf0 */
        0x38, 0x39, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20  /* 0xf8 */
    };
    int  i;

    switch (mode) {
        case 0:
            for (i = 0; i < n; i++) {
                out[i] = jis2ebc[in[i]];
            }
            break;
        case 2:
            for (i = 0; i < n; i++) {
                out[i] = ebc2jis[in[i]];
            }
            break;
        case 3:
            for (i = 0; i < n; i++) {
                out[i] = jis2ebk[in[i]];
            }
            break;
        case 4:
            for (i = 0; i < n; i++) {
                out[i] = ebk2jis[in[i]];
            }
            break;
        default:
            for (i = 0; i < n; i++) {
                out[i] = in[i];
            }
            break;
    }
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
int sjistojis(uint data, uint *out)
{
    union  REGS  inregs, outregs;
    int    ret;

    inregs.h.ah = 0x04;                 /* 機能コード   */
    inregs.x.dx = data;
    int86(0xAF, &inregs, &outregs);
    ret = outregs.h.ah;
    *out = outregs.x.dx;

    return (ret);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
int jistosjis(uint data, uint *out)
{
    union  REGS  inregs, outregs;
    int    ret;

    inregs.h.ah = 0x03;                 /* 機能コード   */
    inregs.x.dx = data;
    int86(0xAF, &inregs, &outregs);
    ret = outregs.h.ah;
    *out = outregs.x.dx;

    return (ret);
}

/*---------------------------------------------------------------------*/
/*                                                                     */
/*---------------------------------------------------------------------*/
int uKYB_lock(int mode)
{
    union  REGS  inregs, outregs;

    inregs.h.ah = 0x04;
    inregs.h.al = mode;
    int86(0x90, &inregs, &outregs);
    return ((int)outregs.h.ah);
}

/*---------------------------------------------------------------------*/
/*  キー入力処理                                                       */
/*---------------------------------------------------------------------*/
int getkey(void)
{
    union  REGS  inregs, outregs;

    inregs.h.ah = 0x07;
    uKYB_lock(0);                                 /* unlock */
    intdos(&inregs, &outregs);
    uKYB_lock(1);                                 /* lock   */
    return ((int)outregs.h.al);
}

/*---------------------------------------------------------------------*/
/*                                                                     */
/*---------------------------------------------------------------------*/
void dump(uchar buf[], long size, int code, int index)
{
    long no = 0;
    int  i, sjis_flag;
    uchar tmp_buf[256];

    if (code != -1) {
        codecnv(code, &buf[no], &tmp_buf[0], (int)size);
    }
    do {
        printf("%08X "
               "%02X %02X %02X %02X %02X %02X %02X %02X-"
               "%02X %02X %02X %02X %02X %02X %02X %02X   ",
               index,
               buf[no+0], buf[no+1], buf[no+2], buf[no+3], buf[no+4], buf[no+5], buf[no+6], buf[no+7],
               buf[no+8], buf[no+9], buf[no+10],buf[no+11],buf[no+12],buf[no+13],buf[no+14],buf[no+15]);

        sjis_flag = OFF;
        for (i = 0; i < 16; i++) {
            if (code == -1) {
                if ((buf[no+i] >= 0x20 && buf[no+i] <= 0x7f) ||
                    (buf[no+i] >= 0xa1 && buf[no+i] <= 0xdf)  ) {
                    putchar(buf[no+i]);
                } else {
                    putchar('.');
                }
            } else if (tmp_buf[no+i] >= 0 && tmp_buf[no+i] <= 0x1f) {
                putchar('.');
            } else {
                if (code == ASCII) {
                    if ((tmp_buf[no+i] >= 0x20 && tmp_buf[no+i] <= 0x7f) ||
                        (tmp_buf[no+i] >= 0xa1 && tmp_buf[no+i] <= 0xdf)  ) {
                        putchar(tmp_buf[no+i]);
                    } else {
                        putchar('.');
                    }
                } else if (code == EBCDIC) {
                    if (tmp_buf[no+i] >= 0x20 && tmp_buf[no+i] <= 0x7f) {
                        putchar(tmp_buf[no+i]);
                    } else {
                        putchar('.');
                    }
                } else if (code == EBCDIK) {
                    if ((tmp_buf[no+i] >= 0x20 && tmp_buf[no+i] <= 0x5f) ||
                        (tmp_buf[no+i] >= 0xa1 && tmp_buf[no+i] <= 0xdf)  ) {
                        putchar(tmp_buf[no+i]);
                    } else {
                        putchar('.');
                    }
                } else {
                    if (sjis_flag == ON) {
                        sjis_flag = OFF;
                        putchar(tmp_buf[no+i]);
                    } else if (iskanji((uint)tmp_buf[no+i]) != FALSE) {
                        if (i == 15) {
                            if (no == 15) {
                                putchar('.');
                            } else if (iskanji2((uint)tmp_buf[no+i+1]) == FALSE) {
                                putchar('.');
                            } else {
                                putchar(tmp_buf[no+i]);
                                putchar(tmp_buf[no+i+1]);
                            }
                        } else if (iskanji2((uint)tmp_buf[no+i+1]) != FALSE) {
                            sjis_flag = ON;
                            putchar(tmp_buf[no+i]);
                        } else {
                            putchar('.');
                        }
                    } else if (isascii(tmp_buf[no+i])) {
                        putchar(tmp_buf[no+i]);
                    } else {
                        putchar('.');
                    }
                }
            }
        }
        putchar (0x0a);

        index = index + 16;
        no    = no + 16;
    } while (no < size);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
int ems_chk(void)
{
    union  REGS inregs, outregs;
    int  ret = 1, fhdl;
                                                  /* EMSの常駐の確認 */
    if ((fhdl = open("EMMXXXX0", O_RDONLY)) != -1) {
        inregs.x.ax = 0x4400;
        inregs.x.bx = fhdl;
        intdos(&inregs, &outregs);
        if ((outregs.x.dx & 0x0080) != 0) {       /* Device or File ? */
            inregs.h.ah = 0x40;
            int86(0x67, &inregs, &outregs);
            if (outregs.h.ah == 0) {              /* Get Status */
                inregs.h.ah = 0x46;
                int86(0x67, &inregs, &outregs);
                if (outregs.h.ah == 0) {          /* Get Version */
                    if (outregs.h.al >= 0x40) {
                        ret = 0;
                    }
                }
            }
        }
    }
    return(ret);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
int ems_alloc(ulong *adr, int *handle)
{
    union  REGS inregs, outregs;
    struct SREGS segregs;
    uint i;
    int  ret = 1, tmp;
    int  free_page, alloc_page;
    static uint map[256];
    static uint far *p;

    while (1) {
        inregs.h.ah = 0x42;
        int86(0x67, &inregs, &outregs); /* Get Uballocated Page Count */
        if (outregs.h.ah != (uchar)0) {
            break;
        }
        free_page = outregs.x.bx;
        tmp = (16*4)/((tr_sz[o_fd_type][18]*tr_sz[o_fd_type][3]*2)/1024);
        alloc_page = tr_sz[o_fd_type][4] * 4 / tmp;
        if ((tmp = alloc_page % 4) != 0) {
            alloc_page+=(4-tmp);
        }
        if (free_page < alloc_page) {
            break;
        }
        inregs.h.ah = 0x43;
        inregs.x.bx = alloc_page;
        int86(0x67, &inregs, &outregs);           /* Allocated Pages */
        if (outregs.h.ah != 0) {
            break;
        }
        *handle = outregs.x.dx;
        inregs.h.ah = 0x41;     
        int86(0x67, &inregs, &outregs);           /* Get Page Frame Address */
        if (outregs.h.ah != 0) {
            break;
        }
        *adr = ((ulong)outregs.x.bx << 16);
        p = map;
        inregs.x.ax = 0x5800;
        segregs.es  = FP_SEG(p);
        inregs.x.di = FP_OFF(p);                  /* Get Mappable Physical Address Array */
        int86x(0x67, &inregs, &outregs, &segregs);
        if (outregs.x.cx < 4 && outregs.h.ah != 0) {
            break;
        }
        for (i = 0; i < outregs.x.cx; i++) {
            if (map[i*2] == (uint)(*adr>>16)) {
                if (map[i*2+1]     == 0 && map[(i+1)*2+1] == 1 &&
                    map[(i+2)*2+1] == 2 && map[(i+3)*2+1] == 3   ) {
                    ret = 0;
                    break;
                }
            }
        }
        break;
    }
    return(ret);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
int ems_map(int far *map, int handle)
{
    union  REGS inregs, outregs;
    struct SREGS segregs;
    int    ret = 0;

    inregs.x.ax = 0x5000;                         /* Map Multiple Pages */
    inregs.x.dx = handle;
    inregs.x.cx = 4;
    segregs.ds  = FP_SEG(map);
    inregs.x.si = FP_OFF(map);
    int86x(0x67, &inregs, &outregs, &segregs);
    if (outregs.h.ah != 0) {
        printf("ems_map err(%02x)\n", outregs.h.ah);
        ret = 1;
    }
    return (ret);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
int ems_free(int handle)
{
    union  REGS inregs, outregs;
    int  ret = 0;

    inregs.h.ah = 0x45;                           /* Deallocate Pages */
    inregs.x.dx = handle;
    int86(0x67, &inregs, &outregs);
    if (outregs.h.ah != 0) {
        ret = 1;
    }
    return (ret);
}

/*-------------------------------------------------------------------*/
/* Checking Ready and Write Protect                                  */
/*-------------------------------------------------------------------*/
void fd_write_ready(int drv)
{
    uint status;
    int  ret;

    while (1) {
        ret = uDKB_rdstatus(devno[drv], &status);
        if ((status & 0x01) != 0) {
            CSL_TOP();
            printf("%c: Drive ready? [Push Any Key]", 'A'+drv);
            getch();
            DEL_STR_TOP();
        } else if ((status & 0x02) != 0) {
            CSL_TOP();
            printf("%c: Can't write then push any key after release it's protect.",
                   'A'+drv);
            getch();
            DEL_STR_TOP();
        } else {
            break;
        }
    }
}

/*-------------------------------------------------------------------*/
/* Check Ready and Can Format this type                              */
/*-------------------------------------------------------------------*/
void get_fd_type(int drv)
{
    uint  status;
    int   i, ret, secnum;
    DKB_SEC secid;
    uchar bf[1024];

    while (1) {
        ret = uDKB_rdstatus(devno[drv], &status);
        if ((status & 0x01) != 0) {
            CSL_TOP();
            printf("%c: Drive ready? [Push Any Key]", 'A'+drv);
            getch();
            DEL_STR_TOP();
        } else {
            break;
        }
    }
    o_fd_type = 0xffff;
                                                  /* o_fd_type set */
    if ((ret = uDKB_rdsecid(devno[drv], 0, 0, &secid)) == 0) {
        for (i = 0; i <= 5; i++) {
            if ((uint)(tr_sz[i][0] | tr_sz[i][1]) == (status & 0x00F0)) {
                if (secid.seccnt == (uchar)tr_sz[i][2]) {
                    o_fd_type = i;
                    break;
                }
            }
        }
        if (o_fd_type == F640) {
            ret = uDKB_read(devno[drv], 0, 0, 1, 1, &bf[0], &secnum);
            if (bf[0x18] != 8) {
                o_fd_type = F720;
            }
        } else if (o_fd_type == F1200) {
            ret = uDKB_read(devno[drv], 0, 0, 1, 1, &bf[0], &secnum);
            if (bf[0x18] == 0x12) {
                o_fd_type = F1440;
            }
        }
    }
}

/*-------------------------------------------------------------------*/
/* Check Drive Ready                                                 */
/*-------------------------------------------------------------------*/
void fd_read_ready(int drv)
{
    uint status;
    int  ret;

    while (1) {
        ret = uDKB_rdstatus(devno[drv], &status);
        if ((status & 0x01) != 0) {
            CSL_TOP();
            printf("%c: Drive ready? [Push Any Key]", 'A'+drv);
            getch();
            DEL_STR_TOP();
        } else {
            break;
        }
    }
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
int fd_set_mode(int drv)
{
    int  ret;
    uint mode1, mode2;

    mode1 = tr_sz[o_fd_type][0] | tr_sz[o_fd_type][1] | tr_sz[o_fd_type][2];
    mode2 = (tr_sz[o_fd_type][5] << 8) | tr_sz[o_fd_type][3];
    ret = uDKB_setmode(devno[drv], mode1, mode2);
    return(ret);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
int fd_chk(int drv)
{
    int   i, ret = 0, ret1 = 0, ret2 = 0, ret3 = 0;
    int   secnum, pre_gap1;
    uchar bf[1024];
    uint  status;
    DKB_SEC secid;

    fd_type = 0xffff;
    if (o_type != FRM) {
        if ((ret = uDKB_rdstatus(devno[drv], &status))     == 0 &&
            (ret = uDKB_rdsecid(devno[drv], 0, 0, &secid)) == 0   ) {
            for (i = 0; i <= 5; i++) {
                if ((uint)(tr_sz[i][0] | tr_sz[i][1]) == (status & 0x00F0)) {
                    if (secid.seccnt == (uchar)tr_sz[i][2]) {
                        fd_type = i;
                        break;
                    }
                }
            }
            if (fd_type == F640) {
                ret = uDKB_read(devno[drv], 0, 0, 1, 1, &bf[0], &secnum);
                if (bf[0x18] != 8) {
                    fd_type = F720;
                }
            } else if (fd_type == F1200) {
                ret = uDKB_read(devno[drv], 0, 0, 1, 1, &bf[0], &secnum);
                if (bf[0x18] == 0x12) {
                    fd_type = F1440;
                }
            }
        }
    }
    if (fd_type != o_fd_type) {
        if (fd_set_mode(drv) == 2) {
            printf("\"1440k FD\" can't support.");
            CSL_ON();
            exit(5);
        }
        ret = uDKB_restore(devno[drv]);
        pre_gap1 = tr_sz[o_fd_type][22];
        for (i = 0; i < tr_sz[o_fd_type][3]; i++) {
            form_data[tr_sz[o_fd_type][6]*i+pre_gap1+16] = 0;
            form_data[tr_sz[o_fd_type][6]*i+pre_gap1+17] = 0;
        }
        ret1 = uDKB_format(devno[drv], 0, 0, form_data);
        ret2 = uDKB_chksec(devno[drv], 0, 0, 1, 1, &secnum);
        ret3 = uDKB_read(devno[drv], 0, 0, 1, 1, &bf[0], &secnum);
    }

    if (!(ret1 == 0 && ret2 == 0 && ret3 == 0)) {
        ret = 1;
    } else {
        ret = 0;
    }

    return(ret);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void time_get(int *min, int *sec, int *hsec)
{
    union  REGS  inregs, outregs;

    inregs.h.ah = 0x2c;
    intdos(&inregs, &outregs);
    *min  = outregs.h.cl;
    *sec  = outregs.h.dh;
    *hsec = outregs.h.dl;
}

/*-------------------------------------------------------------------*/
/*  CTRL+C Interrupt Routine                                         */
/*-------------------------------------------------------------------*/
void interrupt far ctrl_c(void)
{
    end_fdu();
    exit(10);
}

/*-------------------------------------------------------------------*/
/*                                                                   */
/*-------------------------------------------------------------------*/
void end_fdu(void)
{
    union  REGS inregs, outregs;

    if (ems_flag == ON) {
        inregs.h.ah = 0x45;                       /* EMS 使用領域の解放 */
        inregs.x.dx = ems_handle;
        int86(0x67, &inregs, &outregs);
    }

    if (fd_mode_sts == 1) {
        old_fd_mode_set(&old_mode1[0], &old_mode2[0]);
    }

    COLOR_RED();
    printf("Abnormal end");
    COLOR_WHITE();
    CSL_ON();
}

/*-------------------------------------------------------------------*/
/* ドライブモードの設定  (FD)                                        */
/*-------------------------------------------------------------------*/
int uDKB_setmode(int devno, uint mode1, uint mode2)
{
    union  REGS  inregs, outregs;
    int    ret;

    inregs.h.ah = 0x00;                 /* 機能コード   */
    inregs.h.al = (uchar)devno;         /* デバイス番号 */
    inregs.h.dl = (uchar)mode1;         /* ドライブモード１ */
    inregs.x.bx = mode2;                /* ドライブモード２ */
    int86(0x93, &inregs, &outregs);
    ret = outregs.h.ah;

    return (ret);
}

/*-------------------------------------------------------------------*/
/*  ドライブモードの取り出し  (FD)                                   */
/*-------------------------------------------------------------------*/
int uDKB_rdmode(int devno, uint *mode1, uint *mode2)
{
    union  REGS  inregs, outregs;
    int    ret;

    inregs.h.ah = 0x01;                 /* 機能コード   */
    inregs.h.al = (uchar)devno;         /* デバイス番号 */
    int86(0x93, &inregs, &outregs);
    *mode1 = outregs.h.dl;              /* ドライブモード１ */
    *mode2 = outregs.x.bx;              /* ドライブモード２ */
    ret = outregs.h.ah;

    return (ret);
}

/*-------------------------------------------------------------------*/
/* ドライブステータ情報の取り出し  (FD)                              */
/*-------------------------------------------------------------------*/
int uDKB_rdstatus(int devno, uint *status)
{
    union  REGS  inregs, outregs;
    int    ret;

    inregs.h.ah = 0x02;                 /* 機能コード   */
    inregs.h.al = (uchar)devno;         /* デバイス番号 */
    inregs.h.ch = 0x00;                 /*              */
    int86(0x93, &inregs, &outregs);
    *status = outregs.h.dl;
    ret = outregs.h.ah;
    if (ret == 0x80) {
        ret = (outregs.h.ah << 8) | (outregs.x.cx & 0x00ff );
    }

    return (ret);
}

/*-------------------------------------------------------------------*/
/* シリンダ０へのシーク  (FD)                                        */
/*-------------------------------------------------------------------*/
int uDKB_restore(int devno)
{
    union  REGS  inregs, outregs;
    int    ret;
 
    inregs.h.ah = 0x03;                 /* 機能コード   */
    inregs.h.al = (uchar)devno;         /* デバイス番号 */
    inregs.x.cx = 0x00;
    int86(0x93, &inregs, &outregs);
    ret = outregs.h.ah;
    if (ret == 0x80) {
        ret = (outregs.h.ah << 8) | (outregs.x.cx & 0x00ff );
    }

    return (ret);
}

/*-------------------------------------------------------------------*/
/*  データの読み込み  (FD)                                           */
/*-------------------------------------------------------------------*/
int uDKB_read(int  devno, int cylno, int headno, int secno, int seccnt,
              uchar *bf_p,  int *secnum)
{
    union  REGS  inregs, outregs;
    struct SREGS segregs;
    int    ret;

    inregs.h.ah = 0x05;                 /* 機能コード   */
    inregs.h.al = (uchar)devno;         /* デバイス番号 */
    inregs.x.cx = cylno;                /* シリンダ番号 */
    inregs.h.dh = (uchar)headno;        /* ベッド番号   */
    inregs.h.dl = (uchar)secno;         /* セクタ番号   */
    inregs.x.bx = seccnt;               /* セクタ数     */
    segread(&segregs);
    inregs.x.di = FP_OFF(bf_p);
    int86x(0x93, &inregs, &outregs, &segregs);
    *secnum = outregs.x.bx;
    ret = outregs.h.ah;
    if (ret == 0x80) {
        ret = (outregs.h.ah << 8) | (outregs.x.cx & 0x00ff );
    }

    return (ret);
}

/*-------------------------------------------------------------------*/
/*  データの読み込み  (FD)                                           */
/*-------------------------------------------------------------------*/
int uDKB_read1(int  devno, int cylno, int headno, int secno, int seccnt,
              uchar huge *bf_p,  int *secnum)
{
    union  REGS  inregs, outregs;
    struct SREGS segregs;
    int    ret;

    inregs.h.ah = 0x05;                 /* 機能コード   */
    inregs.h.al = (uchar)devno;         /* デバイス番号 */
    inregs.x.cx = cylno;                /* シリンダ番号 */
    inregs.h.dh = (uchar)headno;        /* ベッド番号   */
    inregs.h.dl = (uchar)secno;         /* セクタ番号   */
    inregs.x.bx = seccnt;               /* セクタ数     */
    segregs.ds  = FP_SEG(bf_p);
    inregs.x.di = FP_OFF(bf_p);
    int86x(0x93, &inregs, &outregs, &segregs);
    *secnum = outregs.x.bx;
    ret = outregs.h.ah;
    if (ret == 0x80) {
        ret = (outregs.h.ah << 8) | (outregs.x.cx & 0x00ff );
    }

    return (ret);
}

/*-------------------------------------------------------------------*/
/* データの書き込み  (FD)                                            */
/*-------------------------------------------------------------------*/
int uDKB_write(int devno, int cylno, int headno, int secno, int seccnt,
              uchar *bf_p, int *secnum)
{
    union  REGS  inregs, outregs;
    struct SREGS segregs;
    int    ret;

    inregs.h.ah = 0x06;                 /* 機能コード   */
    inregs.h.al = (uchar)devno;         /* デバイス番号 */
    inregs.x.cx = cylno;                /* シリンダ番号 */
    inregs.h.dh = (uchar)headno;        /* ベッド番号   */
    inregs.h.dl = (uchar)secno;         /* セクタ番号   */
    inregs.x.bx = seccnt;               /* セクタ数     */
    segread(&segregs);
    inregs.x.di = FP_OFF(bf_p);
    int86x(0x93, &inregs, &outregs, &segregs);
    *secnum = outregs.x.bx;
    ret = outregs.h.ah;
    if (ret == 0x80) {
        ret = (outregs.h.ah << 8) | (outregs.x.cx & 0x00ff );
    }

    return (ret);
}

/*-------------------------------------------------------------------*/
/* データの書き込み  (FD)                                            */
/*-------------------------------------------------------------------*/
int uDKB_write1(int devno, int cylno, int headno, int secno, int seccnt,
              uchar huge *bf_p, int *secnum)
{
    union  REGS  inregs, outregs;
    struct SREGS segregs;
    int    ret;

    inregs.h.ah = 0x06;                 /* 機能コード   */
    inregs.h.al = (uchar)devno;         /* デバイス番号 */
    inregs.x.cx = cylno;                /* シリンダ番号 */
    inregs.h.dh = (uchar)headno;        /* ベッド番号   */
    inregs.h.dl = (uchar)secno;         /* セクタ番号   */
    inregs.x.bx = seccnt;               /* セクタ数     */
    segregs.ds  = FP_SEG(bf_p);
    inregs.x.di = FP_OFF(bf_p);
    int86x(0x93, &inregs, &outregs, &segregs);
    *secnum = outregs.x.bx;
    ret = outregs.h.ah;
    if (ret == 0x80) {
        ret = (outregs.h.ah << 8) | (outregs.x.cx & 0x00ff );
    }

    return (ret);
}

/*-------------------------------------------------------------------*/
/*  セクタの検査  (FD)                                               */
/*-------------------------------------------------------------------*/
int uDKB_chksec(int devno, int cylno, int headno, int secno, int seccnt,
                int *secnum)
{
    union  REGS  inregs, outregs;
    int    ret;

    inregs.h.ah = 0x07;                 /* 機能コード   */
    inregs.h.al = (uchar)devno;         /* デバイス番号 */
    inregs.x.cx = cylno;                /* シリンダ番号 */
    inregs.h.dh = (uchar)headno;        /* ベッド番号   */
    inregs.h.dl = (uchar)secno;         /* セクタ番号   */
    inregs.x.bx = seccnt;               /* セクタ数     */
    int86(0x93, &inregs, &outregs);
    *secnum = outregs.x.bx;
    ret = outregs.h.ah;
    if (ret == 0x80) {
        ret = (outregs.h.ah << 8) | (outregs.x.cx & 0x00ff );
    }

    return (ret);
}

/*-------------------------------------------------------------------*/
/* セクタＩＤの取り出し  (FD)                                        */
/*-------------------------------------------------------------------*/
int uDKB_rdsecid(int devno, int cylno, int headno, DKB_SEC *secid)
{
    union  REGS  inregs, outregs;
    struct SREGS segregs;
    int    ret;

    inregs.h.ah = 0x09;                 /* 機能コード   */
    inregs.h.al = (uchar)devno;         /* デバイス番号 */
    inregs.x.cx = cylno;                /*              */
    inregs.h.dh = (uchar)headno;        /*              */
    segread(&segregs);
    inregs.x.di = FP_OFF(secid);
    int86(0x93, &inregs, &outregs);
    ret = outregs.h.ah;
    if (ret == 0x80) {
        ret = (outregs.h.ah << 8) | (outregs.x.cx & 0x00ff );
    }

    return (ret);
}

/*-------------------------------------------------------------------*/
/* トラックのフォーマット  (FD)                                      */
/*-------------------------------------------------------------------*/
int uDKB_format(int devno, int cylno, int headno, uchar *bf_p)
{
    union  REGS  inregs, outregs;
    struct SREGS segregs;
    int    ret;

    inregs.h.ah = 0x0A;                 /* 機能コード   */
    inregs.h.al = (uchar)devno;         /* デバイス番号 */
    inregs.x.cx = cylno;                /* シリンダ番号 */
    inregs.h.dh = (uchar)headno;        /* ベッド番号   */
    segread(&segregs);
    inregs.x.di = FP_OFF(bf_p);
    int86x(0x93, &inregs, &outregs, &segregs);
    ret = outregs.h.ah;
    if (ret == 0x80) {
        ret = (outregs.h.ah << 8) | (outregs.x.cx & 0x00ff );
    }

    return (ret);
}

/*-------------------------------------------------------------------*/
/*  システム情報の取得                                               */
/*-------------------------------------------------------------------*/
int system_get(uchar *p)
{
    union  REGS  inregs, outregs;
    struct SREGS segregs;
    int    ret;

    inregs.h.ah = 0x00;                 /* 機能コード   */
    segread(&segregs);
    inregs.x.di = FP_OFF(p);
    int86x(0x8e, &inregs, &outregs, &segregs);
    ret = outregs.h.ah;

    return (ret);
}
