- fixed IDE register behaviour in case of a channel with one drive connected

* ports for error register, sector count and sector number are shared between
    both drives
  * status register always returns the values of the selected drive (0x00 if
    not present
  * set correct signature for both drives in case of reset
This commit is contained in:
Volker Ruppert 2006-02-06 21:27:34 +00:00
parent d7caed8655
commit e69a129d01
2 changed files with 41 additions and 44 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: harddrv.cc,v 1.157 2006-01-07 12:52:05 vruppert Exp $
// $Id: harddrv.cc,v 1.158 2006-02-06 21:27:34 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
@ -144,7 +144,7 @@ bx_hard_drive_c::init(void)
char string[5];
char sbtext[8];
BX_DEBUG(("Init $Id: harddrv.cc,v 1.157 2006-01-07 12:52:05 vruppert Exp $"));
BX_DEBUG(("Init $Id: harddrv.cc,v 1.158 2006-02-06 21:27:34 vruppert Exp $"));
for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
if (bx_options.ata[channel].Opresent->get() == 1) {
@ -1017,26 +1017,23 @@ bx_hard_drive_c::read(Bit32u address, unsigned io_len)
case 0x01: // hard disk error register 0x1f1
BX_SELECTED_CONTROLLER(channel).status.err = 0;
value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).error_register;
// -- WARNING : On real hardware the controller registers are shared between drives.
// So we must respond even if the select device is not present. Some OS uses this fact
// to detect the disks.... minix2 for example
value8 = (!BX_ANY_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).error_register;
goto return_value8;
break;
case 0x02: // hard disk sector count / interrupt reason 0x1f2
value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).sector_count;
value8 = (!BX_ANY_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).sector_count;
goto return_value8;
break;
case 0x03: // sector number 0x1f3
value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).sector_no;
value8 = (!BX_ANY_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).sector_no;
goto return_value8;
case 0x04: // cylinder low 0x1f4
// -- WARNING : On real hardware the controller registers are shared between drives.
// So we must respond even if the select device is not present. Some OS uses this fact
// to detect the disks.... minix2 for example
value8 = (!BX_ANY_IS_PRESENT(channel)) ? 0 : (BX_SELECTED_CONTROLLER(channel).cylinder_no & 0x00ff);
goto return_value8;
case 0x05: // cylinder high 0x1f5
// -- WARNING : On real hardware the controller registers are shared between drives.
// So we must respond even if the select device is not present. Some OS uses this fact
// to detect the disks.... minix2 for example
value8 = (!BX_ANY_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).cylinder_no >> 8;
goto return_value8;
@ -1058,29 +1055,29 @@ bx_hard_drive_c::read(Bit32u address, unsigned io_len)
case 0x07: // Hard Disk Status 0x1f7
case 0x16: // Hard Disk Alternate Status 0x3f6
if (!BX_ANY_IS_PRESENT(channel)) {
// (mch) Just return zero for these registers
value8 = 0;
if (!BX_SELECTED_IS_PRESENT(channel)) {
// (mch) Just return zero for these registers
value8 = 0;
} else {
value8 = (
(BX_SELECTED_CONTROLLER(channel).status.busy << 7) |
(BX_SELECTED_CONTROLLER(channel).status.drive_ready << 6) |
(BX_SELECTED_CONTROLLER(channel).status.write_fault << 5) |
(BX_SELECTED_CONTROLLER(channel).status.seek_complete << 4) |
(BX_SELECTED_CONTROLLER(channel).status.drq << 3) |
(BX_SELECTED_CONTROLLER(channel).status.corrected_data << 2) |
(BX_SELECTED_CONTROLLER(channel).status.index_pulse << 1) |
(BX_SELECTED_CONTROLLER(channel).status.err) );
BX_SELECTED_CONTROLLER(channel).status.index_pulse_count++;
BX_SELECTED_CONTROLLER(channel).status.index_pulse = 0;
if (BX_SELECTED_CONTROLLER(channel).status.index_pulse_count >= INDEX_PULSE_CYCLE) {
BX_SELECTED_CONTROLLER(channel).status.index_pulse = 1;
BX_SELECTED_CONTROLLER(channel).status.index_pulse_count = 0;
value8 = (
(BX_SELECTED_CONTROLLER(channel).status.busy << 7) |
(BX_SELECTED_CONTROLLER(channel).status.drive_ready << 6) |
(BX_SELECTED_CONTROLLER(channel).status.write_fault << 5) |
(BX_SELECTED_CONTROLLER(channel).status.seek_complete << 4) |
(BX_SELECTED_CONTROLLER(channel).status.drq << 3) |
(BX_SELECTED_CONTROLLER(channel).status.corrected_data << 2) |
(BX_SELECTED_CONTROLLER(channel).status.index_pulse << 1) |
(BX_SELECTED_CONTROLLER(channel).status.err));
BX_SELECTED_CONTROLLER(channel).status.index_pulse_count++;
BX_SELECTED_CONTROLLER(channel).status.index_pulse = 0;
if (BX_SELECTED_CONTROLLER(channel).status.index_pulse_count >= INDEX_PULSE_CYCLE) {
BX_SELECTED_CONTROLLER(channel).status.index_pulse = 1;
BX_SELECTED_CONTROLLER(channel).status.index_pulse_count = 0;
}
}
if (port == 0x07) {
DEV_pic_lower_irq(BX_HD_THIS channels[channel].irq);
}
}
goto return_value8;
break;
@ -2124,7 +2121,7 @@ bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
command_aborted(channel, value);
break;
}
set_signature(channel);
set_signature(channel, BX_SLAVE_SELECTED(channel));
BX_SELECTED_CONTROLLER(channel).error_register = 0x01;
BX_SELECTED_CONTROLLER(channel).status.drq = 0;
BX_SELECTED_CONTROLLER(channel).status.err = 0;
@ -2188,7 +2185,7 @@ bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
break;
}
if (BX_SELECTED_IS_CD(channel)) {
set_signature(channel);
set_signature(channel, BX_SLAVE_SELECTED(channel));
command_aborted(channel, 0xec);
} else {
BX_SELECTED_CONTROLLER(channel).current_command = value;
@ -2301,7 +2298,7 @@ bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
case 0x08: // DEVICE RESET (atapi)
if (BX_SELECTED_IS_CD(channel)) {
set_signature(channel);
set_signature(channel, BX_SLAVE_SELECTED(channel));
BX_SELECTED_CONTROLLER(channel).status.busy = 1;
BX_SELECTED_CONTROLLER(channel).error_register &= ~(1 << 7);
@ -2542,7 +2539,7 @@ bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
BX_CONTROLLER(channel,id).status.drive_ready = 1;
BX_CONTROLLER(channel,id).reset_in_progress = 0;
set_signature(channel);
set_signature(channel, id);
}
}
BX_DEBUG(("s[0].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[0]).controller.control.disable_irq));
@ -3452,18 +3449,18 @@ bx_hard_drive_c::bmdma_complete(Bit8u channel)
}
#endif
void bx_hard_drive_c::set_signature(Bit8u channel)
void bx_hard_drive_c::set_signature(Bit8u channel, Bit8u id)
{
// Device signature
BX_SELECTED_CONTROLLER(channel).head_no = 0;
BX_SELECTED_CONTROLLER(channel).sector_count = 1;
BX_SELECTED_CONTROLLER(channel).sector_no = 1;
if (BX_SELECTED_IS_HD(channel)) {
BX_SELECTED_CONTROLLER(channel).cylinder_no = 0;
} else if (BX_SELECTED_IS_CD(channel)) {
BX_SELECTED_CONTROLLER(channel).cylinder_no = 0xeb14;
BX_CONTROLLER(channel,id).head_no = 0;
BX_CONTROLLER(channel,id).sector_count = 1;
BX_CONTROLLER(channel,id).sector_no = 1;
if (BX_DRIVE_IS_HD(channel,id)) {
BX_CONTROLLER(channel,id).cylinder_no = 0;
} else if (BX_DRIVE_IS_CD(channel,id)) {
BX_CONTROLLER(channel,id).cylinder_no = 0xeb14;
} else {
BX_SELECTED_CONTROLLER(channel).cylinder_no = 0xffff;
BX_CONTROLLER(channel,id).cylinder_no = 0xffff;
}
}

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: harddrv.h,v 1.37 2005-11-06 11:07:01 vruppert Exp $
// $Id: harddrv.h,v 1.38 2006-02-06 21:27:34 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 MandrakeSoft S.A.
@ -203,7 +203,7 @@ private:
BX_HD_SMF void init_mode_sense_single(Bit8u channel, const void* src, int size);
BX_HD_SMF void atapi_cmd_nop(Bit8u channel) BX_CPP_AttrRegparmN(1);
BX_HD_SMF bx_bool bmdma_present(void);
BX_HD_SMF void set_signature(Bit8u channel);
BX_HD_SMF void set_signature(Bit8u channel, Bit8u id);
// FIXME:
// For each ATA channel we should have one controller struct