/* * Copyright (c) 2024 Jiri Svoboda * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup pci-ide * @{ */ /** @file PC Floppy Disk hardware definitions * * Based on * - NEC uPD765A datasheet * - Intel 82077AA Floppy Controller Datasheet */ #ifndef PC_FLOPPY_HW_H #define PC_FLOPPY_HW_H /** Command Codes */ typedef enum { /** Read Data */ fcc_read_data = 0x06, /** Read Delete Data */ fcc_read_ddata = 0x0c, /** Write Data */ fcc_write_data = 0x05, /** Write Deleted Data */ fcc_write_ddata = 0x09, /** Read a Track */ fcc_read_track = 0x02, /** Read ID */ fcc_read_id = 0x0a, /** Format a Track */ fcc_format_track = 0x0d, /** Scan Equal */ fcc_scan_equal = 0x11, /** Scan Low or Equal */ fcc_scan_lequal = 0x19, /** Scan High or Equal */ fcc_scan_hequal = 0x1d, /** Recalibrate */ fcc_recalibrate = 0x07, /** Sense Interrupt Status */ fcc_sense_int_sts = 0x08, /** Specify */ fcc_specify = 0x03, /** Sense Drive Status */ fcc_sense_drv_sts = 0x04, /** Seek */ fcc_seek = 0x0f } pc_fdc_cmd_code_t; /** MT|MF|SK flags used in flags_cc byte */ typedef enum { /** Multi Track */ fcf_mt = 0x80, /** FM or MFM mode */ fcf_mf = 0x40, /** Skip deleted address mark */ fcf_sk = 0x20 } pc_fcd_flags_t; /** Command parameters common for most data commands */ typedef struct { /** [MT] | MF | [SK] | command code */ uint8_t flags_cc; /** XXXXX | HD | US1 | US0 */ uint8_t hd_us; /** Cylinder number */ uint8_t cyl; /** Head number */ uint8_t head; /** Record number */ uint8_t rec; /** Number */ uint8_t number; /** End of Track */ uint8_t eot; /** Gap Length */ uint8_t gpl; /** Data Length */ uint8_t dtl; } pc_fdc_cmd_data_t; /** Status data common for most commands */ typedef struct { /** Status 0 */ uint8_t st0; /** Status 1 */ uint8_t st1; /** Status 2 */ uint8_t st2; /** Cylinder number */ uint8_t cyl; /** Head number */ uint8_t head; /** Record number */ uint8_t rec; /** Number */ uint8_t number; } pc_fdc_cmd_status_t; /** Command parameters for Read ID command */ typedef struct { /** 0 | MF | 0 | command code */ uint8_t flags_cc; /** XXXXX | HD | US1 | US0 */ uint8_t hd_us; } pc_fdc_read_id_data_t; /** Command parameters for Format a Track command */ typedef struct { /** 0 | MF | 0 | command code */ uint8_t flags_cc; /** XXXXX | HD | US1 | US0 */ uint8_t hd_us; /** Number */ uint8_t number; /** Sectors per Cylinder */ uint8_t sec_cyl; /** Gap Length */ uint8_t gpl; /** Data Pattern */ uint8_t dpat; } pc_fdc_format_track_data_t; /** Command parameters for Recalibrate command */ typedef struct { /** 0 | 0 | 0 | command code */ uint8_t cc; /** XXXXX | 0 | US1 | US0 */ uint8_t us; } pc_fdc_recalibrate_data_t; /** Command parameters for Sense Interrupt Status command */ typedef struct { /** 0 | 0 | 0 | command code */ uint8_t cc; } pc_fdc_sense_int_sts_data_t; /** Status data common for Sense Interrupt Status command */ typedef struct { /** Status 0 */ uint8_t st0; /** Present Cylinder Number */ uint8_t pcn; } pc_fdc_sense_int_sts_status_t; /** Command parameters for Specify command */ typedef struct { /** 0 | 0 | 0 | command code */ uint8_t cc; /** Step Rate Time, Head Unload Time */ uint8_t srt_hut; /** Head Load Time, Non-DMA Mode */ uint8_t hlt_nd; } pc_fdc_secify_data_t; /** Command parameters for Sense Drive Status command */ typedef struct { /** 0 | 0 | 0 | command code */ uint8_t cc; /** XXXXX | HD | US1 | US0 */ uint8_t hd_us; } pc_fdc_sense_drive_sts_data_t; /** Command parameters for Seek command */ typedef struct { /** 0 | 0 | 0 | command code */ uint8_t cc; /** XXXXX | HD | US1 | US0 */ uint8_t hd_us; } pc_fdc_seek_data_t; /** Bits in Status Register A (SRA) PS/2 Mode */ enum { fsra2_int_pending = 0x80, fsra2_ndrv2 = 0x40, fsra2_step = 0x20, fsra2_ntrk0 = 0x10, fsra2_hdsel = 0x08, fsra2_nindx = 0x04, fsra2_nwp = 0x02, fsra2_dir = 0x01 }; /** Bits in Status Register A (SRA) Model 30 Mode */ enum { fsra3_int_pending = 0x80, fsra3_drq = 0x40, fsra3_step_ff = 0x20, fsra3_trko = 0x10, fsra3_nhdsel = 0x08, fsra3_index = 0x04, fsra3_wp = 0x02, fsra3_ndir = 0x01 }; /** Bits in Status Register B (SRB) PS/2 Mode */ enum { fsrb_d0sel = 0x20, fsrb_wrd_tgl = 0x10, fsrb_rdd_tgl = 0x08, fsrb_we = 0x04, fsrb_me1 = 0x02, fsrb_me0 = 0x01 }; /** Bits in Status Register B (SRB) Model 30 Mode */ enum { fsrb_ndrv2 = 0x80, fsrb_nds1 = 0x40, fsrb_nds0 = 0x20, fsrb_wrd_ff = 0x10, fsrb_rdd_ff = 0x08, fsrb_we_ff = 0x04, fsrb_nds3 = 0x02, fsrb_nds2 = 0x01 }; /** Bits in Digital Output Register (DOR) */ enum { fdor_me3 = 0x80, fdor_me2 = 0x40, fdor_me1 = 0x20, fdor_me0 = 0x10, fdor_ndmagate = 0x08, fdor_nreset = 0x04, fdor_ds1 = 0x02, fdor_ds0 = 0x01 }; /** Bits in Tape Drive Register (TDR) */ enum { ftdr_ts1 = 0x02, ftdr_ts0 = 0x01 }; /** Bits in Datarate Select Register (DSR) */ enum { fdsr_sw_reset = 0x80, fdsr_power_down = 0x40, fdsr_precomp2 = 0x10, fdsr_precomp1 = 0x08, fdsr_precomp0 = 0x04, fdsr_drate_sel1 = 0x02, fdsr_drate_sel0 = 0x01 }; /** Combined values of DSR.DRATE_SEL1/0 */ enum { fdsr_drate_1mbps = 0x03, fdsr_drate_500kbps = 0x00, fdsr_drate_300kbps = 0x01, fdsr_drate_250kbps = 0x02 }; /** Bits in Main Status Register (MSR) */ enum { /** Request for Master */ fmsr_rqm = 0x80, /** Data Input/Output */ fmsr_dio = 0x40, /** Execution Mode */ fmsr_exm = 0x20, /** FDC Busy */ fmsr_cb = 0x10, /** FDD 3 Busy */ fmsr_d3b = 0x08, /** FDD 2 Busy */ fmsr_d2b = 0x04, /** FDD 1 Busy */ fmsr_d1b = 0x02, /** FDD 0 Busy */ fmsr_d0b = 0x01, }; /** Bits in Digital Input Register, PC-AT Mode */ enum { fdira_dsk_chg = 0x80 }; /** Bits in Digital Input Register, PS/2 Mode */ enum { fdir2_dsk_chg = 0x80, fdir2_drate_sel1 = 0x04, fdir2_drate_sel0 = 0x02, fdir2_nhigh_dens = 0x01 }; /** Bits in Digital Input Register, Model 30 Mode */ enum { fdir3_dsk_chg = 0x80, fdir3_ndma_gate = 0x08, fdir3_noprec = 0x04, fdir3_drate_sel1 = 0x02, fdir3_drate_sel0 = 0x01 }; /** Bits in Configuration Control Register (CCR) */ enum { fccr_noprec = 0x04, fccr_drate_sel1 = 0x02, fccr_drate_sel0 = 0x01 }; /** Bits in Status Register 0 (SR0) */ enum { fsr0_ic_mask = 0xc0, fsr0_ic_normal = 0x00, fsr0_ic_abnormal = 0x40, fsr0_ic_invcmd = 0x80, fsr0_ic_abnormal_poll = 0xc0, fsr0_seek_end = 0x20, fsr0_equip_check = 0x10, fsr0_head_addr = 0x04, fsr0_ds1 = 0x02, fsr0_ds0 = 0x01 }; /** Bits in Status Register 1 (SR1) */ enum { fsr1_end_of_cyl = 0x80, fsr1_data_error = 0x20, fsr1_overr_underr = 0x10, fsr1_no_data = 0x04, fsr1_not_writable = 0x02, fsr1_missing_am = 0x01 }; /** Bits in Status Register 2 (SR2) */ enum { fsr2_control_mark = 0x40, fsr1_derr_df = 0x20, fsr1_wrong_cyl = 0x10, fsr1_bad_cyl = 0x02, fsr1_missing_dam = 0x01 }; /** Registers */ typedef union { struct { /* read only */ /** Status Register A */ uint8_t sra; /** Starus Register B */ uint8_t srb; /** Padding */ uint8_t ro_pad2[2]; /** Main Status Register */ uint8_t msr; /** Padding */ uint8_t ro_pad5[2]; /** Digital Inut Register */ uint8_t dir; }; struct { /* write only */ /** Padding */ uint8_t wo_pad0[4]; /** Datarate Select Register */ uint8_t dsr; /** Padding */ uint8_t wo_pad5[2]; /** Configuration Control Register */ uint8_t ccr; }; struct { /* read/write */ /** Padding */ uint8_t rw_pad0[2]; /** Digital Output Register */ uint8_t dor; /** Tape Drive Register */ uint8_t tdr; /** Padding */ uint8_t rw_pad4; /** Data (FIFO) */ uint8_t data; }; } pc_fdc_regs_t; enum { /** Max. time we need to wait for MSR status */ msr_max_wait_usec = 250 }; #endif /** @} */