📄 old-fdc.c
字号:
/************************************************************************** * FreeDOS32 Floppy Driver * * by Salvo Isaja * * * * Copyright (C) 2003-2005, Salvatore Isaja * * * * This is "fdc.c" - Portable code for Floppy Disk Controller support * * * * * * This file is part of the FreeDOS32 Floppy Driver. * * * * The FreeDOS32 Floppy Driver 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. * * * * The FreeDOS32 Floppy Driver 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 the FreeDOS32 Floppy Driver; see the file COPYING.txt; * * if not, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * * ACKNLOWLEDGEMENT * * This file is derived from fdc.c, floppy controller handler functions * * Copyright (C) 1998 Fabian Nunez * * You can download the original library from Cottontail OS Development * * Library <http://www.0xfi.com/oslib/topx.html>, the file is FDC.ZIP * * The author can be reached by email at: fabian@cs.uct.ac.za * * or by airmail at: Fabian Nunez * * 10 Eastbrooke * * Highstead Road * * Rondebosch 7700 * * South Africa * * Floppy formats and drive parameters table are from the Linux driver * * linux/kernel/floppy.c * * Copyright (C) 1991, 1992 Linus Torvalds * * Copyright (C) 1993, 1994 Alain Knaff * **************************************************************************/#include "hos.h"#define MAXDRIVES 2 /* Newer controllers don't support 4 drives, just 2 */#define SAFESEEK 5 /* Track to seek before issuing a recalibrate *///#define HAS2FDCS//#define __DEBUG__#define LOG_PRINTF(x) printk(x)#define fd32_message printk/* This is called when fdc_logdisk is able to read sectors from the new disk. *//* It fine-tunes format probing by reading informations in the boot sector. */extern int floppy_bootsector(Fdd *fdd, const FloppyFormat *formats, unsigned num_formats);/* Floppy Drive Controller IO ports */enum{ FDC_BPRI = 0x3F0, /* Base port of the primary controller */ FDC_BSEC = 0x370, /* Base port of the secondary controller */ FDC_DOR = 0x002, /* RW: Digital Output Register */ FDC_MSR = 0x004, /* R : Main Status Register */ FDC_DRS = 0x004, /* W : Data Rate Select Register */ FDC_DATA = 0x005, /* RW: Data Register */ FDC_DIR = 0x007, /* R : Digital Input Register */ FDC_CCR = 0x007 /* W : Configuration Control Register */};/* Command bytes (these are NEC765 commands + options such as MFM, etc) */enum{ CMD_SPECIFY = 0x03, /* Specify drive timings */ CMD_WRITE = 0xC5, /* Write data (+ MT,MFM) */ CMD_READ = 0xE6, /* Read data (+ MT,MFM,SK) */ CMD_SENSEI = 0x08, /* Sense interrupt status */ //CMD_FORMAT = 0x4D, /* Format track (+ MFM) */ CMD_READID = 0x4A, /* Read sector Id (+ MFM) */ CMD_RECAL = 0x07, /* Recalibrate */ CMD_SEEK = 0x0F, /* Seek track */ CMD_VERSION = 0x10 /* Get FDC version */};/* Bits for Fdd.flags */enum{ DF_CHANGED = 1 << 0, /* Disk has been changed during the last command */ DF_SPINUP = 1 << 1, /* Motor spinup time elapsed, ready to transfer */ DF_SPINDN = 1 << 2 /* Motor spindown time started */};/* Status structure for a Floppy Disk Controller */// moved to fdc.h#ifdef MYFDC typedef struct Fdc{ unsigned base_port; /* Base port for this controller: XXX0h */ BYTE result[7]; /* Stores the result bytes returned */ BYTE result_size; /* Number of result bytes returned */ BYTE sr0; /* Status Register 0 after a sense interrupt */ BYTE dor; /* Reflects the Digital Output Register */ Fdd drive[4]; /* Drives connected to this controller */}Fdc;#endif/* All Floppy Drive Controllers issue an IRQ6 to report command completion. *//* The irq_signaled variable let us know when IRQ6 happened. *//* Since it is a global variable, this makes the driver not reentrant, thus *//* we use a simple busy flag to protect the critical sections (all... :-) *//* For the same reason, we can use just a single, shared, DMA buffer. *///static IrqSave old_irq6; /* Saves the old IRQ6 handler *//* TODO: At present we have no means to save the old IRQ6 handler */static volatile int busy = 0; /* Set if the driver is busy *///static volatile int irq_signaled = 0; /* Set if IRQ has been signaled */int irq_signaled = 0; /* Set if IRQ has been signaled *///static LOWMEM_ADDR dma_sel; /* Selector/address of DMA buf *///static DWORD dma_addr; /* Physical address of DMA buf */static Fdc pri_fdc; /* Status of the primary FDC */#ifdef HAS2FDCSstatic Fdc sec_fdc; /* Status of the secondary FDC */#endif/* Geometry and other format specifications for floppy disks */static const FloppyFormat floppy_formats[32] ={ /* SIZE SPT HD TRK STR GAP3 RATE SRHUT GAP3F NAME NR DESCRIPTION */ { 0, 0, 0, 0, 0, 0x00, 0x00, 0x00, 0x00, NULL }, /* 0 no testing */ { 720, 9, 2, 40, 0, 0x2A, 0x02, 0xDF, 0x50, "d360" }, /* 1 360KB PC */ { 2400, 15, 2, 80, 0, 0x1B, 0x00, 0xDF, 0x54, "h1200" }, /* 2 1.2MB AT */ { 720, 9, 1, 80, 0, 0x2A, 0x02, 0xDF, 0x50, "D360" }, /* 3 360KB SS 3.5" */ { 1440, 9, 2, 80, 0, 0x2A, 0x02, 0xDF, 0x50, "D720" }, /* 4 720KB 3.5" */ { 720, 9, 2, 40, 1, 0x23, 0x01, 0xDF, 0x50, "h360" }, /* 5 360KB AT */ { 1440, 9, 2, 80, 0, 0x23, 0x01, 0xDF, 0x50, "h720" }, /* 6 720KB AT */// { 2880, 18, 2, 80, 0, 0x1B, 0x00, 0xDF, 0x6C, "H1440" }, /* 7 1.44MB 3.5" */ { 2880, 18, 2, 80, 0, 0x1B, 0x00, 0xCF, 0x6C, "H1440" }, /* 7 1.44MB 3.5" */ { 5760, 36, 2, 80, 0, 0x1B, 0x43, 0xAF, 0x54, "E2880" }, /* 8 2.88MB 3.5" */ { 6240, 39, 2, 80, 0, 0x1B, 0x43, 0xAF, 0x28, "E3120" }, /* 9 3.12MB 3.5" */ { 2880, 18, 2, 80, 0, 0x25, 0x00, 0xDF, 0x02, "h1440" }, /* 10 1.44MB 5.25" */ { 3360, 21, 2, 80, 0, 0x1C, 0x00, 0xCF, 0x0C, "H1680" }, /* 11 1.68MB 3.5" */ { 820, 10, 2, 41, 1, 0x25, 0x01, 0xDF, 0x2E, "h410" }, /* 12 410KB 5.25" */ { 1640, 10, 2, 82, 0, 0x25, 0x02, 0xDF, 0x2E, "H820" }, /* 13 820KB 3.5" */ { 2952, 18, 2, 82, 0, 0x25, 0x00, 0xDF, 0x02, "h1476" }, /* 14 1.48MB 5.25" */ { 3444, 21, 2, 82, 0, 0x25, 0x00, 0xDF, 0x0C, "H1722" }, /* 15 1.72MB 3.5" */ { 840, 10, 2, 42, 1, 0x25, 0x01, 0xDF, 0x2E, "h420" }, /* 16 420KB 5.25" */ { 1660, 10, 2, 83, 0, 0x25, 0x02, 0xDF, 0x2E, "H830" }, /* 17 830KB 3.5" */ { 2988, 18, 2, 83, 0, 0x25, 0x00, 0xDF, 0x02, "h1494" }, /* 18 1.49MB 5.25" */ { 3486, 21, 2, 83, 0, 0x25, 0x00, 0xDF, 0x0C, "H1743" }, /* 19 1.74MB 3.5" */ { 1760, 11, 2, 80, 0, 0x1C, 0x09, 0xCF, 0x00, "h880" }, /* 20 880KB 5.25" */ { 2080, 13, 2, 80, 0, 0x1C, 0x01, 0xCF, 0x00, "D1040" }, /* 21 1.04MB 3.5" */ { 2240, 14, 2, 80, 0, 0x1C, 0x19, 0xCF, 0x00, "D1120" }, /* 22 1.12MB 3.5" */ { 3200, 20, 2, 80, 0, 0x1C, 0x20, 0xCF, 0x2C, "h1600" }, /* 23 1.6MB 5.25" */ { 3520, 22, 2, 80, 0, 0x1C, 0x08, 0xCF, 0x2e, "H1760" }, /* 24 1.76MB 3.5" */ { 3840, 24, 2, 80, 0, 0x1C, 0x20, 0xCF, 0x00, "H1920" }, /* 25 1.92MB 3.5" */ { 6400, 40, 2, 80, 0, 0x25, 0x5B, 0xCF, 0x00, "E3200" }, /* 26 3.20MB 3.5" */ { 7040, 44, 2, 80, 0, 0x25, 0x5B, 0xCF, 0x00, "E3520" }, /* 27 3.52MB 3.5" */ { 7680, 48, 2, 80, 0, 0x25, 0x63, 0xCF, 0x00, "E3840" }, /* 28 3.84MB 3.5" */ { 3680, 23, 2, 80, 0, 0x1C, 0x10, 0xCF, 0x00, "H1840" }, /* 29 1.84MB 3.5" */ { 1600, 10, 2, 80, 0, 0x25, 0x02, 0xDF, 0x2E, "D800" }, /* 30 800KB 3.5" */ { 3200, 20, 2, 80, 0, 0x1C, 0x00, 0xCF, 0x2C, "H1600" } /* 31 1.6MB 3.5" */};/* Parameters to manage a floppy disk drive. *//* Head load time is 16 ms for all drives except 2880 KiB, that have 15 ms. */#define MS 1000 /* From ms to us */static const DriveParams default_drive_params[] ={ /* T HLT spin_up spin_dn sel_d int_tmt Autodetect formats Nat Name */ { 0, 0, 1000*MS, 3000*MS, 20*MS, 3000*MS, { 7, 4, 8, 2, 1, 5, 3,10 }, 0, "unknown" }, { 1, 4, 1000*MS, 3000*MS, 20*MS, 3000*MS, { 1, 0, 0, 0, 0, 0, 0, 0 }, 1, "5.25\" DD, 360 KiB" }, { 2, 8, 400*MS, 3000*MS, 20*MS, 3000*MS, { 2, 5, 6,23,10,20,12, 0 }, 2, "5.25\" HD, 1200 KiB" }, { 3, 4, 1000*MS, 3000*MS, 20*MS, 3000*MS, { 4,22,21,30, 3, 0, 0, 0 }, 4, "3.5\" DD, 720 KiB" }, { 4, 8/*1*/, 400*MS, 3000*MS, 20*MS, 1500*MS, { 7, 4,25,22,31,21,29,11 }, 7, "3.5\" HD, 1440 KiB" }, { 5, 15, 400*MS, 3000*MS, 20*MS, 3000*MS, { 7, 8, 4,25,28,22,31,21 }, 8, "3.5\" ED, 2880 KiB AMI" }, { 6, 15, 400*MS, 3000*MS, 20*MS, 3000*MS, { 7, 8, 4,25,28,22,31,21 }, 8, "3.5\" ED, 2880 KiB" }};/* Constants for DMA transfers */enum{ DMA_CHANNEL = 2, /* Number of the DMA channel for floppy transfer */ DMA_PAGE = 0x81, /* Page register of that DMA channel */ DMA_OFFSET = 0x04, /* Offset register of that DMA channel */ DMA_LENGTH = 0x05 /* Length register of that DMA channel */};#ifdef MYFDC /* Sets up a DMA trasfer between a device and memory. *//* If 'read' is TRUE, then transfer will be from memory to device, *//* else from the device to memory. */static void dma_xfer(DWORD physaddr, unsigned length, int read){ DWORD page, offset; /* Calculate DMA page and offset */ page = physaddr >> 16; offset = physaddr & 0xffff; length -= 1; /* with DMA, if you want k bytes, you ask for k - 1 */ fd32_cli(); /* Disable IRQs */ fd32_outb(0x0A, DMA_CHANNEL | 4); /* Set channel mask bit */ fd32_outb(0x0C, 0); /* Clear flip flop */ fd32_outb(0x0B, (read ? 0x48 : 0x44) + DMA_CHANNEL); /* Mode (write+single+r/w) */ fd32_outb(DMA_PAGE, page); /* Page */ fd32_outb(DMA_OFFSET, offset & 0xFF); /* Offset: low byte */ fd32_outb(DMA_OFFSET, offset >> 8); /* Offset: high byte */ fd32_outb(DMA_LENGTH, length & 0xFF); /* Length: low byte */ fd32_outb(DMA_LENGTH, length >> 8); /* Length: high byte */ fd32_outb(0x0A, DMA_CHANNEL); /* Clear DMA mask bit */ fd32_sti(); /* enable IRQs */}#endif/* Sends a byte to the controller FIFO. *//* Returns FDC_TIMEOUT on timeout. */static int sendbyte(unsigned base_port, unsigned byte){ volatile unsigned msr; unsigned tmo; for (tmo = 0; tmo < 128; tmo++) { msr = fd32_inb(base_port + FDC_MSR); if ((msr & 0xC0) == 0x80) { fd32_outb(base_port + FDC_DATA, byte); return FDC_OK; } fd32_inb(0x80); /* delay */ } return FDC_TIMEOUT; /* write timeout */}/* Gets a byte from the controller FIFO. *//* Returns FDC_TIMEOUT on timeout. */static int getbyte(unsigned base_port){ volatile unsigned msr; unsigned tmo; for (tmo = 0; tmo < 128; tmo++) { msr = fd32_inb(base_port + FDC_MSR); if ((msr & 0xD0) == 0xD0) return fd32_inb(base_port + FDC_DATA); fd32_inb(0x80); /* delay */ } return FDC_TIMEOUT; /* read timeout */}/* Callback function called on IRQ6 timeout */static void irq_timeout_cb(void *params){ *((int *) params) = 1; /* Signal timeout */}#ifdef MYFDC /* Waits for FDC command to complete. Returns FDC_TIMEOUT on time out. */static int wait_fdc(Fdd *fdd){ /* Wait for IRQ6 handler to signal command finished */ volatile int irq_timeout = 0; int irq_timeout_event = fd32_event_post(fdd->dp->int_tmout, irq_timeout_cb, (void *) &irq_timeout); /* TODO: Check for FD32_EVENT_NULL */ WFC(!irq_signaled && !irq_timeout); fd32_event_delete(irq_timeout_event); /* Read in command result bytes while controller is busy */ fdd->fdc->result_size = 0; while ((fdd->fdc->result_size < 7) && (fd32_inb(fdd->fdc->base_port + FDC_MSR) & 0x10)) fdd->fdc->result[fdd->fdc->result_size++] = getbyte(fdd->fdc->base_port); irq_signaled = 0; if (irq_timeout) { LOG_PRINTF(("[FDC] Timeout!\n")); return FDC_TIMEOUT; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -