Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 1 | // 16bit code to access floppy drives. |
| 2 | // |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 3 | // Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net> |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 4 | // Copyright (C) 2002 MandrakeSoft S.A. |
| 5 | // |
Kevin O'Connor | b1b7c2a | 2009-01-15 20:52:58 -0500 | [diff] [blame] | 6 | // This file may be distributed under the terms of the GNU LGPLv3 license. |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 7 | |
| 8 | #include "types.h" // u8 |
| 9 | #include "disk.h" // DISK_RET_SUCCESS |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 10 | #include "config.h" // CONFIG_FLOPPY |
Kevin O'Connor | 9521e26 | 2008-07-04 13:04:29 -0400 | [diff] [blame] | 11 | #include "biosvar.h" // SET_BDA |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 12 | #include "util.h" // irq_disable |
| 13 | #include "cmos.h" // inb_cmos |
Kevin O'Connor | d21c089 | 2008-11-26 17:02:43 -0500 | [diff] [blame] | 14 | #include "pic.h" // eoi_pic1 |
Kevin O'Connor | 9521e26 | 2008-07-04 13:04:29 -0400 | [diff] [blame] | 15 | #include "bregs.h" // struct bregs |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 16 | |
| 17 | #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */ |
| 18 | |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 19 | // New diskette parameter table adding 3 parameters from IBM |
| 20 | // Since no provisions are made for multiple drive types, most |
| 21 | // values in this table are ignored. I set parameters for 1.44M |
| 22 | // floppy here |
Kevin O'Connor | 92f95b0 | 2008-12-29 20:42:40 -0500 | [diff] [blame] | 23 | struct floppy_ext_dbt_s diskette_param_table2 VAR16_32 = { |
Kevin O'Connor | 44c631d | 2008-03-02 11:24:36 -0500 | [diff] [blame] | 24 | .dbt = { |
| 25 | .specify1 = 0xAF, |
| 26 | .specify2 = 0x02, // head load time 0000001, DMA used |
| 27 | .shutoff_ticks = 0x25, |
| 28 | .bps_code = 0x02, |
| 29 | .sectors = 18, |
| 30 | .interblock_len = 0x1B, |
| 31 | .data_len = 0xFF, |
| 32 | .gap_len = 0x6C, |
| 33 | .fill_byte = 0xF6, |
| 34 | .settle_time = 0x0F, |
| 35 | .startup_time = 0x08, |
| 36 | }, |
| 37 | .max_track = 79, // maximum track |
| 38 | .data_rate = 0, // data transfer rate |
| 39 | .drive_type = 4, // drive type in cmos |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 40 | }; |
| 41 | |
Kevin O'Connor | 3085376 | 2009-01-17 18:49:20 -0500 | [diff] [blame] | 42 | // Since no provisions are made for multiple drive types, most |
| 43 | // values in this table are ignored. I set parameters for 1.44M |
| 44 | // floppy here |
| 45 | struct floppy_dbt_s diskette_param_table VAR16FIXED(0xefc7) = { |
| 46 | .specify1 = 0xAF, |
| 47 | .specify2 = 0x02, // head load time 0000001, DMA used |
| 48 | .shutoff_ticks = 0x25, |
| 49 | .bps_code = 0x02, |
| 50 | .sectors = 18, |
| 51 | .interblock_len = 0x1B, |
| 52 | .data_len = 0xFF, |
| 53 | .gap_len = 0x6C, |
| 54 | .fill_byte = 0xF6, |
| 55 | .settle_time = 0x0F, |
| 56 | .startup_time = 0x08, |
| 57 | }; |
| 58 | |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 59 | struct floppyinfo_s { |
| 60 | struct chs_s chs; |
| 61 | u8 config_data; |
| 62 | u8 media_state; |
| 63 | }; |
| 64 | |
| 65 | struct floppyinfo_s FloppyInfo[] VAR16_32 = { |
| 66 | // Unknown |
| 67 | { {0, 0, 0}, 0x00, 0x00}, |
| 68 | // 1 - 360KB, 5.25" - 2 heads, 40 tracks, 9 sectors |
| 69 | { {2, 40, 9}, 0x00, 0x25}, |
| 70 | // 2 - 1.2MB, 5.25" - 2 heads, 80 tracks, 15 sectors |
| 71 | { {2, 80, 15}, 0x00, 0x25}, |
| 72 | // 3 - 720KB, 3.5" - 2 heads, 80 tracks, 9 sectors |
| 73 | { {2, 80, 9}, 0x00, 0x17}, |
| 74 | // 4 - 1.44MB, 3.5" - 2 heads, 80 tracks, 18 sectors |
| 75 | { {2, 80, 18}, 0x00, 0x17}, |
| 76 | // 5 - 2.88MB, 3.5" - 2 heads, 80 tracks, 36 sectors |
| 77 | { {2, 80, 36}, 0xCC, 0xD7}, |
| 78 | // 6 - 160k, 5.25" - 1 heads, 40 tracks, 8 sectors |
| 79 | { {1, 40, 8}, 0x00, 0x27}, |
| 80 | // 7 - 180k, 5.25" - 1 heads, 40 tracks, 9 sectors |
| 81 | { {1, 40, 9}, 0x00, 0x27}, |
| 82 | // 8 - 320k, 5.25" - 2 heads, 40 tracks, 8 sectors |
| 83 | { {2, 40, 8}, 0x00, 0x27}, |
| 84 | }; |
| 85 | |
| 86 | static void |
| 87 | addFloppy(int floppyid, int ftype) |
| 88 | { |
| 89 | if (ftype <= 0 || ftype >= ARRAY_SIZE(FloppyInfo)) { |
| 90 | dprintf(1, "Bad floppy type %d\n", ftype); |
| 91 | return; |
| 92 | } |
| 93 | |
| 94 | int driveid = Drives.drivecount; |
| 95 | if (driveid >= ARRAY_SIZE(Drives.drives)) |
| 96 | return; |
| 97 | Drives.drivecount++; |
| 98 | memset(&Drives.drives[driveid], 0, sizeof(Drives.drives[0])); |
| 99 | Drives.drives[driveid].cntl_id = floppyid; |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 100 | Drives.drives[driveid].floppy_type = ftype; |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 101 | |
| 102 | memcpy(&Drives.drives[driveid].lchs, &FloppyInfo[ftype].chs |
| 103 | , sizeof(FloppyInfo[ftype].chs)); |
| 104 | |
| 105 | map_floppy_drive(driveid); |
| 106 | } |
| 107 | |
Kevin O'Connor | 3bbcc14 | 2008-04-13 17:07:33 -0400 | [diff] [blame] | 108 | void |
Kevin O'Connor | c892b13 | 2009-08-11 21:59:37 -0400 | [diff] [blame] | 109 | floppy_setup() |
Kevin O'Connor | 3bbcc14 | 2008-04-13 17:07:33 -0400 | [diff] [blame] | 110 | { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 111 | if (! CONFIG_FLOPPY) |
Kevin O'Connor | f54c150 | 2008-06-14 15:56:16 -0400 | [diff] [blame] | 112 | return; |
Kevin O'Connor | 35192dd | 2008-06-08 19:18:33 -0400 | [diff] [blame] | 113 | dprintf(3, "init floppy drives\n"); |
Kevin O'Connor | 88c00ee | 2008-05-18 00:14:13 -0400 | [diff] [blame] | 114 | |
Kevin O'Connor | 7661f2f | 2009-02-07 01:21:00 -0500 | [diff] [blame] | 115 | if (CONFIG_COREBOOT) { |
| 116 | // XXX - disable floppies on coreboot for now. |
| 117 | } else { |
| 118 | u8 type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE); |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 119 | if (type & 0xf0) |
| 120 | addFloppy(0, type >> 4); |
| 121 | if (type & 0x0f) |
| 122 | addFloppy(1, type & 0x0f); |
Kevin O'Connor | 88c00ee | 2008-05-18 00:14:13 -0400 | [diff] [blame] | 123 | } |
Kevin O'Connor | 88c00ee | 2008-05-18 00:14:13 -0400 | [diff] [blame] | 124 | |
Kevin O'Connor | 3bbcc14 | 2008-04-13 17:07:33 -0400 | [diff] [blame] | 125 | outb(0x02, PORT_DMA1_MASK_REG); |
Kevin O'Connor | f54c150 | 2008-06-14 15:56:16 -0400 | [diff] [blame] | 126 | |
Kevin O'Connor | d21c089 | 2008-11-26 17:02:43 -0500 | [diff] [blame] | 127 | enable_hwirq(6, entry_0e); |
Kevin O'Connor | 3bbcc14 | 2008-04-13 17:07:33 -0400 | [diff] [blame] | 128 | } |
| 129 | |
Kevin O'Connor | a3b612e | 2009-02-07 11:25:29 -0500 | [diff] [blame] | 130 | |
| 131 | /**************************************************************** |
| 132 | * Low-level floppy IO |
| 133 | ****************************************************************/ |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 134 | |
| 135 | static void |
| 136 | floppy_reset_controller() |
| 137 | { |
| 138 | // Reset controller |
| 139 | u8 val8 = inb(PORT_FD_DOR); |
| 140 | outb(val8 & ~0x04, PORT_FD_DOR); |
| 141 | outb(val8 | 0x04, PORT_FD_DOR); |
| 142 | |
| 143 | // Wait for controller to come out of reset |
| 144 | while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80) |
| 145 | ; |
| 146 | } |
| 147 | |
Kevin O'Connor | a3b612e | 2009-02-07 11:25:29 -0500 | [diff] [blame] | 148 | static int |
| 149 | wait_floppy_irq() |
| 150 | { |
| 151 | irq_enable(); |
| 152 | u8 v; |
| 153 | for (;;) { |
| 154 | if (!GET_BDA(floppy_motor_counter)) { |
| 155 | irq_disable(); |
| 156 | return -1; |
| 157 | } |
| 158 | v = GET_BDA(floppy_recalibration_status); |
| 159 | if (v & FRS_TIMEOUT) |
| 160 | break; |
| 161 | cpu_relax(); |
| 162 | } |
| 163 | irq_disable(); |
| 164 | |
| 165 | v &= ~FRS_TIMEOUT; |
| 166 | SET_BDA(floppy_recalibration_status, v); |
| 167 | return 0; |
| 168 | } |
| 169 | |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 170 | static void |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 171 | floppy_prepare_controller(u8 floppyid) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 172 | { |
| 173 | CLEARBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT); |
| 174 | |
| 175 | // turn on motor of selected drive, DMA & int enabled, normal operation |
| 176 | u8 prev_reset = inb(PORT_FD_DOR) & 0x04; |
| 177 | u8 dor = 0x10; |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 178 | if (floppyid) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 179 | dor = 0x20; |
| 180 | dor |= 0x0c; |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 181 | dor |= floppyid; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 182 | outb(dor, PORT_FD_DOR); |
| 183 | |
| 184 | // reset the disk motor timeout value of INT 08 |
| 185 | SET_BDA(floppy_motor_counter, BX_FLOPPY_ON_CNT); |
| 186 | |
| 187 | // wait for drive readiness |
| 188 | while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80) |
| 189 | ; |
| 190 | |
Kevin O'Connor | a3b612e | 2009-02-07 11:25:29 -0500 | [diff] [blame] | 191 | if (!prev_reset) |
| 192 | wait_floppy_irq(); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 193 | } |
| 194 | |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 195 | static int |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 196 | floppy_pio(u8 *cmd, u8 cmdlen) |
| 197 | { |
| 198 | floppy_prepare_controller(cmd[1] & 1); |
| 199 | |
| 200 | // send command to controller |
| 201 | u8 i; |
| 202 | for (i=0; i<cmdlen; i++) |
| 203 | outb(cmd[i], PORT_FD_DATA); |
| 204 | |
Kevin O'Connor | a3b612e | 2009-02-07 11:25:29 -0500 | [diff] [blame] | 205 | int ret = wait_floppy_irq(); |
| 206 | if (ret) { |
| 207 | floppy_reset_controller(); |
| 208 | return -1; |
Kevin O'Connor | 06ad44e | 2008-04-05 19:30:02 -0400 | [diff] [blame] | 209 | } |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 210 | |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 211 | return 0; |
| 212 | } |
| 213 | |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 214 | static int |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 215 | floppy_cmd(struct bregs *regs, u16 count, u8 *cmd, u8 cmdlen) |
| 216 | { |
| 217 | // es:bx = pointer to where to place information from diskette |
Kevin O'Connor | 35ae726 | 2009-01-19 15:44:44 -0500 | [diff] [blame] | 218 | u32 addr = (u32)MAKE_FLATPTR(regs->es, regs->bx); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 219 | |
| 220 | // check for 64K boundary overrun |
Kevin O'Connor | e10d345 | 2008-07-09 22:45:12 -0400 | [diff] [blame] | 221 | u32 last_addr = addr + count; |
| 222 | if ((addr >> 16) != (last_addr >> 16)) { |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 223 | disk_ret(regs, DISK_RET_EBOUNDARY); |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 224 | return -1; |
| 225 | } |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 226 | |
| 227 | u8 mode_register = 0x4a; // single mode, increment, autoinit disable, |
| 228 | if (cmd[0] == 0xe6) |
| 229 | // read |
| 230 | mode_register = 0x46; |
| 231 | |
Kevin O'Connor | 44c631d | 2008-03-02 11:24:36 -0500 | [diff] [blame] | 232 | //DEBUGF("floppy dma c2\n"); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 233 | outb(0x06, PORT_DMA1_MASK_REG); |
| 234 | outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop |
Kevin O'Connor | e10d345 | 2008-07-09 22:45:12 -0400 | [diff] [blame] | 235 | outb(addr, PORT_DMA_ADDR_2); |
| 236 | outb(addr>>8, PORT_DMA_ADDR_2); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 237 | outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop |
| 238 | outb(count, PORT_DMA_CNT_2); |
| 239 | outb(count>>8, PORT_DMA_CNT_2); |
| 240 | |
| 241 | // port 0b: DMA-1 Mode Register |
| 242 | // transfer type=write, channel 2 |
| 243 | outb(mode_register, PORT_DMA1_MODE_REG); |
| 244 | |
| 245 | // port 81: DMA-1 Page Register, channel 2 |
Kevin O'Connor | e10d345 | 2008-07-09 22:45:12 -0400 | [diff] [blame] | 246 | outb(addr>>16, PORT_DMA_PAGE_2); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 247 | |
| 248 | outb(0x02, PORT_DMA1_MASK_REG); // unmask channel 2 |
| 249 | |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 250 | int ret = floppy_pio(cmd, cmdlen); |
| 251 | if (ret) { |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 252 | disk_ret(regs, DISK_RET_ETIMEOUT); |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 253 | return -1; |
| 254 | } |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 255 | |
Kevin O'Connor | c65a380 | 2008-03-02 13:58:23 -0500 | [diff] [blame] | 256 | // check port 3f4 for accessibility to status bytes |
Kevin O'Connor | 7661f2f | 2009-02-07 01:21:00 -0500 | [diff] [blame] | 257 | if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) { |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 258 | disk_ret(regs, DISK_RET_ECONTROLLER); |
Kevin O'Connor | 7661f2f | 2009-02-07 01:21:00 -0500 | [diff] [blame] | 259 | return -1; |
| 260 | } |
Kevin O'Connor | c65a380 | 2008-03-02 13:58:23 -0500 | [diff] [blame] | 261 | |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 262 | // read 7 return status bytes from controller |
| 263 | u8 i; |
| 264 | for (i=0; i<7; i++) { |
| 265 | u8 v = inb(PORT_FD_DATA); |
| 266 | cmd[i] = v; |
| 267 | SET_BDA(floppy_return_status[i], v); |
| 268 | } |
| 269 | |
| 270 | return 0; |
| 271 | } |
| 272 | |
Kevin O'Connor | a3b612e | 2009-02-07 11:25:29 -0500 | [diff] [blame] | 273 | |
| 274 | /**************************************************************** |
| 275 | * Floppy media sense |
| 276 | ****************************************************************/ |
| 277 | |
| 278 | static inline void |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 279 | set_diskette_current_cyl(u8 floppyid, u8 cyl) |
Kevin O'Connor | a3b612e | 2009-02-07 11:25:29 -0500 | [diff] [blame] | 280 | { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 281 | SET_BDA(floppy_track[floppyid], cyl); |
Kevin O'Connor | a3b612e | 2009-02-07 11:25:29 -0500 | [diff] [blame] | 282 | } |
| 283 | |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 284 | static void |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 285 | floppy_drive_recal(u8 floppyid) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 286 | { |
| 287 | // send Recalibrate command (2 bytes) to controller |
| 288 | u8 data[12]; |
| 289 | data[0] = 0x07; // 07: Recalibrate |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 290 | data[1] = floppyid; // 0=drive0, 1=drive1 |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 291 | floppy_pio(data, 2); |
| 292 | |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 293 | SETBITS_BDA(floppy_recalibration_status, 1<<floppyid); |
| 294 | set_diskette_current_cyl(floppyid, 0); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 295 | } |
| 296 | |
Kevin O'Connor | a3b612e | 2009-02-07 11:25:29 -0500 | [diff] [blame] | 297 | static int |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 298 | floppy_media_sense(u8 driveid) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 299 | { |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 300 | // for now cheat and get drive type from CMOS, |
| 301 | // assume media is same as drive type |
| 302 | |
| 303 | // ** config_data ** |
| 304 | // Bitfields for diskette media control: |
| 305 | // Bit(s) Description (Table M0028) |
| 306 | // 7-6 last data rate set by controller |
| 307 | // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps |
| 308 | // 5-4 last diskette drive step rate selected |
| 309 | // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah |
| 310 | // 3-2 {data rate at start of operation} |
| 311 | // 1-0 reserved |
| 312 | |
| 313 | // ** media_state ** |
| 314 | // Bitfields for diskette drive media state: |
| 315 | // Bit(s) Description (Table M0030) |
| 316 | // 7-6 data rate |
| 317 | // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps |
| 318 | // 5 double stepping required (e.g. 360kB in 1.2MB) |
| 319 | // 4 media type established |
| 320 | // 3 drive capable of supporting 4MB media |
| 321 | // 2-0 on exit from BIOS, contains |
| 322 | // 000 trying 360kB in 360kB |
| 323 | // 001 trying 360kB in 1.2MB |
| 324 | // 010 trying 1.2MB in 1.2MB |
| 325 | // 011 360kB in 360kB established |
| 326 | // 100 360kB in 1.2MB established |
| 327 | // 101 1.2MB in 1.2MB established |
| 328 | // 110 reserved |
| 329 | // 111 all other formats/drives |
| 330 | |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 331 | u8 ftype = GET_GLOBAL(Drives.drives[driveid].floppy_type); |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 332 | SET_BDA(floppy_last_data_rate, GET_GLOBAL(FloppyInfo[ftype].config_data)); |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 333 | u8 floppyid = GET_GLOBAL(Drives.drives[driveid].cntl_id); |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 334 | SET_BDA(floppy_media_state[floppyid] |
| 335 | , GET_GLOBAL(FloppyInfo[ftype].media_state)); |
| 336 | return 0; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 337 | } |
| 338 | |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 339 | static int |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 340 | check_recal_drive(struct bregs *regs, u8 driveid) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 341 | { |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 342 | u8 floppyid = GET_GLOBAL(Drives.drives[driveid].cntl_id); |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 343 | if ((GET_BDA(floppy_recalibration_status) & (1<<floppyid)) |
| 344 | && (GET_BDA(floppy_media_state[floppyid]) & FMS_MEDIA_DRIVE_ESTABLISHED)) |
Kevin O'Connor | a3b612e | 2009-02-07 11:25:29 -0500 | [diff] [blame] | 345 | // Media is known. |
| 346 | return 0; |
| 347 | |
| 348 | // Recalibrate drive. |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 349 | floppy_drive_recal(floppyid); |
Kevin O'Connor | a3b612e | 2009-02-07 11:25:29 -0500 | [diff] [blame] | 350 | |
| 351 | // Sense media. |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 352 | int ret = floppy_media_sense(driveid); |
Kevin O'Connor | d626e55 | 2009-02-27 21:05:59 -0500 | [diff] [blame] | 353 | if (ret) { |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 354 | disk_ret(regs, DISK_RET_EMEDIA); |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 355 | return -1; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 356 | } |
| 357 | return 0; |
| 358 | } |
| 359 | |
Kevin O'Connor | a3b612e | 2009-02-07 11:25:29 -0500 | [diff] [blame] | 360 | |
| 361 | /**************************************************************** |
| 362 | * Floppy int13 handlers |
| 363 | ****************************************************************/ |
| 364 | |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 365 | // diskette controller reset |
| 366 | static void |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 367 | floppy_1300(struct bregs *regs, u8 driveid) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 368 | { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 369 | u8 floppyid = GET_GLOBAL(Drives.drives[driveid].cntl_id); |
| 370 | set_diskette_current_cyl(floppyid, 0); // current cylinder |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 371 | disk_ret(regs, DISK_RET_SUCCESS); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 372 | } |
| 373 | |
| 374 | // Read Diskette Sectors |
| 375 | static void |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 376 | floppy_1302(struct bregs *regs, u8 driveid) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 377 | { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 378 | u8 floppyid = GET_GLOBAL(Drives.drives[driveid].cntl_id); |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 379 | if (check_recal_drive(regs, driveid)) |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 380 | goto fail; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 381 | |
| 382 | u8 num_sectors = regs->al; |
| 383 | u8 track = regs->ch; |
| 384 | u8 sector = regs->cl; |
| 385 | u8 head = regs->dh; |
| 386 | |
| 387 | if (head > 1 || sector == 0 || num_sectors == 0 |
| 388 | || track > 79 || num_sectors > 72) { |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 389 | disk_ret(regs, DISK_RET_EPARAM); |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 390 | goto fail; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 391 | } |
| 392 | |
| 393 | // send read-normal-data command (9 bytes) to controller |
| 394 | u8 data[12]; |
| 395 | data[0] = 0xe6; // e6: read normal data |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 396 | data[1] = (head << 2) | floppyid; // HD DR1 DR2 |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 397 | data[2] = track; |
| 398 | data[3] = head; |
| 399 | data[4] = sector; |
| 400 | data[5] = 2; // 512 byte sector size |
| 401 | data[6] = sector + num_sectors - 1; // last sector to read on track |
| 402 | data[7] = 0; // Gap length |
| 403 | data[8] = 0xff; // Gap length |
| 404 | |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 405 | int ret = floppy_cmd(regs, (num_sectors * 512) - 1, data, 9); |
| 406 | if (ret) |
| 407 | goto fail; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 408 | |
| 409 | if (data[0] & 0xc0) { |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 410 | disk_ret(regs, DISK_RET_ECONTROLLER); |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 411 | goto fail; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 412 | } |
| 413 | |
| 414 | // ??? should track be new val from return_status[3] ? |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 415 | set_diskette_current_cyl(floppyid, track); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 416 | // AL = number of sectors read (same value as passed) |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 417 | disk_ret(regs, DISK_RET_SUCCESS); |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 418 | return; |
| 419 | fail: |
| 420 | regs->al = 0; // no sectors read |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 421 | } |
| 422 | |
| 423 | // Write Diskette Sectors |
| 424 | static void |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 425 | floppy_1303(struct bregs *regs, u8 driveid) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 426 | { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 427 | u8 floppyid = GET_GLOBAL(Drives.drives[driveid].cntl_id); |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 428 | if (check_recal_drive(regs, driveid)) |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 429 | goto fail; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 430 | |
| 431 | u8 num_sectors = regs->al; |
| 432 | u8 track = regs->ch; |
| 433 | u8 sector = regs->cl; |
| 434 | u8 head = regs->dh; |
| 435 | |
| 436 | if (head > 1 || sector == 0 || num_sectors == 0 |
| 437 | || track > 79 || num_sectors > 72) { |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 438 | disk_ret(regs, DISK_RET_EPARAM); |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 439 | goto fail; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 440 | } |
| 441 | |
| 442 | // send write-normal-data command (9 bytes) to controller |
| 443 | u8 data[12]; |
| 444 | data[0] = 0xc5; // c5: write normal data |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 445 | data[1] = (head << 2) | floppyid; // HD DR1 DR2 |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 446 | data[2] = track; |
| 447 | data[3] = head; |
| 448 | data[4] = sector; |
| 449 | data[5] = 2; // 512 byte sector size |
| 450 | data[6] = sector + num_sectors - 1; // last sector to write on track |
| 451 | data[7] = 0; // Gap length |
| 452 | data[8] = 0xff; // Gap length |
| 453 | |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 454 | int ret = floppy_cmd(regs, (num_sectors * 512) - 1, data, 9); |
| 455 | if (ret) |
| 456 | goto fail; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 457 | |
| 458 | if (data[0] & 0xc0) { |
Kevin O'Connor | 7661f2f | 2009-02-07 01:21:00 -0500 | [diff] [blame] | 459 | if (data[1] & 0x02) |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 460 | disk_ret(regs, DISK_RET_EWRITEPROTECT); |
Kevin O'Connor | 7661f2f | 2009-02-07 01:21:00 -0500 | [diff] [blame] | 461 | else |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 462 | disk_ret(regs, DISK_RET_ECONTROLLER); |
Kevin O'Connor | 7661f2f | 2009-02-07 01:21:00 -0500 | [diff] [blame] | 463 | goto fail; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 464 | } |
| 465 | |
| 466 | // ??? should track be new val from return_status[3] ? |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 467 | set_diskette_current_cyl(floppyid, track); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 468 | // AL = number of sectors read (same value as passed) |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 469 | disk_ret(regs, DISK_RET_SUCCESS); |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 470 | return; |
| 471 | fail: |
| 472 | regs->al = 0; // no sectors read |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 473 | } |
| 474 | |
| 475 | // Verify Diskette Sectors |
| 476 | static void |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 477 | floppy_1304(struct bregs *regs, u8 driveid) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 478 | { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 479 | u8 floppyid = GET_GLOBAL(Drives.drives[driveid].cntl_id); |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 480 | if (check_recal_drive(regs, driveid)) |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 481 | goto fail; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 482 | |
| 483 | u8 num_sectors = regs->al; |
| 484 | u8 track = regs->ch; |
| 485 | u8 sector = regs->cl; |
| 486 | u8 head = regs->dh; |
| 487 | |
| 488 | if (head > 1 || sector == 0 || num_sectors == 0 |
| 489 | || track > 79 || num_sectors > 72) { |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 490 | disk_ret(regs, DISK_RET_EPARAM); |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 491 | goto fail; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 492 | } |
| 493 | |
| 494 | // ??? should track be new val from return_status[3] ? |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 495 | set_diskette_current_cyl(floppyid, track); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 496 | // AL = number of sectors verified (same value as passed) |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 497 | disk_ret(regs, DISK_RET_SUCCESS); |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 498 | return; |
| 499 | fail: |
| 500 | regs->al = 0; // no sectors read |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 501 | } |
| 502 | |
| 503 | // format diskette track |
| 504 | static void |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 505 | floppy_1305(struct bregs *regs, u8 driveid) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 506 | { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 507 | u8 floppyid = GET_GLOBAL(Drives.drives[driveid].cntl_id); |
Kevin O'Connor | a05223c | 2008-06-28 12:15:57 -0400 | [diff] [blame] | 508 | dprintf(3, "floppy f05\n"); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 509 | |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 510 | if (check_recal_drive(regs, driveid)) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 511 | return; |
| 512 | |
| 513 | u8 num_sectors = regs->al; |
| 514 | u8 head = regs->dh; |
| 515 | |
| 516 | if (head > 1 || num_sectors == 0 || num_sectors > 18) { |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 517 | disk_ret(regs, DISK_RET_EPARAM); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 518 | return; |
| 519 | } |
| 520 | |
| 521 | // send format-track command (6 bytes) to controller |
| 522 | u8 data[12]; |
| 523 | data[0] = 0x4d; // 4d: format track |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 524 | data[1] = (head << 2) | floppyid; // HD DR1 DR2 |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 525 | data[2] = 2; // 512 byte sector size |
| 526 | data[3] = num_sectors; // number of sectors per track |
| 527 | data[4] = 0; // Gap length |
| 528 | data[5] = 0xf6; // Fill byte |
| 529 | |
Kevin O'Connor | a68aeaf | 2008-07-07 21:37:10 -0400 | [diff] [blame] | 530 | int ret = floppy_cmd(regs, (num_sectors * 4) - 1, data, 6); |
| 531 | if (ret) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 532 | return; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 533 | |
| 534 | if (data[0] & 0xc0) { |
Kevin O'Connor | 7661f2f | 2009-02-07 01:21:00 -0500 | [diff] [blame] | 535 | if (data[1] & 0x02) |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 536 | disk_ret(regs, DISK_RET_EWRITEPROTECT); |
Kevin O'Connor | 7661f2f | 2009-02-07 01:21:00 -0500 | [diff] [blame] | 537 | else |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 538 | disk_ret(regs, DISK_RET_ECONTROLLER); |
Kevin O'Connor | 7661f2f | 2009-02-07 01:21:00 -0500 | [diff] [blame] | 539 | return; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 540 | } |
| 541 | |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 542 | set_diskette_current_cyl(floppyid, 0); |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 543 | disk_ret(regs, DISK_RET_SUCCESS); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 544 | } |
| 545 | |
| 546 | static void |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 547 | floppy_13XX(struct bregs *regs, u8 driveid) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 548 | { |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 549 | disk_ret(regs, DISK_RET_EPARAM); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 550 | } |
| 551 | |
| 552 | void |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 553 | floppy_13(struct bregs *regs, u8 driveid) |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 554 | { |
Kevin O'Connor | b792b3c | 2008-02-29 00:20:32 -0500 | [diff] [blame] | 555 | switch (regs->ah) { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 556 | case 0x00: floppy_1300(regs, driveid); break; |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 557 | case 0x02: floppy_1302(regs, driveid); break; |
| 558 | case 0x03: floppy_1303(regs, driveid); break; |
| 559 | case 0x04: floppy_1304(regs, driveid); break; |
| 560 | case 0x05: floppy_1305(regs, driveid); break; |
Kevin O'Connor | 48410fd | 2009-08-16 14:13:36 -0400 | [diff] [blame^] | 561 | |
| 562 | // These functions are the same as for hard disks |
| 563 | case 0x01: |
| 564 | case 0x08: |
| 565 | case 0x15: |
| 566 | case 0x16: |
| 567 | disk_13(regs, driveid); |
| 568 | break; |
| 569 | |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 570 | default: floppy_13XX(regs, driveid); break; |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 571 | } |
| 572 | } |
| 573 | |
Kevin O'Connor | a3b612e | 2009-02-07 11:25:29 -0500 | [diff] [blame] | 574 | |
| 575 | /**************************************************************** |
| 576 | * HW irqs |
| 577 | ****************************************************************/ |
| 578 | |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 579 | // INT 0Eh Diskette Hardware ISR Entry Point |
Kevin O'Connor | 1978676 | 2008-03-05 21:09:59 -0500 | [diff] [blame] | 580 | void VISIBLE16 |
Kevin O'Connor | ed12849 | 2008-03-11 11:14:59 -0400 | [diff] [blame] | 581 | handle_0e() |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 582 | { |
Kevin O'Connor | 15c1f22 | 2008-06-12 22:59:43 -0400 | [diff] [blame] | 583 | debug_isr(DEBUG_ISR_0e); |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 584 | if (! CONFIG_FLOPPY) |
Kevin O'Connor | 4096702 | 2008-07-21 22:23:05 -0400 | [diff] [blame] | 585 | goto done; |
| 586 | |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 587 | if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) { |
| 588 | outb(0x08, PORT_FD_DATA); // sense interrupt status |
| 589 | while ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) |
| 590 | ; |
| 591 | do { |
| 592 | inb(PORT_FD_DATA); |
| 593 | } while ((inb(PORT_FD_STATUS) & 0xc0) == 0xc0); |
| 594 | } |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 595 | // diskette interrupt has occurred |
| 596 | SETBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT); |
Kevin O'Connor | 4096702 | 2008-07-21 22:23:05 -0400 | [diff] [blame] | 597 | |
| 598 | done: |
| 599 | eoi_pic1(); |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 600 | } |
| 601 | |
| 602 | // Called from int08 handler. |
| 603 | void |
| 604 | floppy_tick() |
| 605 | { |
Kevin O'Connor | 0a0e42e | 2009-08-16 12:09:44 -0400 | [diff] [blame] | 606 | if (! CONFIG_FLOPPY) |
Kevin O'Connor | 4096702 | 2008-07-21 22:23:05 -0400 | [diff] [blame] | 607 | return; |
| 608 | |
Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame] | 609 | // time to turn off drive(s)? |
| 610 | u8 fcount = GET_BDA(floppy_motor_counter); |
| 611 | if (fcount) { |
| 612 | fcount--; |
| 613 | SET_BDA(floppy_motor_counter, fcount); |
| 614 | if (fcount == 0) |
| 615 | // turn motor(s) off |
| 616 | outb(inb(PORT_FD_DOR) & 0xcf, PORT_FD_DOR); |
| 617 | } |
| 618 | } |