| /* Lecture des disquettes Thomson sous MS-DOS |
| * Version 2.1 |
| * Copyright (C) 2000-2003 Eric Botcazou |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| /* Limitations: |
| * - les faces 1 des disquettes ne sont pas accessibles, |
| * - les disquettes simple densité (format FM) ne sont pas lisibles. |
| */ |
| |
| #ifndef SCAN_DEPEND |
| #include <stdio.h> |
| #include <stddef.h> |
| #include <bios.h> |
| #include <dpmi.h> |
| #include <sys/movedata.h> |
| #endif |
| |
| #include "floppy.h" |
| |
| |
| #define DISK_RETRY 3 |
| |
| struct floppy_cmd { |
| int cmd; |
| int head; |
| int track; |
| int sector; |
| int nsects; |
| void *buffer; |
| }; |
| |
| static int drive_type[2]; |
| static int dpt_addr = 0; |
| |
| #define DPT_SIZE 11 |
| |
| static unsigned char pc_dpt[DPT_SIZE]; |
| |
| |
| |
| /* SetDiskParameters: |
| * Initialise les paramètres disquette pour le format Thomson. |
| */ |
| static void SetDiskParameters(int density) |
| { |
| unsigned char to_dpt[DPT_SIZE]; |
| |
| if (!dpt_addr) { |
| /* on récupère le vecteur 0x1E du BIOS qui pointe sur la table |
| des paramètres de la disquette */ |
| _dosmemgetl(0x1E*4, 1, &dpt_addr); |
| |
| /* on sauvegarde les paramètres originaux */ |
| _dosmemgetb(dpt_addr, DPT_SIZE, pc_dpt); |
| } |
| |
| /* on fixe les nouveaux paramètres */ |
| to_dpt[0x0]=0xDF; /* spec1 */ |
| to_dpt[0x1]=0x02; /* spec2 */ |
| to_dpt[0x2]=0x25; /* motor turn off delay */ |
| to_dpt[0x3]=density - 1; /* sector size = 128*2^n */ |
| to_dpt[0x4]=0x10; /* 16 sectors/track */ |
| to_dpt[0x5]=0x1B; /* gap between sectors */ |
| to_dpt[0x6]=(density == 1 ? 0x80 : 0xFF); /* data length */ |
| to_dpt[0x7]=0x2C; /* gap when formatting */ |
| to_dpt[0x8]=0xE5; /* filler byte */ |
| to_dpt[0x9]=0x0F; /* head settle time */ |
| to_dpt[0xA]=0x08; /* motor start time */ |
| _dosmemputb(to_dpt, DPT_SIZE, dpt_addr); |
| |
| /* reset */ |
| biosdisk(0, 0, 0, 0, 1, 0, NULL); |
| } |
| |
| |
| |
| /* ExecCommand: |
| * Exécute la commande spécifiée (via l'interruption 13h du BIOS). |
| */ |
| static int ExecCommand(int drive, int density, struct floppy_cmd *fd_cmd) |
| { |
| int i; |
| int ret=0x10; |
| |
| SetDiskParameters(density); |
| |
| for (i=0; i<DISK_RETRY; i++) { |
| ret=biosdisk(fd_cmd->cmd, drive, fd_cmd->head, fd_cmd->track, |
| fd_cmd->sector, fd_cmd->nsects, fd_cmd->buffer); |
| |
| if (ret==0) /* commande OK? */ |
| break; |
| |
| if ((i>1) && (ret==0x11)) { /* commande non OK mais corrigée par ctrl? */ |
| ret=0; |
| break; |
| } |
| |
| /* reset du lecteur */ |
| biosdisk(0, 0, 0, 0, 1, 0, NULL); |
| } |
| |
| switch (ret) { |
| |
| case 0x02: /* address mark not found */ |
| return 0x04; /* erreur sur l'adresse */ |
| |
| case 0x03: /* disk write-protected */ |
| return 0x01; /* disk protégé en écriture */ |
| |
| case 0x04: /* sector not found */ |
| case 0x07: /* drive parameter activity failed */ |
| case 0x10: /* data read (CRC or ECC) error */ |
| case 0x0A: /* bad sector flag detected */ |
| case 0x0B: /* bad track flag detected */ |
| return 0x08; /* erreur sur les données */ |
| |
| case 0x06: /* floppy disk removed */ |
| case 0x80: /* disk timed out or failed to respond */ |
| return 0x10; /* lecteur non prêt */ |
| |
| default: |
| return 0; /* OK */ |
| } |
| } |
| |
| |
| |
| /* FloppyReadSector: |
| * Lit le secteur spécifié sur la disquette. |
| */ |
| int FloppyReadSector(int drive, int density, int track, int sector, int nsects, unsigned char data[]) |
| { |
| struct floppy_cmd fd_cmd; |
| |
| fd_cmd.cmd = 2; |
| fd_cmd.head = drive%2; |
| fd_cmd.track = track; |
| fd_cmd.sector = sector; |
| fd_cmd.nsects = nsects; |
| fd_cmd.buffer = data; |
| |
| return ExecCommand(drive/2, density, &fd_cmd); |
| } |
| |
| |
| |
| /* FloppyWriteSector: |
| * Ecrit le secteur spécifié sur la disquette. |
| */ |
| int FloppyWriteSector(int drive, int density, int track, int sector, int nsects, const unsigned char data[]) |
| { |
| struct floppy_cmd fd_cmd; |
| |
| fd_cmd.cmd = 3; |
| fd_cmd.head = drive%2; |
| fd_cmd.track = track; |
| fd_cmd.sector = sector; |
| fd_cmd.nsects = nsects; |
| fd_cmd.buffer = (unsigned char *)data; |
| |
| return ExecCommand(drive/2, density, &fd_cmd); |
| } |
| |
| |
| |
| /* FloppyFormatTrack: |
| * Formate la piste en utilisant la table des headers spécifiée. |
| */ |
| int FloppyFormatTrack(int drive, int density, int track, const unsigned char header_table[]) |
| { |
| struct floppy_cmd fd_cmd; |
| int format_type = 0; |
| |
| /* sélection du format de formatage */ |
| switch (drive_type[drive/2]) { |
| |
| case 1: |
| /* 320/360 kb in 360 kb drive */ |
| format_type = 1; |
| break; |
| |
| case 2: |
| /* 320/360 kb in 1.2 Mb drive */ |
| format_type = 2; |
| break; |
| |
| case 3: |
| case 4: |
| case 5: |
| case 6: |
| /* 720 kb in 720 kb/1.44 Mb/2.88 Mb drive */ |
| format_type = 4; |
| break; |
| } |
| |
| biosdisk(23, drive/2, 0, 0, 1, format_type, NULL); |
| |
| fd_cmd.cmd = 5; |
| fd_cmd.head = drive%2; |
| fd_cmd.track = track; |
| fd_cmd.sector = 1; |
| fd_cmd.nsects = 16; |
| fd_cmd.buffer = (unsigned char *)header_table; |
| |
| return ExecCommand(drive/2, density, &fd_cmd); |
| } |
| |
| |
| |
| /* FloppyInit: |
| * Initialise le module de lecture de disquettes. |
| */ |
| int FloppyInit(struct floppy_info *fi, int enable_write_support) |
| { |
| __dpmi_regs r; |
| int i, num_drives = 0; |
| |
| (void) enable_write_support; |
| |
| for (i=0; i<2; i++) { |
| /* get drive parameters (int 13h, function 08h) */ |
| r.h.ah = 0x08; |
| r.h.dl = i; |
| |
| __dpmi_int(0x13, &r); |
| |
| if (r.x.flags&1) { /* CF set? */ |
| drive_type[i] = 0; |
| |
| fi->drive_type[2*i] = 0; |
| fi->drive_type[2*i+1] = 0; |
| } |
| else { |
| if (r.h.bl > 6) { |
| drive_type[i] = 0; |
| |
| fi->drive_type[2*i] = 0; |
| fi->drive_type[2*i+1] = 0; |
| } |
| else { |
| drive_type[i] = r.h.bl; |
| |
| fi->drive_type[2*i] = r.h.bl; |
| fi->drive_type[2*i+1] = 0; /* face 1 unsupported */ |
| } |
| |
| num_drives++; |
| } |
| } |
| |
| fi->num_drives = num_drives; |
| fi->fm_support = 0; |
| fi->write_support = 1; |
| |
| return num_drives; |
| } |
| |
| |
| |
| /* FloppyExit: |
| * Met au repos le module de lecture de disquettes. |
| */ |
| void FloppyExit(void) |
| { |
| if (dpt_addr) { |
| /* restaure les paramètres originaux */ |
| _dosmemputb(pc_dpt, DPT_SIZE, dpt_addr); |
| |
| /* reset */ |
| biosdisk(0, 0, 0, 0, 1, 0, NULL); |
| |
| dpt_addr = 0; |
| } |
| } |
| |