[69501] | 1 | /* $Id: floppy.c 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * PC BIOS - ???
|
---|
| 4 | */
|
---|
| 5 |
|
---|
[38699] | 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
[38699] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[69498] | 26 | * --------------------------------------------------------------------
|
---|
[38699] | 27 | *
|
---|
| 28 | * This code is based on:
|
---|
| 29 | *
|
---|
| 30 | * ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
|
---|
| 31 | *
|
---|
| 32 | * Copyright (C) 2002 MandrakeSoft S.A.
|
---|
| 33 | *
|
---|
| 34 | * MandrakeSoft S.A.
|
---|
| 35 | * 43, rue d'Aboukir
|
---|
| 36 | * 75002 Paris - France
|
---|
| 37 | * http://www.linux-mandrake.com/
|
---|
| 38 | * http://www.mandrakesoft.com/
|
---|
| 39 | *
|
---|
| 40 | * This library is free software; you can redistribute it and/or
|
---|
| 41 | * modify it under the terms of the GNU Lesser General Public
|
---|
| 42 | * License as published by the Free Software Foundation; either
|
---|
| 43 | * version 2 of the License, or (at your option) any later version.
|
---|
| 44 | *
|
---|
| 45 | * This library is distributed in the hope that it will be useful,
|
---|
| 46 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 47 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 48 | * Lesser General Public License for more details.
|
---|
| 49 | *
|
---|
| 50 | * You should have received a copy of the GNU Lesser General Public
|
---|
| 51 | * License along with this library; if not, write to the Free Software
|
---|
| 52 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
---|
| 53 | *
|
---|
| 54 | */
|
---|
| 55 |
|
---|
[69501] | 56 | /*
|
---|
| 57 | * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
|
---|
| 58 | * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
|
---|
| 59 | * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
|
---|
| 60 | * a choice of LGPL license versions is made available with the language indicating
|
---|
| 61 | * that LGPLv2 or any later version may be used, or where a choice of which version
|
---|
| 62 | * of the LGPL is applied is otherwise unspecified.
|
---|
| 63 | */
|
---|
[38699] | 64 |
|
---|
[69501] | 65 |
|
---|
[38699] | 66 | #include <stdint.h>
|
---|
| 67 | #include "inlines.h"
|
---|
| 68 | #include "biosint.h"
|
---|
| 69 |
|
---|
[48069] | 70 | extern uint16_t get_floppy_dpt(uint8_t drive_type);
|
---|
| 71 |
|
---|
[38699] | 72 | //////////////////////
|
---|
| 73 | // FLOPPY functions //
|
---|
| 74 | //////////////////////
|
---|
| 75 |
|
---|
[67069] | 76 | inline void set_diskette_ret_status(uint8_t value)
|
---|
[38699] | 77 | {
|
---|
| 78 | write_byte(0x0040, 0x0041, value);
|
---|
| 79 | }
|
---|
| 80 |
|
---|
| 81 | void set_diskette_current_cyl(uint8_t drive, uint8_t cyl)
|
---|
| 82 | {
|
---|
| 83 | if (drive > 1)
|
---|
| 84 | BX_PANIC("set_diskette_current_cyl: drive > 1\n");
|
---|
| 85 | write_byte(0x0040, 0x0094+drive, cyl);
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | #if 1 //BX_SUPPORT_FLOPPY
|
---|
| 89 |
|
---|
| 90 | #if DEBUG_INT13_FL
|
---|
| 91 | # define BX_DEBUG_INT13_FL(...) BX_DEBUG(__VA_ARGS__)
|
---|
| 92 | #else
|
---|
| 93 | # define BX_DEBUG_INT13_FL(...)
|
---|
| 94 | #endif
|
---|
| 95 |
|
---|
| 96 | #define BX_FLOPPY_ON_CNT 37 /* 2 seconds */
|
---|
| 97 |
|
---|
| 98 | extern int diskette_param_table; /* At a fixed location. */
|
---|
| 99 |
|
---|
[46947] | 100 | #ifndef VBOX_WITH_FLOPPY_IRQ_POLLING
|
---|
| 101 |
|
---|
| 102 | /**
|
---|
| 103 | * Wait for the 7th bit of 0040:003e to be set by int0e_handler.
|
---|
| 104 | * @returns first 7 bits of byte 0040:003e, interrupts disabled.
|
---|
| 105 | */
|
---|
| 106 | uint8_t floppy_wait_for_interrupt(void)
|
---|
| 107 | {
|
---|
| 108 | int_disable();
|
---|
[59115] | 109 | for (;;)
|
---|
[46947] | 110 | {
|
---|
| 111 | uint8_t val8 = read_byte(0x0040, 0x003e);
|
---|
| 112 | if (val8 & 0x80)
|
---|
| 113 | return val8 & ~0x7f;
|
---|
| 114 | int_enable_hlt_disable();
|
---|
| 115 | }
|
---|
| 116 | }
|
---|
| 117 |
|
---|
| 118 | /**
|
---|
| 119 | * Wait for the 7th bit of 0040:003e to be set by int0e_handler or 0040:0040 to
|
---|
| 120 | * be cleared by the timer, clearing the interrupt flag on success.
|
---|
| 121 | *
|
---|
| 122 | * @returns 0 on timeout with interrupts enabled.
|
---|
| 123 | * All 8 bits at 0040:003e on interrupt with interrupts disabled (i.e.
|
---|
| 124 | * non-zero), after first clearing the 7th bit at 0040:003e.
|
---|
| 125 | */
|
---|
| 126 | uint8_t floppy_wait_for_interrupt_or_timeout(void)
|
---|
| 127 | {
|
---|
| 128 | int_disable();
|
---|
| 129 | for (;;)
|
---|
| 130 | {
|
---|
| 131 | uint8_t val8 = read_byte(0x0040, 0x0040);
|
---|
| 132 | if (val8 == 0) {
|
---|
| 133 | int_enable();
|
---|
| 134 | return 0;
|
---|
| 135 | }
|
---|
| 136 |
|
---|
| 137 | val8 = read_byte(0x0040, 0x003e);
|
---|
| 138 | if (val8 & 0x80) {
|
---|
| 139 | write_byte(0x0040, 0x003e, val8 & 0x7f);
|
---|
| 140 | return val8;
|
---|
| 141 | }
|
---|
| 142 | int_enable_hlt_disable();
|
---|
| 143 | }
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 | #endif /* !VBOX_WITH_FLOPPY_IRQ_POLLING */
|
---|
| 147 |
|
---|
[62301] | 148 | void floppy_reset_controller(uint16_t drive)
|
---|
[38699] | 149 | {
|
---|
| 150 | uint8_t val8;
|
---|
[48947] | 151 |
|
---|
[38699] | 152 | // Reset controller
|
---|
| 153 | val8 = inb(0x03f2);
|
---|
| 154 | outb(0x03f2, val8 & ~0x04);
|
---|
| 155 | outb(0x03f2, val8 | 0x04);
|
---|
[48947] | 156 |
|
---|
[38699] | 157 | // Wait for controller to come out of reset
|
---|
| 158 | do {
|
---|
| 159 | val8 = inb(0x3f4);
|
---|
| 160 | } while ( (val8 & 0xc0) != 0x80 );
|
---|
[62301] | 161 |
|
---|
| 162 | // Mark media in drive as unknown
|
---|
| 163 | val8 = read_byte(0x0040, 0x0090 + drive);
|
---|
| 164 | val8 &= ~0x10;
|
---|
| 165 | write_byte(0x0040, 0x90 + drive, val8);
|
---|
| 166 |
|
---|
[38699] | 167 | }
|
---|
| 168 |
|
---|
| 169 | void floppy_prepare_controller(uint16_t drive)
|
---|
| 170 | {
|
---|
| 171 | uint8_t val8, dor, prev_reset;
|
---|
[48947] | 172 |
|
---|
[38699] | 173 | // set 40:3e bit 7 to 0
|
---|
| 174 | val8 = read_byte(0x0040, 0x003e);
|
---|
| 175 | val8 &= 0x7f;
|
---|
| 176 | write_byte(0x0040, 0x003e, val8);
|
---|
[48947] | 177 |
|
---|
[38699] | 178 | // turn on motor of selected drive, DMA & int enabled, normal operation
|
---|
| 179 | prev_reset = inb(0x03f2) & 0x04;
|
---|
| 180 | if (drive)
|
---|
| 181 | dor = 0x20;
|
---|
| 182 | else
|
---|
| 183 | dor = 0x10;
|
---|
| 184 | dor |= 0x0c;
|
---|
| 185 | dor |= drive;
|
---|
| 186 | outb(0x03f2, dor);
|
---|
[48947] | 187 |
|
---|
[38699] | 188 | // reset the disk motor timeout value of INT 08
|
---|
[46947] | 189 | write_byte(0x0040,0x0040, BX_FLOPPY_ON_CNT);
|
---|
[48947] | 190 |
|
---|
[38699] | 191 | // program data rate
|
---|
| 192 | val8 = read_byte(0x0040, 0x008b);
|
---|
| 193 | val8 >>= 6;
|
---|
| 194 | outb(0x03f7, val8);
|
---|
[48947] | 195 |
|
---|
[38699] | 196 | // wait for drive readiness
|
---|
| 197 | do {
|
---|
| 198 | val8 = inb(0x3f4);
|
---|
| 199 | } while ( (val8 & 0xc0) != 0x80 );
|
---|
[48947] | 200 |
|
---|
[38699] | 201 | if (prev_reset == 0) {
|
---|
[46947] | 202 | #ifdef VBOX_WITH_FLOPPY_IRQ_POLLING
|
---|
[38699] | 203 | // turn on interrupts
|
---|
| 204 | int_enable();
|
---|
| 205 | // wait on 40:3e bit 7 to become 1
|
---|
| 206 | do {
|
---|
| 207 | val8 = read_byte(0x0040, 0x003e);
|
---|
[59115] | 208 | } while ( (val8 & 0x80) == 0 );
|
---|
[38699] | 209 | val8 &= 0x7f;
|
---|
| 210 | int_disable();
|
---|
[46947] | 211 | #else
|
---|
| 212 | val8 = floppy_wait_for_interrupt(); /* (7th bit cleared in ret val) */
|
---|
| 213 | #endif
|
---|
[38699] | 214 | write_byte(0x0040, 0x003e, val8);
|
---|
| 215 | }
|
---|
| 216 | }
|
---|
| 217 |
|
---|
| 218 | bx_bool floppy_media_known(uint16_t drive)
|
---|
| 219 | {
|
---|
| 220 | uint8_t val8;
|
---|
| 221 | uint16_t media_state_offset;
|
---|
[48947] | 222 |
|
---|
[38699] | 223 | val8 = read_byte(0x0040, 0x003e); // diskette recal status
|
---|
| 224 | if (drive)
|
---|
| 225 | val8 >>= 1;
|
---|
| 226 | val8 &= 0x01;
|
---|
| 227 | if (val8 == 0)
|
---|
| 228 | return 0;
|
---|
[48947] | 229 |
|
---|
[38699] | 230 | media_state_offset = 0x0090;
|
---|
| 231 | if (drive)
|
---|
| 232 | media_state_offset += 1;
|
---|
[48947] | 233 |
|
---|
[38699] | 234 | val8 = read_byte(0x0040, media_state_offset);
|
---|
| 235 | val8 = (val8 >> 4) & 0x01;
|
---|
| 236 | if (val8 == 0)
|
---|
| 237 | return 0;
|
---|
[48947] | 238 |
|
---|
[38699] | 239 | // checks passed, return KNOWN
|
---|
| 240 | return 1;
|
---|
| 241 | }
|
---|
| 242 |
|
---|
| 243 | bx_bool floppy_read_id(uint16_t drive)
|
---|
| 244 | {
|
---|
[46947] | 245 | #ifdef VBOX_WITH_FLOPPY_IRQ_POLLING
|
---|
[38699] | 246 | uint8_t val8;
|
---|
[46947] | 247 | #endif
|
---|
[38699] | 248 | int i;
|
---|
[48947] | 249 |
|
---|
[38699] | 250 | floppy_prepare_controller(drive);
|
---|
[48947] | 251 |
|
---|
[38699] | 252 | // send Read ID command (2 bytes) to controller
|
---|
| 253 | outb(0x03f5, 0x4a); // 4a: Read ID (MFM)
|
---|
| 254 | outb(0x03f5, drive); // 0=drive0, 1=drive1, head always 0
|
---|
[48947] | 255 |
|
---|
[46947] | 256 | #ifdef VBOX_WITH_FLOPPY_IRQ_POLLING
|
---|
[38699] | 257 | // turn on interrupts
|
---|
| 258 | int_enable();
|
---|
[48947] | 259 |
|
---|
[38699] | 260 | // wait on 40:3e bit 7 to become 1
|
---|
| 261 | do {
|
---|
| 262 | val8 = (read_byte(0x0040, 0x003e) & 0x80);
|
---|
| 263 | } while ( val8 == 0 );
|
---|
[48947] | 264 |
|
---|
[38699] | 265 | val8 = 0; // separate asm from while() loop
|
---|
| 266 | // turn off interrupts
|
---|
| 267 | int_disable();
|
---|
[46947] | 268 | #else
|
---|
| 269 | floppy_wait_for_interrupt();
|
---|
| 270 | #endif
|
---|
[48947] | 271 |
|
---|
[38699] | 272 | // read 7 return status bytes from controller
|
---|
[67069] | 273 | for (i = 0; i < 7; ++i)
|
---|
| 274 | write_byte(0x0040, 0x0042 + i, inb(0x3f5));
|
---|
[48947] | 275 |
|
---|
[67069] | 276 | if ((read_byte(0x0040, 0x0042 + 0) & 0xc0) != 0)
|
---|
[38699] | 277 | return 0;
|
---|
| 278 | else
|
---|
| 279 | return 1;
|
---|
| 280 | }
|
---|
| 281 |
|
---|
| 282 | bx_bool floppy_drive_recal(uint16_t drive)
|
---|
| 283 | {
|
---|
| 284 | uint8_t val8;
|
---|
| 285 | uint16_t curr_cyl_offset;
|
---|
[48947] | 286 |
|
---|
[38699] | 287 | floppy_prepare_controller(drive);
|
---|
[48947] | 288 |
|
---|
[38699] | 289 | // send Recalibrate command (2 bytes) to controller
|
---|
| 290 | outb(0x03f5, 0x07); // 07: Recalibrate
|
---|
| 291 | outb(0x03f5, drive); // 0=drive0, 1=drive1
|
---|
[48947] | 292 |
|
---|
[46947] | 293 | #ifdef VBOX_WITH_FLOPPY_IRQ_POLLING
|
---|
[38699] | 294 | // turn on interrupts
|
---|
| 295 | int_enable();
|
---|
[48947] | 296 |
|
---|
[38699] | 297 | // wait on 40:3e bit 7 to become 1
|
---|
| 298 | do {
|
---|
| 299 | val8 = (read_byte(0x0040, 0x003e) & 0x80);
|
---|
| 300 | } while ( val8 == 0 );
|
---|
[48947] | 301 |
|
---|
[38699] | 302 | val8 = 0; // separate asm from while() loop
|
---|
| 303 | // turn off interrupts
|
---|
| 304 | int_disable();
|
---|
[46947] | 305 |
|
---|
[38699] | 306 | // set 40:3e bit 7 to 0, and calibrated bit
|
---|
| 307 | val8 = read_byte(0x0040, 0x003e);
|
---|
| 308 | val8 &= 0x7f;
|
---|
[46947] | 309 | #else
|
---|
| 310 | val8 = floppy_wait_for_interrupt(); /* (7th bit cleared in ret val) */
|
---|
| 311 |
|
---|
| 312 | // set 40:3e bit 7 to 0, and calibrated bit
|
---|
| 313 | #endif
|
---|
[38699] | 314 | if (drive) {
|
---|
| 315 | val8 |= 0x02; // Drive 1 calibrated
|
---|
| 316 | curr_cyl_offset = 0x0095;
|
---|
| 317 | } else {
|
---|
| 318 | val8 |= 0x01; // Drive 0 calibrated
|
---|
| 319 | curr_cyl_offset = 0x0094;
|
---|
| 320 | }
|
---|
| 321 | write_byte(0x0040, 0x003e, val8);
|
---|
| 322 | write_byte(0x0040, curr_cyl_offset, 0); // current cylinder is 0
|
---|
[48947] | 323 |
|
---|
[38699] | 324 | return 1;
|
---|
| 325 | }
|
---|
| 326 |
|
---|
| 327 |
|
---|
| 328 | bx_bool floppy_media_sense(uint16_t drive)
|
---|
| 329 | {
|
---|
| 330 | bx_bool retval;
|
---|
| 331 | uint16_t media_state_offset;
|
---|
| 332 | uint8_t drive_type, config_data, media_state;
|
---|
[48947] | 333 |
|
---|
[38699] | 334 | if (floppy_drive_recal(drive) == 0)
|
---|
| 335 | return 0;
|
---|
[48947] | 336 |
|
---|
[38699] | 337 | // Try the diskette data rates in the following order:
|
---|
| 338 | // 1 Mbps -> 500 Kbps -> 300 Kbps -> 250 Kbps
|
---|
| 339 | // The 1 Mbps rate is only tried for 2.88M drives.
|
---|
[48947] | 340 |
|
---|
[38699] | 341 | // ** config_data **
|
---|
| 342 | // Bitfields for diskette media control:
|
---|
| 343 | // Bit(s) Description (Table M0028)
|
---|
| 344 | // 7-6 last data rate set by controller
|
---|
| 345 | // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
|
---|
| 346 | // 5-4 last diskette drive step rate selected
|
---|
| 347 | // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
|
---|
| 348 | // 3-2 {data rate at start of operation}
|
---|
| 349 | // 1-0 reserved
|
---|
[48947] | 350 |
|
---|
[38699] | 351 | // ** media_state **
|
---|
| 352 | // Bitfields for diskette drive media state:
|
---|
| 353 | // Bit(s) Description (Table M0030)
|
---|
| 354 | // 7-6 data rate
|
---|
| 355 | // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
|
---|
| 356 | // 5 double stepping required (e.g. 360kB in 1.2MB)
|
---|
| 357 | // 4 media type established
|
---|
| 358 | // 3 drive capable of supporting 4MB media
|
---|
| 359 | // 2-0 on exit from BIOS, contains
|
---|
| 360 | // 000 trying 360kB in 360kB
|
---|
| 361 | // 001 trying 360kB in 1.2MB
|
---|
| 362 | // 010 trying 1.2MB in 1.2MB
|
---|
| 363 | // 011 360kB in 360kB established
|
---|
| 364 | // 100 360kB in 1.2MB established
|
---|
| 365 | // 101 1.2MB in 1.2MB established
|
---|
| 366 | // 110 reserved
|
---|
| 367 | // 111 all other formats/drives
|
---|
| 368 |
|
---|
[63562] | 369 | /// @todo break out drive type determination
|
---|
[38699] | 370 | drive_type = inb_cmos(0x10);
|
---|
| 371 | if (drive == 0)
|
---|
| 372 | drive_type >>= 4;
|
---|
| 373 | else
|
---|
| 374 | drive_type &= 0x0f;
|
---|
| 375 | if ( drive_type == 1 ) {
|
---|
| 376 | // 360K 5.25" drive
|
---|
| 377 | config_data = 0x00; // 0000 0000
|
---|
| 378 | media_state = 0x15; // 0001 0101
|
---|
| 379 | retval = 1;
|
---|
| 380 | }
|
---|
| 381 | else if ( drive_type == 2 ) {
|
---|
| 382 | // 1.2 MB 5.25" drive
|
---|
| 383 | config_data = 0x00; // 0000 0000
|
---|
| 384 | media_state = 0x35; // 0011 0101 // need double stepping??? (bit 5)
|
---|
| 385 | retval = 1;
|
---|
| 386 | }
|
---|
| 387 | else if ( drive_type == 3 ) {
|
---|
| 388 | // 720K 3.5" drive
|
---|
| 389 | config_data = 0x00; // 0000 0000 ???
|
---|
| 390 | media_state = 0x17; // 0001 0111
|
---|
| 391 | retval = 1;
|
---|
| 392 | }
|
---|
| 393 | else if ( drive_type == 4 ) {
|
---|
| 394 | // 1.44 MB 3.5" drive
|
---|
| 395 | config_data = 0x00; // 0000 0000
|
---|
| 396 | media_state = 0x17; // 0001 0111
|
---|
| 397 | retval = 1;
|
---|
| 398 | }
|
---|
| 399 | else if ( drive_type == 5 ) {
|
---|
| 400 | // 2.88 MB 3.5" drive
|
---|
| 401 | config_data = 0xCC; // 1100 1100
|
---|
| 402 | media_state = 0xD7; // 1101 0111
|
---|
| 403 | retval = 1;
|
---|
| 404 | }
|
---|
| 405 | // Extended floppy size uses special cmos setting
|
---|
[47036] | 406 | else if ( drive_type == 14 || drive_type == 15 ) {
|
---|
| 407 | // 15.6 MB 3.5" (fake) || 63.5 MB 3.5" (fake) - report same as 2.88 MB.
|
---|
| 408 | config_data = 0xCC; // 1100 1100
|
---|
| 409 | media_state = 0xD7; // 1101 0111
|
---|
| 410 | retval = 1;
|
---|
| 411 | }
|
---|
[38699] | 412 | else {
|
---|
| 413 | // not recognized
|
---|
| 414 | config_data = 0x00; // 0000 0000
|
---|
| 415 | media_state = 0x00; // 0000 0000
|
---|
| 416 | retval = 0;
|
---|
| 417 | }
|
---|
[48947] | 418 |
|
---|
[38699] | 419 | write_byte(0x0040, 0x008B, config_data);
|
---|
| 420 | while (!floppy_read_id(drive)) {
|
---|
| 421 | if ((config_data & 0xC0) == 0x80) {
|
---|
| 422 | // If even 250 Kbps failed, we can't do much
|
---|
| 423 | break;
|
---|
| 424 | }
|
---|
| 425 | switch (config_data & 0xC0) {
|
---|
| 426 | case 0xC0: // 1 Mbps
|
---|
| 427 | config_data = config_data & 0x3F | 0x00;
|
---|
| 428 | break;
|
---|
| 429 | case 0x00: // 500 Kbps
|
---|
| 430 | config_data = config_data & 0x3F | 0x40;
|
---|
| 431 | break;
|
---|
| 432 | case 0x40: // 300 Kbps
|
---|
| 433 | config_data = config_data & 0x3F | 0x80;
|
---|
| 434 | break;
|
---|
| 435 | }
|
---|
| 436 | write_byte(0x0040, 0x008B, config_data);
|
---|
| 437 | }
|
---|
[48947] | 438 |
|
---|
[38699] | 439 | if (drive == 0)
|
---|
| 440 | media_state_offset = 0x0090;
|
---|
| 441 | else
|
---|
| 442 | media_state_offset = 0x0091;
|
---|
| 443 | write_byte(0x0040, 0x008B, config_data);
|
---|
| 444 | write_byte(0x0040, media_state_offset, media_state);
|
---|
[48947] | 445 |
|
---|
[38699] | 446 | return retval;
|
---|
| 447 | }
|
---|
| 448 |
|
---|
| 449 |
|
---|
| 450 | bx_bool floppy_drive_exists(uint16_t drive)
|
---|
| 451 | {
|
---|
| 452 | uint8_t drive_type;
|
---|
[48947] | 453 |
|
---|
[38699] | 454 | // check CMOS to see if drive exists
|
---|
[63562] | 455 | /// @todo break out drive type determination
|
---|
[38699] | 456 | drive_type = inb_cmos(0x10);
|
---|
| 457 | if (drive == 0)
|
---|
| 458 | drive_type >>= 4;
|
---|
| 459 | else
|
---|
| 460 | drive_type &= 0x0f;
|
---|
| 461 | return drive_type != 0;
|
---|
| 462 | }
|
---|
| 463 |
|
---|
[63562] | 464 | /// @todo put in a header
|
---|
[38699] | 465 | #define AX r.gr.u.r16.ax
|
---|
| 466 | #define BX r.gr.u.r16.bx
|
---|
| 467 | #define CX r.gr.u.r16.cx
|
---|
| 468 | #define DX r.gr.u.r16.dx
|
---|
[67069] | 469 | #define SI r.gr.u.r16.si // not used
|
---|
[38699] | 470 | #define DI r.gr.u.r16.di
|
---|
[67069] | 471 | #define BP r.gr.u.r16.bp // not used
|
---|
[38699] | 472 | #define ELDX r.gr.u.r16.sp
|
---|
[67069] | 473 | #define DS r.ds // not used
|
---|
[38699] | 474 | #define ES r.es
|
---|
| 475 | #define FLAGS r.ra.flags.u.r16.flags
|
---|
| 476 |
|
---|
| 477 | void BIOSCALL int13_diskette_function(disk_regs_t r)
|
---|
| 478 | {
|
---|
| 479 | uint8_t drive, num_sectors, track, sector, head;
|
---|
| 480 | uint16_t base_address, base_count, base_es;
|
---|
[54563] | 481 | uint8_t page, mode_register, val8, media_state;
|
---|
[67069] | 482 | uint8_t drive_type, num_floppies;
|
---|
[38699] | 483 | uint16_t last_addr;
|
---|
| 484 | int i;
|
---|
[48947] | 485 |
|
---|
[38699] | 486 | BX_DEBUG_INT13_FL("%s: AX=%04x BX=%04x CX=%04x DX=%04x ES=%04x\n", __func__, AX, BX, CX, DX, ES);
|
---|
[48947] | 487 |
|
---|
[67694] | 488 | SET_IF(); /* INT 13h always returns with interrupts enabled. */
|
---|
| 489 |
|
---|
[67069] | 490 | switch ( GET_AH() ) {
|
---|
[38699] | 491 | case 0x00: // diskette controller reset
|
---|
| 492 | BX_DEBUG_INT13_FL("floppy f00\n");
|
---|
| 493 | drive = GET_ELDL();
|
---|
| 494 | if (drive > 1) {
|
---|
| 495 | SET_AH(1); // invalid param
|
---|
| 496 | set_diskette_ret_status(1);
|
---|
| 497 | SET_CF();
|
---|
| 498 | return;
|
---|
| 499 | }
|
---|
[63562] | 500 | /// @todo break out drive type determination
|
---|
[38699] | 501 | drive_type = inb_cmos(0x10);
|
---|
| 502 | if (drive == 0)
|
---|
| 503 | drive_type >>= 4;
|
---|
| 504 | else
|
---|
| 505 | drive_type &= 0x0f;
|
---|
| 506 | if (drive_type == 0) {
|
---|
| 507 | SET_AH(0x80); // drive not responding
|
---|
| 508 | set_diskette_ret_status(0x80);
|
---|
| 509 | SET_CF();
|
---|
| 510 | return;
|
---|
| 511 | }
|
---|
[48947] | 512 |
|
---|
[38699] | 513 | // force re-calibration etc.
|
---|
| 514 | write_byte(0x0040, 0x003e, 0);
|
---|
[48947] | 515 |
|
---|
[38699] | 516 | SET_AH(0);
|
---|
| 517 | set_diskette_ret_status(0);
|
---|
| 518 | CLEAR_CF(); // successful
|
---|
| 519 | set_diskette_current_cyl(drive, 0); // current cylinder
|
---|
| 520 | return;
|
---|
[48947] | 521 |
|
---|
[38699] | 522 | case 0x01: // Read Diskette Status
|
---|
| 523 | CLEAR_CF();
|
---|
| 524 | val8 = read_byte(0x0000, 0x0441);
|
---|
| 525 | SET_AH(val8);
|
---|
| 526 | if (val8) {
|
---|
| 527 | SET_CF();
|
---|
| 528 | }
|
---|
| 529 | return;
|
---|
[48947] | 530 |
|
---|
[38699] | 531 | case 0x02: // Read Diskette Sectors
|
---|
| 532 | case 0x03: // Write Diskette Sectors
|
---|
| 533 | case 0x04: // Verify Diskette Sectors
|
---|
| 534 | num_sectors = GET_AL();
|
---|
| 535 | track = GET_CH();
|
---|
| 536 | sector = GET_CL();
|
---|
| 537 | head = GET_DH();
|
---|
| 538 | drive = GET_ELDL();
|
---|
[48947] | 539 |
|
---|
[38699] | 540 | if ( (drive > 1) || (head > 1) ||
|
---|
| 541 | (num_sectors == 0) || (num_sectors > 72) ) {
|
---|
| 542 | BX_INFO("%s: drive>1 || head>1 ...\n", __func__);
|
---|
| 543 | SET_AH(1);
|
---|
| 544 | set_diskette_ret_status(1);
|
---|
| 545 | SET_AL(0); // no sectors read
|
---|
| 546 | SET_CF(); // error occurred
|
---|
| 547 | return;
|
---|
| 548 | }
|
---|
[48947] | 549 |
|
---|
[38699] | 550 | // see if drive exists
|
---|
| 551 | if (floppy_drive_exists(drive) == 0) {
|
---|
[62301] | 552 | BX_DEBUG_INT13_FL("failed (not ready)\n");
|
---|
[38699] | 553 | SET_AH(0x80); // not responding
|
---|
| 554 | set_diskette_ret_status(0x80);
|
---|
| 555 | SET_AL(0); // no sectors read
|
---|
| 556 | SET_CF(); // error occurred
|
---|
| 557 | return;
|
---|
| 558 | }
|
---|
[48947] | 559 |
|
---|
[38699] | 560 | // see if media in drive, and type is known
|
---|
| 561 | if (floppy_media_known(drive) == 0) {
|
---|
| 562 | if (floppy_media_sense(drive) == 0) {
|
---|
[62301] | 563 | BX_DEBUG_INT13_FL("media not found\n");
|
---|
[38699] | 564 | SET_AH(0x0C); // Media type not found
|
---|
| 565 | set_diskette_ret_status(0x0C);
|
---|
| 566 | SET_AL(0); // no sectors read
|
---|
| 567 | SET_CF(); // error occurred
|
---|
| 568 | return;
|
---|
| 569 | }
|
---|
| 570 | }
|
---|
[48947] | 571 |
|
---|
[67069] | 572 | if (GET_AH() == 0x02) {
|
---|
[38699] | 573 | // Read Diskette Sectors
|
---|
[48947] | 574 |
|
---|
[38699] | 575 | //-----------------------------------
|
---|
| 576 | // set up DMA controller for transfer
|
---|
| 577 | //-----------------------------------
|
---|
[48947] | 578 |
|
---|
[38699] | 579 | // es:bx = pointer to where to place information from diskette
|
---|
| 580 | // port 04: DMA-1 base and current address, channel 2
|
---|
| 581 | // port 05: DMA-1 base and current count, channel 2
|
---|
[63562] | 582 | /// @todo merge/factor out pointer normalization
|
---|
[38699] | 583 | page = (ES >> 12); // upper 4 bits
|
---|
| 584 | base_es = (ES << 4); // lower 16bits contributed by ES
|
---|
| 585 | base_address = base_es + BX; // lower 16 bits of address
|
---|
| 586 | // contributed by ES:BX
|
---|
| 587 | if ( base_address < base_es ) {
|
---|
| 588 | // in case of carry, adjust page by 1
|
---|
| 589 | page++;
|
---|
| 590 | }
|
---|
| 591 | base_count = (num_sectors * 512) - 1;
|
---|
[48947] | 592 |
|
---|
[38699] | 593 | // check for 64K boundary overrun
|
---|
| 594 | last_addr = base_address + base_count;
|
---|
| 595 | if (last_addr < base_address) {
|
---|
| 596 | SET_AH(0x09);
|
---|
| 597 | set_diskette_ret_status(0x09);
|
---|
| 598 | SET_AL(0); // no sectors read
|
---|
| 599 | SET_CF(); // error occurred
|
---|
| 600 | return;
|
---|
| 601 | }
|
---|
[48947] | 602 |
|
---|
[38699] | 603 | BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
|
---|
| 604 | outb(0x000a, 0x06);
|
---|
[48947] | 605 |
|
---|
[38699] | 606 | BX_DEBUG_INT13_FL("clear flip-flop\n");
|
---|
| 607 | outb(0x000c, 0x00); // clear flip-flop
|
---|
| 608 | outb(0x0004, base_address);
|
---|
| 609 | outb(0x0004, base_address>>8);
|
---|
| 610 | BX_DEBUG_INT13_FL("clear flip-flop\n");
|
---|
| 611 | outb(0x000c, 0x00); // clear flip-flop
|
---|
| 612 | outb(0x0005, base_count);
|
---|
| 613 | outb(0x0005, base_count>>8);
|
---|
[53624] | 614 | BX_DEBUG_INT13_FL("xfer buf %x bytes at %x:%x\n",
|
---|
[62301] | 615 | base_count + 1, page, base_address);
|
---|
[48947] | 616 |
|
---|
[38699] | 617 | // port 0b: DMA-1 Mode Register
|
---|
| 618 | mode_register = 0x46; // single mode, increment, autoinit disable,
|
---|
| 619 | // transfer type=write, channel 2
|
---|
| 620 | BX_DEBUG_INT13_FL("setting mode register\n");
|
---|
| 621 | outb(0x000b, mode_register);
|
---|
[48947] | 622 |
|
---|
[38699] | 623 | BX_DEBUG_INT13_FL("setting page register\n");
|
---|
| 624 | // port 81: DMA-1 Page Register, channel 2
|
---|
| 625 | outb(0x0081, page);
|
---|
[48947] | 626 |
|
---|
[52479] | 627 | BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
|
---|
[38699] | 628 | outb(0x000a, 0x02); // unmask channel 2
|
---|
[48947] | 629 |
|
---|
[38699] | 630 | //--------------------------------------
|
---|
| 631 | // set up floppy controller for transfer
|
---|
| 632 | //--------------------------------------
|
---|
| 633 | floppy_prepare_controller(drive);
|
---|
[48947] | 634 |
|
---|
[38699] | 635 | // send read-normal-data command (9 bytes) to controller
|
---|
| 636 | outb(0x03f5, 0xe6); // e6: read normal data
|
---|
| 637 | outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
|
---|
| 638 | outb(0x03f5, track);
|
---|
| 639 | outb(0x03f5, head);
|
---|
| 640 | outb(0x03f5, sector);
|
---|
| 641 | outb(0x03f5, 2); // 512 byte sector size
|
---|
| 642 | outb(0x03f5, sector + num_sectors - 1); // last sector to read on track
|
---|
| 643 | outb(0x03f5, 0); // Gap length
|
---|
| 644 | outb(0x03f5, 0xff); // Gap length
|
---|
[62301] | 645 | BX_DEBUG_INT13_FL("read initiated\n");
|
---|
[48947] | 646 |
|
---|
[46947] | 647 | #ifdef VBOX_WITH_FLOPPY_IRQ_POLLING
|
---|
[38699] | 648 | // turn on interrupts
|
---|
| 649 | int_enable();
|
---|
[48947] | 650 |
|
---|
[46947] | 651 | // wait on 40:3e bit 7 to become 1 or timeout (latter isn't armed so it won't happen)
|
---|
[38699] | 652 | do {
|
---|
[46947] | 653 | val8 = read_byte(0x0040, 0x0040);
|
---|
[38699] | 654 | if (val8 == 0) {
|
---|
[62301] | 655 | BX_DEBUG_INT13_FL("failed (not ready)\n");
|
---|
| 656 | floppy_reset_controller(drive);
|
---|
[38699] | 657 | SET_AH(0x80); // drive not ready (timeout)
|
---|
| 658 | set_diskette_ret_status(0x80);
|
---|
| 659 | SET_AL(0); // no sectors read
|
---|
| 660 | SET_CF(); // error occurred
|
---|
| 661 | return;
|
---|
| 662 | }
|
---|
| 663 | val8 = (read_byte(0x0040, 0x003e) & 0x80);
|
---|
| 664 | } while ( val8 == 0 );
|
---|
[48947] | 665 |
|
---|
[38699] | 666 | val8 = 0; // separate asm from while() loop
|
---|
| 667 | // turn off interrupts
|
---|
| 668 | int_disable();
|
---|
[46947] | 669 |
|
---|
[38699] | 670 | // set 40:3e bit 7 to 0
|
---|
| 671 | val8 = read_byte(0x0040, 0x003e);
|
---|
| 672 | val8 &= 0x7f;
|
---|
| 673 | write_byte(0x0040, 0x003e, val8);
|
---|
[46947] | 674 |
|
---|
| 675 | #else
|
---|
| 676 | val8 = floppy_wait_for_interrupt_or_timeout();
|
---|
| 677 | if (val8 == 0) { /* Note! Interrupts enabled in this branch. */
|
---|
[62301] | 678 | BX_DEBUG_INT13_FL("failed (not ready)\n");
|
---|
| 679 | floppy_reset_controller(drive);
|
---|
[46947] | 680 | SET_AH(0x80); // drive not ready (timeout)
|
---|
| 681 | set_diskette_ret_status(0x80);
|
---|
| 682 | SET_AL(0); // no sectors read
|
---|
| 683 | SET_CF(); // error occurred
|
---|
| 684 | return;
|
---|
| 685 | }
|
---|
| 686 | #endif
|
---|
[48947] | 687 |
|
---|
[38699] | 688 | // check port 3f4 for accessibility to status bytes
|
---|
| 689 | val8 = inb(0x3f4);
|
---|
| 690 | if ( (val8 & 0xc0) != 0xc0 )
|
---|
| 691 | BX_PANIC("%s: ctrl not ready\n", __func__);
|
---|
| 692 |
|
---|
| 693 | // read 7 return status bytes from controller and store in BDA
|
---|
[67069] | 694 | for (i = 0; i < 7; ++i)
|
---|
| 695 | write_byte(0x0040, 0x0042 + i, inb(0x3f5));
|
---|
[48947] | 696 |
|
---|
[67069] | 697 | if ((read_byte(0x0040, 0x0042 + 0) & 0xc0) != 0) {
|
---|
[62301] | 698 | BX_DEBUG_INT13_FL("failed (FDC failure)\n");
|
---|
| 699 | floppy_reset_controller(drive);
|
---|
[38699] | 700 | SET_AH(0x20);
|
---|
| 701 | set_diskette_ret_status(0x20);
|
---|
| 702 | SET_AL(0); // no sectors read
|
---|
| 703 | SET_CF(); // error occurred
|
---|
| 704 | return;
|
---|
| 705 | }
|
---|
[38997] | 706 |
|
---|
| 707 | #ifdef DMA_WORKAROUND
|
---|
| 708 | rep_movsw(ES :> BX, ES :> BX, num_sectors * 512 / 2);
|
---|
| 709 | #endif
|
---|
[62301] | 710 | BX_DEBUG_INT13_FL("success!\n");
|
---|
[38699] | 711 | // ??? should track be new val from return_status[3] ?
|
---|
| 712 | set_diskette_current_cyl(drive, track);
|
---|
| 713 | // AL = number of sectors read (same value as passed)
|
---|
| 714 | SET_AH(0x00); // success
|
---|
| 715 | CLEAR_CF(); // success
|
---|
| 716 | return;
|
---|
[67069] | 717 | } else if (GET_AH() == 0x03) {
|
---|
[38699] | 718 | // Write Diskette Sectors
|
---|
[48947] | 719 |
|
---|
[38699] | 720 | //-----------------------------------
|
---|
| 721 | // set up DMA controller for transfer
|
---|
| 722 | //-----------------------------------
|
---|
[48947] | 723 |
|
---|
[38699] | 724 | // es:bx = pointer to where to place information from diskette
|
---|
| 725 | // port 04: DMA-1 base and current address, channel 2
|
---|
| 726 | // port 05: DMA-1 base and current count, channel 2
|
---|
[63562] | 727 | /// @todo merge/factor out pointer normalization
|
---|
[38699] | 728 | page = (ES >> 12); // upper 4 bits
|
---|
| 729 | base_es = (ES << 4); // lower 16bits contributed by ES
|
---|
| 730 | base_address = base_es + BX; // lower 16 bits of address
|
---|
| 731 | // contributed by ES:BX
|
---|
| 732 | if ( base_address < base_es ) {
|
---|
| 733 | // in case of carry, adjust page by 1
|
---|
| 734 | page++;
|
---|
| 735 | }
|
---|
| 736 | base_count = (num_sectors * 512) - 1;
|
---|
[48947] | 737 |
|
---|
[38699] | 738 | // check for 64K boundary overrun
|
---|
| 739 | last_addr = base_address + base_count;
|
---|
| 740 | if (last_addr < base_address) {
|
---|
| 741 | SET_AH(0x09);
|
---|
| 742 | set_diskette_ret_status(0x09);
|
---|
| 743 | SET_AL(0); // no sectors read
|
---|
| 744 | SET_CF(); // error occurred
|
---|
| 745 | return;
|
---|
| 746 | }
|
---|
[48947] | 747 |
|
---|
[38699] | 748 | BX_DEBUG_INT13_FL("masking DMA-1 c2\n");
|
---|
| 749 | outb(0x000a, 0x06);
|
---|
[48947] | 750 |
|
---|
[38699] | 751 | outb(0x000c, 0x00); // clear flip-flop
|
---|
| 752 | outb(0x0004, base_address);
|
---|
| 753 | outb(0x0004, base_address>>8);
|
---|
| 754 | outb(0x000c, 0x00); // clear flip-flop
|
---|
| 755 | outb(0x0005, base_count);
|
---|
| 756 | outb(0x0005, base_count>>8);
|
---|
[53624] | 757 | BX_DEBUG_INT13_FL("xfer buf %x bytes at %x:%x\n",
|
---|
[52479] | 758 | base_count, page, base_address);
|
---|
[48947] | 759 |
|
---|
[38699] | 760 | // port 0b: DMA-1 Mode Register
|
---|
| 761 | mode_register = 0x4a; // single mode, increment, autoinit disable,
|
---|
| 762 | // transfer type=read, channel 2
|
---|
| 763 | outb(0x000b, mode_register);
|
---|
[48947] | 764 |
|
---|
[38699] | 765 | // port 81: DMA-1 Page Register, channel 2
|
---|
| 766 | outb(0x0081, page);
|
---|
[48947] | 767 |
|
---|
[38699] | 768 | BX_DEBUG_INT13_FL("unmasking DMA-1 c2\n");
|
---|
| 769 | outb(0x000a, 0x02);
|
---|
[48947] | 770 |
|
---|
[38699] | 771 | //--------------------------------------
|
---|
| 772 | // set up floppy controller for transfer
|
---|
| 773 | //--------------------------------------
|
---|
| 774 | floppy_prepare_controller(drive);
|
---|
[48947] | 775 |
|
---|
[38699] | 776 | // send write-normal-data command (9 bytes) to controller
|
---|
| 777 | outb(0x03f5, 0xc5); // c5: write normal data
|
---|
| 778 | outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
|
---|
| 779 | outb(0x03f5, track);
|
---|
| 780 | outb(0x03f5, head);
|
---|
| 781 | outb(0x03f5, sector);
|
---|
| 782 | outb(0x03f5, 2); // 512 byte sector size
|
---|
| 783 | outb(0x03f5, sector + num_sectors - 1); // last sector to write on track
|
---|
| 784 | outb(0x03f5, 0); // Gap length
|
---|
| 785 | outb(0x03f5, 0xff); // Gap length
|
---|
[48947] | 786 |
|
---|
[46947] | 787 | #ifdef VBOX_WITH_FLOPPY_IRQ_POLLING
|
---|
[38699] | 788 | // turn on interrupts
|
---|
| 789 | int_enable();
|
---|
[48947] | 790 |
|
---|
[38699] | 791 | // wait on 40:3e bit 7 to become 1
|
---|
| 792 | do {
|
---|
| 793 | val8 = read_byte(0x0040, 0x0040);
|
---|
| 794 | if (val8 == 0) {
|
---|
[62301] | 795 | floppy_reset_controller(drive);
|
---|
[38699] | 796 | SET_AH(0x80); // drive not ready (timeout)
|
---|
| 797 | set_diskette_ret_status(0x80);
|
---|
| 798 | SET_AL(0); // no sectors written
|
---|
| 799 | SET_CF(); // error occurred
|
---|
| 800 | return;
|
---|
| 801 | }
|
---|
| 802 | val8 = (read_byte(0x0040, 0x003e) & 0x80);
|
---|
| 803 | } while ( val8 == 0 );
|
---|
[48947] | 804 |
|
---|
[38699] | 805 | val8 = 0; // separate asm from while() loop @todo: why??
|
---|
| 806 | // turn off interrupts
|
---|
| 807 | int_disable();
|
---|
[46947] | 808 |
|
---|
[38699] | 809 | // set 40:3e bit 7 to 0
|
---|
| 810 | val8 = read_byte(0x0040, 0x003e);
|
---|
| 811 | val8 &= 0x7f;
|
---|
| 812 | write_byte(0x0040, 0x003e, val8);
|
---|
[46947] | 813 | #else
|
---|
| 814 | val8 = floppy_wait_for_interrupt_or_timeout();
|
---|
| 815 | if (val8 == 0) { /* Note! Interrupts enabled in this branch. */
|
---|
[62301] | 816 | floppy_reset_controller(drive);
|
---|
[46947] | 817 | SET_AH(0x80); // drive not ready (timeout)
|
---|
| 818 | set_diskette_ret_status(0x80);
|
---|
| 819 | SET_AL(0); // no sectors written
|
---|
| 820 | SET_CF(); // error occurred
|
---|
| 821 | return;
|
---|
| 822 | }
|
---|
| 823 | #endif
|
---|
[48947] | 824 |
|
---|
[38699] | 825 | // check port 3f4 for accessibility to status bytes
|
---|
| 826 | val8 = inb(0x3f4);
|
---|
| 827 | if ( (val8 & 0xc0) != 0xc0 )
|
---|
| 828 | BX_PANIC("%s: ctrl not ready\n", __func__);
|
---|
[48947] | 829 |
|
---|
[38699] | 830 | // read 7 return status bytes from controller and store in BDA
|
---|
[67069] | 831 | for (i = 0; i < 7; ++i)
|
---|
| 832 | write_byte(0x0040, 0x0042 + i, inb(0x3f5));
|
---|
[48947] | 833 |
|
---|
[67069] | 834 | if ((read_byte(0x0040, 0x0042 + 0) & 0xc0) != 0) {
|
---|
| 835 | if ((read_byte(0x0040, 0x0042 + 1) & 0x02) != 0) {
|
---|
[38699] | 836 | // diskette not writable.
|
---|
| 837 | // AH=status code=0x03 (tried to write on write-protected disk)
|
---|
| 838 | // AL=number of sectors written=0
|
---|
| 839 | AX = 0x0300;
|
---|
| 840 | } else {
|
---|
[43676] | 841 | // Some other problem occurred.
|
---|
| 842 | AX = 0x0100;
|
---|
[38699] | 843 | }
|
---|
[43676] | 844 | SET_CF();
|
---|
| 845 | return;
|
---|
[38699] | 846 | }
|
---|
[48947] | 847 |
|
---|
[38699] | 848 | // ??? should track be new val from return_status[3] ?
|
---|
| 849 | set_diskette_current_cyl(drive, track);
|
---|
| 850 | // AL = number of sectors read (same value as passed)
|
---|
| 851 | SET_AH(0x00); // success
|
---|
| 852 | CLEAR_CF(); // success
|
---|
| 853 | return;
|
---|
| 854 | } else { // if (ah == 0x04)
|
---|
| 855 | // Verify Diskette Sectors
|
---|
[48947] | 856 |
|
---|
[38699] | 857 | // ??? should track be new val from return_status[3] ?
|
---|
| 858 | set_diskette_current_cyl(drive, track);
|
---|
| 859 | // AL = number of sectors verified (same value as passed)
|
---|
| 860 | CLEAR_CF(); // success
|
---|
| 861 | SET_AH(0x00); // success
|
---|
| 862 | return;
|
---|
| 863 | }
|
---|
| 864 | break;
|
---|
[48947] | 865 |
|
---|
[38699] | 866 | case 0x05: // format diskette track
|
---|
| 867 | BX_DEBUG_INT13_FL("floppy f05\n");
|
---|
[48947] | 868 |
|
---|
[38699] | 869 | num_sectors = GET_AL();
|
---|
| 870 | track = GET_CH();
|
---|
| 871 | head = GET_DH();
|
---|
| 872 | drive = GET_ELDL();
|
---|
[48947] | 873 |
|
---|
[38699] | 874 | if ((drive > 1) || (head > 1) || (track > 79) ||
|
---|
| 875 | (num_sectors == 0) || (num_sectors > 18)) {
|
---|
| 876 | SET_AH(1);
|
---|
| 877 | set_diskette_ret_status(1);
|
---|
| 878 | SET_CF(); // error occurred
|
---|
| 879 | }
|
---|
[48947] | 880 |
|
---|
[38699] | 881 | // see if drive exists
|
---|
| 882 | if (floppy_drive_exists(drive) == 0) {
|
---|
| 883 | SET_AH(0x80); // drive not responding
|
---|
| 884 | set_diskette_ret_status(0x80);
|
---|
| 885 | SET_CF(); // error occurred
|
---|
| 886 | return;
|
---|
| 887 | }
|
---|
[48947] | 888 |
|
---|
[38699] | 889 | // see if media in drive, and type is known
|
---|
| 890 | if (floppy_media_known(drive) == 0) {
|
---|
| 891 | if (floppy_media_sense(drive) == 0) {
|
---|
| 892 | SET_AH(0x0C); // Media type not found
|
---|
| 893 | set_diskette_ret_status(0x0C);
|
---|
| 894 | SET_AL(0); // no sectors read
|
---|
| 895 | SET_CF(); // error occurred
|
---|
| 896 | return;
|
---|
| 897 | }
|
---|
| 898 | }
|
---|
[48947] | 899 |
|
---|
[38699] | 900 | // set up DMA controller for transfer
|
---|
[63562] | 901 | /// @todo merge/factor out pointer normalization
|
---|
[38699] | 902 | page = (ES >> 12); // upper 4 bits
|
---|
| 903 | base_es = (ES << 4); // lower 16bits contributed by ES
|
---|
| 904 | base_address = base_es + BX; // lower 16 bits of address
|
---|
| 905 | // contributed by ES:BX
|
---|
| 906 | if ( base_address < base_es ) {
|
---|
| 907 | // in case of carry, adjust page by 1
|
---|
| 908 | page++;
|
---|
| 909 | }
|
---|
| 910 | base_count = (num_sectors * 4) - 1;
|
---|
[48947] | 911 |
|
---|
[38699] | 912 | // check for 64K boundary overrun
|
---|
| 913 | last_addr = base_address + base_count;
|
---|
| 914 | if (last_addr < base_address) {
|
---|
| 915 | SET_AH(0x09);
|
---|
| 916 | set_diskette_ret_status(0x09);
|
---|
| 917 | SET_AL(0); // no sectors read
|
---|
| 918 | SET_CF(); // error occurred
|
---|
| 919 | return;
|
---|
| 920 | }
|
---|
[48947] | 921 |
|
---|
[38699] | 922 | outb(0x000a, 0x06);
|
---|
| 923 | outb(0x000c, 0x00); // clear flip-flop
|
---|
| 924 | outb(0x0004, base_address);
|
---|
| 925 | outb(0x0004, base_address>>8);
|
---|
| 926 | outb(0x000c, 0x00); // clear flip-flop
|
---|
| 927 | outb(0x0005, base_count);
|
---|
| 928 | outb(0x0005, base_count>>8);
|
---|
| 929 | mode_register = 0x4a; // single mode, increment, autoinit disable,
|
---|
| 930 | // transfer type=read, channel 2
|
---|
| 931 | outb(0x000b, mode_register);
|
---|
| 932 | // port 81: DMA-1 Page Register, channel 2
|
---|
| 933 | outb(0x0081, page);
|
---|
| 934 | outb(0x000a, 0x02);
|
---|
[48947] | 935 |
|
---|
[38699] | 936 | // set up floppy controller for transfer
|
---|
| 937 | floppy_prepare_controller(drive);
|
---|
[48947] | 938 |
|
---|
[49331] | 939 | // send seek command to controller
|
---|
| 940 | outb(0x03f5, 0x0f); // 0f: seek
|
---|
| 941 | outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
|
---|
| 942 | outb(0x03f5, track);
|
---|
| 943 |
|
---|
[38699] | 944 | // send format-track command (6 bytes) to controller
|
---|
| 945 | outb(0x03f5, 0x4d); // 4d: format track
|
---|
| 946 | outb(0x03f5, (head << 2) | drive); // HD DR1 DR2
|
---|
| 947 | outb(0x03f5, 2); // 512 byte sector size
|
---|
| 948 | outb(0x03f5, num_sectors); // number of sectors per track
|
---|
| 949 | outb(0x03f5, 0); // Gap length
|
---|
| 950 | outb(0x03f5, 0xf6); // Fill byte
|
---|
[46947] | 951 |
|
---|
| 952 | #ifdef VBOX_WITH_FLOPPY_IRQ_POLLING
|
---|
[38699] | 953 | // turn on interrupts
|
---|
| 954 | int_enable();
|
---|
[48947] | 955 |
|
---|
[38699] | 956 | // wait on 40:3e bit 7 to become 1
|
---|
| 957 | do {
|
---|
| 958 | val8 = read_byte(0x0040, 0x0040);
|
---|
| 959 | if (val8 == 0) {
|
---|
[62301] | 960 | floppy_reset_controller(drive);
|
---|
[38699] | 961 | SET_AH(0x80); // drive not ready (timeout)
|
---|
| 962 | set_diskette_ret_status(0x80);
|
---|
| 963 | SET_CF(); // error occurred
|
---|
| 964 | return;
|
---|
| 965 | }
|
---|
| 966 | val8 = (read_byte(0x0040, 0x003e) & 0x80);
|
---|
| 967 | } while ( val8 == 0 );
|
---|
[48947] | 968 |
|
---|
[38699] | 969 | val8 = 0; // separate asm from while() loop
|
---|
| 970 | // turn off interrupts
|
---|
| 971 | int_disable();
|
---|
[46947] | 972 |
|
---|
[38699] | 973 | // set 40:3e bit 7 to 0
|
---|
| 974 | val8 = read_byte(0x0040, 0x003e);
|
---|
| 975 | val8 &= 0x7f;
|
---|
| 976 | write_byte(0x0040, 0x003e, val8);
|
---|
[46947] | 977 | #else
|
---|
| 978 | val8 = floppy_wait_for_interrupt_or_timeout();
|
---|
| 979 | if (val8 == 0) { /* Note! Interrupts enabled in this branch. */
|
---|
[62301] | 980 | floppy_reset_controller(drive);
|
---|
[46947] | 981 | SET_AH(0x80); // drive not ready (timeout)
|
---|
| 982 | set_diskette_ret_status(0x80);
|
---|
| 983 | SET_CF(); // error occurred
|
---|
| 984 | return;
|
---|
| 985 | }
|
---|
| 986 | #endif
|
---|
| 987 |
|
---|
[38699] | 988 | // check port 3f4 for accessibility to status bytes
|
---|
| 989 | val8 = inb(0x3f4);
|
---|
| 990 | if ( (val8 & 0xc0) != 0xc0 )
|
---|
| 991 | BX_PANIC("%s: ctrl not ready\n", __func__);
|
---|
[48947] | 992 |
|
---|
[38699] | 993 | // read 7 return status bytes from controller and store in BDA
|
---|
[67069] | 994 | for (i = 0; i < 7; ++i)
|
---|
| 995 | write_byte(0x0040, 0x0042 + i, inb(0x3f5));
|
---|
[48947] | 996 |
|
---|
[67069] | 997 | if ((read_byte(0x0040, 0x0042 + 0) & 0xc0) != 0) {
|
---|
| 998 | if ((read_byte(0x0040, 0x0042 + 1) & 0x02) != 0) {
|
---|
[38699] | 999 | // diskette not writable.
|
---|
| 1000 | // AH=status code=0x03 (tried to write on write-protected disk)
|
---|
| 1001 | // AL=number of sectors written=0
|
---|
| 1002 | AX = 0x0300;
|
---|
| 1003 | SET_CF();
|
---|
| 1004 | return;
|
---|
| 1005 | } else {
|
---|
| 1006 | BX_PANIC("%s: write error\n", __func__);
|
---|
| 1007 | }
|
---|
| 1008 | }
|
---|
[48947] | 1009 |
|
---|
[38699] | 1010 | SET_AH(0);
|
---|
| 1011 | set_diskette_ret_status(0);
|
---|
| 1012 | set_diskette_current_cyl(drive, 0);
|
---|
| 1013 | CLEAR_CF(); // successful
|
---|
| 1014 | return;
|
---|
[48947] | 1015 |
|
---|
| 1016 |
|
---|
[38699] | 1017 | case 0x08: // read diskette drive parameters
|
---|
| 1018 | BX_DEBUG_INT13_FL("floppy f08\n");
|
---|
| 1019 | drive = GET_ELDL();
|
---|
[48947] | 1020 |
|
---|
[38699] | 1021 | if (drive > 1) {
|
---|
| 1022 | AX = 0;
|
---|
| 1023 | BX = 0;
|
---|
| 1024 | CX = 0;
|
---|
| 1025 | DX = 0;
|
---|
| 1026 | ES = 0;
|
---|
| 1027 | DI = 0;
|
---|
| 1028 | SET_DL(num_floppies);
|
---|
| 1029 | SET_CF();
|
---|
| 1030 | return;
|
---|
| 1031 | }
|
---|
[48947] | 1032 |
|
---|
[63562] | 1033 | /// @todo break out drive type determination
|
---|
[38699] | 1034 | drive_type = inb_cmos(0x10);
|
---|
| 1035 | num_floppies = 0;
|
---|
| 1036 | if (drive_type & 0xf0)
|
---|
| 1037 | num_floppies++;
|
---|
| 1038 | if (drive_type & 0x0f)
|
---|
| 1039 | num_floppies++;
|
---|
[48947] | 1040 |
|
---|
[38699] | 1041 | if (drive == 0)
|
---|
| 1042 | drive_type >>= 4;
|
---|
| 1043 | else
|
---|
| 1044 | drive_type &= 0x0f;
|
---|
[48947] | 1045 |
|
---|
[38699] | 1046 | SET_BH(0);
|
---|
| 1047 | SET_BL(drive_type);
|
---|
| 1048 | SET_AH(0);
|
---|
| 1049 | SET_AL(0);
|
---|
| 1050 | SET_DL(num_floppies);
|
---|
[47036] | 1051 | SET_DH(1); // max head #
|
---|
[48947] | 1052 |
|
---|
[38699] | 1053 | switch (drive_type) {
|
---|
| 1054 | case 0: // none
|
---|
| 1055 | CX = 0;
|
---|
| 1056 | SET_DH(0); // max head #
|
---|
| 1057 | break;
|
---|
[48947] | 1058 |
|
---|
[38699] | 1059 | case 1: // 360KB, 5.25"
|
---|
| 1060 | CX = 0x2709; // 40 tracks, 9 sectors
|
---|
| 1061 | break;
|
---|
[48947] | 1062 |
|
---|
[38699] | 1063 | case 2: // 1.2MB, 5.25"
|
---|
| 1064 | CX = 0x4f0f; // 80 tracks, 15 sectors
|
---|
| 1065 | break;
|
---|
[48947] | 1066 |
|
---|
[38699] | 1067 | case 3: // 720KB, 3.5"
|
---|
| 1068 | CX = 0x4f09; // 80 tracks, 9 sectors
|
---|
| 1069 | break;
|
---|
[48947] | 1070 |
|
---|
[38699] | 1071 | case 4: // 1.44MB, 3.5"
|
---|
| 1072 | CX = 0x4f12; // 80 tracks, 18 sectors
|
---|
| 1073 | break;
|
---|
[48947] | 1074 |
|
---|
[38699] | 1075 | case 5: // 2.88MB, 3.5"
|
---|
| 1076 | CX = 0x4f24; // 80 tracks, 36 sectors
|
---|
| 1077 | break;
|
---|
[48947] | 1078 |
|
---|
[47036] | 1079 | case 14: // 15.6 MB 3.5" (fake)
|
---|
| 1080 | CX = 0xfe3f; // 255 tracks, 63 sectors
|
---|
| 1081 | break;
|
---|
| 1082 |
|
---|
| 1083 | case 15: // 63.5 MB 3.5" (fake)
|
---|
| 1084 | CX = 0xfeff; // 255 tracks, 255 sectors - This works because the cylinder
|
---|
| 1085 | break; // and sectors limits/encoding aren't checked by the BIOS
|
---|
| 1086 | // due to copy protection schemes and such stuff.
|
---|
| 1087 |
|
---|
[38699] | 1088 | default: // ?
|
---|
| 1089 | BX_PANIC("%s: bad floppy type\n", __func__);
|
---|
| 1090 | }
|
---|
[48947] | 1091 |
|
---|
[38699] | 1092 | /* set es & di to point to 11 byte diskette param table in ROM */
|
---|
[63562] | 1093 | ES = 0xF000; /// @todo any way to make this relocatable?
|
---|
[48069] | 1094 | DI = get_floppy_dpt(drive_type);
|
---|
[38699] | 1095 | CLEAR_CF(); // success
|
---|
| 1096 | /* disk status not changed upon success */
|
---|
| 1097 | return;
|
---|
[48947] | 1098 |
|
---|
[38699] | 1099 | case 0x15: // read diskette drive type
|
---|
| 1100 | BX_DEBUG_INT13_FL("floppy f15\n");
|
---|
| 1101 | drive = GET_ELDL();
|
---|
| 1102 | if (drive > 1) {
|
---|
| 1103 | SET_AH(0); // only 2 drives supported
|
---|
| 1104 | // set_diskette_ret_status here ???
|
---|
| 1105 | SET_CF();
|
---|
| 1106 | return;
|
---|
| 1107 | }
|
---|
[63562] | 1108 | /// @todo break out drive type determination
|
---|
[38699] | 1109 | drive_type = inb_cmos(0x10);
|
---|
| 1110 | if (drive == 0)
|
---|
| 1111 | drive_type >>= 4;
|
---|
| 1112 | else
|
---|
| 1113 | drive_type &= 0x0f;
|
---|
| 1114 | CLEAR_CF(); // successful, not present
|
---|
| 1115 | if (drive_type==0) {
|
---|
| 1116 | SET_AH(0); // drive not present
|
---|
[47531] | 1117 | } else if (drive_type > 1) {
|
---|
| 1118 | SET_AH(2); // drive present, supports change line
|
---|
| 1119 | } else {
|
---|
[38699] | 1120 | SET_AH(1); // drive present, does not support change line
|
---|
| 1121 | }
|
---|
[48947] | 1122 |
|
---|
[38699] | 1123 | return;
|
---|
[48947] | 1124 |
|
---|
[38699] | 1125 | case 0x16: // get diskette change line status
|
---|
| 1126 | BX_DEBUG_INT13_FL("floppy f16\n");
|
---|
| 1127 | drive = GET_ELDL();
|
---|
| 1128 | if (drive > 1) {
|
---|
| 1129 | SET_AH(0x01); // invalid drive
|
---|
| 1130 | set_diskette_ret_status(0x01);
|
---|
| 1131 | SET_CF();
|
---|
[95388] | 1132 | return;
|
---|
[38699] | 1133 | }
|
---|
[48947] | 1134 |
|
---|
[38699] | 1135 | SET_AH(0x06); // change line not supported
|
---|
| 1136 | set_diskette_ret_status(0x06);
|
---|
| 1137 | SET_CF();
|
---|
| 1138 | return;
|
---|
[48947] | 1139 |
|
---|
[38699] | 1140 | case 0x17: // set diskette type for format(old)
|
---|
| 1141 | BX_DEBUG_INT13_FL("floppy f17\n");
|
---|
[54563] | 1142 | // NOTE: 1.44M diskette not supported by this function, use INT14h/18h instead.
|
---|
| 1143 | // Drive number (0 or 1) values allowed
|
---|
| 1144 | drive = GET_ELDL();
|
---|
| 1145 |
|
---|
| 1146 | // Format type (AL)
|
---|
[56316] | 1147 | // 00 - NOT USED
|
---|
| 1148 | // 01 - DISKETTE 360K IN 360K DRIVE
|
---|
[54563] | 1149 | // 02 - DISKETTE 360K IN 1.2M DRIVE
|
---|
| 1150 | // 03 - DISKETTE 1.2M IN 1.2M DRIVE
|
---|
| 1151 | // 04 - DISKETTE 720K IN 720K DRIVE
|
---|
| 1152 | val8 = GET_AL();
|
---|
| 1153 |
|
---|
| 1154 | BX_DEBUG_INT13_FL("floppy f17 - drive: %d, format type: %d\n", drive, val8);
|
---|
| 1155 |
|
---|
| 1156 | if (drive > 1) {
|
---|
| 1157 | SET_AH(0x01); // invalid drive
|
---|
| 1158 | set_diskette_ret_status(0x01); // bad parameter
|
---|
| 1159 | SET_CF();
|
---|
| 1160 | return;
|
---|
| 1161 | }
|
---|
[56316] | 1162 |
|
---|
[54563] | 1163 | // see if drive exists
|
---|
| 1164 | if (floppy_drive_exists(drive) == 0) {
|
---|
| 1165 | SET_AH(0x80); // not responding/time out
|
---|
| 1166 | set_diskette_ret_status(0x80);
|
---|
| 1167 | SET_CF();
|
---|
| 1168 | return;
|
---|
| 1169 | }
|
---|
| 1170 |
|
---|
| 1171 | // Get current drive state. Set 'base_address' to media status offset address
|
---|
| 1172 | base_address = (drive) ? 0x0091 : 0x0090;
|
---|
| 1173 | media_state = read_byte(0x0040, base_address);
|
---|
| 1174 |
|
---|
| 1175 | // Mask out (clear) bits 4-7 (4:media type established, 5:double stepping, 6-7:data rate)
|
---|
| 1176 | media_state &= 0x0f;
|
---|
| 1177 |
|
---|
| 1178 | switch (val8) {
|
---|
| 1179 | case 1:
|
---|
| 1180 | // 360K media in 360K drive
|
---|
| 1181 | media_state |= 0x90; // 1001 0000 (media type established, 250 kbps)
|
---|
| 1182 | break;
|
---|
| 1183 | case 2:
|
---|
| 1184 | // 360K media in 1.2M drive
|
---|
| 1185 | media_state |= 0x70; // 0111 0000 (media type established, double stepping, 300 kbps)
|
---|
| 1186 | break;
|
---|
| 1187 | case 3:
|
---|
| 1188 | // 1.2M media in 1.2M drive
|
---|
| 1189 | media_state |= 0x10; // 0001 0000 (media type established, 500 kbps)
|
---|
| 1190 | break;
|
---|
| 1191 | case 4:
|
---|
| 1192 | // 720K media in 720K drive
|
---|
| 1193 | media_state |= 0x90; // 1001 0000 (media type established, 250 kbps)
|
---|
| 1194 | break;
|
---|
| 1195 | default:
|
---|
| 1196 | // bad parameter
|
---|
| 1197 | SET_AH(0x01); // invalid format mode parameter
|
---|
| 1198 | set_diskette_ret_status(0x01);
|
---|
| 1199 | SET_CF();
|
---|
| 1200 | return;
|
---|
| 1201 | }
|
---|
| 1202 |
|
---|
| 1203 | // Update media status
|
---|
| 1204 | write_byte(0x0040, base_address, media_state);
|
---|
| 1205 | BX_DEBUG_INT13_FL("floppy f17 - media status set to: %02x\n", media_state);
|
---|
| 1206 |
|
---|
| 1207 | // return success!
|
---|
| 1208 | SET_AH(0);
|
---|
| 1209 | set_diskette_ret_status(0);
|
---|
| 1210 | CLEAR_CF();
|
---|
[38699] | 1211 | return;
|
---|
[48947] | 1212 |
|
---|
[38699] | 1213 | case 0x18: // set diskette type for format(new)
|
---|
| 1214 | BX_DEBUG_INT13_FL("floppy f18\n");
|
---|
[54563] | 1215 | // Set Media Type for Format. Verifies that the device supports a specific geometry.
|
---|
| 1216 | // Unlike INT13h/17h, this service supports higher capacity drives (1.44M and 2.88M).
|
---|
| 1217 | // Drive number (0 or 1) values allowed
|
---|
| 1218 | drive = GET_ELDL();
|
---|
| 1219 |
|
---|
| 1220 | val8 = GET_CL();
|
---|
| 1221 | num_sectors = val8 & 0x3f; // max sector number per cylinder
|
---|
| 1222 | track = ((val8 >> 6) << 8) + GET_CH(); // max cylinder number (max cylinders - 1)
|
---|
| 1223 |
|
---|
| 1224 | BX_DEBUG_INT13_FL("floppy f18 - drive: %d, max cylinder/track number: %d, sectors-per-tracks: %d\n",
|
---|
| 1225 | drive, track, num_sectors);
|
---|
| 1226 |
|
---|
| 1227 | if (drive > 1) {
|
---|
| 1228 | SET_AH(0x01); // invalid drive
|
---|
| 1229 | set_diskette_ret_status(0x01);
|
---|
| 1230 | SET_CF();
|
---|
| 1231 | return;
|
---|
| 1232 | }
|
---|
| 1233 |
|
---|
| 1234 | // see if drive exists
|
---|
| 1235 | if (floppy_drive_exists(drive) == 0) {
|
---|
| 1236 | SET_AH(0x80); // not responding/time out
|
---|
| 1237 | set_diskette_ret_status(0x80);
|
---|
| 1238 | SET_CF();
|
---|
| 1239 | return;
|
---|
| 1240 | }
|
---|
| 1241 |
|
---|
| 1242 | // see if media in drive, and media type is known
|
---|
| 1243 | if (floppy_media_known(drive) == 0) {
|
---|
| 1244 | if (floppy_media_sense(drive) == 0) {
|
---|
| 1245 | SET_AH(0x0C); // drive/media type unknown
|
---|
| 1246 | set_diskette_ret_status(0x0C);
|
---|
[56316] | 1247 | SET_CF();
|
---|
[54563] | 1248 | return;
|
---|
| 1249 | }
|
---|
| 1250 | }
|
---|
| 1251 |
|
---|
[63562] | 1252 | /// @todo break out drive type determination
|
---|
[54563] | 1253 | drive_type = inb_cmos(0x10);
|
---|
| 1254 | if (drive == 0)
|
---|
| 1255 | drive_type >>= 4;
|
---|
| 1256 | else
|
---|
| 1257 | drive_type &= 0x0f;
|
---|
[56316] | 1258 |
|
---|
[54563] | 1259 | // Get current drive state. Set 'base_address' to media status offset address
|
---|
| 1260 | base_address = (drive) ? 0x0091 : 0x0090;
|
---|
| 1261 | media_state = read_byte(0x0040, base_address);
|
---|
| 1262 |
|
---|
| 1263 | // Mask out (clear) bits 4-7 (4:media type established, 5:double stepping, 6-7:data rate)
|
---|
| 1264 | media_state &= 0x0f;
|
---|
| 1265 |
|
---|
| 1266 | switch (drive_type) {
|
---|
| 1267 | case 1: // 360KB, 5.25"
|
---|
| 1268 | if (track == 39 && num_sectors == 9)
|
---|
| 1269 | media_state |= 0x90; // 1001 0000 (media type established, 250 kbps)
|
---|
| 1270 |
|
---|
| 1271 | break;
|
---|
| 1272 | case 2: // 1.2MB, 5.25"
|
---|
[56316] | 1273 | if (track == 39 && num_sectors == 9) { // 360K disk in 1.2M drive
|
---|
[54563] | 1274 | media_state |= 0x70; // 0111 0000 (media type established, double stepping, 300 kbps)
|
---|
| 1275 | } else if (track == 79 && num_sectors == 15) { // 1.2M disk in 1.2M drive
|
---|
| 1276 | media_state |= 0x10; // 0001 0000 (media type established, 500 kbps)
|
---|
| 1277 | }
|
---|
| 1278 | break;
|
---|
| 1279 | case 3: // 720KB, 3.5"
|
---|
| 1280 | if (track == 79 && num_sectors == 9)
|
---|
| 1281 | media_state |= 0x90; // 1001 0000 (media type established, 250 kbps)
|
---|
| 1282 |
|
---|
[56316] | 1283 | break;
|
---|
[54563] | 1284 | case 4: // 1.44MB, 3.5"
|
---|
| 1285 | if (track == 79) {
|
---|
| 1286 | if (num_sectors == 9) { // 720K disk in 1.44M drive
|
---|
| 1287 | media_state |= 0x90; // 1001 0000 (media type established, 250 kbps)
|
---|
| 1288 | } else if (num_sectors == 18) { // 1.44M disk in 1.44M drive
|
---|
| 1289 | media_state |= 0x10; // 0001 0000 (media type established, 500 kbps)
|
---|
| 1290 | }
|
---|
[56316] | 1291 | }
|
---|
[54563] | 1292 | break;
|
---|
| 1293 | case 5: // 2.88MB, 3.5"
|
---|
| 1294 | if (track == 79) {
|
---|
| 1295 | if (num_sectors == 9) { // 720K disk in 2.88M drive
|
---|
| 1296 | media_state |= 0x90; // 1001 0000 (media type established, 250 kbps)
|
---|
| 1297 | } else if (num_sectors == 18) { // 1.44M disk in 2.88M drive
|
---|
| 1298 | media_state |= 0x10; // 0001 0000 (media type established, 500 kbps)
|
---|
| 1299 | } else if (num_sectors == 36) { // 2.88M disk in 2.88M drive
|
---|
| 1300 | media_state |= 0xD0; // 1101 0000 (media type established, 1 Mbps)
|
---|
| 1301 | }
|
---|
| 1302 | }
|
---|
| 1303 | break;
|
---|
| 1304 | default:
|
---|
| 1305 | break;
|
---|
| 1306 | }
|
---|
| 1307 |
|
---|
| 1308 | // Error if bit 4 (media type established) has not just been set above.
|
---|
| 1309 | if (((media_state >> 4) & 0x01) == 0) {
|
---|
| 1310 | // Error - assume requested tracks/sectors-per-track not supported
|
---|
| 1311 | // for current drive type - or drive type is unknown!
|
---|
| 1312 | SET_AH(0x0C);
|
---|
| 1313 | set_diskette_ret_status(0x0C);
|
---|
[56316] | 1314 | SET_CF();
|
---|
[54563] | 1315 | return;
|
---|
| 1316 | }
|
---|
| 1317 |
|
---|
| 1318 | // Update media status
|
---|
| 1319 | write_byte(0x0040, base_address, media_state);
|
---|
| 1320 |
|
---|
[56316] | 1321 | // set es & di to point to 11 byte diskette param table in ROM
|
---|
[63562] | 1322 | ES = 0xF000; /// @todo any way to make this relocatable?
|
---|
[54563] | 1323 | DI = get_floppy_dpt(drive_type);
|
---|
| 1324 |
|
---|
| 1325 | // return success!
|
---|
| 1326 | SET_AH(0);
|
---|
| 1327 | set_diskette_ret_status(0);
|
---|
| 1328 | CLEAR_CF();
|
---|
[38699] | 1329 | return;
|
---|
[48947] | 1330 |
|
---|
[38699] | 1331 | default:
|
---|
| 1332 | BX_INFO("%s: unsupported AH=%02x\n", __func__, GET_AH());
|
---|
[48947] | 1333 |
|
---|
[38699] | 1334 | // if ( (ah==0x20) || ((ah>=0x41) && (ah<=0x49)) || (ah==0x4e) ) {
|
---|
| 1335 | SET_AH(0x01); // ???
|
---|
| 1336 | set_diskette_ret_status(1);
|
---|
| 1337 | SET_CF();
|
---|
| 1338 | return;
|
---|
| 1339 | // }
|
---|
| 1340 | }
|
---|
| 1341 | }
|
---|
| 1342 |
|
---|
| 1343 | #else // #if BX_SUPPORT_FLOPPY
|
---|
| 1344 |
|
---|
| 1345 | void BIOSCALL int13_diskette_function(disk_regs_t r)
|
---|
| 1346 | {
|
---|
| 1347 | uint8_t val8;
|
---|
[48947] | 1348 |
|
---|
[38699] | 1349 | switch ( GET_AH() ) {
|
---|
[48947] | 1350 |
|
---|
[38699] | 1351 | case 0x01: // Read Diskette Status
|
---|
| 1352 | CLEAR_CF();
|
---|
| 1353 | val8 = read_byte(0x0000, 0x0441);
|
---|
| 1354 | SET_AH(val8);
|
---|
| 1355 | if (val8) {
|
---|
| 1356 | SET_CF();
|
---|
| 1357 | }
|
---|
| 1358 | return;
|
---|
[48947] | 1359 |
|
---|
[38699] | 1360 | default:
|
---|
| 1361 | SET_CF();
|
---|
| 1362 | write_byte(0x0000, 0x0441, 0x01);
|
---|
| 1363 | SET_AH(0x01);
|
---|
| 1364 | }
|
---|
| 1365 | }
|
---|
| 1366 |
|
---|
| 1367 | #endif // #if BX_SUPPORT_FLOPPY
|
---|
| 1368 |
|
---|
[67069] | 1369 | /* Avoid saving general registers already saved by caller (PUSHA). */
|
---|
| 1370 | #pragma aux int13_diskette_function modify [di si cx dx bx];
|
---|