diff --git a/bochs/patches/patch.4ata-channels b/bochs/patches/patch.4ata-channels new file mode 100644 index 000000000..2379406a0 --- /dev/null +++ b/bochs/patches/patch.4ata-channels @@ -0,0 +1,5880 @@ +---------------------------------------------------------------------- +Patch name: patch.4ata-channels +Author: christophe Bothamy +Date: 14 september 2002 + +Detailed description: + +This patch adds 4 ata channels support for Bochs. Features : + - number of active channels defined at boot-time config + - new options in bochsrc + - up to 8 devices support (disks or cdroms) + - up to 4 cdrom devices can be changed at runtime config + +You'll want to use BIOS-bochs-new-ata to be able to access new +devices from the bios. + +I have not split "harddrv.cc" in simpler files yet. + +Patch was created with: + cvs diff -u +Apply patch to what version: + cvs checked out on 14 september 2002 +Instructions: + To patch, go to main bochs directory. + Type "patch -p0 < THIS_PATCH_FILE". +---------------------------------------------------------------------- +Index: misc/bximage.c +=================================================================== +RCS file: /cvsroot/bochs/bochs/misc/bximage.c,v +retrieving revision 1.10 +diff -u -r1.10 bximage.c +--- misc/bximage.c 5 Sep 2002 16:50:03 -0000 1.10 ++++ misc/bximage.c 14 Sep 2002 07:27:49 -0000 +@@ -261,7 +261,7 @@ + printf (" total size=%.2f megabytes\n", (float)sectors*512.0/1024.0/1024.0); + if (ask_string ("\nWhat should I name the image?\n[c.img] ", "c.img", filename) < 0) + fatal (EOF_ERR); +- sprintf (bochsrc_line, "diskc: file=\"%s\", cyl=%d, heads=%d, spt=%d", filename, cyl, heads, spt); ++ sprintf (bochsrc_line, "ata0-master: type=disk, path=\"%s\", cylinders=%d, heads=%d, spt=%d", filename, cyl, heads, spt); + } else { + int fdsize, cyl=0, heads=0, spt=0; + char *name = NULL; +Index: bochs.h +=================================================================== +RCS file: /cvsroot/bochs/bochs/bochs.h,v +retrieving revision 1.93 +diff -u -r1.93 bochs.h +--- bochs.h 13 Sep 2002 00:15:23 -0000 1.93 ++++ bochs.h 14 Sep 2002 07:27:50 -0000 +@@ -483,6 +483,7 @@ + + + ++/* Already in gui/siminterface.h ??? + #define BX_FLOPPY_NONE 10 // floppy not present + #define BX_FLOPPY_1_2 11 // 1.2M 5.25" + #define BX_FLOPPY_1_44 12 // 1.44M 3.5" +@@ -490,6 +491,7 @@ + #define BX_FLOPPY_720K 14 // 720K 3.5" + #define BX_FLOPPY_360K 15 // 360K 5.25" + #define BX_FLOPPY_LAST 15 // last one ++*/ + + + #define BX_READ 0 +@@ -541,6 +543,13 @@ + #define BX_PATHNAME_LEN 512 + + typedef struct { ++ bx_param_bool_c *Opresent; ++ bx_param_num_c *Oioaddr1; ++ bx_param_num_c *Oioaddr2; ++ bx_param_num_c *Oirq; ++ } bx_ata_options; ++ ++typedef struct { + bx_param_string_c *Opath; + bx_param_num_c *Oaddress; + } bx_rom_options; +@@ -625,10 +634,12 @@ + typedef struct { + bx_floppy_options floppya; + bx_floppy_options floppyb; +- bx_disk_options diskc; +- bx_disk_options diskd; ++ bx_ata_options ata[BX_MAX_ATA_CHANNEL]; ++ bx_atadevice_options atadevice[BX_MAX_ATA_CHANNEL][2]; ++ // bx_disk_options diskc; ++ // bx_disk_options diskd; ++ // bx_cdrom_options cdromd; + bx_serial_options com[BX_N_SERIAL_PORTS]; +- bx_cdrom_options cdromd; + bx_rom_options rom; + bx_vgarom_options vgarom; + bx_rom_options optrom[BX_N_OPTROM_IMAGES]; // Optional rom images +Index: config.h.in +=================================================================== +RCS file: /cvsroot/bochs/bochs/config.h.in,v +retrieving revision 1.65 +diff -u -r1.65 config.h.in +--- config.h.in 12 Sep 2002 07:16:35 -0000 1.65 ++++ config.h.in 14 Sep 2002 07:27:50 -0000 +@@ -268,6 +268,13 @@ + // [[Provide example of partitioning]] + #define BX_SPLIT_HD_SUPPORT 0 + ++// This option defines the number of supported ATA channels. ++// There are up to two drives per ATA channel. ++#define BX_MAX_ATA_CHANNEL 4 ++ ++#if (BX_MAX_ATA_CHANNEL>4 || BX_MAX_ATA_CHANNEL<1) ++# error "BX_MAX_ATA_CHANNEL should be between 1 and 4" ++#endif + + // ================================================================= + // BEGIN: OPTIONAL DEBUGGER SECTION +Index: main.cc +=================================================================== +RCS file: /cvsroot/bochs/bochs/main.cc,v +retrieving revision 1.141 +diff -u -r1.141 main.cc +--- main.cc 9 Sep 2002 07:19:23 -0000 1.141 ++++ main.cc 14 Sep 2002 07:27:52 -0000 +@@ -113,9 +113,18 @@ + SIM->get_param (BXP_LOAD32BITOS_INITRD)->set_enabled (enable); + } + break; +- case BXP_CDROM_STATUS: ++ case BXP_ATA0_MASTER_STATUS: ++ case BXP_ATA0_SLAVE_STATUS: ++ case BXP_ATA1_MASTER_STATUS: ++ case BXP_ATA1_SLAVE_STATUS: ++ case BXP_ATA2_MASTER_STATUS: ++ case BXP_ATA2_SLAVE_STATUS: ++ case BXP_ATA3_MASTER_STATUS: ++ case BXP_ATA3_SLAVE_STATUS: + if ((set) && (SIM->get_init_done ())) { +- bx_devices.hard_drive->set_cd_media_status(val == BX_INSERTED); ++ Bit8u device = id - BXP_ATA0_MASTER_STATUS; ++ Bit32u handle = bx_devices.hard_drive->get_device_handle (device/2, device%2); ++ bx_devices.hard_drive->set_cd_media_status(handle, val == BX_INSERTED); + bx_gui.update_drive_status_buttons (); + } + break; +@@ -144,6 +153,67 @@ + case BXP_KBD_PASTE_DELAY: + if (set) bx_keyboard.paste_delay_changed (); + break; ++ case BXP_ATA0_PRESENT: ++ case BXP_ATA1_PRESENT: ++ case BXP_ATA2_PRESENT: ++ case BXP_ATA3_PRESENT: ++ if (set) { ++ int channel = id - BXP_ATA0_PRESENT; ++ int enable = (val != 0); ++ ++ SIM->get_param ((bx_id)(BXP_ATA0_IOADDR1 + channel))->set_enabled (enable); ++ SIM->get_param ((bx_id)(BXP_ATA0_IOADDR2 + channel))->set_enabled (enable); ++ SIM->get_param ((bx_id)(BXP_ATA0_IRQ + channel))->set_enabled (enable); ++ } ++ break; ++ ++ case BXP_ATA0_MASTER_TYPE: ++ case BXP_ATA0_SLAVE_TYPE: ++ case BXP_ATA1_MASTER_TYPE: ++ case BXP_ATA1_SLAVE_TYPE: ++ case BXP_ATA2_MASTER_TYPE: ++ case BXP_ATA2_SLAVE_TYPE: ++ case BXP_ATA3_MASTER_TYPE: ++ case BXP_ATA3_SLAVE_TYPE: ++ if (set) { ++ int device = id - BXP_ATA0_MASTER_TYPE; ++ switch (val) { ++ case BX_ATA_DEVICE_NONE: ++ SIM->get_param_num ((bx_id)(BXP_ATA0_MASTER_PRESENT + device))->set (0); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_PATH + device))->set_enabled (0); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_CYLINDERS + device))->set_enabled (0); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_HEADS + device))->set_enabled (0); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_SPT + device))->set_enabled (0); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_STATUS + device))->set_enabled (0); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_MODEL + device))->set_enabled (0); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_BIOSDETECT + device))->set_enabled (0); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_TRANSLATION + device))->set_enabled (0); ++ break; ++ case BX_ATA_DEVICE_DISK: ++ SIM->get_param_num ((bx_id)(BXP_ATA0_MASTER_PRESENT + device))->set (1); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_PATH + device))->set_enabled (1); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_CYLINDERS + device))->set_enabled (1); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_HEADS + device))->set_enabled (1); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_SPT + device))->set_enabled (1); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_STATUS + device))->set_enabled (0); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_MODEL + device))->set_enabled (1); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_BIOSDETECT + device))->set_enabled (1); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_TRANSLATION + device))->set_enabled (1); ++ break; ++ case BX_ATA_DEVICE_CDROM: ++ SIM->get_param_num ((bx_id)(BXP_ATA0_MASTER_PRESENT + device))->set (1); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_PATH + device))->set_enabled (1); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_CYLINDERS + device))->set_enabled (0); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_HEADS + device))->set_enabled (0); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_SPT + device))->set_enabled (0); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_STATUS + device))->set_enabled (1); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_MODEL + device))->set_enabled (1); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_BIOSDETECT + device))->set_enabled (1); ++ SIM->get_param ((bx_id)(BXP_ATA0_MASTER_TRANSLATION + device))->set_enabled (0); ++ break; ++ } ++ } ++ break; + default: + BX_PANIC (("bx_param_handler called with unknown id %d", id)); + return -1; +@@ -153,12 +223,14 @@ + + char *bx_param_string_handler (bx_param_string_c *param, int set, char *val, int maxlen) + { ++ bx_id id = param->get_id (); ++ + int empty = 0; + if ((strlen(val) < 1) || !strcmp ("none", val)) { + empty = 1; + val = "none"; + } +- switch (param->get_id ()) { ++ switch (id) { + case BXP_FLOPPYA_PATH: + if (set==1) { + if (SIM->get_init_done ()) { +@@ -209,46 +281,44 @@ + } + } + break; +- case BXP_DISKC_PATH: +- if (set==1) { +- SIM->get_param_num(BXP_DISKC_PRESENT)->set (!empty); +- SIM->get_param_num(BXP_DISKC_CYLINDERS)->set_enabled (!empty); +- SIM->get_param_num(BXP_DISKC_HEADS)->set_enabled (!empty); +- SIM->get_param_num(BXP_DISKC_SPT)->set_enabled (!empty); +- } +- break; +- case BXP_DISKD_PATH: +- if (set==1) { +- SIM->get_param_num(BXP_DISKD_PRESENT)->set (!empty); +- SIM->get_param_num(BXP_DISKD_CYLINDERS)->set_enabled (!empty); +- SIM->get_param_num(BXP_DISKD_HEADS)->set_enabled (!empty); +- SIM->get_param_num(BXP_DISKD_SPT)->set_enabled (!empty); +- } +- break; +- case BXP_CDROM_PATH: ++ ++ case BXP_ATA0_MASTER_PATH: ++ case BXP_ATA0_SLAVE_PATH: ++ case BXP_ATA1_MASTER_PATH: ++ case BXP_ATA1_SLAVE_PATH: ++ case BXP_ATA2_MASTER_PATH: ++ case BXP_ATA2_SLAVE_PATH: ++ case BXP_ATA3_MASTER_PATH: ++ case BXP_ATA3_SLAVE_PATH: + if (set==1) { ++ Bit8u device = id - BXP_ATA0_MASTER_PATH; ++ Bit32u handle = bx_devices.hard_drive->get_device_handle(device/2, device%2); ++ + if (SIM->get_init_done ()) { + if (empty) { +- bx_devices.hard_drive->set_cd_media_status(0); ++ bx_devices.hard_drive->set_cd_media_status(handle, 0); + bx_gui.update_drive_status_buttons (); + } else { +- if (!SIM->get_param_num(BXP_CDROM_PRESENT)->get ()) { ++ if (!SIM->get_param_num((bx_id)(BXP_ATA0_MASTER_PRESENT + device))->get ()) { + BX_ERROR(("Cannot add a cdrom drive at runtime")); +- bx_options.cdromd.Opath->set ("none"); ++ bx_options.atadevice[device/2][device%2].Opresent->set (0); ++ } ++ if (SIM->get_param_num((bx_id)(BXP_ATA0_MASTER_TYPE + device))->get () != BX_ATA_DEVICE_CDROM) { ++ BX_ERROR(("Device is not a cdrom drive")); ++ bx_options.atadevice[device/2][device%2].Opresent->set (0); + } + } + if ((bx_devices.hard_drive) && +- (SIM->get_param_num(BXP_CDROM_STATUS)->get () == BX_INSERTED)) { ++ (SIM->get_param_num((bx_id)(BXP_ATA0_MASTER_STATUS + device))->get () == BX_INSERTED) && ++ (SIM->get_param_num((bx_id)(BXP_ATA0_MASTER_TYPE + device))->get () == BX_ATA_DEVICE_CDROM)) { + // tell the device model that we removed, then inserted the cd +- bx_devices.hard_drive->set_cd_media_status(0); +- bx_devices.hard_drive->set_cd_media_status(1); ++ bx_devices.hard_drive->set_cd_media_status(handle, 0); ++ bx_devices.hard_drive->set_cd_media_status(handle, 1); + } +- } else { +- SIM->get_param_num(BXP_CDROM_PRESENT)->set (!empty); +- SIM->get_param_num(BXP_CDROM_STATUS)->set_enabled (!empty); + } + } + break; ++ + case BXP_SCREENMODE: + if (set==1) { + BX_INFO (("Screen mode changed to %s", val)); +@@ -274,7 +344,7 @@ + bx_options.log.actions[2] = ACT_REPORT; + bx_options.log.actions[3] = ACT_ASK; + +- // quick start option, set by command line arg ++ // quick start ption, set by command line arg + new bx_param_bool_c (BXP_QUICK_START, + "Quick start", + "Quick start option: if true, read the bochsrc and start simulation immediately", +@@ -374,127 +444,301 @@ + bx_options.floppyb.Otype->set_handler (bx_param_handler); + bx_options.floppyb.Ostatus->set_handler (bx_param_handler); + +- // diskc options +- bx_options.diskc.Opresent = new bx_param_bool_c (BXP_DISKC_PRESENT, +- "diskc:present", +- "Controls whether diskc is installed or not", +- 0); +- bx_options.diskc.Opath = new bx_param_filename_c (BXP_DISKC_PATH, +- "", +- "Pathname of the hard drive image", +- "", BX_PATHNAME_LEN); +- bx_options.diskc.Ocylinders = new bx_param_num_c (BXP_DISKC_CYLINDERS, +- "diskc:cylinders", +- "Number of cylinders", +- 0, 65535, +- 0); +- bx_options.diskc.Oheads = new bx_param_num_c (BXP_DISKC_HEADS, +- "diskc:heads", +- "Number of heads", +- 0, 65535, +- 0); +- bx_options.diskc.Ospt = new bx_param_num_c (BXP_DISKC_SPT, +- "diskc:spt", +- "Number of sectors per track", +- 0, 65535, +- 0); +- bx_options.diskc.Opath->set_ask_format ("Enter new filename, or 'none' for no disk: [%s] "); +- bx_options.diskc.Ocylinders->set_ask_format ("Enter number of cylinders: [%d] "); +- bx_options.diskc.Oheads->set_ask_format ("Enter number of heads: [%d] "); +- bx_options.diskc.Ospt->set_ask_format ("Enter number of sectors per track: [%d] "); +- bx_options.diskc.Opath->set_format ("%s"); +- bx_options.diskc.Ocylinders->set_format (", %d cylinders, "); +- bx_options.diskc.Oheads->set_format ("%d heads, "); +- bx_options.diskc.Ospt->set_format ("%d sectors/track"); +- bx_param_c *diskc_init_list[] = { +- bx_options.diskc.Opath, +- bx_options.diskc.Ocylinders, +- bx_options.diskc.Oheads, +- bx_options.diskc.Ospt, +- NULL +- }; +- menu = new bx_list_c (BXP_DISKC, "Hard disk 0", "All options for hard disk 0", diskc_init_list); +- menu->get_options ()->set (menu->BX_SERIES_ASK); +- // if path is the word "none", then do not ask the other options and +- // set present=0. +- bx_options.diskc.Opath->set_handler (bx_param_string_handler); +- bx_options.diskc.Opath->set ("none"); +- +- // diskd options +- bx_options.diskd.Opresent = new bx_param_bool_c (BXP_DISKD_PRESENT, +- "diskd:present", +- "Controls whether diskd is installed or not", +- 0); +- bx_options.diskd.Opath = new bx_param_filename_c (BXP_DISKD_PATH, +- "diskd:path", +- "Pathname of the hard drive image", +- "", BX_PATHNAME_LEN); +- bx_options.diskd.Ocylinders = new bx_param_num_c (BXP_DISKD_CYLINDERS, +- "diskd:cylinders", +- "Number of cylinders", +- 0, 65535, +- 0); +- bx_options.diskd.Oheads = new bx_param_num_c (BXP_DISKD_HEADS, +- "diskd:heads", +- "Number of heads", +- 0, 65535, +- 0); +- bx_options.diskd.Ospt = new bx_param_num_c (BXP_DISKD_SPT, +- "diskd:spt", +- "Number of sectors per track", +- 0, 65535, +- 0); +- bx_options.diskd.Opath->set_ask_format ("Enter new filename, or none for no disk: [%s] "); +- bx_options.diskd.Ocylinders->set_ask_format ("Enter number of cylinders: [%d] "); +- bx_options.diskd.Oheads->set_ask_format ("Enter number of heads: [%d] "); +- bx_options.diskd.Ospt->set_ask_format ("Enter number of sectors per track: [%d] "); +- bx_options.diskd.Opath->set_format ("%s"); +- bx_options.diskd.Ocylinders->set_format (", %d cylinders, "); +- bx_options.diskd.Oheads->set_format ("%d heads, "); +- bx_options.diskd.Ospt->set_format ("%d sectors/track"); +- bx_param_c *diskd_init_list[] = { +- bx_options.diskd.Opath, +- bx_options.diskd.Ocylinders, +- bx_options.diskd.Oheads, +- bx_options.diskd.Ospt, +- NULL ++ // disk options ++ for (Bit8u channel=0; channelset_initial_val(1); ++ bx_options.ata[0].Oioaddr1->set_initial_val(0x1f0); ++ bx_options.ata[0].Oioaddr2->set_initial_val(0x3f0); ++ bx_options.ata[0].Oirq->set_initial_val(14); ++ ++ // FIXME use descr and name ++ char *s_atachannel[] = { ++ "ATA channel 0", ++ "ATA channel 1", ++ "ATA channel 2", ++ "ATA channel 3", ++ }; ++ char *s_atadevice[][2] = { ++ "Master ATA device on channel 0", ++ "Slave ATA device on channel 0", ++ "Master ATA device on channel 1", ++ "Slave ATA device on channel 1", ++ "Master ATA device on channel 2", ++ "Slave ATA device on channel 2", ++ "Master ATA device on channel 3", ++ "Slave ATA device on channel 3", ++ }; ++ ++ bx_param_c *atachannel_init_list[BX_MAX_ATA_CHANNEL][5] = { ++ { bx_options.ata[0].Opresent, ++ bx_options.ata[0].Oioaddr1, ++ bx_options.ata[0].Oioaddr2, ++ bx_options.ata[0].Oirq, ++ NULL ++ }, ++#if BX_MAX_ATA_CHANNEL>1 ++ { bx_options.ata[1].Opresent, ++ bx_options.ata[1].Oioaddr1, ++ bx_options.ata[1].Oioaddr2, ++ bx_options.ata[1].Oirq, ++ NULL ++ }, ++#endif ++#if BX_MAX_ATA_CHANNEL>2 ++ { bx_options.ata[2].Opresent, ++ bx_options.ata[2].Oioaddr1, ++ bx_options.ata[2].Oioaddr2, ++ bx_options.ata[2].Oirq, ++ NULL ++ }, ++#endif ++#if BX_MAX_ATA_CHANNEL>3 ++ { bx_options.ata[3].Opresent, ++ bx_options.ata[3].Oioaddr1, ++ bx_options.ata[3].Oioaddr2, ++ bx_options.ata[3].Oirq, ++ NULL ++ }, ++#endif + }; +- menu = new bx_list_c (BXP_DISKD, "Hard disk 1", "All options for hard disk 1", diskd_init_list); +- menu->get_options ()->set (menu->BX_SERIES_ASK); +- bx_options.diskd.Opath->set_handler (bx_param_string_handler); +- bx_options.diskd.Opath->set ("none"); + +- // cdrom options +- bx_options.cdromd.Opresent = new bx_param_bool_c (BXP_CDROM_PRESENT, +- "CDROM is present", +- "Controls whether cdromd is installed or not", +- 0); +- bx_options.cdromd.Opath = new bx_param_filename_c (BXP_CDROM_PATH, +- "CDROM image filename", +- "Pathname of the cdrom device or image", +- "", BX_PATHNAME_LEN); +- bx_options.cdromd.Opath->set_format ("%s"); +-#if BX_UI_TEXT +- bx_options.cdromd.Opath->set_ask_format ("Enter new filename, or 'none' for no CDROM: [%s] "); ++ bx_param_c *atadevice_init_list[BX_MAX_ATA_CHANNEL*2][10] = { ++ { bx_options.atadevice[0][0].Otype, ++ bx_options.atadevice[0][0].Opath, ++ bx_options.atadevice[0][0].Ocylinders, ++ bx_options.atadevice[0][0].Oheads, ++ bx_options.atadevice[0][0].Ospt, ++ bx_options.atadevice[0][0].Ostatus, ++ bx_options.atadevice[0][0].Omodel, ++ bx_options.atadevice[0][0].Obiosdetect, ++ bx_options.atadevice[0][0].Otranslation, ++ NULL ++ }, ++ { bx_options.atadevice[0][1].Otype, ++ bx_options.atadevice[0][1].Opath, ++ bx_options.atadevice[0][1].Ocylinders, ++ bx_options.atadevice[0][1].Oheads, ++ bx_options.atadevice[0][1].Ospt, ++ bx_options.atadevice[0][1].Ostatus, ++ bx_options.atadevice[0][1].Omodel, ++ bx_options.atadevice[0][1].Obiosdetect, ++ bx_options.atadevice[0][1].Otranslation, ++ NULL ++ }, ++#if BX_MAX_ATA_CHANNEL>1 ++ { bx_options.atadevice[1][0].Otype, ++ bx_options.atadevice[1][0].Opath, ++ bx_options.atadevice[1][0].Ocylinders, ++ bx_options.atadevice[1][0].Oheads, ++ bx_options.atadevice[1][0].Ospt, ++ bx_options.atadevice[1][0].Ostatus, ++ bx_options.atadevice[1][0].Omodel, ++ bx_options.atadevice[1][0].Obiosdetect, ++ bx_options.atadevice[1][0].Otranslation, ++ NULL ++ }, ++ { bx_options.atadevice[1][1].Otype, ++ bx_options.atadevice[1][1].Opath, ++ bx_options.atadevice[1][1].Ocylinders, ++ bx_options.atadevice[1][1].Oheads, ++ bx_options.atadevice[1][1].Ospt, ++ bx_options.atadevice[1][1].Ostatus, ++ bx_options.atadevice[1][1].Omodel, ++ bx_options.atadevice[1][1].Obiosdetect, ++ bx_options.atadevice[1][1].Otranslation, ++ NULL ++ }, ++#endif ++#if BX_MAX_ATA_CHANNEL>2 ++ { bx_options.atadevice[2][0].Otype, ++ bx_options.atadevice[2][0].Opath, ++ bx_options.atadevice[2][0].Ocylinders, ++ bx_options.atadevice[2][0].Oheads, ++ bx_options.atadevice[2][0].Ospt, ++ bx_options.atadevice[2][0].Ostatus, ++ bx_options.atadevice[2][0].Omodel, ++ bx_options.atadevice[2][0].Obiosdetect, ++ bx_options.atadevice[2][0].Otranslation, ++ NULL ++ }, ++ { bx_options.atadevice[2][1].Otype, ++ bx_options.atadevice[2][1].Opath, ++ bx_options.atadevice[2][1].Ocylinders, ++ bx_options.atadevice[2][1].Oheads, ++ bx_options.atadevice[2][1].Ospt, ++ bx_options.atadevice[2][1].Ostatus, ++ bx_options.atadevice[2][1].Omodel, ++ bx_options.atadevice[2][1].Obiosdetect, ++ bx_options.atadevice[2][1].Otranslation, ++ NULL ++ }, ++#endif ++#if BX_MAX_ATA_CHANNEL>3 ++ { bx_options.atadevice[3][0].Otype, ++ bx_options.atadevice[3][0].Opath, ++ bx_options.atadevice[3][0].Ocylinders, ++ bx_options.atadevice[3][0].Oheads, ++ bx_options.atadevice[3][0].Ospt, ++ bx_options.atadevice[3][0].Ostatus, ++ bx_options.atadevice[3][0].Omodel, ++ bx_options.atadevice[3][0].Obiosdetect, ++ bx_options.atadevice[3][0].Otranslation, ++ NULL ++ }, ++ { bx_options.atadevice[3][1].Otype, ++ bx_options.atadevice[3][1].Opath, ++ bx_options.atadevice[3][1].Ocylinders, ++ bx_options.atadevice[3][1].Oheads, ++ bx_options.atadevice[3][1].Ospt, ++ bx_options.atadevice[3][1].Ostatus, ++ bx_options.atadevice[3][1].Omodel, ++ bx_options.atadevice[3][1].Obiosdetect, ++ bx_options.atadevice[3][1].Otranslation, ++ NULL ++ }, + #endif +- bx_options.cdromd.Ostatus = new bx_param_enum_c (BXP_CDROM_STATUS, +- "Is the CDROM inserted or ejected", +- "Inserted or ejected", +- floppy_status_names, +- BX_INSERTED, +- BX_EJECTED); +- bx_options.cdromd.Ostatus->set_format (", %s"); +- bx_options.cdromd.Ostatus->set_ask_format ("Is the CDROM inserted or ejected? [%s] "); +- bx_param_c *cdromd_init_list[] = { +- bx_options.cdromd.Opath, +- bx_options.cdromd.Ostatus, +- NULL + }; +- menu = new bx_list_c (BXP_CDROMD, "CDROM", "Options for the CDROM", cdromd_init_list); +- menu->get_options ()->set (menu->BX_SERIES_ASK); +- bx_options.cdromd.Opath->set_handler (bx_param_string_handler); +- bx_options.cdromd.Opath->set ("none"); +- bx_options.cdromd.Ostatus->set_handler (bx_param_handler); ++ ++ for (Bit8u channel=0; channelset_ask_format ("Channel is enabled: [%s] "); ++ bx_options.ata[channel].Oioaddr1->set_ask_format ("Enter new ioaddr1: [0x%x] "); ++ bx_options.ata[channel].Oioaddr2->set_ask_format ("Enter new ioaddr2: [0x%x] "); ++ bx_options.ata[channel].Oirq->set_ask_format ("Enter new irq: [%d] "); ++ bx_options.ata[channel].Opresent->set_format ("enabled: %s"); ++ bx_options.ata[channel].Oioaddr1->set_format (", ioaddr1: 0x%x"); ++ bx_options.ata[channel].Oioaddr2->set_format (", ioaddr2: 0x%x"); ++ bx_options.ata[channel].Oirq->set_format (", irq: %d"); ++ bx_options.ata[channel].Oioaddr1->set_base (16); ++ bx_options.ata[channel].Oioaddr2->set_base (16); ++ ++ menu = new bx_list_c ((bx_id)(BXP_ATA0+channel), s_atachannel[channel], s_atachannel[channel], atachannel_init_list[channel]); ++ menu->get_options ()->set (menu->BX_SERIES_ASK); ++ ++ bx_options.ata[channel].Opresent->set_handler (bx_param_handler); ++ ++ for (Bit8u slave=0; slave<2; slave++) { ++ ++ bx_options.atadevice[channel][slave].Otype->set_ask_format ("Enter type of ATA device or 'none' for no device: [%s] "); ++ bx_options.atadevice[channel][slave].Opath->set_ask_format ("Enter new filename: [%s] "); ++ bx_options.atadevice[channel][slave].Ocylinders->set_ask_format ("Enter number of cylinders: [%d] "); ++ bx_options.atadevice[channel][slave].Oheads->set_ask_format ("Enter number of heads: [%d] "); ++ bx_options.atadevice[channel][slave].Ospt->set_ask_format ("Enter number of sectors per track: [%d] "); ++ bx_options.atadevice[channel][slave].Ostatus->set_ask_format ("Is the device inserted or ejected? [%s] "); ++ bx_options.atadevice[channel][slave].Omodel->set_ask_format ("Enter new model name: [%s]"); ++ bx_options.atadevice[channel][slave].Otranslation->set_ask_format ("Enter translation type: [%s]"); ++ bx_options.atadevice[channel][slave].Obiosdetect->set_ask_format ("Enter bios detection type: [%s]"); ++ ++ bx_options.atadevice[channel][slave].Otype->set_format ("%s"); ++ bx_options.atadevice[channel][slave].Opath->set_format (" on %s"); ++ bx_options.atadevice[channel][slave].Ocylinders->set_format (", %d cylinders"); ++ bx_options.atadevice[channel][slave].Oheads->set_format (", %d heads"); ++ bx_options.atadevice[channel][slave].Ospt->set_format (", %d sectors/track"); ++ bx_options.atadevice[channel][slave].Ostatus->set_format (", %s"); ++ bx_options.atadevice[channel][slave].Omodel->set_format (", model '%s'"); ++ bx_options.atadevice[channel][slave].Otranslation->set_format (", translation '%s'"); ++ bx_options.atadevice[channel][slave].Obiosdetect->set_format (", biosdetect '%s'"); ++ ++ menu = new bx_list_c ((bx_id)(BXP_ATA0_MASTER+channel*2+slave), s_atadevice[channel][slave], ++ s_atadevice[channel][slave], atadevice_init_list[channel*2+slave]); ++ menu->get_options ()->set (menu->BX_SERIES_ASK); ++ ++ bx_options.atadevice[channel][slave].Otype->set_handler (bx_param_handler); ++ bx_options.atadevice[channel][slave].Otype->set(BX_ATA_DEVICE_NONE); ++ ++ bx_options.atadevice[channel][slave].Ostatus->set_handler (bx_param_handler); ++ bx_options.atadevice[channel][slave].Opath->set_handler (bx_param_string_handler); ++ } ++ } + + bx_options.OnewHardDriveSupport = new bx_param_bool_c (BXP_NEWHARDDRIVESUPPORT, + "New hard drive support", +@@ -519,9 +763,27 @@ + bx_param_c *disk_menu_init_list[] = { + SIM->get_param (BXP_FLOPPYA), + SIM->get_param (BXP_FLOPPYB), +- SIM->get_param (BXP_DISKC), +- SIM->get_param (BXP_DISKD), +- SIM->get_param (BXP_CDROMD), ++ //SIM->get_param (BXP_DISKC), ++ //SIM->get_param (BXP_DISKD), ++ //SIM->get_param (BXP_CDROMD), ++ SIM->get_param (BXP_ATA0), ++ SIM->get_param (BXP_ATA0_MASTER), ++ SIM->get_param (BXP_ATA0_SLAVE), ++#if BX_MAX_ATA_CHANNEL>1 ++ SIM->get_param (BXP_ATA1), ++ SIM->get_param (BXP_ATA1_MASTER), ++ SIM->get_param (BXP_ATA1_SLAVE), ++#endif ++#if BX_MAX_ATA_CHANNEL>2 ++ SIM->get_param (BXP_ATA2), ++ SIM->get_param (BXP_ATA2_MASTER), ++ SIM->get_param (BXP_ATA2_SLAVE), ++#endif ++#if BX_MAX_ATA_CHANNEL>3 ++ SIM->get_param (BXP_ATA3), ++ SIM->get_param (BXP_ATA3_MASTER), ++ SIM->get_param (BXP_ATA3_SLAVE), ++#endif + SIM->get_param (BXP_NEWHARDDRIVESUPPORT), + SIM->get_param (BXP_BOOTDRIVE), + SIM->get_param (BXP_FLOPPYSIGCHECK), +@@ -994,19 +1256,26 @@ + bx_options.floppyb.Odevtype->reset(); + bx_options.floppyb.Otype->reset(); + bx_options.floppyb.Ostatus->reset(); +- bx_options.diskc.Opresent->reset(); +- bx_options.diskc.Opath->reset(); +- bx_options.diskc.Ocylinders->reset(); +- bx_options.diskc.Oheads->reset(); +- bx_options.diskc.Ospt->reset(); +- bx_options.diskd.Opresent->reset(); +- bx_options.diskd.Opath->reset(); +- bx_options.diskd.Ocylinders->reset(); +- bx_options.diskd.Oheads->reset(); +- bx_options.diskd.Ospt->reset(); +- bx_options.cdromd.Opresent->reset(); +- bx_options.cdromd.Opath->reset(); +- bx_options.cdromd.Ostatus->reset(); ++ ++ for (Bit8u channel=0; channelreset(); ++ bx_options.ata[channel].Oioaddr1->reset(); ++ bx_options.ata[channel].Oioaddr2->reset(); ++ bx_options.ata[channel].Oirq->reset(); ++ ++ for (Bit8u slave=0; slave<2; slave++) { ++ bx_options.atadevice[channel][slave].Opresent->reset(); ++ bx_options.atadevice[channel][slave].Otype->reset(); ++ bx_options.atadevice[channel][slave].Opath->reset(); ++ bx_options.atadevice[channel][slave].Ocylinders->reset(); ++ bx_options.atadevice[channel][slave].Oheads->reset(); ++ bx_options.atadevice[channel][slave].Ospt->reset(); ++ bx_options.atadevice[channel][slave].Ostatus->reset(); ++ bx_options.atadevice[channel][slave].Omodel->reset(); ++ bx_options.atadevice[channel][slave].Obiosdetect->reset(); ++ bx_options.atadevice[channel][slave].Otranslation->reset(); ++ } ++ } + bx_options.OnewHardDriveSupport->reset(); + + // boot & memory +@@ -1826,7 +2095,168 @@ + } + } + ++ else if ((!strncmp(params[0], "ata", 3)) && (strlen(params[0]) == 4)) { ++ Bit8u channel = params[0][3]; ++ ++ if ((channel < '0') || (channel > '9')) { ++ BX_PANIC(("%s: ataX directive malformed.", context)); ++ } ++ channel-='0'; ++ if (channel >= BX_MAX_ATA_CHANNEL) { ++ BX_PANIC(("%s: ataX directive malformed.", context)); ++ } ++ ++ if ((num_params < 2) || (num_params > 5)) { ++ BX_PANIC(("%s: ataX directive malformed.", context)); ++ } ++ ++ if (strncmp(params[1], "enabled=", 8)) { ++ BX_PANIC(("%s: ataX directive malformed.", context)); ++ } ++ else { ++ bx_options.ata[channel].Opresent->set (atol(¶ms[1][8])); ++ } ++ ++ if (num_params > 2) { ++ if (strncmp(params[2], "ioaddr1=", 8)) { ++ BX_PANIC(("%s: ataX directive malformed.", context)); ++ } ++ else { ++ if ( (params[2][8] == '0') && (params[2][9] == 'x') ) ++ bx_options.ata[channel].Oioaddr1->set (strtoul (¶ms[2][8], NULL, 16)); ++ else ++ bx_options.ata[channel].Oioaddr1->set (strtoul (¶ms[2][8], NULL, 10)); ++ } ++ } ++ ++ if (num_params > 3) { ++ if (strncmp(params[3], "ioaddr2=", 8)) { ++ BX_PANIC(("%s: ataX directive malformed.", context)); ++ } ++ else { ++ if ( (params[3][8] == '0') && (params[3][9] == 'x') ) ++ bx_options.ata[channel].Oioaddr2->set (strtoul (¶ms[3][8], NULL, 16)); ++ else ++ bx_options.ata[channel].Oioaddr2->set (strtoul (¶ms[3][8], NULL, 10)); ++ } ++ } ++ ++ if (num_params > 4) { ++ if (strncmp(params[4], "irq=", 4)) { ++ BX_PANIC(("%s: ataX directive malformed.", context)); ++ } ++ else { ++ bx_options.ata[channel].Oirq->set (atol(¶ms[4][4])); ++ } ++ } ++ } ++ ++ // ataX-master, ataX-slave ++ else if ((!strncmp(params[0], "ata", 3)) && (strlen(params[0]) > 4)) { ++ Bit8u channel = params[0][3], slave = 0; ++ ++ if ((channel < '0') || (channel > '9')) { ++ BX_PANIC(("%s: ataX-master/slave directive malformed.", context)); ++ } ++ channel-='0'; ++ if (channel >= BX_MAX_ATA_CHANNEL) { ++ BX_PANIC(("%s: ataX-master/slave directive malformed.", context)); ++ } ++ ++ if ((strcmp(¶ms[0][4], "-slave")) && ++ (strcmp(¶ms[0][4], "-master"))) { ++ BX_PANIC(("%s: ataX-master/slave directive malformed.", context)); ++ } ++ ++ if (!strcmp(¶ms[0][4], "-slave")) { ++ slave = 1; ++ } ++ ++ if (bx_options.atadevice[channel][slave].Opresent->get()) { ++ BX_PANIC(("%s: %s device of ata channel %d already defined.", slave?"slave":"master",channel)); ++ } ++ ++ for (i=1; iset (BX_ATA_DEVICE_DISK); ++ } ++ else if (!strcmp(params[i], "type=cdrom")) { ++ bx_options.atadevice[channel][slave].Otype->set (BX_ATA_DEVICE_CDROM); ++ } ++ else if (!strncmp(params[i], "path=", 5)) { ++ bx_options.atadevice[channel][slave].Opath->set (¶ms[i][5]); ++ } ++ else if (!strncmp(params[i], "cylinders=", 10)) { ++ bx_options.atadevice[channel][slave].Ocylinders->set (atol(¶ms[i][10])); ++ } ++ else if (!strncmp(params[i], "heads=", 6)) { ++ bx_options.atadevice[channel][slave].Oheads->set (atol(¶ms[i][6])); ++ } ++ else if (!strncmp(params[i], "spt=", 4)) { ++ bx_options.atadevice[channel][slave].Ospt->set (atol(¶ms[i][4])); ++ } ++ else if (!strncmp(params[i], "model=", 6)) { ++ bx_options.atadevice[channel][slave].Omodel->set(¶ms[i][6]); ++ } ++ else if (!strcmp(params[i], "biosdetect=none")) { ++ bx_options.atadevice[channel][slave].Obiosdetect->set(BX_ATA_BIOSDETECT_NONE); ++ } ++ else if (!strcmp(params[i], "biosdetect=cmos")) { ++ bx_options.atadevice[channel][slave].Obiosdetect->set(BX_ATA_BIOSDETECT_CMOS); ++ } ++ else if (!strcmp(params[i], "biosdetect=auto")) { ++ bx_options.atadevice[channel][slave].Obiosdetect->set(BX_ATA_BIOSDETECT_AUTO); ++ } ++ else if (!strcmp(params[i], "translation=none")) { ++ bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_NONE); ++ } ++ else if (!strcmp(params[i], "translation=lba")) { ++ bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_LBA); ++ } ++ else if (!strcmp(params[i], "translation=large")) { ++ bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_LARGE); ++ } ++ else if (!strcmp(params[i], "status=ejected")) { ++ bx_options.atadevice[channel][slave].Ostatus->set(BX_EJECTED); ++ } ++ else if (!strcmp(params[i], "status=inserted")) { ++ bx_options.atadevice[channel][slave].Ostatus->set(BX_INSERTED); ++ } ++ else { ++ BX_PANIC(("%s: ataX-master/slave directive malformed.", context)); ++ } ++ } ++ ++ // Enables the ata device ++ bx_options.atadevice[channel][slave].Opresent->set(1); ++ ++ // if enabled check if device ok ++ if (bx_options.atadevice[channel][slave].Opresent->get() == 1) { ++ if (bx_options.atadevice[channel][slave].Otype->get() == BX_ATA_DEVICE_DISK) { ++ if ((strlen(bx_options.atadevice[channel][slave].Opath->getptr()) ==0) || ++ (bx_options.atadevice[channel][slave].Ocylinders->get() == 0) || ++ (bx_options.atadevice[channel][slave].Oheads->get() ==0 ) || ++ (bx_options.atadevice[channel][slave].Ospt->get() == 0)) { ++ BX_PANIC(("%s: ataX-master/slave directive malformed.", context)); ++ } ++ } ++ else if (bx_options.atadevice[channel][slave].Otype->get() == BX_ATA_DEVICE_CDROM) { ++ if (strlen(bx_options.atadevice[channel][slave].Opath->getptr()) == 0) { ++ BX_PANIC(("%s: ataX-master/slave directive malformed.", context)); ++ } ++ } ++ else { ++ BX_PANIC(("%s: ataX-master/slave: type sould be specified ", context)); ++ } ++ } ++ ++ } ++ ++ // Legacy disk options emulation + else if (!strcmp(params[0], "diskc")) { ++ if (bx_options.atadevice[0][0].Opresent->get()) { ++ BX_PANIC(("%s: master device of ata channel 0 already defined.", context)); ++ } + if (num_params != 5) { + BX_PANIC(("%s: diskc directive malformed.", context)); + } +@@ -1836,13 +2266,18 @@ + strncmp(params[4], "spt=", 4)) { + BX_PANIC(("%s: diskc directive malformed.", context)); + } +- bx_options.diskc.Opath->set (¶ms[1][5]); +- bx_options.diskc.Ocylinders->set (atol(¶ms[2][4])); +- bx_options.diskc.Oheads->set (atol(¶ms[3][6])); +- bx_options.diskc.Ospt->set (atol(¶ms[4][4])); +- bx_options.diskc.Opresent->set (1); ++ bx_options.ata[0].Opresent->set(1); ++ bx_options.atadevice[0][0].Otype->set (BX_ATA_DEVICE_DISK); ++ bx_options.atadevice[0][0].Opath->set (¶ms[1][5]); ++ bx_options.atadevice[0][0].Ocylinders->set (atol(¶ms[2][4])); ++ bx_options.atadevice[0][0].Oheads->set (atol(¶ms[3][6])); ++ bx_options.atadevice[0][0].Ospt->set (atol(¶ms[4][4])); ++ bx_options.atadevice[0][0].Opresent->set (1); + } + else if (!strcmp(params[0], "diskd")) { ++ if (bx_options.atadevice[0][1].Opresent->get()) { ++ BX_PANIC(("%s: slave device of ata channel 0 already defined.", context)); ++ } + if (num_params != 5) { + BX_PANIC(("%s: diskd directive malformed.", context)); + } +@@ -1852,11 +2287,47 @@ + strncmp(params[4], "spt=", 4)) { + BX_PANIC(("%s: diskd directive malformed.", context)); + } +- bx_options.diskd.Opath->set (¶ms[1][5]); +- bx_options.diskd.Ocylinders->set (atol( ¶ms[2][4])); +- bx_options.diskd.Oheads->set (atol( ¶ms[3][6] )); +- bx_options.diskd.Ospt->set (atol( ¶ms[4][4] )); +- bx_options.diskd.Opresent->set (1); ++ bx_options.ata[0].Opresent->set(1); ++ bx_options.atadevice[0][1].Otype->set (BX_ATA_DEVICE_DISK); ++ bx_options.atadevice[0][1].Opath->set (¶ms[1][5]); ++ bx_options.atadevice[0][1].Ocylinders->set (atol( ¶ms[2][4])); ++ bx_options.atadevice[0][1].Oheads->set (atol( ¶ms[3][6])); ++ bx_options.atadevice[0][1].Ospt->set (atol( ¶ms[4][4])); ++ bx_options.atadevice[0][1].Opresent->set (1); ++ } ++ else if (!strcmp(params[0], "cdromd")) { ++ if (bx_options.atadevice[0][1].Opresent->get()) { ++ BX_PANIC(("%s: slave device of ata channel 0 already defined.", context)); ++ } ++ if (num_params != 3) { ++ BX_PANIC(("%s: cdromd directive malformed.", context)); ++ } ++ if (strncmp(params[1], "dev=", 4) || strncmp(params[2], "status=", 7)) { ++ BX_PANIC(("%s: cdromd directive malformed.", context)); ++ } ++ bx_options.ata[0].Opresent->set(1); ++ bx_options.atadevice[0][1].Otype->set (BX_ATA_DEVICE_CDROM); ++ bx_options.atadevice[0][1].Opath->set (¶ms[1][4]); ++ if (!strcmp(params[2], "status=inserted")) ++ bx_options.atadevice[0][1].Ostatus->set (BX_INSERTED); ++ else if (!strcmp(params[2], "status=ejected")) ++ bx_options.atadevice[0][1].Ostatus->set (BX_EJECTED); ++ else { ++ BX_PANIC(("%s: cdromd directive malformed.", context)); ++ } ++ bx_options.atadevice[0][1].Opresent->set (1); ++ } ++ ++ else if (!strcmp(params[0], "boot")) { ++ if (!strcmp(params[1], "a")) { ++ bx_options.Obootdrive->set (BX_BOOT_FLOPPYA); ++ } else if (!strcmp(params[1], "c")) { ++ bx_options.Obootdrive->set (BX_BOOT_DISKC); ++ } else if (!strcmp(params[1], "cdrom")) { ++ bx_options.Obootdrive->set (BX_BOOT_CDROM); ++ } else { ++ BX_PANIC(("%s: boot directive with unknown boot device '%s'. use 'a', 'c' or 'cdrom'.", context, params[1])); ++ } + } + + else if (!strcmp(params[0], "com1")) { +@@ -1918,35 +2389,6 @@ + } + #endif + +- else if (!strcmp(params[0], "cdromd")) { +- if (num_params != 3) { +- BX_PANIC(("%s: cdromd directive malformed.", context)); +- } +- if (strncmp(params[1], "dev=", 4) || strncmp(params[2], "status=", 7)) { +- BX_PANIC(("%s: cdromd directive malformed.", context)); +- } +- bx_options.cdromd.Opath->set (¶ms[1][4]); +- if (!strcmp(params[2], "status=inserted")) +- bx_options.cdromd.Ostatus->set (BX_INSERTED); +- else if (!strcmp(params[2], "status=ejected")) +- bx_options.cdromd.Ostatus->set (BX_EJECTED); +- else { +- BX_PANIC(("%s: cdromd directive malformed.", context)); +- } +- bx_options.cdromd.Opresent->set (1); +- } +- +- else if (!strcmp(params[0], "boot")) { +- if (!strcmp(params[1], "a")) { +- bx_options.Obootdrive->set (BX_BOOT_FLOPPYA); +- } else if (!strcmp(params[1], "c")) { +- bx_options.Obootdrive->set (BX_BOOT_DISKC); +- } else if (!strcmp(params[1], "cdrom")) { +- bx_options.Obootdrive->set (BX_BOOT_CDROM); +- } else { +- BX_PANIC(("%s: boot directive with unknown boot device '%s'. use 'a', 'c' or 'cdrom'.", context, params[1])); +- } +- } + else if (!strcmp(params[0], "floppy_bootsig_check")) { + if (num_params != 2) { + BX_PANIC(("%s: floppy_bootsig_check directive malformed.", context)); +@@ -2507,15 +2949,11 @@ + if(!strncmp(params[1], "keys=", 4)) { + bx_options.Ouser_shortcut->set (strdup(¶ms[1][5])); + } +- } +- +- ++ } + else { + BX_PANIC(( "%s: directive '%s' not understood", context, params[0])); + } + +- if (bx_options.diskd.Opresent->get () && bx_options.cdromd.Opresent->get ()) +- BX_PANIC(("At present, using both diskd and cdromd at once is not supported.")); + } + + static char *fdtypes[] = { +@@ -2540,32 +2978,64 @@ + } + + int +-bx_write_disk_options (FILE *fp, int drive, bx_disk_options *opt) ++bx_write_ata_options (FILE *fp, Bit8u channel, bx_ata_options *opt) + { +- if (!opt->Opresent->get ()) { +- fprintf (fp, "# no disk%c\n", (char)'c'+drive); +- return 0; +- } +- fprintf (fp, "disk%c: file=\"%s\", cyl=%d, heads=%d, spt=%d\n", +- (char)'c'+drive, +- opt->Opath->getptr (), +- opt->Ocylinders->get (), +- opt->Oheads->get (), +- opt->Ospt->get ()); ++ fprintf (fp, "ata%d: enabled=%d", channel, opt->Opresent->get()); ++ ++ if (opt->Opresent->get()) { ++ fprintf (fp, ", ioaddr1=0x%x ioaddr2=0x%x, irq=%d", opt->Oioaddr1->get(), ++ opt->Oioaddr2->get(), opt->Oirq->get()); ++ } ++ ++ fprintf (fp, "\n"); + return 0; + } + + int +-bx_write_cdrom_options (FILE *fp, int drive, bx_cdrom_options *opt) ++bx_write_atadevice_options (FILE *fp, Bit8u channel, Bit8u drive, bx_atadevice_options *opt) + { +- BX_ASSERT (drive == 0); +- if (!opt->Opresent->get ()) { +- fprintf (fp, "# no cdromd\n"); +- return 0; ++ if (opt->Opresent->get()) { ++ fprintf (fp, "ata%d-%s: ", channel, drive==0?"master":"slave"); ++ ++ if (opt->Otype->get() == BX_ATA_DEVICE_DISK) { ++ fprintf (fp, ", type=disk, path=\"%s\", cylinders=%d, heads=%d, spt=%d", ++ opt->Opath->getptr(), opt->Ocylinders->get(), opt->Oheads->get(), opt->Ospt->get()); ++ ++ switch(opt->Otranslation->get()) { ++ case BX_ATA_TRANSLATION_NONE: ++ fprintf (fp, ", translation=none"); ++ break; ++ case BX_ATA_TRANSLATION_LBA: ++ fprintf (fp, ", translation=lba"); ++ break; ++ case BX_ATA_TRANSLATION_LARGE: ++ fprintf (fp, ", translation=large"); ++ break; ++ } ++ } ++ else if (opt->Otype->get() == BX_ATA_DEVICE_CDROM) { ++ fprintf (fp, ", type=cdrom, path=\"%s\", status=%s", ++ opt->Opath->getptr(), ++ opt->Ostatus->get ()==BX_EJECTED ? "ejected" : "inserted"); ++ } ++ ++ switch(opt->Obiosdetect->get()) { ++ case BX_ATA_BIOSDETECT_NONE: ++ fprintf (fp, ", biosdetect=none"); ++ break; ++ case BX_ATA_BIOSDETECT_CMOS: ++ fprintf (fp, ", biosdetect=cmos"); ++ break; ++ case BX_ATA_BIOSDETECT_AUTO: ++ fprintf (fp, ", biosdetect=auto"); ++ break; ++ } ++ if (strlen(opt->Omodel->getptr())>0) { ++ fprintf (fp, " model=\"%s\"", opt->Omodel->getptr()); ++ } ++ ++ fprintf (fp, "\n"); + } +- fprintf (fp, "cdromd: dev=%s, status=%s\n", +- opt->Opath->getptr (), +- opt->Ostatus->get ()==BX_INSERTED ? "inserted" : "ejected"); + return 0; + } + +@@ -2713,9 +3183,11 @@ + // the structs like bx_floppy_options::print or something. + bx_write_floppy_options (fp, 0, &bx_options.floppya); + bx_write_floppy_options (fp, 1, &bx_options.floppyb); +- bx_write_disk_options (fp, 0, &bx_options.diskc); +- bx_write_disk_options (fp, 1, &bx_options.diskd); +- bx_write_cdrom_options (fp, 0, &bx_options.cdromd); ++ for (Bit8u channel=0; channelgetptr ()) > 0) + fprintf (fp, "romimage: file=%s, address=0x%05x\n", bx_options.rom.Opath->getptr(), (unsigned int)bx_options.rom.Oaddress->get ()); + else +Index: .bochsrc +=================================================================== +RCS file: /cvsroot/bochs/bochs/.bochsrc,v +retrieving revision 1.47 +diff -u -r1.47 .bochsrc +--- .bochsrc 24 Aug 2002 17:11:32 -0000 1.47 ++++ .bochsrc 14 Sep 2002 07:27:52 -0000 +@@ -84,6 +84,79 @@ + floppyb: 1_44=b.img, status=inserted + + #======================================================================= ++# ATA[0-3]: enabled=[0|1], ioaddr1=, ioaddr2=, irq= ++# ++# These options enables up to 4 ata channels. For each channel ++# the two base io address and the irq must be specified. ++# ++# ata0 is enabled by default, with ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 ++# ++# Examples: ++# ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 ++# ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 ++# ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e8, irq=12 ++# ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x368, irq=11 ++#======================================================================= ++ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 ++ata1: enabled=0, ioaddr1=0x170, ioaddr2=0x370, irq=15 ++ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e8, irq=12 ++ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x368, irq=11 ++ ++#======================================================================= ++# ++# ATA[0-3]-MASTER: ++# ATA[0-3]-SLAVE: ++# ++# This defines the type and characteristics of all attached ata devices: ++# type= type of attached device [disk|cdrom] ++# path= path of the image ++# cylinders= only valid for disks ++# heads= only valid for disks ++# spt= only valid for disks ++# status= only valid for cdroms [inserted|ejected] ++# biosdetect= type of biosdetection [none|auto], only for disks on ata0 [cmos] ++# translation=type of transation of the bios, only for disks [none|lba|large] ++# model= string returned by identify device command ++# ++# Point this at a 10M, 20M, or 30M hard disk image file, cdrom iso file, ++# or physical cdrom device. ++# To create # a hard disk image, try running bximage. ++# It will help you choose the size and then suggest a line that ++# works with it. ++# ++# In UNIX it may be possible to use a raw device as a Bochs hard disk, ++# but WE DON'T RECOMMEND IT. In Windows there is no easy way. ++# ++# In windows, the drive letter + colon notation should be used for cdroms. ++# Depending on versions of windows and drivers, you may only be able to ++# access the "first" cdrom in the system. ++# ++# The path, cylinders, heads, and spt are mandatory for type=disk ++# The path is mandatory for type=cdrom ++# ++# Default values are: ++# biosdetect=auto, translation=lba, model="Generic 1234" ++# ++# The biosdetect and translation options have currently no effect on the bios ++# ++# Examples: ++# ata0-master: type=disk, path=10M.sample, cylinders=306, heads=4, spt=17 ++# ata0-slave: type=disk, path=20M.sample, cylinders=615, heads=4, spt=17 ++# ata1-master: type=disk, path=30M.sample, cylinders=615, heads=6, spt=17 ++# ata1-slave: type=disk, path=46M.sample, cylinders=940, heads=6, spt=17 ++# ata2-master: type=disk, path=62M.sample, cylinders=940, heads=8, spt=17 ++# ata2-slave: type=disk, path=112M.sample, cylinders=900, heads=15, spt=17 ++# ata3-master: type=disk, path=483M.sample, cylinders=1024, heads=15, spt=63 ++# ata3-slave: type=cdrom, path=iso.sample, status=inserted ++#======================================================================= ++ata0-master: type=disk, path="30M.sample", cylinders=615, heads=6, spt=17 ++#ata0-slave: dev=D:, status=inserted # for win32 ++#ata0-slave: dev=/dev/cdrom, status=inserted ++ ++#======================================================================= ++# ++# The DISKC option is deprecated. Use ATA* options instead. ++# + # DISKC: file=, cyl=, heads=, spt= + # Point this at a 10M, 20M, or 30M hard disk image file. To create + # a hard disk image, try running bximage. It will help you choose the +@@ -101,9 +174,12 @@ + # diskc: file=112M.sample, cyl=900, heads=15, spt=17 + # diskc: file=483M.sample, cyl=1024, heads=15, spt=63 + #======================================================================= +-diskc: file="30M.sample", cyl=615, heads=6, spt=17 ++#diskc: file="30M.sample", cyl=615, heads=6, spt=17 + + #======================================================================= ++# ++# The DISKD option is deprecated. Use ATA* options instead. ++# + # DISKD: + # See DISKC above for syntax + # +@@ -112,7 +188,10 @@ + #diskd: file="diskd.img", cyl=615, heads=6, spt=17 + + #======================================================================= +-# CDROM ++# ++# The CDROMD option is deprecated. Use ATA* options instead. ++# ++# CDROMD: + # + # cdromd: dev=/dev/cdrom, status=inserted + # cdromd: dev=/dev/cdrom, status=ejected +Index: gui/control.cc +=================================================================== +RCS file: /cvsroot/bochs/bochs/gui/control.cc,v +retrieving revision 1.60 +diff -u -r1.60 control.cc +--- gui/control.cc 6 Sep 2002 16:43:23 -0000 1.60 ++++ gui/control.cc 14 Sep 2002 07:27:53 -0000 +@@ -302,19 +302,22 @@ + "---------------------\n" + "1. Floppy disk 0: %s\n" + "2. Floppy disk 1: %s\n" +-"3. CDROM: %s\n" +-"4. (not implemented)\n" +-"5. Log options for all devices\n" +-"6. Log options for individual devices\n" +-"7. VGA Update Interval: %d\n" +-"8. Mouse: %s\n" +-"9. Keyboard paste delay: %d\n" +-"10. Userbutton shortcut: %s\n" +-"11. Instruction tracing: off (doesn't exist yet)\n" +-"12. Continue simulation\n" +-"13. Quit now\n" ++"3. 1st CDROM: %s\n" ++"4. 2nd CDROM: %s\n" ++"5. 3rd CDROM: %s\n" ++"6. 4th CDROM: %s\n" ++"7. (not implemented)\n" ++"8. Log options for all devices\n" ++"9. Log options for individual devices\n" ++"10. VGA Update Interval: %d\n" ++"11. Mouse: %s\n" ++"12. Keyboard paste delay: %d\n" ++"13. Userbutton shortcut: %s\n" ++"14. Instruction tracing: off (doesn't exist yet)\n" ++"15. Continue simulation\n" ++"16. Quit now\n" + "\n" +-"Please choose one: [12] "; ++"Please choose one: [15] "; + + char *menu_prompt_list[BX_CI_N_MENUS] = { + NULL, +@@ -338,9 +341,9 @@ + void build_runtime_options_prompt (char *format, char *buf, int size) + { + bx_floppy_options floppyop; +- bx_cdrom_options cdromop; ++ bx_atadevice_options cdromop; + /* bx_param_num_c *ips = SIM->get_param_num (BXP_IPS); */ +- char buffer[3][128]; ++ char buffer[6][128]; + for (int i=0; i<2; i++) { + SIM->get_floppy_options (i, &floppyop); + if (floppyop.Odevtype->get () == BX_FLOPPY_NONE) +@@ -352,14 +355,20 @@ + if (!floppyop.Opath->getptr ()[0]) strcpy (buffer[i], "none"); + } + } +- SIM->get_cdrom_options (0, &cdromop); +- if (!cdromop.Opresent->get ()) +- sprintf (buffer[2], "(not present)"); +- else +- sprintf (buffer[2], "%s, %s", +- cdromop.Opath->getptr (), +- (cdromop.Ostatus->get () == BX_INSERTED)? "inserted" : "ejected"); ++ ++ // 4 cdroms supported at run time ++ int device; ++ for (Bit8u cdrom=0; cdrom<4; cdrom++) { ++ if (!SIM->get_cdrom_options (cdrom, &cdromop, &device) || !cdromop.Opresent->get ()) ++ sprintf (buffer[2+cdrom], "(not present)"); ++ else ++ sprintf (buffer[2+cdrom], "(%s on ata%d) %s, %s", ++ device&1?"slave":"master", device/2, cdromop.Opath->getptr (), ++ (cdromop.Ostatus->get () == BX_INSERTED)? "inserted" : "ejected"); ++ } ++ + snprintf (buf, size, format, buffer[0], buffer[1], buffer[2], ++ buffer[3], buffer[4], buffer[5], + /* ips->get (), */ + SIM->get_param_num (BXP_VGA_UPDATE_INTERVAL)->get (), + SIM->get_param_num (BXP_MOUSE_ENABLED)->get () ? "enabled" : "disabled", +@@ -452,9 +461,9 @@ + case BX_CI_RUNTIME: + char prompt[1024]; + bx_floppy_options floppyop; +- bx_cdrom_options cdromop; ++ bx_atadevice_options cdromop; + build_runtime_options_prompt (runtime_menu_prompt, prompt, 1024); +- if (ask_uint (prompt, 1, 13, 12, &choice, 10) < 0) return -1; ++ if (ask_uint (prompt, 1, 16, 15, &choice, 10) < 0) return -1; + switch (choice) { + case 1: + SIM->get_floppy_options (0, &floppyop); +@@ -465,22 +474,31 @@ + if (floppyop.Odevtype->get () != BX_FLOPPY_NONE) do_menu (BXP_FLOPPYB); + break; + case 3: +- SIM->get_cdrom_options (0, &cdromop); +- if (cdromop.Opresent->get ()) do_menu (BXP_CDROMD); ++ case 4: ++ case 5: ++ case 6: ++ int device; ++ if (SIM->get_cdrom_options (choice - 3, &cdromop, &device) && cdromop.Opresent->get ()) { ++ // disable type selection ++ SIM->get_param((bx_id)(BXP_ATA0_MASTER_TYPE + device))->set_enabled(0); ++ SIM->get_param((bx_id)(BXP_ATA0_MASTER_MODEL + device))->set_enabled(0); ++ SIM->get_param((bx_id)(BXP_ATA0_MASTER_BIOSDETECT + device))->set_enabled(0); ++ do_menu ((bx_id)(BXP_ATA0_MASTER + device)); ++ } + break; +- case 4: // not implemented yet because I would have to mess with ++ case 7: // not implemented yet because I would have to mess with + // resetting timers and pits and everything on the fly. + // askparam (BXP_IPS); + break; +- case 5: bx_log_options (0); break; +- case 6: bx_log_options (1); break; +- case 7: askparam (BXP_VGA_UPDATE_INTERVAL); break; +- case 8: askparam (BXP_MOUSE_ENABLED); break; +- case 9: askparam (BXP_KBD_PASTE_DELAY); break; +- case 10: askparam (BXP_USER_SHORTCUT); break; +- case 11: NOT_IMPLEMENTED (choice); break; +- case 12: fprintf (stderr, "Continuing simulation\n"); return 0; +- case 13: ++ case 8: bx_log_options (0); break; ++ case 9: bx_log_options (1); break; ++ case 10: askparam (BXP_VGA_UPDATE_INTERVAL); break; ++ case 11: askparam (BXP_MOUSE_ENABLED); break; ++ case 12: askparam (BXP_KBD_PASTE_DELAY); break; ++ case 13: askparam (BXP_USER_SHORTCUT); break; ++ case 14: NOT_IMPLEMENTED (choice); break; ++ case 15: fprintf (stderr, "Continuing simulation\n"); return 0; ++ case 16: + fprintf (stderr, "You chose quit on the configuration interface.\n"); + SIM->quit_sim (1); + return -1; +Index: gui/gui.cc +=================================================================== +RCS file: /cvsroot/bochs/bochs/gui/gui.cc,v +retrieving revision 1.46 +diff -u -r1.46 gui.cc +--- gui/gui.cc 8 Sep 2002 07:56:09 -0000 1.46 ++++ gui/gui.cc 14 Sep 2002 07:27:53 -0000 +@@ -108,9 +108,9 @@ + BX_GRAVITY_LEFT, floppyB_handler); + + // CDROM +- BX_GUI_THIS cdromD_status = +- bx_devices.hard_drive->get_cd_media_status() +- && bx_options.cdromd.Opresent->get (); ++ Bit32u handle = bx_devices.hard_drive->get_first_cd_handle(); ++ BX_GUI_THIS cdromD_status = bx_devices.hard_drive->get_cd_media_status(handle); ++ + if (BX_GUI_THIS cdromD_status) + BX_GUI_THIS cdromD_hbar_id = headerbar_bitmap(BX_GUI_THIS cdromD_bmap_id, + BX_GRAVITY_LEFT, cdromD_handler); +@@ -162,9 +162,8 @@ + BX_GUI_THIS floppyB_status = + bx_devices.floppy->get_media_status (1) + && bx_options.floppyb.Ostatus->get (); +- BX_GUI_THIS cdromD_status = +- bx_devices.hard_drive->get_cd_media_status() +- && bx_options.cdromd.Opresent->get (); ++ Bit32u handle = bx_devices.hard_drive->get_first_cd_handle(); ++ BX_GUI_THIS cdromD_status = bx_devices.hard_drive->get_cd_media_status(handle); + if (BX_GUI_THIS floppyA_status) + replace_bitmap(BX_GUI_THIS floppyA_hbar_id, BX_GUI_THIS floppyA_bmap_id); + else { +@@ -243,6 +242,7 @@ + void + bx_gui_c::cdromD_handler(void) + { ++ Bit32u handle = bx_devices.hard_drive->get_first_cd_handle(); + #if BX_WITH_WX + // instead of just toggling the status, call wxWindows to bring up + // a dialog asking what disk image you want to switch to. +@@ -250,15 +250,15 @@ + if (ret < 0) return; // cancelled + // eject and then insert the disk. If the new path is invalid, + // the status will return 0. +- unsigned status = bx_devices.hard_drive->set_cd_media_status(0); ++ unsigned status = bx_devices.hard_drive->set_cd_media_status(handle, 0); + printf ("eject disk, new_status is %d\n", status); +- status = bx_devices.hard_drive->set_cd_media_status(1); ++ status = bx_devices.hard_drive->set_cd_media_status(handle, 1); + printf ("insert disk, new_status is %d\n", status); + fflush (stdout); + BX_GUI_THIS cdromD_status = status; + #else + BX_GUI_THIS cdromD_status = +- bx_devices.hard_drive->set_cd_media_status(!BX_GUI_THIS cdromD_status); ++ bx_devices.hard_drive->set_cd_media_status(handle, !BX_GUI_THIS cdromD_status); + #endif + BX_GUI_THIS update_drive_status_buttons (); + } +Index: gui/siminterface.cc +=================================================================== +RCS file: /cvsroot/bochs/bochs/gui/siminterface.cc,v +retrieving revision 1.58 +diff -u -r1.58 siminterface.cc +--- gui/siminterface.cc 13 Sep 2002 20:02:07 -0000 1.58 ++++ gui/siminterface.cc 14 Sep 2002 07:27:54 -0000 +@@ -66,7 +66,7 @@ + virtual int get_log_prefix (char *prefix, int len); + virtual int set_log_prefix (char *prefix); + virtual int get_floppy_options (int drive, bx_floppy_options *out); +- virtual int get_cdrom_options (int drive, bx_cdrom_options *out); ++ virtual int get_cdrom_options (int drive, bx_atadevice_options *out, int *device = NULL); + virtual char *get_floppy_type_name (int type); + virtual void set_notify_callback (sim_interface_callback_t func, void *arg); + virtual BxEvent* sim_to_ci_event (BxEvent *event); +@@ -325,10 +325,20 @@ + } + + int +-bx_real_sim_c::get_cdrom_options (int drive, bx_cdrom_options *out) ++bx_real_sim_c::get_cdrom_options (int level, bx_atadevice_options *out, int *where = NULL) + { +- BX_ASSERT (drive == 0); +- *out = bx_options.cdromd; ++ for (Bit8u channel=0; channelget() == BX_ATA_DEVICE_CDROM) { ++ if (level==0) { ++ *out = bx_options.atadevice[channel][device]; ++ if (where != NULL) *where=(channel*2)+device; ++ return 1; ++ } ++ else level--; ++ } ++ } ++ } + return 0; + } + +@@ -343,6 +353,14 @@ + int n_loader_os_names = 3; + char *keyboard_type_names[] = { "xt", "at", "mf", NULL }; + int n_keyboard_type_names = 3; ++char *atadevice_type_names[] = { "none", "disk", "cdrom", NULL }; ++int n_atadevice_type_names = 3; ++char *atadevice_status_names[] = { "ejected", "inserted", NULL }; ++int n_atadevice_status_names = 2; ++char *atadevice_biosdetect_names[] = { "none", "auto", "cmos", NULL }; ++int n_atadevice_biosdetect_names = 3; ++char *atadevice_translation_names[] = { "none", "lba", "large", NULL }; ++int n_atadevice_translation_names = 3; + + char * + bx_real_sim_c::get_floppy_type_name (int type) +@@ -776,9 +794,9 @@ + : bx_param_num_c (id, name, description, 0, 1, initial_val) + { + set_type (BXT_PARAM_BOOL); +- // dependent_list must be initialized before the set(), +- // because set calls update_dependents(). +- dependent_list = NULL; ++ // dependent_list must be initialized before the set(), ++ // because set calls update_dependents(). ++ dependent_list = NULL; + set (initial_val); + } + +Index: gui/siminterface.h +=================================================================== +RCS file: /cvsroot/bochs/bochs/gui/siminterface.h,v +retrieving revision 1.61 +diff -u -r1.61 siminterface.h +--- gui/siminterface.h 13 Sep 2002 19:39:38 -0000 1.61 ++++ gui/siminterface.h 14 Sep 2002 07:27:55 -0000 +@@ -124,12 +124,12 @@ + BXP_ROM_ADDRESS, + BXP_VGA_ROM_PATH, + BXP_OPTROM1_PATH, +- BXP_OPTROM1_ADDRESS, + BXP_OPTROM2_PATH, +- BXP_OPTROM2_ADDRESS, + BXP_OPTROM3_PATH, +- BXP_OPTROM3_ADDRESS, + BXP_OPTROM4_PATH, ++ BXP_OPTROM1_ADDRESS, ++ BXP_OPTROM2_ADDRESS, ++ BXP_OPTROM3_ADDRESS, + BXP_OPTROM4_ADDRESS, + BXP_KBD_SERIAL_DELAY, + BXP_KBD_PASTE_DELAY, +@@ -145,18 +145,116 @@ + BXP_FLOPPYB_TYPE, + BXP_FLOPPYB_STATUS, + BXP_FLOPPYB, +- BXP_DISKC_PRESENT, +- BXP_DISKC_PATH, +- BXP_DISKC_CYLINDERS, +- BXP_DISKC_HEADS, +- BXP_DISKC_SPT, +- BXP_DISKC, +- BXP_DISKD_PRESENT, +- BXP_DISKD_PATH, +- BXP_DISKD_CYLINDERS, +- BXP_DISKD_HEADS, +- BXP_DISKD_SPT, +- BXP_DISKD, ++ ++ BXP_ATA0, ++ BXP_ATA1, ++ BXP_ATA2, ++ BXP_ATA3, ++ BXP_ATA0_PRESENT, ++ BXP_ATA1_PRESENT, ++ BXP_ATA2_PRESENT, ++ BXP_ATA3_PRESENT, ++ BXP_ATA0_IOADDR1, ++ BXP_ATA1_IOADDR1, ++ BXP_ATA2_IOADDR1, ++ BXP_ATA3_IOADDR1, ++ BXP_ATA0_IOADDR2, ++ BXP_ATA1_IOADDR2, ++ BXP_ATA2_IOADDR2, ++ BXP_ATA3_IOADDR2, ++ BXP_ATA0_IRQ, ++ BXP_ATA1_IRQ, ++ BXP_ATA2_IRQ, ++ BXP_ATA3_IRQ, ++ BXP_ATA0_MASTER, ++ BXP_ATA0_SLAVE, ++ BXP_ATA1_MASTER, ++ BXP_ATA1_SLAVE, ++ BXP_ATA2_MASTER, ++ BXP_ATA2_SLAVE, ++ BXP_ATA3_MASTER, ++ BXP_ATA3_SLAVE, ++ BXP_ATA0_MASTER_PRESENT, ++ BXP_ATA0_SLAVE_PRESENT, ++ BXP_ATA1_MASTER_PRESENT, ++ BXP_ATA1_SLAVE_PRESENT, ++ BXP_ATA2_MASTER_PRESENT, ++ BXP_ATA2_SLAVE_PRESENT, ++ BXP_ATA3_MASTER_PRESENT, ++ BXP_ATA3_SLAVE_PRESENT, ++ BXP_ATA0_MASTER_TYPE, ++ BXP_ATA0_SLAVE_TYPE, ++ BXP_ATA1_MASTER_TYPE, ++ BXP_ATA1_SLAVE_TYPE, ++ BXP_ATA2_MASTER_TYPE, ++ BXP_ATA2_SLAVE_TYPE, ++ BXP_ATA3_MASTER_TYPE, ++ BXP_ATA3_SLAVE_TYPE, ++ BXP_ATA0_MASTER_PATH, ++ BXP_ATA0_SLAVE_PATH, ++ BXP_ATA1_MASTER_PATH, ++ BXP_ATA1_SLAVE_PATH, ++ BXP_ATA2_MASTER_PATH, ++ BXP_ATA2_SLAVE_PATH, ++ BXP_ATA3_MASTER_PATH, ++ BXP_ATA3_SLAVE_PATH, ++ BXP_ATA0_MASTER_CYLINDERS, ++ BXP_ATA0_SLAVE_CYLINDERS, ++ BXP_ATA1_MASTER_CYLINDERS, ++ BXP_ATA1_SLAVE_CYLINDERS, ++ BXP_ATA2_MASTER_CYLINDERS, ++ BXP_ATA2_SLAVE_CYLINDERS, ++ BXP_ATA3_MASTER_CYLINDERS, ++ BXP_ATA3_SLAVE_CYLINDERS, ++ BXP_ATA0_MASTER_HEADS, ++ BXP_ATA0_SLAVE_HEADS, ++ BXP_ATA1_MASTER_HEADS, ++ BXP_ATA1_SLAVE_HEADS, ++ BXP_ATA2_MASTER_HEADS, ++ BXP_ATA2_SLAVE_HEADS, ++ BXP_ATA3_MASTER_HEADS, ++ BXP_ATA3_SLAVE_HEADS, ++ BXP_ATA0_MASTER_SPT, ++ BXP_ATA0_SLAVE_SPT, ++ BXP_ATA1_MASTER_SPT, ++ BXP_ATA1_SLAVE_SPT, ++ BXP_ATA2_MASTER_SPT, ++ BXP_ATA2_SLAVE_SPT, ++ BXP_ATA3_MASTER_SPT, ++ BXP_ATA3_SLAVE_SPT, ++ BXP_ATA0_MASTER_STATUS, ++ BXP_ATA0_SLAVE_STATUS, ++ BXP_ATA1_MASTER_STATUS, ++ BXP_ATA1_SLAVE_STATUS, ++ BXP_ATA2_MASTER_STATUS, ++ BXP_ATA2_SLAVE_STATUS, ++ BXP_ATA3_MASTER_STATUS, ++ BXP_ATA3_SLAVE_STATUS, ++ BXP_ATA0_MASTER_MODEL, ++ BXP_ATA0_SLAVE_MODEL, ++ BXP_ATA1_MASTER_MODEL, ++ BXP_ATA1_SLAVE_MODEL, ++ BXP_ATA2_MASTER_MODEL, ++ BXP_ATA2_SLAVE_MODEL, ++ BXP_ATA3_MASTER_MODEL, ++ BXP_ATA3_SLAVE_MODEL, ++ BXP_ATA0_MASTER_BIOSDETECT, ++ BXP_ATA0_SLAVE_BIOSDETECT, ++ BXP_ATA1_MASTER_BIOSDETECT, ++ BXP_ATA1_SLAVE_BIOSDETECT, ++ BXP_ATA2_MASTER_BIOSDETECT, ++ BXP_ATA2_SLAVE_BIOSDETECT, ++ BXP_ATA3_MASTER_BIOSDETECT, ++ BXP_ATA3_SLAVE_BIOSDETECT, ++ BXP_ATA0_MASTER_TRANSLATION, ++ BXP_ATA0_SLAVE_TRANSLATION, ++ BXP_ATA1_MASTER_TRANSLATION, ++ BXP_ATA1_SLAVE_TRANSLATION, ++ BXP_ATA2_MASTER_TRANSLATION, ++ BXP_ATA2_SLAVE_TRANSLATION, ++ BXP_ATA3_MASTER_TRANSLATION, ++ BXP_ATA3_SLAVE_TRANSLATION, ++ + #define BXP_PARAMS_PER_SERIAL_PORT 2 + BXP_COM1_ENABLED, + BXP_COM1_PATH, +@@ -166,10 +264,6 @@ + BXP_COM3_PATH, + BXP_COM4_ENABLED, + BXP_COM4_PATH, +- BXP_CDROM_PRESENT, +- BXP_CDROM_PATH, +- BXP_CDROM_STATUS, +- BXP_CDROMD, + BXP_PRIVATE_COLORMAP, + BXP_FULLSCREEN, + BXP_SCREENMODE, +@@ -691,6 +785,7 @@ + virtual Bit32s get (); + virtual void set (Bit32s val); + void set_base (int base) { this->base = base; } ++ void set_initial_val (Bit32s initial_val) { this->val.number = this->initial_val = initial_val;} + int get_base () { return base; } + Bit32s get_min () { return min; } + Bit32s get_max () { return max; } +@@ -908,6 +1003,20 @@ + #define BX_FLOPPY_LAST 15 // last legal value of floppy type + #define BX_FLOPPY_GUESS 20 // decide based on image size + ++#define BX_ATA_DEVICE_NONE 0 ++#define BX_ATA_DEVICE_DISK 1 ++#define BX_ATA_DEVICE_CDROM 2 ++#define BX_ATA_DEVICE_LAST 2 ++ ++#define BX_ATA_BIOSDETECT_NONE 0 ++#define BX_ATA_BIOSDETECT_AUTO 1 ++#define BX_ATA_BIOSDETECT_CMOS 2 ++ ++#define BX_ATA_TRANSLATION_NONE 0 ++#define BX_ATA_TRANSLATION_LBA 1 ++#define BX_ATA_TRANSLATION_LARGE 2 ++#define BX_ATA_TRANSLATION_LAST 2 ++ + extern char *floppy_type_names[]; + extern int floppy_type_n_sectors[]; + extern int n_floppy_type_names; +@@ -919,6 +1028,14 @@ + extern int n_loader_os_names; + extern char *keyboard_type_names[]; + extern int n_keyboard_type_names; ++extern char *atadevice_type_names[]; ++extern int n_atadevice_type_names; ++extern char *atadevice_status_names[]; ++extern int n_atadevice_status_names; ++extern char *atadevice_biosdetect_names[]; ++extern int n_atadevice_biosdetect_names; ++extern char *atadevice_translation_names[]; ++extern int n_atadevice_translation_names; + + typedef struct { + bx_param_enum_c *Odevtype; +@@ -929,24 +1046,22 @@ + + typedef struct { + bx_param_bool_c *Opresent; ++ bx_param_enum_c *Otype; + bx_param_string_c *Opath; + bx_param_num_c *Ocylinders; + bx_param_num_c *Oheads; + bx_param_num_c *Ospt; +- } bx_disk_options; ++ bx_param_enum_c *Ostatus; ++ bx_param_string_c *Omodel; ++ bx_param_enum_c *Obiosdetect; ++ bx_param_enum_c *Otranslation; ++ } bx_atadevice_options; + + typedef struct { + bx_param_bool_c *Oenabled; + bx_param_string_c *Odev; + } bx_serial_options; + +-struct bx_cdrom_options +-{ +- bx_param_bool_c *Opresent; +- bx_param_string_c *Opath; +- bx_param_enum_c *Ostatus; +-}; +- + + //////////////////////////////////////////////////////////////////// + // base class simulator interface, contains just virtual functions. +@@ -992,7 +1107,7 @@ + virtual int get_log_prefix (char *prefix, int len) {return -1;} + virtual int set_log_prefix (char *prefix) {return -1;} + virtual int get_floppy_options (int drive, bx_floppy_options *out) {return -1;} +- virtual int get_cdrom_options (int drive, bx_cdrom_options *out) {return -1;} ++ virtual int get_cdrom_options (int drive, bx_atadevice_options *out, int *where = NULL) {return -1;} + virtual char *get_floppy_type_name (int type) {return NULL;} + + // The CI calls set_notify_callback to register its event handler function. +Index: iodev/harddrv.cc +=================================================================== +RCS file: /cvsroot/bochs/bochs/iodev/harddrv.cc,v +retrieving revision 1.71 +diff -u -r1.71 harddrv.cc +--- iodev/harddrv.cc 12 Sep 2002 06:49:04 -0000 1.71 ++++ iodev/harddrv.cc 14 Sep 2002 07:27:57 -0000 +@@ -56,76 +56,99 @@ + #endif + + +-static unsigned char model_no[41] = +- "Generic 1234 "; +- + static unsigned max_multiple_sectors = 0; // was 0x3f + static unsigned curr_multiple_sectors = 0; // was 0x3f + + // some packet handling macros + #define EXTRACT_FIELD(arr,byte,start,num_bits) (((arr)[(byte)] >> (start)) & ((1 << (num_bits)) - 1)) +-#define get_packet_field(b,s,n) (EXTRACT_FIELD((BX_SELECTED_CONTROLLER.buffer),(b),(s),(n))) +-#define get_packet_byte(b) (BX_SELECTED_CONTROLLER.buffer[(b)]) +-#define get_packet_word(b) (((uint16)BX_SELECTED_CONTROLLER.buffer[(b)] << 8) | BX_SELECTED_CONTROLLER.buffer[(b)+1]) +- +- +-#define BX_CONTROLLER(a) (BX_HD_THIS s[(a)]).controller +-#define BX_SELECTED_CONTROLLER (BX_CONTROLLER(BX_HD_THIS drive_select)) +- +-#define WRITE_FEATURES(a) do { uint8 _a = a; BX_CONTROLLER(0).features = _a; BX_CONTROLLER(1).features = _a; } while(0) +-#define WRITE_SECTOR_COUNT(a) do { uint8 _a = a; BX_CONTROLLER(0).sector_count = _a; BX_CONTROLLER(1).sector_count = _a; } while(0) +-#define WRITE_SECTOR_NUMBER(a) do { uint8 _a = a; BX_CONTROLLER(0).sector_no = _a; BX_CONTROLLER(1).sector_no = _a; } while(0) +-#define WRITE_CYLINDER_LOW(a) do { uint8 _a = a; BX_CONTROLLER(0).cylinder_no = (BX_CONTROLLER(0).cylinder_no & 0xff00) | _a; BX_CONTROLLER(1).cylinder_no = (BX_CONTROLLER(1).cylinder_no & 0xff00) | _a; } while(0) +-#define WRITE_CYLINDER_HIGH(a) do { uint16 _a = a; BX_CONTROLLER(0).cylinder_no = (_a << 8) | (BX_CONTROLLER(0).cylinder_no & 0xff); BX_CONTROLLER(1).cylinder_no = (_a << 8) | (BX_CONTROLLER(1).cylinder_no & 0xff); } while(0) +-#define WRITE_HEAD_NO(a) do { uint8 _a = a; BX_CONTROLLER(0).head_no = _a; BX_CONTROLLER(1).head_no = _a; } while(0) +-#define WRITE_LBA_MODE(a) do { uint8 _a = a; BX_CONTROLLER(0).lba_mode = _a; BX_CONTROLLER(1).lba_mode = _a; } while(0) ++#define get_packet_field(c,b,s,n) (EXTRACT_FIELD((BX_SELECTED_CONTROLLER((c)).buffer),(b),(s),(n))) ++#define get_packet_byte(c,b) (BX_SELECTED_CONTROLLER((c)).buffer[(b)]) ++#define get_packet_word(c,b) (((uint16)BX_SELECTED_CONTROLLER((c)).buffer[(b)] << 8) | BX_SELECTED_CONTROLLER((c)).buffer[(b)+1]) ++ ++ ++#define BX_CONTROLLER(c,a) (BX_HD_THIS channels[(c)].drives[(a)]).controller ++#define BX_DRIVE(c,a) (BX_HD_THIS channels[(c)].drives[(a)]) ++ ++#define BX_DRIVE_IS_PRESENT(c,a) (BX_HD_THIS channels[(c)].drives[(a)].device_type != IDE_NONE) ++#define BX_DRIVE_IS_HD(c,a) (BX_HD_THIS channels[(c)].drives[(a)].device_type == IDE_DISK) ++#define BX_DRIVE_IS_CD(c,a) (BX_HD_THIS channels[(c)].drives[(a)].device_type == IDE_CDROM) ++ ++#define BX_MASTER_IS_PRESENT(c) BX_DRIVE_IS_PRESENT((c),0) ++#define BX_SLAVE_IS_PRESENT(c) BX_DRIVE_IS_PRESENT((c),1) ++ ++#define BX_SELECTED_CONTROLLER(c) (BX_CONTROLLER((c),BX_HD_THIS channels[(c)].drive_select)) ++#define BX_SELECTED_DRIVE(c) (BX_DRIVE((c),BX_HD_THIS channels[(c)].drive_select)) ++#define BX_MASTER_SELECTED(c) (!BX_HD_THIS channels[(c)].drive_select) ++#define BX_SLAVE_SELECTED(c) (BX_HD_THIS channels[(c)].drive_select) ++ ++#define BX_SELECTED_IS_PRESENT(c) (BX_DRIVE_IS_PRESENT((c),BX_SLAVE_SELECTED((c)))) ++#define BX_SELECTED_IS_HD(c) (BX_DRIVE_IS_HD((c),BX_SLAVE_SELECTED((c)))) ++#define BX_SELECTED_IS_CD(c) (BX_DRIVE_IS_CD((c),BX_SLAVE_SELECTED((c)))) ++ ++#define BX_SELECTED_MODEL(c) (BX_HD_THIS channels[(c)].drives[BX_HD_THIS channels[(c)].drive_select].model_no) ++#define BX_SELECTED_TYPE_STRING(channel) ((BX_SELECTED_IS_CD(channel)) ? "CD-ROM" : "DISK") ++ ++#define WRITE_FEATURES(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).features = _a; BX_CONTROLLER((c),1).features = _a; } while(0) ++#define WRITE_SECTOR_COUNT(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).sector_count = _a; BX_CONTROLLER((c),1).sector_count = _a; } while(0) ++#define WRITE_SECTOR_NUMBER(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).sector_no = _a; BX_CONTROLLER((c),1).sector_no = _a; } while(0) ++#define WRITE_CYLINDER_LOW(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).cylinder_no = (BX_CONTROLLER((c),0).cylinder_no & 0xff00) | _a; BX_CONTROLLER((c),1).cylinder_no = (BX_CONTROLLER((c),1).cylinder_no & 0xff00) | _a; } while(0) ++#define WRITE_CYLINDER_HIGH(c,a) do { uint16 _a = a; BX_CONTROLLER((c),0).cylinder_no = (_a << 8) | (BX_CONTROLLER((c),0).cylinder_no & 0xff); BX_CONTROLLER((c),1).cylinder_no = (_a << 8) | (BX_CONTROLLER((c),1).cylinder_no & 0xff); } while(0) ++#define WRITE_HEAD_NO(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).head_no = _a; BX_CONTROLLER((c),1).head_no = _a; } while(0) ++#define WRITE_LBA_MODE(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).lba_mode = _a; BX_CONTROLLER((c),1).lba_mode = _a; } while(0) + + + //static unsigned im_here = 0; + + bx_hard_drive_c::bx_hard_drive_c(void) + { +- s[0].hard_drive = NULL; +- s[1].hard_drive = NULL; ++#if DLL_HD_SUPPORT ++# error code must be fixed to use DLL_HD_SUPPORT and 4 ata channels ++#endif ++ ++ for (Bit8u channel=0; channelget() == 1) { ++ BX_HD_THIS channels[channel].ioaddr1 = bx_options.ata[channel].Oioaddr1->get(); ++ BX_HD_THIS channels[channel].ioaddr2 = bx_options.ata[channel].Oioaddr2->get(); ++ BX_HD_THIS channels[channel].irq = bx_options.ata[channel].Oirq->get(); ++ ++ // Coherency check ++ if ( (BX_HD_THIS channels[channel].ioaddr1 == 0) || ++ (BX_HD_THIS channels[channel].ioaddr2 == 0) || ++ (BX_HD_THIS channels[channel].irq == 0) ) { ++ BX_PANIC(("incoherency for ata channel %d: io1=0x%x, io2=%x, irq=%d", ++ channel, ++ BX_HD_THIS channels[channel].ioaddr1, ++ BX_HD_THIS channels[channel].ioaddr2, ++ BX_HD_THIS channels[channel].irq)); ++ } ++ } ++ else { ++ BX_HD_THIS channels[channel].ioaddr1 = 0; ++ BX_HD_THIS channels[channel].ioaddr2 = 0; ++ BX_HD_THIS channels[channel].irq = 0; ++ } ++ } ++ ++ for (channel=0; channelregister_irq(14, "Hard Drive 0"); +- for (unsigned addr=0x01F0; addr<=0x01F7; addr++) { +- BX_HD_THIS devices->register_io_read_handler(this, read_handler, +- addr, "Hard Drive 0"); +- BX_HD_THIS devices->register_io_write_handler(this, write_handler, +- addr, "Hard Drive 0"); +- } +-#if 0 +- // this would be necessary to make the second HD master on the +- // second controller, using 0x170-0x177 and irq15. But it currently +- // works as second disk on the first IDE controller, so this code +- // is not needed. +- BX_HD_THIS devices->register_irq(15, "Hard Drive 1"); +- for (unsigned addr=0x0170; addr<=0x0177; addr++) { +- BX_HD_THIS devices->register_io_read_handler(this, read_handler, +- addr, "Hard Drive 1"); +- BX_HD_THIS devices->register_io_write_handler(this, write_handler, +- addr, "Hard Drive 1"); ++ if (BX_HD_THIS channels[channel].irq != 0) ++ BX_HD_THIS devices->register_irq(BX_HD_THIS channels[channel].irq, strdup(string)); ++ ++ if (BX_HD_THIS channels[channel].ioaddr1 != 0) { ++ for (unsigned addr=0x0; addr<=0x7; addr++) { ++ BX_HD_THIS devices->register_io_read_handler(this, read_handler, ++ BX_HD_THIS channels[channel].ioaddr1+addr, strdup(string)); ++ BX_HD_THIS devices->register_io_write_handler(this, write_handler, ++ BX_HD_THIS channels[channel].ioaddr1+addr, strdup(string)); ++ } ++ } ++ ++ // We don't want to register addresses 0x3f6 and 0x3f7 as they are handled by the floppy controller ++ if ((BX_HD_THIS channels[channel].ioaddr2 != 0) && (BX_HD_THIS channels[channel].ioaddr2 != 0x3f0)) { ++ for (unsigned addr=0x6; addr<=0x7; addr++) { ++ BX_HD_THIS devices->register_io_read_handler(this, read_handler, ++ BX_HD_THIS channels[channel].ioaddr2+addr, strdup(string)); ++ BX_HD_THIS devices->register_io_write_handler(this, write_handler, ++ BX_HD_THIS channels[channel].ioaddr2+addr, strdup(string)); ++ } ++ } ++ ++ BX_HD_THIS channels[channel].drive_select = 0; + } +-#endif + +- BX_HD_THIS drive_select = 0; +- +- BX_HD_THIS s[0].hard_drive->cylinders = bx_options.diskc.Ocylinders->get (); +- BX_HD_THIS s[0].hard_drive->heads = bx_options.diskc.Oheads->get (); +- BX_HD_THIS s[0].hard_drive->sectors = bx_options.diskc.Ospt->get (); +- BX_HD_THIS s[0].device_type = IDE_DISK; +- BX_HD_THIS s[1].hard_drive->cylinders = bx_options.diskd.Ocylinders->get (); +- BX_HD_THIS s[1].hard_drive->heads = bx_options.diskd.Oheads->get (); +- BX_HD_THIS s[1].hard_drive->sectors = bx_options.diskd.Ospt->get (); +- BX_HD_THIS s[1].device_type = IDE_DISK; +- +- if (bx_options.cdromd.Opresent->get ()) { +- bx_options.diskd.Opresent->set (1); +- BX_DEBUG(( "Experimental CDROM on target 1" )); +- BX_HD_THIS s[1].device_type = IDE_CDROM; +- BX_HD_THIS s[1].cdrom.locked = 0; +- BX_HD_THIS s[1].sense.sense_key = SENSE_NONE; +- BX_HD_THIS s[1].sense.asc = 0; +- BX_HD_THIS s[1].sense.ascq = 0; +- // Check bit fields +- BX_CONTROLLER(1).sector_count = 0; +- BX_CONTROLLER(1).interrupt_reason.c_d = 1; +- if (BX_CONTROLLER(1).sector_count != 0x01) +- BX_PANIC(("interrupt reason bit field error")); ++ channel = 0; ++ for (channel=0; channelget()) { ++ continue; ++ } + +- BX_CONTROLLER(1).sector_count = 0; +- BX_CONTROLLER(1).interrupt_reason.i_o = 1; +- if (BX_CONTROLLER(1).sector_count != 0x02) +- BX_PANIC(("interrupt reason bit field error")); ++ // Make model string ++ strncpy((char*)BX_HD_THIS channels[channel].drives[device].model_no, ++ bx_options.atadevice[channel][device].Omodel->getptr(), 40); ++ while (strlen((char *)BX_HD_THIS channels[channel].drives[device].model_no) < 40) { ++ strcat ((char*)BX_HD_THIS channels[channel].drives[device].model_no, " "); ++ } + +- BX_CONTROLLER(1).sector_count = 0; +- BX_CONTROLLER(1).interrupt_reason.rel = 1; +- if (BX_CONTROLLER(1).sector_count != 0x04) ++ if (bx_options.atadevice[channel][device].Otype->get() == BX_ATA_DEVICE_DISK) { ++ BX_DEBUG(( "Hard-Disk on target %d/%d",channel,device)); ++ BX_HD_THIS channels[channel].drives[device].device_type = IDE_DISK; ++ BX_HD_THIS channels[channel].drives[device].hard_drive->cylinders = bx_options.atadevice[channel][device].Ocylinders->get (); ++ BX_HD_THIS channels[channel].drives[device].hard_drive->heads = bx_options.atadevice[channel][device].Oheads->get (); ++ BX_HD_THIS channels[channel].drives[device].hard_drive->sectors = bx_options.atadevice[channel][device].Ospt->get (); ++ ++ /* open hard drive image file */ ++ if ((BX_HD_THIS channels[channel].drives[device].hard_drive->open(bx_options.atadevice[channel][device].Opath->getptr ())) < 0) { ++ BX_PANIC(("could not open hard drive image file '%s'", bx_options.atadevice[channel][device].Opath->getptr ())); ++ } ++ BX_INFO(("HD on ata%d-%d: '%s'",channel, device, bx_options.atadevice[channel][device].Opath->getptr ())); ++ } ++ else if (bx_options.atadevice[channel][device].Otype->get() == BX_ATA_DEVICE_CDROM) { ++ BX_DEBUG(( "CDROM on target %d/%d",channel,device)); ++ BX_HD_THIS channels[channel].drives[device].device_type = IDE_CDROM; ++ BX_HD_THIS channels[channel].drives[device].cdrom.locked = 0; ++ BX_HD_THIS channels[channel].drives[device].sense.sense_key = SENSE_NONE; ++ BX_HD_THIS channels[channel].drives[device].sense.asc = 0; ++ BX_HD_THIS channels[channel].drives[device].sense.ascq = 0; ++ ++ // Check bit fields ++ BX_CONTROLLER(channel,device).sector_count = 0; ++ BX_CONTROLLER(channel,device).interrupt_reason.c_d = 1; ++ if (BX_CONTROLLER(channel,device).sector_count != 0x01) ++ BX_PANIC(("interrupt reason bit field error")); ++ ++ BX_CONTROLLER(channel,device).sector_count = 0; ++ BX_CONTROLLER(channel,device).interrupt_reason.i_o = 1; ++ if (BX_CONTROLLER(channel,device).sector_count != 0x02) ++ BX_PANIC(("interrupt reason bit field error")); ++ ++ BX_CONTROLLER(channel,device).sector_count = 0; ++ BX_CONTROLLER(channel,device).interrupt_reason.rel = 1; ++ if (BX_CONTROLLER(channel,device).sector_count != 0x04) + BX_PANIC(("interrupt reason bit field error")); + +- BX_CONTROLLER(1).sector_count = 0; +- BX_CONTROLLER(1).interrupt_reason.tag = 3; +- if (BX_CONTROLLER(1).sector_count != 0x18) ++ BX_CONTROLLER(channel,device).sector_count = 0; ++ BX_CONTROLLER(channel,device).interrupt_reason.tag = 3; ++ if (BX_CONTROLLER(channel,device).sector_count != 0x18) + BX_PANIC(("interrupt reason bit field error")); +- BX_CONTROLLER(1).sector_count = 0; ++ BX_CONTROLLER(channel,device).sector_count = 0; + + // allocate low level driver + #ifdef LOWLEVEL_CDROM +- BX_HD_THIS s[1].cdrom.cd = new LOWLEVEL_CDROM(bx_options.cdromd.Opath->getptr ()); +-#endif ++ BX_HD_THIS channels[channel].drives[device].cdrom.cd = new LOWLEVEL_CDROM(bx_options.atadevice[channel][device].Opath->getptr ()); ++ BX_INFO(("CD on ata%d-%d: '%s'",channel, device, bx_options.atadevice[channel][device].Opath->getptr ())); + +-#ifdef LOWLEVEL_CDROM +- if (bx_options.cdromd.Ostatus->get () == BX_INSERTED) { +- if (BX_HD_THIS s[1].cdrom.cd->insert_cdrom()) { ++ if (bx_options.atadevice[channel][device].Ostatus->get () == BX_INSERTED) { ++ if (BX_HD_THIS channels[channel].drives[device].cdrom.cd->insert_cdrom()) { + BX_INFO(( "Media present in CD-ROM drive")); +- BX_HD_THIS s[1].cdrom.ready = 1; +- BX_HD_THIS s[1].cdrom.capacity = BX_HD_THIS s[1].cdrom.cd->capacity(); ++ BX_HD_THIS channels[channel].drives[device].cdrom.ready = 1; ++ BX_HD_THIS channels[channel].drives[device].cdrom.capacity = BX_HD_THIS channels[channel].drives[device].cdrom.cd->capacity(); + } else { + BX_INFO(( "Could not locate CD-ROM, continuing with media not present")); +- BX_HD_THIS s[1].cdrom.ready = 0; +- bx_options.cdromd.Ostatus->set(BX_EJECTED); ++ BX_HD_THIS channels[channel].drives[device].cdrom.ready = 0; ++ bx_options.atadevice[channel][device].Ostatus->set(BX_EJECTED); + } + } else { + #endif + BX_INFO(( "Media not present in CD-ROM drive" )); +- BX_HD_THIS s[1].cdrom.ready = 0; ++ BX_HD_THIS channels[channel].drives[device].cdrom.ready = 0; + #ifdef LOWLEVEL_CDROM + } + #endif +- } ++ } + +- /* open hard drive image file */ +- if (bx_options.diskc.Opresent->get ()) { +- if ((BX_HD_THIS s[0].hard_drive->open(bx_options.diskc.Opath->getptr ())) < 0) { +- BX_PANIC(("could not open hard drive image file '%s'", +- bx_options.diskc.Opath->getptr ())); +- } +- BX_INFO(("hd0: '%s'",bx_options.diskc.Opath->getptr ())); +- } +- if (bx_options.diskd.Opresent->get () && !bx_options.cdromd.Opresent->get ()) { +- if ((BX_HD_THIS s[1].hard_drive->open(bx_options.diskd.Opath->getptr ())) < 0) { +- BX_PANIC(("could not open hard drive image file '%s'", +- bx_options.diskd.Opath->getptr ())); +- } +- BX_INFO(("hd1: '%s'",bx_options.diskd.Opath->getptr())); ++ BX_CONTROLLER(channel,device).status.busy = 0; ++ BX_CONTROLLER(channel,device).status.drive_ready = 1; ++ BX_CONTROLLER(channel,device).status.write_fault = 0; ++ BX_CONTROLLER(channel,device).status.seek_complete = 1; ++ BX_CONTROLLER(channel,device).status.drq = 0; ++ BX_CONTROLLER(channel,device).status.corrected_data = 0; ++ BX_CONTROLLER(channel,device).status.index_pulse = 0; ++ BX_CONTROLLER(channel,device).status.index_pulse_count = 0; ++ BX_CONTROLLER(channel,device).status.err = 0; ++ ++ BX_CONTROLLER(channel,device).error_register = 0x01; // diagnostic code: no error ++ BX_CONTROLLER(channel,device).head_no = 0; ++ BX_CONTROLLER(channel,device).sector_count = 1; ++ BX_CONTROLLER(channel,device).sector_no = 1; ++ BX_CONTROLLER(channel,device).cylinder_no = 0; ++ BX_CONTROLLER(channel,device).current_command = 0x00; ++ BX_CONTROLLER(channel,device).buffer_index = 0; ++ ++ BX_CONTROLLER(channel,device).control.reset = 0; ++ BX_CONTROLLER(channel,device).control.disable_irq = 0; ++ ++ BX_CONTROLLER(channel,device).reset_in_progress = 0; ++ ++ BX_CONTROLLER(channel,device).sectors_per_block = 0x80; ++ BX_CONTROLLER(channel,device).lba_mode = 0; ++ ++ BX_CONTROLLER(channel,device).features = 0; ++ } + } + + // generate CMOS values for hard drive if not using a CMOS image + if (!bx_options.cmos.OcmosImage->get ()) { + cmos->s.reg[0x12] = 0x00; // start out with: no drive 0, no drive 1 + +- if (bx_options.diskc.Opresent->get ()) { ++ if (BX_DRIVE_IS_HD(0,0)) { + // Flag drive type as Fh, use extended CMOS location as real type + cmos->s.reg[0x12] = (cmos->s.reg[0x12] & 0x0f) | 0xf0; + cmos->s.reg[0x19] = 47; // user definable type + // AMI BIOS: 1st hard disk #cyl low byte +- cmos->s.reg[0x1b] = (bx_options.diskc.Ocylinders->get () & 0x00ff); ++ cmos->s.reg[0x1b] = (bx_options.atadevice[0][0].Ocylinders->get () & 0x00ff); + // AMI BIOS: 1st hard disk #cyl high byte +- cmos->s.reg[0x1c] = (bx_options.diskc.Ocylinders->get () & 0xff00) >> 8; ++ cmos->s.reg[0x1c] = (bx_options.atadevice[0][0].Ocylinders->get () & 0xff00) >> 8; + // AMI BIOS: 1st hard disk #heads +- cmos->s.reg[0x1d] = (bx_options.diskc.Oheads->get ()); ++ cmos->s.reg[0x1d] = (bx_options.atadevice[0][0].Oheads->get ()); + // AMI BIOS: 1st hard disk write precompensation cylinder, low byte + cmos->s.reg[0x1e] = 0xff; // -1 + // AMI BIOS: 1st hard disk write precompensation cylinder, high byte + cmos->s.reg[0x1f] = 0xff; // -1 + // AMI BIOS: 1st hard disk control byte +- cmos->s.reg[0x20] = 0xc0 | ((bx_options.diskc.Oheads->get () > 8) << 3); ++ cmos->s.reg[0x20] = 0xc0 | ((bx_options.atadevice[0][0].Oheads->get () > 8) << 3); + // AMI BIOS: 1st hard disk landing zone, low byte + cmos->s.reg[0x21] = cmos->s.reg[0x1b]; + // AMI BIOS: 1st hard disk landing zone, high byte + cmos->s.reg[0x22] = cmos->s.reg[0x1c]; + // AMI BIOS: 1st hard disk sectors/track +- cmos->s.reg[0x23] = bx_options.diskc.Ospt->get (); ++ cmos->s.reg[0x23] = bx_options.atadevice[0][0].Ospt->get (); + } + + //set up cmos for second hard drive +- if (bx_options.diskd.Opresent->get () && !bx_options.cdromd.Opresent->get ()) { ++ if (BX_DRIVE_IS_HD(0,1)) { + BX_DEBUG(("1: I will put 0xf into the second hard disk field")); + // fill in lower 4 bits of 0x12 for second HD + cmos->s.reg[0x12] = (cmos->s.reg[0x12] & 0xf0) | 0x0f; + cmos->s.reg[0x1a] = 47; // user definable type + // AMI BIOS: 2nd hard disk #cyl low byte +- cmos->s.reg[0x24] = (bx_options.diskd.Ocylinders->get () & 0x00ff); ++ cmos->s.reg[0x24] = (bx_options.atadevice[0][1].Ocylinders->get () & 0x00ff); + // AMI BIOS: 2nd hard disk #cyl high byte +- cmos->s.reg[0x25] = (bx_options.diskd.Ocylinders->get () & 0xff00) >> 8; ++ cmos->s.reg[0x25] = (bx_options.atadevice[0][1].Ocylinders->get () & 0xff00) >> 8; + // AMI BIOS: 2nd hard disk #heads +- cmos->s.reg[0x26] = (bx_options.diskd.Oheads->get ()); ++ cmos->s.reg[0x26] = (bx_options.atadevice[0][1].Oheads->get ()); + // AMI BIOS: 2nd hard disk write precompensation cylinder, low byte + cmos->s.reg[0x27] = 0xff; // -1 + // AMI BIOS: 2nd hard disk write precompensation cylinder, high byte + cmos->s.reg[0x28] = 0xff; // -1 + // AMI BIOS: 2nd hard disk, 0x80 if heads>8 +- cmos->s.reg[0x29] = (bx_options.diskd.Oheads->get () > 8) ? 0x80 : 0x00; ++ cmos->s.reg[0x29] = (bx_options.atadevice[0][1].Oheads->get () > 8) ? 0x80 : 0x00; + // AMI BIOS: 2nd hard disk landing zone, low byte + cmos->s.reg[0x2a] = cmos->s.reg[0x24]; + // AMI BIOS: 2nd hard disk landing zone, high byte + cmos->s.reg[0x2b] = cmos->s.reg[0x25]; + // AMI BIOS: 2nd hard disk sectors/track +- cmos->s.reg[0x2c] = bx_options.diskd.Ospt->get (); ++ cmos->s.reg[0x2c] = bx_options.atadevice[0][1].Ospt->get (); + } + + +@@ -330,38 +417,6 @@ + BX_INFO(("Floppy boot signature check is %sabled", bx_options.OfloppySigCheck->get() ? "dis" : "en")); + } + +- //switch (stat_buf.st_size) { +- // } +- +- for (int id = 0; id < 2; id++) { +- BX_CONTROLLER(id).status.busy = 0; +- BX_CONTROLLER(id).status.drive_ready = 1; +- BX_CONTROLLER(id).status.write_fault = 0; +- BX_CONTROLLER(id).status.seek_complete = 1; +- BX_CONTROLLER(id).status.drq = 0; +- BX_CONTROLLER(id).status.corrected_data = 0; +- BX_CONTROLLER(id).status.index_pulse = 0; +- BX_CONTROLLER(id).status.index_pulse_count = 0; +- BX_CONTROLLER(id).status.err = 0; +- +- BX_CONTROLLER(id).error_register = 0x01; // diagnostic code: no error +- BX_CONTROLLER(id).head_no = 0; +- BX_CONTROLLER(id).sector_count = 1; +- BX_CONTROLLER(id).sector_no = 1; +- BX_CONTROLLER(id).cylinder_no = 0; +- BX_CONTROLLER(id).current_command = 0x00; +- BX_CONTROLLER(id).buffer_index = 0; +- +- BX_CONTROLLER(id).control.reset = 0; +- BX_CONTROLLER(id).control.disable_irq = 0; +- +- BX_CONTROLLER(id).reset_in_progress = 0; +- +- BX_CONTROLLER(id).sectors_per_block = 0x80; +- BX_CONTROLLER(id).lba_mode = 0; +- +- BX_CONTROLLER(id).features = 0; +- } + } + + void +@@ -406,27 +461,47 @@ + Bit16u value16; + Bit32u value32; + +- if (io_len>1 && address!=0x1f0) { ++ Bit8u channel = BX_MAX_ATA_CHANNEL; ++ Bit32u port; ++ ++ for (channel=0; channel= BX_HD_THIS channels[channel].ioaddr1) ++ && (address <= BX_HD_THIS channels[channel].ioaddr1 + 7) ) { ++ port = address - BX_HD_THIS channels[channel].ioaddr1; ++ break; ++ } ++ else if ((address >= BX_HD_THIS channels[channel].ioaddr2) ++ && (address <= BX_HD_THIS channels[channel].ioaddr2 + 7) ) { ++ port = address - BX_HD_THIS channels[channel].ioaddr2 + 0x10; ++ break; ++ } ++ } ++ ++ if (channel == BX_MAX_ATA_CHANNEL) { ++ BX_PANIC(("Unable to find ATA channel, ioport=0x%04x", address)); ++ } ++ ++ if (io_len>1 && port!=0x00) { + BX_PANIC(("non-byte IO read to %04x", (unsigned) address)); + } + +- switch (address) { +- case 0x1f0: // hard disk data (16bit) +- if (BX_SELECTED_CONTROLLER.status.drq == 0) { ++ switch (port) { ++ case 0x00: // hard disk data (16bit) 0x1f0 ++ if (BX_SELECTED_CONTROLLER(channel).status.drq == 0) { + BX_ERROR(("IO read(1f0h) with drq == 0: last command was %02xh", +- (unsigned) BX_SELECTED_CONTROLLER.current_command)); ++ (unsigned) BX_SELECTED_CONTROLLER(channel).current_command)); + return(0); + } + BX_DEBUG(("IO read(1f0h): current command is %02xh", +- (unsigned) BX_SELECTED_CONTROLLER.current_command)); +- switch (BX_SELECTED_CONTROLLER.current_command) { ++ (unsigned) BX_SELECTED_CONTROLLER(channel).current_command)); ++ switch (BX_SELECTED_CONTROLLER(channel).current_command) { + case 0x20: // READ SECTORS, with retries + case 0x21: // READ SECTORS, without retries + if (io_len == 1) { + BX_PANIC(("byte IO read from %04x", + (unsigned) address)); + } +- if (BX_SELECTED_CONTROLLER.buffer_index >= 512) ++ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512) + BX_PANIC(("IO read(1f0): buffer_index >= 512")); + + #if BX_SupportRepeatSpeedups +@@ -455,70 +530,69 @@ + value32 = 0L; + switch(io_len){ + case 4: +- value32 |= (BX_SELECTED_CONTROLLER.buffer[BX_SELECTED_CONTROLLER.buffer_index+3] << 24); +- value32 |= (BX_SELECTED_CONTROLLER.buffer[BX_SELECTED_CONTROLLER.buffer_index+2] << 16); ++ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+3] << 24); ++ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+2] << 16); + case 2: +- value32 |= (BX_SELECTED_CONTROLLER.buffer[BX_SELECTED_CONTROLLER.buffer_index+1] << 8); +- value32 |= BX_SELECTED_CONTROLLER.buffer[BX_SELECTED_CONTROLLER.buffer_index]; ++ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+1] << 8); ++ value32 |= BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index]; + } +- +- BX_SELECTED_CONTROLLER.buffer_index += io_len; + } ++ BX_SELECTED_CONTROLLER(channel).buffer_index += io_len; + + // if buffer completely read +- if (BX_SELECTED_CONTROLLER.buffer_index >= 512) { ++ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512) { + // update sector count, sector number, cylinder, + // drive, head, status + // if there are more sectors, read next one in... + // +- BX_SELECTED_CONTROLLER.buffer_index = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer_index = 0; + +- increment_address(); ++ increment_address(channel); + +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.write_fault = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0; + if (bx_options.OnewHardDriveSupport->get ()) +- BX_SELECTED_CONTROLLER.status.seek_complete = 1; ++ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1; + else +- BX_SELECTED_CONTROLLER.status.seek_complete = 0; +- BX_SELECTED_CONTROLLER.status.corrected_data = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 0; ++ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; + +- if (BX_SELECTED_CONTROLLER.sector_count==0) { +- BX_SELECTED_CONTROLLER.status.drq = 0; ++ if (BX_SELECTED_CONTROLLER(channel).sector_count==0) { ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; + } + else { /* read next one into controller buffer */ + Bit32u logical_sector; + int ret; + +- BX_SELECTED_CONTROLLER.status.drq = 1; +- BX_SELECTED_CONTROLLER.status.seek_complete = 1; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 1; ++ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1; + + #if TEST_READ_BEYOND_END==1 +- BX_SELECTED_CONTROLLER.cylinder_no += 100000; ++ BX_SELECTED_CONTROLLER(channel).cylinder_no += 100000; + #endif +- if (!calculate_logical_address(&logical_sector)) { ++ if (!calculate_logical_address(channel, &logical_sector)) { + BX_ERROR(("multi-sector read reached invalid sector %u, aborting", logical_sector)); +- command_aborted (BX_SELECTED_CONTROLLER.current_command); ++ command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command); + GOTO_RETURN_VALUE ; + } +- ret = BX_SELECTED_HD.hard_drive->lseek(logical_sector * 512, SEEK_SET); ++ ret = BX_SELECTED_DRIVE(channel).hard_drive->lseek(logical_sector * 512, SEEK_SET); + if (ret < 0) { + BX_ERROR(("could not lseek() hard drive image file")); +- command_aborted (BX_SELECTED_CONTROLLER.current_command); ++ command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command); + GOTO_RETURN_VALUE ; + } +- ret = BX_SELECTED_HD.hard_drive->read((bx_ptr_t) BX_SELECTED_CONTROLLER.buffer, 512); ++ ret = BX_SELECTED_DRIVE(channel).hard_drive->read((bx_ptr_t) BX_SELECTED_CONTROLLER(channel).buffer, 512); + if (ret < 512) { + BX_ERROR(("logical sector was %u", (unsigned) logical_sector)); + BX_ERROR(("could not read() hard drive image file at byte %d", logical_sector*512)); +- command_aborted (BX_SELECTED_CONTROLLER.current_command); ++ command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command); + GOTO_RETURN_VALUE ; + } + +- BX_SELECTED_CONTROLLER.buffer_index = 0; +- raise_interrupt(); ++ BX_SELECTED_CONTROLLER(channel).buffer_index = 0; ++ raise_interrupt(channel); + } + } + GOTO_RETURN_VALUE ; +@@ -529,61 +603,61 @@ + if (bx_options.OnewHardDriveSupport->get ()) { + unsigned index; + +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.write_fault = 0; +- BX_SELECTED_CONTROLLER.status.seek_complete = 1; +- BX_SELECTED_CONTROLLER.status.corrected_data = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0; ++ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1; ++ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; + +- index = BX_SELECTED_CONTROLLER.buffer_index; +- value32 = BX_SELECTED_CONTROLLER.buffer[index]; ++ index = BX_SELECTED_CONTROLLER(channel).buffer_index; ++ value32 = BX_SELECTED_CONTROLLER(channel).buffer[index]; + index++; + if (io_len >= 2) { +- value32 |= (BX_SELECTED_CONTROLLER.buffer[index] << 8); ++ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index] << 8); + index++; + } + if (io_len == 4) { +- value32 |= (BX_SELECTED_CONTROLLER.buffer[index] << 16); +- value32 |= (BX_SELECTED_CONTROLLER.buffer[index+1] << 24); ++ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index] << 16); ++ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index+1] << 24); + index += 2; + } +- BX_SELECTED_CONTROLLER.buffer_index = index; ++ BX_SELECTED_CONTROLLER(channel).buffer_index = index; + +- if (BX_SELECTED_CONTROLLER.buffer_index >= 512) { +- BX_SELECTED_CONTROLLER.status.drq = 0; +- if (bx_dbg.disk || (CDROM_SELECTED && bx_dbg.cdrom)) ++ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512) { ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) + BX_INFO(("Read all drive ID Bytes ...")); + } + GOTO_RETURN_VALUE; + } + else + BX_PANIC(("IO read(1f0h): current command is %02xh", +- (unsigned) BX_SELECTED_CONTROLLER.current_command)); ++ (unsigned) BX_SELECTED_CONTROLLER(channel).current_command)); + + case 0xa0: { +- unsigned index = BX_SELECTED_CONTROLLER.buffer_index; ++ unsigned index = BX_SELECTED_CONTROLLER(channel).buffer_index; + unsigned increment = 0; + + // Load block if necessary + if (index >= 2048) { + if (index > 2048) + BX_PANIC(("index > 2048 : 0x%x",index)); +- switch (BX_SELECTED_HD.atapi.command) { ++ switch (BX_SELECTED_DRIVE(channel).atapi.command) { + case 0x28: // read (10) + case 0xa8: // read (12) + #ifdef LOWLEVEL_CDROM +- BX_SELECTED_HD.cdrom.cd->read_block(BX_SELECTED_CONTROLLER.buffer, +- BX_SELECTED_HD.cdrom.next_lba); +- BX_SELECTED_HD.cdrom.next_lba++; +- BX_SELECTED_HD.cdrom.remaining_blocks--; ++ BX_SELECTED_DRIVE(channel).cdrom.cd->read_block(BX_SELECTED_CONTROLLER(channel).buffer, ++ BX_SELECTED_DRIVE(channel).cdrom.next_lba); ++ BX_SELECTED_DRIVE(channel).cdrom.next_lba++; ++ BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks--; + +- if (bx_dbg.disk || (CDROM_SELECTED && bx_dbg.cdrom)) +- if (!BX_SELECTED_HD.cdrom.remaining_blocks) ++ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) ++ if (!BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks) + BX_INFO(("Last READ block loaded {CDROM}")); + else + BX_INFO(("READ block loaded (%d remaining) {CDROM}", +- BX_SELECTED_HD.cdrom.remaining_blocks)); ++ BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks)); + + // one block transfered, start at beginning + index = 0; +@@ -597,55 +671,55 @@ + } + } + +- value32 = BX_SELECTED_CONTROLLER.buffer[index+increment]; ++ value32 = BX_SELECTED_CONTROLLER(channel).buffer[index+increment]; + increment++; + if (io_len >= 2) { +- value32 |= (BX_SELECTED_CONTROLLER.buffer[index+increment] << 8); ++ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index+increment] << 8); + increment++; + } + if (io_len == 4) { +- value32 |= (BX_SELECTED_CONTROLLER.buffer[index+increment] << 16); +- value32 |= (BX_SELECTED_CONTROLLER.buffer[index+increment+1] << 24); ++ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index+increment] << 16); ++ value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index+increment+1] << 24); + increment += 2; + } +- BX_SELECTED_CONTROLLER.buffer_index = index + increment; +- BX_SELECTED_CONTROLLER.drq_index += increment; ++ BX_SELECTED_CONTROLLER(channel).buffer_index = index + increment; ++ BX_SELECTED_CONTROLLER(channel).drq_index += increment; + +- if (BX_SELECTED_CONTROLLER.drq_index >= (unsigned)BX_SELECTED_HD.atapi.drq_bytes) { +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.drq_index = 0; ++ if (BX_SELECTED_CONTROLLER(channel).drq_index >= (unsigned)BX_SELECTED_DRIVE(channel).atapi.drq_bytes) { ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).drq_index = 0; + +- BX_SELECTED_HD.atapi.total_bytes_remaining -= BX_SELECTED_HD.atapi.drq_bytes; ++ BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining -= BX_SELECTED_DRIVE(channel).atapi.drq_bytes; + +- if (BX_SELECTED_HD.atapi.total_bytes_remaining > 0) { ++ if (BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining > 0) { + // one or more blocks remaining (works only for single block commands) +- if (bx_dbg.disk || (CDROM_SELECTED && bx_dbg.cdrom)) ++ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) + BX_INFO(("PACKET drq bytes read")); +- BX_SELECTED_CONTROLLER.interrupt_reason.i_o = 1; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drq = 1; +- BX_SELECTED_CONTROLLER.interrupt_reason.c_d = 0; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 1; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 0; + + // set new byte count if last block +- if (BX_SELECTED_HD.atapi.total_bytes_remaining < BX_SELECTED_CONTROLLER.byte_count) { +- BX_SELECTED_CONTROLLER.byte_count = BX_SELECTED_HD.atapi.total_bytes_remaining; ++ if (BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining < BX_SELECTED_CONTROLLER(channel).byte_count) { ++ BX_SELECTED_CONTROLLER(channel).byte_count = BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining; + } +- BX_SELECTED_HD.atapi.drq_bytes = BX_SELECTED_CONTROLLER.byte_count; ++ BX_SELECTED_DRIVE(channel).atapi.drq_bytes = BX_SELECTED_CONTROLLER(channel).byte_count; + +- raise_interrupt(); ++ raise_interrupt(channel); + } else { + // all bytes read +- if (bx_dbg.disk || (CDROM_SELECTED && bx_dbg.cdrom)) ++ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) + BX_INFO(("PACKET all bytes read")); +- BX_SELECTED_CONTROLLER.interrupt_reason.i_o = 1; +- BX_SELECTED_CONTROLLER.interrupt_reason.c_d = 1; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.interrupt_reason.rel = 0; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 1; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.rel = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; + +- raise_interrupt(); ++ raise_interrupt(channel); + } + } + GOTO_RETURN_VALUE; +@@ -655,111 +729,111 @@ + // List all the read operations that are defined in the ATA/ATAPI spec + // that we don't support. Commands that are listed here will cause a + // BX_ERROR, which is non-fatal, and the command will be aborted. +- case 0x08: BX_ERROR(("read cmd 0x08 (DEVICE RESET) not supported")); command_aborted(0x08); break; +- case 0x10: BX_ERROR(("read cmd 0x10 (RECALIBRATE) not supported")); command_aborted(0x10); break; +- case 0x22: BX_ERROR(("read cmd 0x22 (READ LONG) not supported")); command_aborted(0x22); break; +- case 0x23: BX_ERROR(("read cmd 0x23 (READ LONG NO RETRY) not supported")); command_aborted(0x23); break; +- case 0x24: BX_ERROR(("read cmd 0x24 (READ SECTORS EXT) not supported")); command_aborted(0x24); break; +- case 0x25: BX_ERROR(("read cmd 0x25 (READ DMA EXT) not supported")); command_aborted(0x25); break; +- case 0x26: BX_ERROR(("read cmd 0x26 (READ DMA QUEUED EXT) not supported")); command_aborted(0x26); break; +- case 0x27: BX_ERROR(("read cmd 0x27 (READ NATIVE MAX ADDRESS EXT) not supported")); command_aborted(0x27); break; +- case 0x29: BX_ERROR(("read cmd 0x29 (READ MULTIPLE EXT) not supported")); command_aborted(0x29); break; +- case 0x2A: BX_ERROR(("read cmd 0x2A (READ STREAM DMA) not supported")); command_aborted(0x2A); break; +- case 0x2B: BX_ERROR(("read cmd 0x2B (READ STREAM PIO) not supported")); command_aborted(0x2B); break; +- case 0x2F: BX_ERROR(("read cmd 0x2F (READ LOG EXT) not supported")); command_aborted(0x2F); break; +- case 0x30: BX_ERROR(("read cmd 0x30 (WRITE SECTORS) not supported")); command_aborted(0x30); break; +- case 0x31: BX_ERROR(("read cmd 0x31 (WRITE SECTORS NO RETRY) not supported")); command_aborted(0x31); break; +- case 0x32: BX_ERROR(("read cmd 0x32 (WRITE LONG) not supported")); command_aborted(0x32); break; +- case 0x33: BX_ERROR(("read cmd 0x33 (WRITE LONG NO RETRY) not supported")); command_aborted(0x33); break; +- case 0x34: BX_ERROR(("read cmd 0x34 (WRITE SECTORS EXT) not supported")); command_aborted(0x34); break; +- case 0x35: BX_ERROR(("read cmd 0x35 (WRITE DMA EXT) not supported")); command_aborted(0x35); break; +- case 0x36: BX_ERROR(("read cmd 0x36 (WRITE DMA QUEUED EXT) not supported")); command_aborted(0x36); break; +- case 0x37: BX_ERROR(("read cmd 0x37 (SET MAX ADDRESS EXT) not supported")); command_aborted(0x37); break; +- case 0x38: BX_ERROR(("read cmd 0x38 (CFA WRITE SECTORS W/OUT ERASE) not supported")); command_aborted(0x38); break; +- case 0x39: BX_ERROR(("read cmd 0x39 (WRITE MULTIPLE EXT) not supported")); command_aborted(0x39); break; +- case 0x3A: BX_ERROR(("read cmd 0x3A (WRITE STREAM DMA) not supported")); command_aborted(0x3A); break; +- case 0x3B: BX_ERROR(("read cmd 0x3B (WRITE STREAM PIO) not supported")); command_aborted(0x3B); break; +- case 0x3F: BX_ERROR(("read cmd 0x3F (WRITE LOG EXT) not supported")); command_aborted(0x3F); break; +- case 0x40: BX_ERROR(("read cmd 0x40 (READ VERIFY SECTORS) not supported")); command_aborted(0x40); break; +- case 0x41: BX_ERROR(("read cmd 0x41 (READ VERIFY SECTORS NO RETRY) not supported")); command_aborted(0x41); break; +- case 0x42: BX_ERROR(("read cmd 0x42 (READ VERIFY SECTORS EXT) not supported")); command_aborted(0x42); break; +- case 0x50: BX_ERROR(("read cmd 0x50 (FORMAT TRACK) not supported")); command_aborted(0x50); break; +- case 0x51: BX_ERROR(("read cmd 0x51 (CONFIGURE STREAM) not supported")); command_aborted(0x51); break; +- case 0x70: BX_ERROR(("read cmd 0x70 (SEEK) not supported")); command_aborted(0x70); break; +- case 0x87: BX_ERROR(("read cmd 0x87 (CFA TRANSLATE SECTOR) not supported")); command_aborted(0x87); break; +- case 0x90: BX_ERROR(("read cmd 0x90 (EXECUTE DEVICE DIAGNOSTIC) not supported")); command_aborted(0x90); break; +- case 0x91: BX_ERROR(("read cmd 0x91 (INITIALIZE DEVICE PARAMETERS) not supported")); command_aborted(0x91); break; +- case 0x92: BX_ERROR(("read cmd 0x92 (DOWNLOAD MICROCODE) not supported")); command_aborted(0x92); break; +- case 0x94: BX_ERROR(("read cmd 0x94 (STANDBY IMMEDIATE) not supported")); command_aborted(0x94); break; +- case 0x95: BX_ERROR(("read cmd 0x95 (IDLE IMMEDIATE) not supported")); command_aborted(0x95); break; +- case 0x96: BX_ERROR(("read cmd 0x96 (STANDBY) not supported")); command_aborted(0x96); break; +- case 0x97: BX_ERROR(("read cmd 0x97 (IDLE) not supported")); command_aborted(0x97); break; +- case 0x98: BX_ERROR(("read cmd 0x98 (CHECK POWER MODE) not supported")); command_aborted(0x98); break; +- case 0x99: BX_ERROR(("read cmd 0x99 (SLEEP) not supported")); command_aborted(0x99); break; +- case 0xA2: BX_ERROR(("read cmd 0xA2 (SERVICE) not supported")); command_aborted(0xA2); break; +- case 0xB0: BX_ERROR(("read cmd 0xB0 (SMART DISABLE OPERATIONS) not supported")); command_aborted(0xB0); break; +- case 0xB1: BX_ERROR(("read cmd 0xB1 (DEVICE CONFIGURATION FREEZE LOCK) not supported")); command_aborted(0xB1); break; +- case 0xC0: BX_ERROR(("read cmd 0xC0 (CFA ERASE SECTORS) not supported")); command_aborted(0xC0); break; +- case 0xC4: BX_ERROR(("read cmd 0xC4 (READ MULTIPLE) not supported")); command_aborted(0xC4); break; +- case 0xC5: BX_ERROR(("read cmd 0xC5 (WRITE MULTIPLE) not supported")); command_aborted(0xC5); break; +- case 0xC6: BX_ERROR(("read cmd 0xC6 (SET MULTIPLE MODE) not supported")); command_aborted(0xC6); break; +- case 0xC7: BX_ERROR(("read cmd 0xC7 (READ DMA QUEUED) not supported")); command_aborted(0xC7); break; +- case 0xC8: BX_ERROR(("read cmd 0xC8 (READ DMA) not supported")); command_aborted(0xC8); break; +- case 0xC9: BX_ERROR(("read cmd 0xC9 (READ DMA NO RETRY) not supported")); command_aborted(0xC9); break; +- case 0xCA: BX_ERROR(("read cmd 0xCA (WRITE DMA) not supported")); command_aborted(0xCA); break; +- case 0xCC: BX_ERROR(("read cmd 0xCC (WRITE DMA QUEUED) not supported")); command_aborted(0xCC); break; +- case 0xCD: BX_ERROR(("read cmd 0xCD (CFA WRITE MULTIPLE W/OUT ERASE) not supported")); command_aborted(0xCD); break; +- case 0xD1: BX_ERROR(("read cmd 0xD1 (CHECK MEDIA CARD TYPE) not supported")); command_aborted(0xD1); break; +- case 0xDA: BX_ERROR(("read cmd 0xDA (GET MEDIA STATUS) not supported")); command_aborted(0xDA); break; +- case 0xDE: BX_ERROR(("read cmd 0xDE (MEDIA LOCK) not supported")); command_aborted(0xDE); break; +- case 0xDF: BX_ERROR(("read cmd 0xDF (MEDIA UNLOCK) not supported")); command_aborted(0xDF); break; +- case 0xE0: BX_ERROR(("read cmd 0xE0 (STANDBY IMMEDIATE) not supported")); command_aborted(0xE0); break; +- case 0xE1: BX_ERROR(("read cmd 0xE1 (IDLE IMMEDIATE) not supported")); command_aborted(0xE1); break; +- case 0xE2: BX_ERROR(("read cmd 0xE2 (STANDBY) not supported")); command_aborted(0xE2); break; +- case 0xE3: BX_ERROR(("read cmd 0xE3 (IDLE) not supported")); command_aborted(0xE3); break; +- case 0xE4: BX_ERROR(("read cmd 0xE4 (READ BUFFER) not supported")); command_aborted(0xE4); break; +- case 0xE5: BX_ERROR(("read cmd 0xE5 (CHECK POWER MODE) not supported")); command_aborted(0xE5); break; +- case 0xE6: BX_ERROR(("read cmd 0xE6 (SLEEP) not supported")); command_aborted(0xE6); break; +- case 0xE7: BX_ERROR(("read cmd 0xE7 (FLUSH CACHE) not supported")); command_aborted(0xE7); break; +- case 0xE8: BX_ERROR(("read cmd 0xE8 (WRITE BUFFER) not supported")); command_aborted(0xE8); break; +- case 0xEA: BX_ERROR(("read cmd 0xEA (FLUSH CACHE EXT) not supported")); command_aborted(0xEA); break; +- case 0xED: BX_ERROR(("read cmd 0xED (MEDIA EJECT) not supported")); command_aborted(0xED); break; +- case 0xEF: BX_ERROR(("read cmd 0xEF (SET FEATURES) not supported")); command_aborted(0xEF); break; +- case 0xF1: BX_ERROR(("read cmd 0xF1 (SECURITY SET PASSWORD) not supported")); command_aborted(0xF1); break; +- case 0xF2: BX_ERROR(("read cmd 0xF2 (SECURITY UNLOCK) not supported")); command_aborted(0xF2); break; +- case 0xF3: BX_ERROR(("read cmd 0xF3 (SECURITY ERASE PREPARE) not supported")); command_aborted(0xF3); break; +- case 0xF4: BX_ERROR(("read cmd 0xF4 (SECURITY ERASE UNIT) not supported")); command_aborted(0xF4); break; +- case 0xF5: BX_ERROR(("read cmd 0xF5 (SECURITY FREEZE LOCK) not supported")); command_aborted(0xF5); break; +- case 0xF6: BX_ERROR(("read cmd 0xF6 (SECURITY DISABLE PASSWORD) not supported")); command_aborted(0xF6); break; +- case 0xF8: BX_ERROR(("read cmd 0xF8 (READ NATIVE MAX ADDRESS) not supported")); command_aborted(0xF8); break; +- case 0xF9: BX_ERROR(("read cmd 0xF9 (SET MAX ADDRESS) not supported")); command_aborted(0xF9); break; ++ case 0x08: BX_ERROR(("read cmd 0x08 (DEVICE RESET) not supported")); command_aborted(channel, 0x08); break; ++ case 0x10: BX_ERROR(("read cmd 0x10 (RECALIBRATE) not supported")); command_aborted(channel, 0x10); break; ++ case 0x22: BX_ERROR(("read cmd 0x22 (READ LONG) not supported")); command_aborted(channel, 0x22); break; ++ case 0x23: BX_ERROR(("read cmd 0x23 (READ LONG NO RETRY) not supported")); command_aborted(channel, 0x23); break; ++ case 0x24: BX_ERROR(("read cmd 0x24 (READ SECTORS EXT) not supported")); command_aborted(channel, 0x24); break; ++ case 0x25: BX_ERROR(("read cmd 0x25 (READ DMA EXT) not supported")); command_aborted(channel, 0x25); break; ++ case 0x26: BX_ERROR(("read cmd 0x26 (READ DMA QUEUED EXT) not supported")); command_aborted(channel, 0x26); break; ++ case 0x27: BX_ERROR(("read cmd 0x27 (READ NATIVE MAX ADDRESS EXT) not supported")); command_aborted(channel, 0x27); break; ++ case 0x29: BX_ERROR(("read cmd 0x29 (READ MULTIPLE EXT) not supported")); command_aborted(channel, 0x29); break; ++ case 0x2A: BX_ERROR(("read cmd 0x2A (READ STREAM DMA) not supported")); command_aborted(channel, 0x2A); break; ++ case 0x2B: BX_ERROR(("read cmd 0x2B (READ STREAM PIO) not supported")); command_aborted(channel, 0x2B); break; ++ case 0x2F: BX_ERROR(("read cmd 0x2F (READ LOG EXT) not supported")); command_aborted(channel, 0x2F); break; ++ case 0x30: BX_ERROR(("read cmd 0x30 (WRITE SECTORS) not supported")); command_aborted(channel, 0x30); break; ++ case 0x31: BX_ERROR(("read cmd 0x31 (WRITE SECTORS NO RETRY) not supported")); command_aborted(channel, 0x31); break; ++ case 0x32: BX_ERROR(("read cmd 0x32 (WRITE LONG) not supported")); command_aborted(channel, 0x32); break; ++ case 0x33: BX_ERROR(("read cmd 0x33 (WRITE LONG NO RETRY) not supported")); command_aborted(channel, 0x33); break; ++ case 0x34: BX_ERROR(("read cmd 0x34 (WRITE SECTORS EXT) not supported")); command_aborted(channel, 0x34); break; ++ case 0x35: BX_ERROR(("read cmd 0x35 (WRITE DMA EXT) not supported")); command_aborted(channel, 0x35); break; ++ case 0x36: BX_ERROR(("read cmd 0x36 (WRITE DMA QUEUED EXT) not supported")); command_aborted(channel, 0x36); break; ++ case 0x37: BX_ERROR(("read cmd 0x37 (SET MAX ADDRESS EXT) not supported")); command_aborted(channel, 0x37); break; ++ case 0x38: BX_ERROR(("read cmd 0x38 (CFA WRITE SECTORS W/OUT ERASE) not supported")); command_aborted(channel, 0x38); break; ++ case 0x39: BX_ERROR(("read cmd 0x39 (WRITE MULTIPLE EXT) not supported")); command_aborted(channel, 0x39); break; ++ case 0x3A: BX_ERROR(("read cmd 0x3A (WRITE STREAM DMA) not supported")); command_aborted(channel, 0x3A); break; ++ case 0x3B: BX_ERROR(("read cmd 0x3B (WRITE STREAM PIO) not supported")); command_aborted(channel, 0x3B); break; ++ case 0x3F: BX_ERROR(("read cmd 0x3F (WRITE LOG EXT) not supported")); command_aborted(channel, 0x3F); break; ++ case 0x40: BX_ERROR(("read cmd 0x40 (READ VERIFY SECTORS) not supported")); command_aborted(channel, 0x40); break; ++ case 0x41: BX_ERROR(("read cmd 0x41 (READ VERIFY SECTORS NO RETRY) not supported")); command_aborted(channel, 0x41); break; ++ case 0x42: BX_ERROR(("read cmd 0x42 (READ VERIFY SECTORS EXT) not supported")); command_aborted(channel, 0x42); break; ++ case 0x50: BX_ERROR(("read cmd 0x50 (FORMAT TRACK) not supported")); command_aborted(channel, 0x50); break; ++ case 0x51: BX_ERROR(("read cmd 0x51 (CONFIGURE STREAM) not supported")); command_aborted(channel, 0x51); break; ++ case 0x70: BX_ERROR(("read cmd 0x70 (SEEK) not supported")); command_aborted(channel, 0x70); break; ++ case 0x87: BX_ERROR(("read cmd 0x87 (CFA TRANSLATE SECTOR) not supported")); command_aborted(channel, 0x87); break; ++ case 0x90: BX_ERROR(("read cmd 0x90 (EXECUTE DEVICE DIAGNOSTIC) not supported")); command_aborted(channel, 0x90); break; ++ case 0x91: BX_ERROR(("read cmd 0x91 (INITIALIZE DEVICE PARAMETERS) not supported")); command_aborted(channel, 0x91); break; ++ case 0x92: BX_ERROR(("read cmd 0x92 (DOWNLOAD MICROCODE) not supported")); command_aborted(channel, 0x92); break; ++ case 0x94: BX_ERROR(("read cmd 0x94 (STANDBY IMMEDIATE) not supported")); command_aborted(channel, 0x94); break; ++ case 0x95: BX_ERROR(("read cmd 0x95 (IDLE IMMEDIATE) not supported")); command_aborted(channel, 0x95); break; ++ case 0x96: BX_ERROR(("read cmd 0x96 (STANDBY) not supported")); command_aborted(channel, 0x96); break; ++ case 0x97: BX_ERROR(("read cmd 0x97 (IDLE) not supported")); command_aborted(channel, 0x97); break; ++ case 0x98: BX_ERROR(("read cmd 0x98 (CHECK POWER MODE) not supported")); command_aborted(channel, 0x98); break; ++ case 0x99: BX_ERROR(("read cmd 0x99 (SLEEP) not supported")); command_aborted(channel, 0x99); break; ++ case 0xA2: BX_ERROR(("read cmd 0xA2 (SERVICE) not supported")); command_aborted(channel, 0xA2); break; ++ case 0xB0: BX_ERROR(("read cmd 0xB0 (SMART DISABLE OPERATIONS) not supported")); command_aborted(channel, 0xB0); break; ++ case 0xB1: BX_ERROR(("read cmd 0xB1 (DEVICE CONFIGURATION FREEZE LOCK) not supported")); command_aborted(channel, 0xB1); break; ++ case 0xC0: BX_ERROR(("read cmd 0xC0 (CFA ERASE SECTORS) not supported")); command_aborted(channel, 0xC0); break; ++ case 0xC4: BX_ERROR(("read cmd 0xC4 (READ MULTIPLE) not supported")); command_aborted(channel, 0xC4); break; ++ case 0xC5: BX_ERROR(("read cmd 0xC5 (WRITE MULTIPLE) not supported")); command_aborted(channel, 0xC5); break; ++ case 0xC6: BX_ERROR(("read cmd 0xC6 (SET MULTIPLE MODE) not supported")); command_aborted(channel, 0xC6); break; ++ case 0xC7: BX_ERROR(("read cmd 0xC7 (READ DMA QUEUED) not supported")); command_aborted(channel, 0xC7); break; ++ case 0xC8: BX_ERROR(("read cmd 0xC8 (READ DMA) not supported")); command_aborted(channel, 0xC8); break; ++ case 0xC9: BX_ERROR(("read cmd 0xC9 (READ DMA NO RETRY) not supported")); command_aborted(channel, 0xC9); break; ++ case 0xCA: BX_ERROR(("read cmd 0xCA (WRITE DMA) not supported")); command_aborted(channel, 0xCA); break; ++ case 0xCC: BX_ERROR(("read cmd 0xCC (WRITE DMA QUEUED) not supported")); command_aborted(channel, 0xCC); break; ++ case 0xCD: BX_ERROR(("read cmd 0xCD (CFA WRITE MULTIPLE W/OUT ERASE) not supported")); command_aborted(channel, 0xCD); break; ++ case 0xD1: BX_ERROR(("read cmd 0xD1 (CHECK MEDIA CARD TYPE) not supported")); command_aborted(channel, 0xD1); break; ++ case 0xDA: BX_ERROR(("read cmd 0xDA (GET MEDIA STATUS) not supported")); command_aborted(channel, 0xDA); break; ++ case 0xDE: BX_ERROR(("read cmd 0xDE (MEDIA LOCK) not supported")); command_aborted(channel, 0xDE); break; ++ case 0xDF: BX_ERROR(("read cmd 0xDF (MEDIA UNLOCK) not supported")); command_aborted(channel, 0xDF); break; ++ case 0xE0: BX_ERROR(("read cmd 0xE0 (STANDBY IMMEDIATE) not supported")); command_aborted(channel, 0xE0); break; ++ case 0xE1: BX_ERROR(("read cmd 0xE1 (IDLE IMMEDIATE) not supported")); command_aborted(channel, 0xE1); break; ++ case 0xE2: BX_ERROR(("read cmd 0xE2 (STANDBY) not supported")); command_aborted(channel, 0xE2); break; ++ case 0xE3: BX_ERROR(("read cmd 0xE3 (IDLE) not supported")); command_aborted(channel, 0xE3); break; ++ case 0xE4: BX_ERROR(("read cmd 0xE4 (READ BUFFER) not supported")); command_aborted(channel, 0xE4); break; ++ case 0xE5: BX_ERROR(("read cmd 0xE5 (CHECK POWER MODE) not supported")); command_aborted(channel, 0xE5); break; ++ case 0xE6: BX_ERROR(("read cmd 0xE6 (SLEEP) not supported")); command_aborted(channel, 0xE6); break; ++ case 0xE7: BX_ERROR(("read cmd 0xE7 (FLUSH CACHE) not supported")); command_aborted(channel, 0xE7); break; ++ case 0xE8: BX_ERROR(("read cmd 0xE8 (WRITE BUFFER) not supported")); command_aborted(channel, 0xE8); break; ++ case 0xEA: BX_ERROR(("read cmd 0xEA (FLUSH CACHE EXT) not supported")); command_aborted(channel, 0xEA); break; ++ case 0xED: BX_ERROR(("read cmd 0xED (MEDIA EJECT) not supported")); command_aborted(channel, 0xED); break; ++ case 0xEF: BX_ERROR(("read cmd 0xEF (SET FEATURES) not supported")); command_aborted(channel, 0xEF); break; ++ case 0xF1: BX_ERROR(("read cmd 0xF1 (SECURITY SET PASSWORD) not supported")); command_aborted(channel, 0xF1); break; ++ case 0xF2: BX_ERROR(("read cmd 0xF2 (SECURITY UNLOCK) not supported")); command_aborted(channel, 0xF2); break; ++ case 0xF3: BX_ERROR(("read cmd 0xF3 (SECURITY ERASE PREPARE) not supported")); command_aborted(channel, 0xF3); break; ++ case 0xF4: BX_ERROR(("read cmd 0xF4 (SECURITY ERASE UNIT) not supported")); command_aborted(channel, 0xF4); break; ++ case 0xF5: BX_ERROR(("read cmd 0xF5 (SECURITY FREEZE LOCK) not supported")); command_aborted(channel, 0xF5); break; ++ case 0xF6: BX_ERROR(("read cmd 0xF6 (SECURITY DISABLE PASSWORD) not supported")); command_aborted(channel, 0xF6); break; ++ case 0xF8: BX_ERROR(("read cmd 0xF8 (READ NATIVE MAX ADDRESS) not supported")); command_aborted(channel, 0xF8); break; ++ case 0xF9: BX_ERROR(("read cmd 0xF9 (SET MAX ADDRESS) not supported")); command_aborted(channel, 0xF9); break; + + default: + BX_PANIC(("IO read(1f0h): current command is %02xh", +- (unsigned) BX_SELECTED_CONTROLLER.current_command)); ++ (unsigned) BX_SELECTED_CONTROLLER(channel).current_command)); + } + break; + +- case 0x1f1: // hard disk error register +- BX_SELECTED_CONTROLLER.status.err = 0; +- value8 = BX_SELECTED_CONTROLLER.error_register; ++ 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; + goto return_value8; + break; +- case 0x1f2: // hard disk sector count / interrupt reason +- value8 = BX_SELECTED_CONTROLLER.sector_count; ++ case 0x02: // hard disk sector count / interrupt reason 0x1f2 ++ value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).sector_count; + goto return_value8; + break; +- case 0x1f3: // sector number +- value8 = BX_SELECTED_CONTROLLER.sector_no; ++ case 0x03: // sector number 0x1f3 ++ value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).sector_no; + goto return_value8; +- case 0x1f4: // cylinder low +- value8 = (BX_SELECTED_CONTROLLER.cylinder_no & 0x00ff); ++ case 0x04: // cylinder low 0x1f4 ++ value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : (BX_SELECTED_CONTROLLER(channel).cylinder_no & 0x00ff); + goto return_value8; +- case 0x1f5: // cylinder high +- value8 = BX_SELECTED_CONTROLLER.cylinder_no >> 8; ++ case 0x05: // cylinder high 0x1f5 ++ value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).cylinder_no >> 8; + goto return_value8; + +- case 0x1f6: // hard disk drive and head register ++ case 0x06: // hard disk drive and head register 0x1f6 + // b7 Extended data field for ECC + // b6/b5: Used to be sector size. 00=256,01=512,10=1024,11=128 + // Since 512 was always used, bit 6 was taken to mean LBA mode: +@@ -768,42 +842,41 @@ + // b4: DRV + // b3..0 HD3..HD0 + value8 = (1 << 7) | +- ((BX_SELECTED_CONTROLLER.lba_mode>0) << 6) | ++ ((BX_SELECTED_CONTROLLER(channel).lba_mode>0) << 6) | + (1 << 5) | // 01b = 512 sector size +- (BX_HD_THIS drive_select << 4) | +- (BX_SELECTED_CONTROLLER.head_no << 0); ++ (BX_HD_THIS channels[channel].drive_select << 4) | ++ (BX_SELECTED_CONTROLLER(channel).head_no << 0); + goto return_value8; + break; +-//BX_CONTROLLER(0).lba_mode ++//BX_CONTROLLER(channel,0).lba_mode + +- case 0x1f7: // Hard Disk Status +- case 0x3f6: // Hard Disk Alternate Status +- if ((!BX_HD_THIS drive_select && !bx_options.diskc.Opresent->get ()) || +- (BX_HD_THIS drive_select && !bx_options.diskd.Opresent->get ())) { ++ case 0x07: // Hard Disk Status 0x1f7 ++ case 0x16: // Hard Disk Alternate Status 0x3f6 ++ if (!BX_SELECTED_IS_PRESENT(channel)) { + // (mch) Just return zero for these registers + value8 = 0; + } else { + value8 = ( +- (BX_SELECTED_CONTROLLER.status.busy << 7) | +- (BX_SELECTED_CONTROLLER.status.drive_ready << 6) | +- (BX_SELECTED_CONTROLLER.status.write_fault << 5) | +- (BX_SELECTED_CONTROLLER.status.seek_complete << 4) | +- (BX_SELECTED_CONTROLLER.status.drq << 3) | +- (BX_SELECTED_CONTROLLER.status.corrected_data << 2) | +- (BX_SELECTED_CONTROLLER.status.index_pulse << 1) | +- (BX_SELECTED_CONTROLLER.status.err) ); +- BX_SELECTED_CONTROLLER.status.index_pulse_count++; +- BX_SELECTED_CONTROLLER.status.index_pulse = 0; +- if (BX_SELECTED_CONTROLLER.status.index_pulse_count >= INDEX_PULSE_CYCLE) { +- BX_SELECTED_CONTROLLER.status.index_pulse = 1; +- BX_SELECTED_CONTROLLER.status.index_pulse_count = 0; ++ (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 (address == 0x1f7) BX_HD_THIS devices->pic->lower_irq(14); ++ if (port == 0x07) BX_HD_THIS devices->pic->lower_irq(BX_HD_THIS channels[channel].irq); + goto return_value8; + break; + +- case 0x3f7: // Hard Disk Address Register ++ case 0x17: // Hard Disk Address Register 0x3f7 + // Obsolete and unsupported register. Not driven by hard + // disk controller. Report all 1's. If floppy controller + // is handling this address, it will call this function +@@ -813,19 +886,6 @@ + goto return_value8; + break; + +-#if 0 +- // you'll need these to support second IDE controller, not needed yet. +- case 0x170: +- case 0x171: +- case 0x172: +- case 0x173: +- case 0x174: +- case 0x175: +- case 0x176: +- case 0x177: +- BX_INFO(("[disk] ignoring read from 0x%04x", address)); +- break; +-#endif + default: + BX_PANIC(("hard drive: io read to address %x unsupported", + (unsigned) address)); +@@ -836,17 +896,17 @@ + + return_value32: + BX_DEBUG(("32-bit read from %04x = %08x {%s}", +- (unsigned) address, value32, DEVICE_TYPE_STRING)); ++ (unsigned) address, value32, BX_SELECTED_TYPE_STRING(channel))); + return value32; + + return_value16: + BX_DEBUG(("16-bit read from %04x = %04x {%s}", +- (unsigned) address, value16, DEVICE_TYPE_STRING)); ++ (unsigned) address, value16, BX_SELECTED_TYPE_STRING(channel))); + return value16; + + return_value8: + BX_DEBUG(("8-bit read from %04x = %02x {%s}", +- (unsigned) address, value8, DEVICE_TYPE_STRING)); ++ (unsigned) address, value8, BX_SELECTED_TYPE_STRING(channel))); + return value8; + } + +@@ -873,44 +933,64 @@ + int ret; + Boolean prev_control_reset; + +- if (io_len>1 && address!=0x1f0) { ++ Bit8u channel = BX_MAX_ATA_CHANNEL; ++ Bit32u port; ++ ++ for (channel=0; channel= BX_HD_THIS channels[channel].ioaddr1) ++ && (address <= BX_HD_THIS channels[channel].ioaddr1 + 7) ) { ++ port = address - BX_HD_THIS channels[channel].ioaddr1; ++ break; ++ } ++ else if ((address >= BX_HD_THIS channels[channel].ioaddr2) ++ && (address <= BX_HD_THIS channels[channel].ioaddr2 + 7) ) { ++ port = address - BX_HD_THIS channels[channel].ioaddr2 + 0x10; ++ break; ++ } ++ } ++ ++ if (channel == BX_MAX_ATA_CHANNEL) { ++ BX_PANIC(("Unable to find ATA channel, ioport=0x%04x", address)); ++ } ++ ++ if (io_len>1 && port!=0x00) { + BX_PANIC(("non-byte IO write to %04x", (unsigned) address)); + } + +- if (bx_dbg.disk || (CDROM_SELECTED && bx_dbg.cdrom)) { ++ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) { + switch (io_len) { + case 1: + BX_INFO(("8-bit write to %04x = %02x {%s}", +- (unsigned) address, (unsigned) value, DEVICE_TYPE_STRING)); ++ (unsigned) address, (unsigned) value, BX_SELECTED_TYPE_STRING(channel))); + break; + + case 2: + BX_INFO(("16-bit write to %04x = %04x {%s}", +- (unsigned) address, (unsigned) value, DEVICE_TYPE_STRING)); ++ (unsigned) address, (unsigned) value, BX_SELECTED_TYPE_STRING(channel))); + break; + + case 4: + BX_INFO(("32-bit write to %04x = %08x {%s}", +- (unsigned) address, (unsigned) value, DEVICE_TYPE_STRING)); ++ (unsigned) address, (unsigned) value, BX_SELECTED_TYPE_STRING(channel))); + break; + + default: + BX_INFO(("unknown-size write to %04x = %08x {%s}", +- (unsigned) address, (unsigned) value, DEVICE_TYPE_STRING)); ++ (unsigned) address, (unsigned) value, BX_SELECTED_TYPE_STRING(channel))); + break; + } + } + + BX_DEBUG(("IO write to %04x = %02x", (unsigned) address, (unsigned) value)); + +- switch (address) { +- case 0x1f0: ++ switch (port) { ++ case 0x00: // 0x1f0 + if (io_len == 1) { + BX_PANIC(("byte IO write to 0x1f0")); + } +- switch (BX_SELECTED_CONTROLLER.current_command) { ++ switch (BX_SELECTED_CONTROLLER(channel).current_command) { + case 0x30: // WRITE SECTORS +- if (BX_SELECTED_CONTROLLER.buffer_index >= 512) ++ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512) + BX_PANIC(("IO write(1f0): buffer_index >= 512")); + + #if BX_SupportRepeatSpeedups +@@ -938,231 +1018,232 @@ + { + switch(io_len){ + case 4: +- BX_SELECTED_CONTROLLER.buffer[BX_SELECTED_CONTROLLER.buffer_index+3] = (Bit8u)(value >> 24); +- BX_SELECTED_CONTROLLER.buffer[BX_SELECTED_CONTROLLER.buffer_index+2] = (Bit8u)(value >> 16); ++ BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+3] = (Bit8u)(value >> 24); ++ BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+2] = (Bit8u)(value >> 16); + case 2: +- BX_SELECTED_CONTROLLER.buffer[BX_SELECTED_CONTROLLER.buffer_index+1] = (Bit8u)(value >> 8); +- BX_SELECTED_CONTROLLER.buffer[BX_SELECTED_CONTROLLER.buffer_index] = (Bit8u) value; ++ BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+1] = (Bit8u)(value >> 8); ++ BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index] = (Bit8u) value; + } + +- BX_SELECTED_CONTROLLER.buffer_index += io_len; ++ BX_SELECTED_CONTROLLER(channel).buffer_index += io_len; + } + + /* if buffer completely writtten */ +- if (BX_SELECTED_CONTROLLER.buffer_index >= 512) { ++ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512) { + Bit32u logical_sector; + int ret; + + #if TEST_WRITE_BEYOND_END==1 +- BX_SELECTED_CONTROLLER.cylinder_no += 100000; ++ BX_SELECTED_CONTROLLER(channel).cylinder_no += 100000; + #endif +- if (!calculate_logical_address(&logical_sector)) { ++ if (!calculate_logical_address(channel, &logical_sector)) { + BX_ERROR(("write reached invalid sector %u, aborting", logical_sector)); +- command_aborted (BX_SELECTED_CONTROLLER.current_command); ++ command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command); + return; + } + #if TEST_WRITE_BEYOND_END==2 + logical_sector += 100000; + #endif +- ret = BX_SELECTED_HD.hard_drive->lseek(logical_sector * 512, SEEK_SET); ++ ret = BX_SELECTED_DRIVE(channel).hard_drive->lseek(logical_sector * 512, SEEK_SET); + if (ret < 0) { + BX_ERROR(("could not lseek() hard drive image file at byte %u", logical_sector * 512)); +- command_aborted (BX_SELECTED_CONTROLLER.current_command); ++ command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command); + return; + } +- ret = BX_SELECTED_HD.hard_drive->write((bx_ptr_t) BX_SELECTED_CONTROLLER.buffer, 512); ++ ret = BX_SELECTED_DRIVE(channel).hard_drive->write((bx_ptr_t) BX_SELECTED_CONTROLLER(channel).buffer, 512); + if (ret < 512) { + BX_ERROR(("could not write() hard drive image file at byte %d", logical_sector*512)); +- command_aborted (BX_SELECTED_CONTROLLER.current_command); ++ command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command); + return; + } + +- BX_SELECTED_CONTROLLER.buffer_index = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer_index = 0; + + /* update sector count, sector number, cylinder, + * drive, head, status + * if there are more sectors, read next one in... + */ + +- increment_address(); ++ increment_address(channel); + + /* When the write is complete, controller clears the DRQ bit and + * sets the BSY bit. + * If at least one more sector is to be written, controller sets DRQ bit, +- * clears BSY bit, and issues IRQ 14 ++ * clears BSY bit, and issues IRQ + */ + +- if (BX_SELECTED_CONTROLLER.sector_count!=0) { +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.drq = 1; +- BX_SELECTED_CONTROLLER.status.corrected_data = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; ++ if (BX_SELECTED_CONTROLLER(channel).sector_count!=0) { ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 1; ++ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; + } + else { /* no more sectors to write */ +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; +- BX_SELECTED_CONTROLLER.status.corrected_data = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0; + } +- raise_interrupt(); ++ raise_interrupt(channel); + } + break; + + case 0xa0: // PACKET +- if (BX_SELECTED_CONTROLLER.buffer_index >= PACKET_SIZE) ++ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= PACKET_SIZE) + BX_PANIC(("IO write(1f0): buffer_index >= PACKET_SIZE")); +- BX_SELECTED_CONTROLLER.buffer[BX_SELECTED_CONTROLLER.buffer_index] = value; +- BX_SELECTED_CONTROLLER.buffer[BX_SELECTED_CONTROLLER.buffer_index+1] = (value >> 8); +- BX_SELECTED_CONTROLLER.buffer_index += 2; ++ BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index] = value; ++ BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+1] = (value >> 8); ++ BX_SELECTED_CONTROLLER(channel).buffer_index += 2; + + /* if packet completely writtten */ +- if (BX_SELECTED_CONTROLLER.buffer_index >= PACKET_SIZE) { ++ if (BX_SELECTED_CONTROLLER(channel).buffer_index >= PACKET_SIZE) { + // complete command received +- Bit8u atapi_command = BX_SELECTED_CONTROLLER.buffer[0]; ++ Bit8u atapi_command = BX_SELECTED_CONTROLLER(channel).buffer[0]; + + if (bx_dbg.cdrom) + BX_INFO(("cdrom: ATAPI command 0x%x started", atapi_command)); + + switch (atapi_command) { + case 0x00: // test unit ready +- if (BX_SELECTED_HD.cdrom.ready) { +- atapi_cmd_nop(); ++ if (BX_SELECTED_DRIVE(channel).cdrom.ready) { ++ atapi_cmd_nop(channel); + } else { +- atapi_cmd_error(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); ++ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + } +- raise_interrupt(); ++ raise_interrupt(channel); + break; + + case 0x03: { // request sense +- int alloc_length = BX_SELECTED_CONTROLLER.buffer[4]; +- init_send_atapi_command(atapi_command, 18, alloc_length); ++ int alloc_length = BX_SELECTED_CONTROLLER(channel).buffer[4]; ++ init_send_atapi_command(channel, atapi_command, 18, alloc_length); + + // sense data +- BX_SELECTED_CONTROLLER.buffer[0] = 0x70 | (1 << 7); +- BX_SELECTED_CONTROLLER.buffer[1] = 0; +- BX_SELECTED_CONTROLLER.buffer[2] = BX_SELECTED_HD.sense.sense_key; +- BX_SELECTED_CONTROLLER.buffer[3] = BX_SELECTED_HD.sense.information.arr[0]; +- BX_SELECTED_CONTROLLER.buffer[4] = BX_SELECTED_HD.sense.information.arr[1]; +- BX_SELECTED_CONTROLLER.buffer[5] = BX_SELECTED_HD.sense.information.arr[2]; +- BX_SELECTED_CONTROLLER.buffer[6] = BX_SELECTED_HD.sense.information.arr[3]; +- BX_SELECTED_CONTROLLER.buffer[7] = 17-7; +- BX_SELECTED_CONTROLLER.buffer[8] = BX_SELECTED_HD.sense.specific_inf.arr[0]; +- BX_SELECTED_CONTROLLER.buffer[9] = BX_SELECTED_HD.sense.specific_inf.arr[1]; +- BX_SELECTED_CONTROLLER.buffer[10] = BX_SELECTED_HD.sense.specific_inf.arr[2]; +- BX_SELECTED_CONTROLLER.buffer[11] = BX_SELECTED_HD.sense.specific_inf.arr[3]; +- BX_SELECTED_CONTROLLER.buffer[12] = BX_SELECTED_HD.sense.asc; +- BX_SELECTED_CONTROLLER.buffer[13] = BX_SELECTED_HD.sense.ascq; +- BX_SELECTED_CONTROLLER.buffer[14] = BX_SELECTED_HD.sense.fruc; +- BX_SELECTED_CONTROLLER.buffer[15] = BX_SELECTED_HD.sense.key_spec.arr[0]; +- BX_SELECTED_CONTROLLER.buffer[16] = BX_SELECTED_HD.sense.key_spec.arr[1]; +- BX_SELECTED_CONTROLLER.buffer[17] = BX_SELECTED_HD.sense.key_spec.arr[2]; ++ BX_SELECTED_CONTROLLER(channel).buffer[0] = 0x70 | (1 << 7); ++ BX_SELECTED_CONTROLLER(channel).buffer[1] = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer[2] = BX_SELECTED_DRIVE(channel).sense.sense_key; ++ BX_SELECTED_CONTROLLER(channel).buffer[3] = BX_SELECTED_DRIVE(channel).sense.information.arr[0]; ++ BX_SELECTED_CONTROLLER(channel).buffer[4] = BX_SELECTED_DRIVE(channel).sense.information.arr[1]; ++ BX_SELECTED_CONTROLLER(channel).buffer[5] = BX_SELECTED_DRIVE(channel).sense.information.arr[2]; ++ BX_SELECTED_CONTROLLER(channel).buffer[6] = BX_SELECTED_DRIVE(channel).sense.information.arr[3]; ++ BX_SELECTED_CONTROLLER(channel).buffer[7] = 17-7; ++ BX_SELECTED_CONTROLLER(channel).buffer[8] = BX_SELECTED_DRIVE(channel).sense.specific_inf.arr[0]; ++ BX_SELECTED_CONTROLLER(channel).buffer[9] = BX_SELECTED_DRIVE(channel).sense.specific_inf.arr[1]; ++ BX_SELECTED_CONTROLLER(channel).buffer[10] = BX_SELECTED_DRIVE(channel).sense.specific_inf.arr[2]; ++ BX_SELECTED_CONTROLLER(channel).buffer[11] = BX_SELECTED_DRIVE(channel).sense.specific_inf.arr[3]; ++ BX_SELECTED_CONTROLLER(channel).buffer[12] = BX_SELECTED_DRIVE(channel).sense.asc; ++ BX_SELECTED_CONTROLLER(channel).buffer[13] = BX_SELECTED_DRIVE(channel).sense.ascq; ++ BX_SELECTED_CONTROLLER(channel).buffer[14] = BX_SELECTED_DRIVE(channel).sense.fruc; ++ BX_SELECTED_CONTROLLER(channel).buffer[15] = BX_SELECTED_DRIVE(channel).sense.key_spec.arr[0]; ++ BX_SELECTED_CONTROLLER(channel).buffer[16] = BX_SELECTED_DRIVE(channel).sense.key_spec.arr[1]; ++ BX_SELECTED_CONTROLLER(channel).buffer[17] = BX_SELECTED_DRIVE(channel).sense.key_spec.arr[2]; + +- ready_to_send_atapi(); ++ ready_to_send_atapi(channel); + } + break; + + case 0x1b: { // start stop unit +- //Boolean Immed = (BX_SELECTED_CONTROLLER.buffer[1] >> 0) & 1; +- Boolean LoEj = (BX_SELECTED_CONTROLLER.buffer[4] >> 1) & 1; +- Boolean Start = (BX_SELECTED_CONTROLLER.buffer[4] >> 0) & 1; ++ //Boolean Immed = (BX_SELECTED_CONTROLLER(channel).buffer[1] >> 0) & 1; ++ Boolean LoEj = (BX_SELECTED_CONTROLLER(channel).buffer[4] >> 1) & 1; ++ Boolean Start = (BX_SELECTED_CONTROLLER(channel).buffer[4] >> 0) & 1; + + if (!LoEj && !Start) { // stop the disc + BX_PANIC(("Stop disc not implemented")); + } else if (!LoEj && Start) { // start the disc and read the TOC + // BX_PANIC(("Start disc not implemented")); + BX_ERROR(("FIXME: ATAPI start disc not reading TOC")); +- atapi_cmd_nop(); +- raise_interrupt(); ++ atapi_cmd_nop(channel); ++ raise_interrupt(channel); + } else if (LoEj && !Start) { // Eject the disc +- atapi_cmd_nop(); +- if (BX_HD_THIS s[1].cdrom.ready) { ++ atapi_cmd_nop(channel); ++ ++ if (BX_SELECTED_DRIVE(channel).cdrom.ready) { + #ifdef LOWLEVEL_CDROM +- BX_HD_THIS s[1].cdrom.cd->eject_cdrom(); ++ BX_SELECTED_DRIVE(channel).cdrom.cd->eject_cdrom(); + #endif +- BX_HD_THIS s[1].cdrom.ready = 0; +- bx_options.cdromd.Ostatus->set(BX_EJECTED); ++ BX_SELECTED_DRIVE(channel).cdrom.ready = 0; ++ bx_options.atadevice[channel][BX_SLAVE_SELECTED(channel)].Ostatus->set(BX_EJECTED); + bx_gui.update_drive_status_buttons(); + } +- raise_interrupt(); ++ raise_interrupt(channel); + } else { // Load the disc + // My guess is that this command only closes the tray, that's a no-op for us +- atapi_cmd_nop(); +- raise_interrupt(); ++ atapi_cmd_nop(channel); ++ raise_interrupt(channel); + } + } + break; + + case 0xbd: { // mechanism status +- uint16 alloc_length = read_16bit(BX_SELECTED_CONTROLLER.buffer + 8); ++ uint16 alloc_length = read_16bit(BX_SELECTED_CONTROLLER(channel).buffer + 8); + + if (alloc_length == 0) + BX_PANIC(("Zero allocation length to MECHANISM STATUS not impl.")); + +- init_send_atapi_command(atapi_command, 8, alloc_length); ++ init_send_atapi_command(channel, atapi_command, 8, alloc_length); + +- BX_SELECTED_CONTROLLER.buffer[0] = 0; // reserved for non changers +- BX_SELECTED_CONTROLLER.buffer[1] = 0; // reserved for non changers ++ BX_SELECTED_CONTROLLER(channel).buffer[0] = 0; // reserved for non changers ++ BX_SELECTED_CONTROLLER(channel).buffer[1] = 0; // reserved for non changers + +- BX_SELECTED_CONTROLLER.buffer[2] = 0; // Current LBA (TODO!) +- BX_SELECTED_CONTROLLER.buffer[3] = 0; // Current LBA (TODO!) +- BX_SELECTED_CONTROLLER.buffer[4] = 0; // Current LBA (TODO!) ++ BX_SELECTED_CONTROLLER(channel).buffer[2] = 0; // Current LBA (TODO!) ++ BX_SELECTED_CONTROLLER(channel).buffer[3] = 0; // Current LBA (TODO!) ++ BX_SELECTED_CONTROLLER(channel).buffer[4] = 0; // Current LBA (TODO!) + +- BX_SELECTED_CONTROLLER.buffer[5] = 1; // one slot ++ BX_SELECTED_CONTROLLER(channel).buffer[5] = 1; // one slot + +- BX_SELECTED_CONTROLLER.buffer[6] = 0; // slot table length +- BX_SELECTED_CONTROLLER.buffer[7] = 0; // slot table length ++ BX_SELECTED_CONTROLLER(channel).buffer[6] = 0; // slot table length ++ BX_SELECTED_CONTROLLER(channel).buffer[7] = 0; // slot table length + +- ready_to_send_atapi(); ++ ready_to_send_atapi(channel); + } + break; + + case 0x5a: { // mode sense +- uint16 alloc_length = read_16bit(BX_SELECTED_CONTROLLER.buffer + 7); ++ uint16 alloc_length = read_16bit(BX_SELECTED_CONTROLLER(channel).buffer + 7); + +- Bit8u PC = BX_SELECTED_CONTROLLER.buffer[2] >> 6; +- Bit8u PageCode = BX_SELECTED_CONTROLLER.buffer[2] & 0x3f; ++ Bit8u PC = BX_SELECTED_CONTROLLER(channel).buffer[2] >> 6; ++ Bit8u PageCode = BX_SELECTED_CONTROLLER(channel).buffer[2] & 0x3f; + + switch (PC) { + case 0x0: // current values + switch (PageCode) { + case 0x01: // error recovery +- init_send_atapi_command(atapi_command, sizeof(error_recovery_t) + 8, alloc_length); ++ init_send_atapi_command(channel, atapi_command, sizeof(error_recovery_t) + 8, alloc_length); + +- init_mode_sense_single(&BX_SELECTED_HD.cdrom.current.error_recovery, ++ init_mode_sense_single(channel, &BX_SELECTED_DRIVE(channel).cdrom.current.error_recovery, + sizeof(error_recovery_t)); +- ready_to_send_atapi(); ++ ready_to_send_atapi(channel); + break; + + case 0x2a: // CD-ROM capabilities & mech. status +- init_send_atapi_command(atapi_command, 28, alloc_length); +- init_mode_sense_single(&BX_SELECTED_CONTROLLER.buffer[8], 28); +- BX_SELECTED_CONTROLLER.buffer[8] = 0x2a; +- BX_SELECTED_CONTROLLER.buffer[9] = 0x12; +- BX_SELECTED_CONTROLLER.buffer[10] = 0x00; +- BX_SELECTED_CONTROLLER.buffer[11] = 0x00; +- BX_SELECTED_CONTROLLER.buffer[12] = 0x00; +- BX_SELECTED_CONTROLLER.buffer[13] = (3 << 5); +- BX_SELECTED_CONTROLLER.buffer[14] = (unsigned char) ++ init_send_atapi_command(channel, atapi_command, 28, alloc_length); ++ init_mode_sense_single(channel, &BX_SELECTED_CONTROLLER(channel).buffer[8], 28); ++ BX_SELECTED_CONTROLLER(channel).buffer[8] = 0x2a; ++ BX_SELECTED_CONTROLLER(channel).buffer[9] = 0x12; ++ BX_SELECTED_CONTROLLER(channel).buffer[10] = 0x00; ++ BX_SELECTED_CONTROLLER(channel).buffer[11] = 0x00; ++ BX_SELECTED_CONTROLLER(channel).buffer[12] = 0x00; ++ BX_SELECTED_CONTROLLER(channel).buffer[13] = (3 << 5); ++ BX_SELECTED_CONTROLLER(channel).buffer[14] = (unsigned char) + (1 | +- (BX_SELECTED_HD.cdrom.locked ? (1 << 1) : 0) | ++ (BX_SELECTED_DRIVE(channel).cdrom.locked ? (1 << 1) : 0) | + (1 << 3) | + (1 << 5)); +- BX_SELECTED_CONTROLLER.buffer[15] = 0x00; +- BX_SELECTED_CONTROLLER.buffer[16] = (706 >> 8) & 0xff; +- BX_SELECTED_CONTROLLER.buffer[17] = 706 & 0xff; +- BX_SELECTED_CONTROLLER.buffer[18] = 0; +- BX_SELECTED_CONTROLLER.buffer[19] = 2; +- BX_SELECTED_CONTROLLER.buffer[20] = (512 >> 8) & 0xff; +- BX_SELECTED_CONTROLLER.buffer[21] = 512 & 0xff; +- BX_SELECTED_CONTROLLER.buffer[22] = (706 >> 8) & 0xff; +- BX_SELECTED_CONTROLLER.buffer[23] = 706 & 0xff; +- BX_SELECTED_CONTROLLER.buffer[24] = 0; +- BX_SELECTED_CONTROLLER.buffer[25] = 0; +- BX_SELECTED_CONTROLLER.buffer[26] = 0; +- BX_SELECTED_CONTROLLER.buffer[27] = 0; +- ready_to_send_atapi(); ++ BX_SELECTED_CONTROLLER(channel).buffer[15] = 0x00; ++ BX_SELECTED_CONTROLLER(channel).buffer[16] = (706 >> 8) & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[17] = 706 & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[18] = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer[19] = 2; ++ BX_SELECTED_CONTROLLER(channel).buffer[20] = (512 >> 8) & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[21] = 512 & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[22] = (706 >> 8) & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[23] = 706 & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[24] = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer[25] = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer[26] = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer[27] = 0; ++ ready_to_send_atapi(channel); + break; + + case 0x0d: // CD-ROM +@@ -1171,9 +1252,9 @@ + BX_ERROR(("cdrom: MODE SENSE (curr), code=%x" + " not implemented yet", + PageCode)); +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); +- raise_interrupt(); ++ raise_interrupt(channel); + break; + + default: +@@ -1181,9 +1262,9 @@ + BX_INFO(("cdrom: MODE SENSE PC=%x, PageCode=%x," + " not implemented by device", + PC, PageCode)); +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); +- raise_interrupt(); ++ raise_interrupt(channel); + break; + } + break; +@@ -1198,9 +1279,9 @@ + BX_ERROR(("cdrom: MODE SENSE (chg), code=%x", + " not implemented yet", + PageCode)); +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); +- raise_interrupt(); ++ raise_interrupt(channel); + break; + + default: +@@ -1208,9 +1289,9 @@ + BX_INFO(("cdrom: MODE SENSE PC=%x, PageCode=%x," + " not implemented by device", + PC, PageCode)); +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); +- raise_interrupt(); ++ raise_interrupt(channel); + break; + } + break; +@@ -1231,16 +1312,16 @@ + BX_INFO(("cdrom: MODE SENSE PC=%x, PageCode=%x," + " not implemented by device", + PC, PageCode)); +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); +- raise_interrupt(); ++ raise_interrupt(channel); + break; + } + break; + + case 0x3: // saved values not implemented +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ASC_SAVING_PARAMETERS_NOT_SUPPORTED); +- raise_interrupt(); ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_SAVING_PARAMETERS_NOT_SUPPORTED); ++ raise_interrupt(channel); + break; + + default: +@@ -1251,96 +1332,96 @@ + break; + + case 0x12: { // inquiry +- uint8 alloc_length = BX_SELECTED_CONTROLLER.buffer[4]; ++ uint8 alloc_length = BX_SELECTED_CONTROLLER(channel).buffer[4]; + +- init_send_atapi_command(atapi_command, 36, alloc_length); ++ init_send_atapi_command(channel, atapi_command, 36, alloc_length); + +- BX_SELECTED_CONTROLLER.buffer[0] = 0x05; // CD-ROM +- BX_SELECTED_CONTROLLER.buffer[1] = 0x80; // Removable +- BX_SELECTED_CONTROLLER.buffer[2] = 0x00; // ISO, ECMA, ANSI version +- BX_SELECTED_CONTROLLER.buffer[3] = 0x21; // ATAPI-2, as specified +- BX_SELECTED_CONTROLLER.buffer[4] = 31; // additional length (total 36) +- BX_SELECTED_CONTROLLER.buffer[5] = 0x00; // reserved +- BX_SELECTED_CONTROLLER.buffer[6] = 0x00; // reserved +- BX_SELECTED_CONTROLLER.buffer[7] = 0x00; // reserved ++ BX_SELECTED_CONTROLLER(channel).buffer[0] = 0x05; // CD-ROM ++ BX_SELECTED_CONTROLLER(channel).buffer[1] = 0x80; // Removable ++ BX_SELECTED_CONTROLLER(channel).buffer[2] = 0x00; // ISO, ECMA, ANSI version ++ BX_SELECTED_CONTROLLER(channel).buffer[3] = 0x21; // ATAPI-2, as specified ++ BX_SELECTED_CONTROLLER(channel).buffer[4] = 31; // additional length (total 36) ++ BX_SELECTED_CONTROLLER(channel).buffer[5] = 0x00; // reserved ++ BX_SELECTED_CONTROLLER(channel).buffer[6] = 0x00; // reserved ++ BX_SELECTED_CONTROLLER(channel).buffer[7] = 0x00; // reserved + + // Vendor ID + const char* vendor_id = "VTAB\0\0\0\0"; + int i; + for (i = 0; i < 8; i++) +- BX_SELECTED_CONTROLLER.buffer[8+i] = vendor_id[i]; ++ BX_SELECTED_CONTROLLER(channel).buffer[8+i] = vendor_id[i]; + + // Product ID + const char* product_id = "Turbo CD-ROM\0\0\0\0"; + for (i = 0; i < 16; i++) +- BX_SELECTED_CONTROLLER.buffer[16+i] = product_id[i]; ++ BX_SELECTED_CONTROLLER(channel).buffer[16+i] = product_id[i]; + + // Product Revision level + const char* rev_level = "R0\0\0"; + for (i = 0; i < 4; i++) +- BX_SELECTED_CONTROLLER.buffer[32+i] = rev_level[i]; ++ BX_SELECTED_CONTROLLER(channel).buffer[32+i] = rev_level[i]; + +- ready_to_send_atapi(); ++ ready_to_send_atapi(channel); + } + break; + + case 0x25: { // read cd-rom capacity + // no allocation length??? +- init_send_atapi_command(atapi_command, 8, 8); ++ init_send_atapi_command(channel, atapi_command, 8, 8); + +- if (BX_SELECTED_HD.cdrom.ready) { +- uint32 capacity = BX_SELECTED_HD.cdrom.capacity; ++ if (BX_SELECTED_DRIVE(channel).cdrom.ready) { ++ uint32 capacity = BX_SELECTED_DRIVE(channel).cdrom.capacity; + BX_INFO(("Capacity is %d sectors (%d bytes)", capacity, capacity * 2048)); +- BX_SELECTED_CONTROLLER.buffer[0] = (capacity >> 24) & 0xff; +- BX_SELECTED_CONTROLLER.buffer[1] = (capacity >> 16) & 0xff; +- BX_SELECTED_CONTROLLER.buffer[2] = (capacity >> 8) & 0xff; +- BX_SELECTED_CONTROLLER.buffer[3] = (capacity >> 0) & 0xff; +- BX_SELECTED_CONTROLLER.buffer[4] = (2048 >> 24) & 0xff; +- BX_SELECTED_CONTROLLER.buffer[5] = (2048 >> 16) & 0xff; +- BX_SELECTED_CONTROLLER.buffer[6] = (2048 >> 8) & 0xff; +- BX_SELECTED_CONTROLLER.buffer[7] = (2048 >> 0) & 0xff; +- ready_to_send_atapi(); ++ BX_SELECTED_CONTROLLER(channel).buffer[0] = (capacity >> 24) & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[1] = (capacity >> 16) & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[2] = (capacity >> 8) & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[3] = (capacity >> 0) & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[4] = (2048 >> 24) & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[5] = (2048 >> 16) & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[6] = (2048 >> 8) & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[7] = (2048 >> 0) & 0xff; ++ ready_to_send_atapi(channel); + } else { +- atapi_cmd_error(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); +- raise_interrupt(); ++ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); ++ raise_interrupt(channel); + } + } + break; + + case 0xbe: { // read cd +- if (BX_SELECTED_HD.cdrom.ready) { ++ if (BX_SELECTED_DRIVE(channel).cdrom.ready) { + BX_ERROR(("Read CD with CD present not implemented")); +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); +- raise_interrupt(); ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); ++ raise_interrupt(channel); + } else { +- atapi_cmd_error(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); +- raise_interrupt(); ++ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); ++ raise_interrupt(channel); + } + } + break; + + case 0x43: { // read toc +- if (BX_SELECTED_HD.cdrom.ready) { ++ if (BX_SELECTED_DRIVE(channel).cdrom.ready) { + #ifdef LOWLEVEL_CDROM +- bool msf = (BX_SELECTED_CONTROLLER.buffer[1] >> 1) & 1; +- uint8 starting_track = BX_SELECTED_CONTROLLER.buffer[6]; ++ bool msf = (BX_SELECTED_CONTROLLER(channel).buffer[1] >> 1) & 1; ++ uint8 starting_track = BX_SELECTED_CONTROLLER(channel).buffer[6]; + #endif +- uint16 alloc_length = read_16bit(BX_SELECTED_CONTROLLER.buffer + 7); ++ uint16 alloc_length = read_16bit(BX_SELECTED_CONTROLLER(channel).buffer + 7); + +- uint8 format = (BX_SELECTED_CONTROLLER.buffer[9] >> 6); ++ uint8 format = (BX_SELECTED_CONTROLLER(channel).buffer[9] >> 6); + int i; + switch (format) { + case 0: + #ifdef LOWLEVEL_CDROM + int toc_length; +- if (!BX_SELECTED_HD.cdrom.cd->read_toc(BX_SELECTED_CONTROLLER.buffer, +- &toc_length, msf, starting_track)) { +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ++ if (!(BX_SELECTED_DRIVE(channel).cdrom.cd->read_toc(BX_SELECTED_CONTROLLER(channel).buffer, ++ &toc_length, msf, starting_track))) { ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); +- raise_interrupt(); ++ raise_interrupt(channel); + } else { +- init_send_atapi_command(atapi_command, toc_length, alloc_length); +- ready_to_send_atapi(); ++ init_send_atapi_command(channel, atapi_command, toc_length, alloc_length); ++ ready_to_send_atapi(channel); + } + #else + BX_PANIC(("LOWLEVEL_CDROM not defined")); +@@ -1349,16 +1430,16 @@ + + case 1: + // multi session stuff. we ignore this and emulate a single session only +- init_send_atapi_command(atapi_command, 12, alloc_length); ++ init_send_atapi_command(channel, atapi_command, 12, alloc_length); + +- BX_SELECTED_CONTROLLER.buffer[0] = 0; +- BX_SELECTED_CONTROLLER.buffer[1] = 0x0a; +- BX_SELECTED_CONTROLLER.buffer[2] = 1; +- BX_SELECTED_CONTROLLER.buffer[3] = 1; ++ BX_SELECTED_CONTROLLER(channel).buffer[0] = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer[1] = 0x0a; ++ BX_SELECTED_CONTROLLER(channel).buffer[2] = 1; ++ BX_SELECTED_CONTROLLER(channel).buffer[3] = 1; + for (i = 0; i < 8; i++) +- BX_SELECTED_CONTROLLER.buffer[4+i] = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer[4+i] = 0; + +- ready_to_send_atapi(); ++ ready_to_send_atapi(channel); + break; + + case 2: +@@ -1367,114 +1448,114 @@ + break; + } + } else { +- atapi_cmd_error(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); +- raise_interrupt(); ++ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); ++ raise_interrupt(channel); + } + } + break; + + case 0x28: { // read (10) +- uint32 transfer_length = read_16bit(BX_SELECTED_CONTROLLER.buffer + 7); +- uint32 lba = read_32bit(BX_SELECTED_CONTROLLER.buffer + 2); ++ uint32 transfer_length = read_16bit(BX_SELECTED_CONTROLLER(channel).buffer + 7); ++ uint32 lba = read_32bit(BX_SELECTED_CONTROLLER(channel).buffer + 2); + +- if (!BX_SELECTED_HD.cdrom.ready) { +- atapi_cmd_error(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); +- raise_interrupt(); ++ if (!BX_SELECTED_DRIVE(channel).cdrom.ready) { ++ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); ++ raise_interrupt(channel); + break; + } + + if (transfer_length == 0) { +- atapi_cmd_nop(); +- raise_interrupt(); ++ atapi_cmd_nop(channel); ++ raise_interrupt(channel); + BX_INFO(("READ(10) with transfer length 0, ok")); + break; + } + +- if (lba + transfer_length > BX_SELECTED_HD.cdrom.capacity) { +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR); +- raise_interrupt(); ++ if (lba + transfer_length > BX_SELECTED_DRIVE(channel).cdrom.capacity) { ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR); ++ raise_interrupt(channel); + break; + } + + //BX_INFO(("cdrom: READ LBA=%d LEN=%d", lba, transfer_length)); + + // handle command +- init_send_atapi_command(atapi_command, transfer_length * 2048, ++ init_send_atapi_command(channel, atapi_command, transfer_length * 2048, + transfer_length * 2048, true); +- BX_SELECTED_HD.cdrom.remaining_blocks = transfer_length; +- BX_SELECTED_HD.cdrom.next_lba = lba; +- ready_to_send_atapi(); ++ BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks = transfer_length; ++ BX_SELECTED_DRIVE(channel).cdrom.next_lba = lba; ++ ready_to_send_atapi(channel); + } + break; + + case 0x2b: { // seek +- uint32 lba = read_32bit(BX_SELECTED_CONTROLLER.buffer + 2); +- if (!BX_SELECTED_HD.cdrom.ready) { +- atapi_cmd_error(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); +- raise_interrupt(); ++ uint32 lba = read_32bit(BX_SELECTED_CONTROLLER(channel).buffer + 2); ++ if (!BX_SELECTED_DRIVE(channel).cdrom.ready) { ++ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); ++ raise_interrupt(channel); + break; + } + +- if (lba > BX_SELECTED_HD.cdrom.capacity) { +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR); +- raise_interrupt(); ++ if (lba > BX_SELECTED_DRIVE(channel).cdrom.capacity) { ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR); ++ raise_interrupt(channel); + break; + } + BX_INFO(("cdrom: SEEK (ignored)")); +- atapi_cmd_nop(); +- raise_interrupt(); ++ atapi_cmd_nop(channel); ++ raise_interrupt(channel); + } + break; + + case 0x1e: { // prevent/allow medium removal +- if (BX_SELECTED_HD.cdrom.ready) { +- BX_SELECTED_HD.cdrom.locked = BX_SELECTED_CONTROLLER.buffer[4] & 1; +- atapi_cmd_nop(); ++ if (BX_SELECTED_DRIVE(channel).cdrom.ready) { ++ BX_SELECTED_DRIVE(channel).cdrom.locked = BX_SELECTED_CONTROLLER(channel).buffer[4] & 1; ++ atapi_cmd_nop(channel); + } else { +- atapi_cmd_error(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); ++ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + } +- raise_interrupt(); ++ raise_interrupt(channel); + } + break; + + case 0x42: { // read sub-channel +- bool msf = get_packet_field(1, 1, 1); +- bool sub_q = get_packet_field(2, 6, 1); +- uint8 data_format = get_packet_byte(3); +- uint8 track_number = get_packet_byte(6); +- uint16 alloc_length = get_packet_word(7); ++ bool msf = get_packet_field(channel,1, 1, 1); ++ bool sub_q = get_packet_field(channel,2, 6, 1); ++ uint8 data_format = get_packet_byte(channel,3); ++ uint8 track_number = get_packet_byte(channel,6); ++ uint16 alloc_length = get_packet_word(channel,7); + UNUSED(msf); + UNUSED(data_format); + UNUSED(track_number); + +- if (!BX_SELECTED_HD.cdrom.ready) { +- atapi_cmd_error(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); +- raise_interrupt(); ++ if (!BX_SELECTED_DRIVE(channel).cdrom.ready) { ++ atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); ++ raise_interrupt(channel); + } else { +- BX_SELECTED_CONTROLLER.buffer[0] = 0; +- BX_SELECTED_CONTROLLER.buffer[1] = 0; // audio not supported +- BX_SELECTED_CONTROLLER.buffer[2] = 0; +- BX_SELECTED_CONTROLLER.buffer[3] = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer[0] = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer[1] = 0; // audio not supported ++ BX_SELECTED_CONTROLLER(channel).buffer[2] = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer[3] = 0; + + int ret_len = 4; // header size + + if (sub_q) { // !sub_q == header only + BX_ERROR(("Read sub-channel with SubQ not implemented")); +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, + ASC_INV_FIELD_IN_CMD_PACKET); +- raise_interrupt(); ++ raise_interrupt(channel); + } + +- init_send_atapi_command(atapi_command, ret_len, alloc_length); +- ready_to_send_atapi(); ++ init_send_atapi_command(channel, atapi_command, ret_len, alloc_length); ++ ready_to_send_atapi(channel); + } + } + break; + + case 0x51: { // read disc info + // no-op to keep the Linux CD-ROM driver happy +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); +- raise_interrupt(); ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); ++ raise_interrupt(channel); + } + break; + +@@ -1492,8 +1573,8 @@ + case 0x4e: // stop play/scan + BX_ERROR(("ATAPI command 0x%x not implemented yet", + atapi_command)); +- atapi_cmd_error(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); +- raise_interrupt(); ++ atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); ++ raise_interrupt(channel); + break; + default: + BX_PANIC(("Unknown ATAPI command 0x%x (%d)", +@@ -1506,45 +1587,45 @@ + + default: + BX_PANIC(("IO write(1f0h): current command is %02xh", +- (unsigned) BX_SELECTED_CONTROLLER.current_command)); ++ (unsigned) BX_SELECTED_CONTROLLER(channel).current_command)); + } + break; + +- case 0x1f1: /* hard disk write precompensation */ +- WRITE_FEATURES(value); +- if (bx_dbg.disk || (CDROM_SELECTED && bx_dbg.cdrom)) { ++ case 0x01: // hard disk write precompensation 0x1f1 ++ WRITE_FEATURES(channel,value); ++ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) { + if (value == 0xff) +- BX_INFO(("no precompensation {%s}", DEVICE_TYPE_STRING)); ++ BX_INFO(("no precompensation {%s}", BX_SELECTED_TYPE_STRING(channel))); + else +- BX_INFO(("precompensation value %02x {%s}", (unsigned) value, DEVICE_TYPE_STRING)); ++ BX_INFO(("precompensation value %02x {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel))); + } + break; + +- case 0x1f2: /* hard disk sector count */ +- WRITE_SECTOR_COUNT(value); +- if (bx_dbg.disk || (CDROM_SELECTED && bx_dbg.cdrom)) +- BX_INFO(("sector count = %u {%s}", (unsigned) value, DEVICE_TYPE_STRING)); ++ case 0x02: // hard disk sector count 0x1f2 ++ WRITE_SECTOR_COUNT(channel,value); ++ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) ++ BX_INFO(("sector count = %u {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel))); + break; + +- case 0x1f3: /* hard disk sector number */ +- WRITE_SECTOR_NUMBER(value); +- if (bx_dbg.disk || (CDROM_SELECTED && bx_dbg.cdrom)) +- BX_INFO(("sector number = %u {%s}", (unsigned) value, DEVICE_TYPE_STRING)); ++ case 0x03: // hard disk sector number 0x1f3 ++ WRITE_SECTOR_NUMBER(channel,value); ++ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) ++ BX_INFO(("sector number = %u {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel))); + break; + +- case 0x1f4: /* hard disk cylinder low */ +- WRITE_CYLINDER_LOW(value); +- if (bx_dbg.disk || (CDROM_SELECTED && bx_dbg.cdrom)) +- BX_INFO(("cylinder low = %02xh {%s}", (unsigned) value, DEVICE_TYPE_STRING)); ++ case 0x04: // hard disk cylinder low 0x1f4 ++ WRITE_CYLINDER_LOW(channel,value); ++ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) ++ BX_INFO(("cylinder low = %02xh {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel))); + break; + +- case 0x1f5: /* hard disk cylinder high */ +- WRITE_CYLINDER_HIGH(value); +- if (bx_dbg.disk || (CDROM_SELECTED && bx_dbg.cdrom)) +- BX_INFO(("cylinder high = %02xh {%s}", (unsigned) value, DEVICE_TYPE_STRING)); ++ case 0x05: // hard disk cylinder high 0x1f5 ++ WRITE_CYLINDER_HIGH(channel,value); ++ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) ++ BX_INFO(("cylinder high = %02xh {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel))); + break; + +- case 0x1f6: // hard disk drive and head register ++ case 0x06: // hard disk drive and head register 0x1f6 + // b7 Extended data field for ECC + // b6/b5: Used to be sector size. 00=256,01=512,10=1024,11=128 + // Since 512 was always used, bit 6 was taken to mean LBA mode: +@@ -1555,410 +1636,399 @@ + { + if ( (value & 0xa0) != 0xa0 ) // 1x1xxxxx + BX_INFO(("IO write 1f6 (%02x): not 1x1xxxxxb", (unsigned) value)); +- Bit32u drvsel = BX_HD_THIS drive_select = (value >> 4) & 0x01; +- WRITE_HEAD_NO(value & 0xf); +- if (BX_SELECTED_CONTROLLER.lba_mode == 0 && ((value >> 6) & 1) == 1) ++ Bit32u drvsel = BX_HD_THIS channels[channel].drive_select = (value >> 4) & 0x01; ++ WRITE_HEAD_NO(channel,value & 0xf); ++ if (BX_SELECTED_CONTROLLER(channel).lba_mode == 0 && ((value >> 6) & 1) == 1) + BX_INFO(("enabling LBA mode")); +- WRITE_LBA_MODE((value >> 6) & 1); +- if (!drvsel && !bx_options.diskc.Opresent->get ()) { +- BX_ERROR (("device set to 0 which does not exist")); +- BX_SELECTED_CONTROLLER.error_register = 0x04; // aborted +- BX_SELECTED_CONTROLLER.status.err = 1; +- } else if (drvsel && !bx_options.diskd.Opresent->get ()) { +- BX_ERROR (("device set to 1 which does not exist")); +- BX_SELECTED_CONTROLLER.error_register = 0x04; // aborted +- BX_SELECTED_CONTROLLER.status.err = 1; +- } ++ WRITE_LBA_MODE(channel,(value >> 6) & 1); ++ if (!BX_SELECTED_IS_PRESENT(channel)) { ++ BX_ERROR (("device set to %d which does not exist",drvsel)); ++ BX_SELECTED_CONTROLLER(channel).error_register = 0x04; // aborted ++ BX_SELECTED_CONTROLLER(channel).status.err = 1; ++ } + break; + } + +- case 0x1f7: // hard disk command ++ case 0x07: // hard disk command 0x1f7 + // (mch) Writes to the command register with drive_select != 0 + // are ignored if no secondary device is present +- if (BX_HD_THIS drive_select != 0 && value != 0x90 && !bx_options.diskd.Opresent->get ()) ++ if ((BX_SLAVE_SELECTED(channel)) && (!BX_SLAVE_IS_PRESENT(channel))) + break; + +- if (BX_SELECTED_CONTROLLER.status.busy) ++ if (BX_SELECTED_CONTROLLER(channel).status.busy) + BX_PANIC(("hard disk: command sent, controller BUSY")); + if ( (value & 0xf0) == 0x10 ) + value = 0x10; + switch (value) { + + case 0x10: // CALIBRATE DRIVE +- if (BX_SELECTED_HD.device_type != IDE_DISK) ++ if (!BX_SELECTED_IS_HD(channel)) + BX_PANIC(("calibrate drive issued to non-disk")); +- if ((BX_HD_THIS drive_select == 0 && !bx_options.diskc.Opresent->get ()) || +- (BX_HD_THIS drive_select != 0 && !bx_options.diskd.Opresent->get ())) { +- BX_SELECTED_CONTROLLER.error_register = 0x02; // Track 0 not found +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.seek_complete = 0; +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.err = 1; +- raise_interrupt(); +- BX_INFO(("calibrate drive: disk%c not present", BX_HD_THIS drive_select+67)); ++ if (!BX_SELECTED_IS_PRESENT(channel)) { ++ BX_SELECTED_CONTROLLER(channel).error_register = 0x02; // Track 0 not found ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 1; ++ raise_interrupt(channel); ++ BX_INFO(("calibrate drive: disk ata%d-%d not present", channel, BX_SLAVE_SELECTED(channel))); + break; + } + +- /* move head to cylinder 0, issue IRQ 14 */ +- BX_SELECTED_CONTROLLER.error_register = 0; +- BX_SELECTED_CONTROLLER.cylinder_no = 0; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.seek_complete = 1; +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; +- raise_interrupt(); ++ /* move head to cylinder 0, issue IRQ */ ++ BX_SELECTED_CONTROLLER(channel).error_register = 0; ++ BX_SELECTED_CONTROLLER(channel).cylinder_no = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; ++ raise_interrupt(channel); + break; + + case 0x20: // READ MULTIPLE SECTORS, with retries + case 0x21: // READ MULTIPLE SECTORS, without retries + /* update sector_no, always points to current sector +- * after each sector is read to buffer, DRQ bit set and issue IRQ 14 ++ * after each sector is read to buffer, DRQ bit set and issue IRQ + * if interrupt handler transfers all data words into main memory, + * and more sectors to read, then set BSY bit again, clear DRQ and + * read next sector into buffer + * sector count of 0 means 256 sectors + */ + +- if (BX_SELECTED_HD.device_type != IDE_DISK) ++ if (!BX_SELECTED_IS_HD(channel)) + BX_PANIC(("read multiple issued to non-disk")); + +- BX_SELECTED_CONTROLLER.current_command = value; ++ BX_SELECTED_CONTROLLER(channel).current_command = value; + + // Lose98 accesses 0/0/0 in CHS mode +- if (!BX_SELECTED_CONTROLLER.lba_mode && +- !BX_SELECTED_CONTROLLER.head_no && +- !BX_SELECTED_CONTROLLER.cylinder_no && +- !BX_SELECTED_CONTROLLER.sector_no) { ++ if (!BX_SELECTED_CONTROLLER(channel).lba_mode && ++ !BX_SELECTED_CONTROLLER(channel).head_no && ++ !BX_SELECTED_CONTROLLER(channel).cylinder_no && ++ !BX_SELECTED_CONTROLLER(channel).sector_no) { + BX_INFO(("Read from 0/0/0, aborting command")); +- command_aborted(value); ++ command_aborted(channel, value); + break; + } + + #if TEST_READ_BEYOND_END==2 +- BX_SELECTED_CONTROLLER.cylinder_no += 100000; ++ BX_SELECTED_CONTROLLER(channel).cylinder_no += 100000; + #endif +- if (!calculate_logical_address(&logical_sector)) { ++ if (!calculate_logical_address(channel, &logical_sector)) { + BX_ERROR(("initial read from sector %u out of bounds, aborting", logical_sector)); +- command_aborted(value); ++ command_aborted(channel, value); + break; + } + #if TEST_READ_BEYOND_END==3 + logical_sector += 100000; + #endif +- ret=BX_SELECTED_HD.hard_drive->lseek(logical_sector * 512, SEEK_SET); ++ ret=BX_SELECTED_DRIVE(channel).hard_drive->lseek(logical_sector * 512, SEEK_SET); + if (ret < 0) { + BX_ERROR (("could not lseek() hard drive image file, aborting")); +- command_aborted(value); ++ command_aborted(channel, value); + break; + } +- ret = BX_SELECTED_HD.hard_drive->read((bx_ptr_t) BX_SELECTED_CONTROLLER.buffer, 512); ++ ret = BX_SELECTED_DRIVE(channel).hard_drive->read((bx_ptr_t) BX_SELECTED_CONTROLLER(channel).buffer, 512); + if (ret < 512) { + BX_ERROR(("logical sector was %u", (unsigned) logical_sector)); + BX_ERROR(("could not read() hard drive image file at byte %d", logical_sector*512)); +- command_aborted(value); ++ command_aborted(channel, value); + break; + } + +- BX_SELECTED_CONTROLLER.error_register = 0; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.seek_complete = 1; +- BX_SELECTED_CONTROLLER.status.drq = 1; +- BX_SELECTED_CONTROLLER.status.corrected_data = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; +- BX_SELECTED_CONTROLLER.buffer_index = 0; +- raise_interrupt(); ++ BX_SELECTED_CONTROLLER(channel).error_register = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 1; ++ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer_index = 0; ++ raise_interrupt(channel); + break; + + case 0x30: /* WRITE SECTORS, with retries */ + /* update sector_no, always points to current sector +- * after each sector is read to buffer, DRQ bit set and issue IRQ 14 ++ * after each sector is read to buffer, DRQ bit set and issue IRQ + * if interrupt handler transfers all data words into main memory, + * and more sectors to read, then set BSY bit again, clear DRQ and + * read next sector into buffer + * sector count of 0 means 256 sectors + */ + +- if (BX_SELECTED_HD.device_type != IDE_DISK) ++ if (!BX_SELECTED_IS_HD(channel)) + BX_PANIC(("write multiple issued to non-disk")); + +- if (BX_SELECTED_CONTROLLER.status.busy) { ++ if (BX_SELECTED_CONTROLLER(channel).status.busy) { + BX_PANIC(("write command: BSY bit set")); + } +- BX_SELECTED_CONTROLLER.current_command = value; ++ BX_SELECTED_CONTROLLER(channel).current_command = value; + + // implicit seek done :^) +- BX_SELECTED_CONTROLLER.error_register = 0; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- // BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.seek_complete = 1; +- BX_SELECTED_CONTROLLER.status.drq = 1; +- BX_SELECTED_CONTROLLER.status.err = 0; +- BX_SELECTED_CONTROLLER.buffer_index = 0; ++ BX_SELECTED_CONTROLLER(channel).error_register = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ // BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 1; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer_index = 0; + break; + + case 0x90: // EXECUTE DEVICE DIAGNOSTIC +- if (BX_SELECTED_CONTROLLER.status.busy) { ++ if (BX_SELECTED_CONTROLLER(channel).status.busy) { + BX_PANIC(("diagnostic command: BSY bit set")); + } +- if (BX_SELECTED_HD.device_type != IDE_DISK) ++ if (!BX_SELECTED_IS_HD(channel)) + BX_PANIC(("drive diagnostics issued to non-disk")); +- BX_SELECTED_CONTROLLER.error_register = 0x81; // Drive 1 failed, no error on drive 0 +- // BX_SELECTED_CONTROLLER.status.busy = 0; // not needed +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).error_register = 0x81; // Drive 1 failed, no error on drive 0 ++ // BX_SELECTED_CONTROLLER(channel).status.busy = 0; // not needed ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; + break; + + case 0x91: // INITIALIZE DRIVE PARAMETERS +- if (BX_SELECTED_CONTROLLER.status.busy) { ++ if (BX_SELECTED_CONTROLLER(channel).status.busy) { + BX_PANIC(("init drive parameters command: BSY bit set")); + } +- if (BX_SELECTED_HD.device_type != IDE_DISK) ++ if (!BX_SELECTED_IS_HD(channel)) + BX_PANIC(("initialize drive parameters issued to non-disk")); + // sets logical geometry of specified drive + BX_DEBUG(("init drive params: sec=%u, drive sel=%u, head=%u", +- (unsigned) BX_SELECTED_CONTROLLER.sector_count, +- (unsigned) BX_HD_THIS drive_select, +- (unsigned) BX_SELECTED_CONTROLLER.head_no)); +- if ((BX_HD_THIS drive_select == 0 && !bx_options.diskc.Opresent->get ()) || +- (BX_HD_THIS drive_select != 0 && !bx_options.diskd.Opresent->get ())) { +- BX_PANIC(("init drive params: disk%c not present", BX_HD_THIS drive_select+67)); +- //BX_SELECTED_CONTROLLER.error_register = 0x12; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; +- raise_interrupt(); ++ (unsigned) BX_SELECTED_CONTROLLER(channel).sector_count, ++ (unsigned) BX_HD_THIS channels[channel].drive_select, ++ (unsigned) BX_SELECTED_CONTROLLER(channel).head_no)); ++ if (!BX_SELECTED_IS_PRESENT(channel)) { ++ BX_PANIC(("init drive params: disk ata%d-%d% not present", channel, BX_SLAVE_SELECTED(channel))); ++ //BX_SELECTED_CONTROLLER(channel).error_register = 0x12; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; ++ raise_interrupt(channel); + break; + } +- if (BX_SELECTED_CONTROLLER.sector_count != BX_SELECTED_HD.hard_drive->sectors) +- BX_PANIC(("init drive params: sector count doesnt match")); +- if ( BX_SELECTED_CONTROLLER.head_no != (BX_SELECTED_HD.hard_drive->heads-1) ) +- BX_PANIC(("init drive params: head number doesn't match")); +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; +- raise_interrupt(); ++ if (BX_SELECTED_CONTROLLER(channel).sector_count != BX_SELECTED_DRIVE(channel).hard_drive->sectors) ++ BX_PANIC(("init drive params: sector count doesnt match %ld!=%ld", BX_SELECTED_CONTROLLER(channel).sector_count, BX_SELECTED_DRIVE(channel).hard_drive->sectors)); ++ if ( BX_SELECTED_CONTROLLER(channel).head_no != (BX_SELECTED_DRIVE(channel).hard_drive->heads-1) ) ++ BX_PANIC(("init drive params: head number doesn't match %d != %d",BX_SELECTED_CONTROLLER(channel).head_no, BX_SELECTED_DRIVE(channel).hard_drive->heads-1)); ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; ++ raise_interrupt(channel); + break; + + case 0xec: // IDENTIFY DEVICE + if (bx_options.OnewHardDriveSupport->get ()) { +- if (bx_dbg.disk || (CDROM_SELECTED && bx_dbg.cdrom)) ++ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) + BX_INFO(("Drive ID Command issued : 0xec ")); + +- if (!BX_HD_THIS drive_select && !bx_options.diskc.Opresent->get ()) { +- BX_INFO(("1st drive not present, aborting")); +- command_aborted(value); +- break; +- } +- if (BX_HD_THIS drive_select && !bx_options.diskd.Opresent->get ()) { +- BX_INFO(("2nd drive not present, aborting")); +- command_aborted(value); ++ if (!BX_SELECTED_IS_PRESENT(channel)) { ++ BX_INFO(("disk ata%d-%d not present, aborting",channel,BX_SLAVE_SELECTED(channel))); ++ command_aborted(channel, value); + break; + } +- if (BX_SELECTED_HD.device_type == IDE_CDROM) { +- BX_SELECTED_CONTROLLER.head_no = 0; +- BX_SELECTED_CONTROLLER.sector_count = 1; +- BX_SELECTED_CONTROLLER.sector_no = 1; +- BX_SELECTED_CONTROLLER.cylinder_no = 0xeb14; +- command_aborted(0xec); ++ if (BX_SELECTED_IS_CD(channel)) { ++ BX_SELECTED_CONTROLLER(channel).head_no = 0; ++ BX_SELECTED_CONTROLLER(channel).sector_count = 1; ++ BX_SELECTED_CONTROLLER(channel).sector_no = 1; ++ BX_SELECTED_CONTROLLER(channel).cylinder_no = 0xeb14; ++ command_aborted(channel, 0xec); + } else { +- BX_SELECTED_CONTROLLER.current_command = value; +- BX_SELECTED_CONTROLLER.error_register = 0; ++ BX_SELECTED_CONTROLLER(channel).current_command = value; ++ BX_SELECTED_CONTROLLER(channel).error_register = 0; + + // See ATA/ATAPI-4, 8.12 +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.write_fault = 0; +- BX_SELECTED_CONTROLLER.status.drq = 1; +- BX_SELECTED_CONTROLLER.status.err = 0; +- +- BX_SELECTED_CONTROLLER.status.seek_complete = 1; +- BX_SELECTED_CONTROLLER.status.corrected_data = 0; +- +- BX_SELECTED_CONTROLLER.buffer_index = 0; +- raise_interrupt(); +- identify_drive(BX_HD_THIS drive_select); ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 1; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; ++ ++ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1; ++ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0; ++ ++ BX_SELECTED_CONTROLLER(channel).buffer_index = 0; ++ raise_interrupt(channel); ++ identify_drive(channel); + } + } + else { + BX_INFO(("sent IDENTIFY DEVICE (0xec) to old hard drive")); +- command_aborted(value); ++ command_aborted(channel, value); + } + break; + + case 0xef: // SET FEATURES +- switch(BX_SELECTED_CONTROLLER.features) { ++ switch(BX_SELECTED_CONTROLLER(channel).features) { + case 0x02: // Enable and + case 0x82: // Disable write cache. + case 0xAA: // Enable and + case 0x55: // Disable look-ahead cache. ++ case 0xCC: // Enable and + case 0x66: // Disable reverting to power-on default +- case 0xCC: // Enable reverting to power-on default +- BX_INFO(("SET FEATURES subcommand 0x%02x not supported by disk.", (unsigned) BX_SELECTED_CONTROLLER.features)); +- command_aborted(value); ++ BX_INFO(("SET FEATURES subcommand 0x%02x not supported by disk.", (unsigned) BX_SELECTED_CONTROLLER(channel).features)); ++ command_aborted(channel, value); + break; + + default: +- BX_PANIC(("SET FEATURES with unknown subcommand: 0x%02x", (unsigned) BX_SELECTED_CONTROLLER.features )); ++ BX_PANIC(("SET FEATURES with unknown subcommand: 0x%02x", (unsigned) BX_SELECTED_CONTROLLER(channel).features )); + } + break; + + case 0x40: // READ VERIFY SECTORS + if (bx_options.OnewHardDriveSupport->get ()) { +- if (BX_SELECTED_HD.device_type != IDE_DISK) ++ if (!BX_SELECTED_IS_HD(channel)) + BX_PANIC(("read verify issued to non-disk")); + BX_INFO(("Verify Command : 0x40 ! ")); +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; +- raise_interrupt(); ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; ++ raise_interrupt(channel); + } + else { + BX_INFO(("sent READ VERIFY SECTORS (0x40) to old hard drive")); +- command_aborted(value); ++ command_aborted(channel, value); + } + break; + + case 0xc6: // SET MULTIPLE MODE (mch) +- if (BX_SELECTED_CONTROLLER.sector_count != 128 && +- BX_SELECTED_CONTROLLER.sector_count != 64 && +- BX_SELECTED_CONTROLLER.sector_count != 32 && +- BX_SELECTED_CONTROLLER.sector_count != 16 && +- BX_SELECTED_CONTROLLER.sector_count != 8 && +- BX_SELECTED_CONTROLLER.sector_count != 4 && +- BX_SELECTED_CONTROLLER.sector_count != 2) +- command_aborted(value); ++ if (BX_SELECTED_CONTROLLER(channel).sector_count != 128 && ++ BX_SELECTED_CONTROLLER(channel).sector_count != 64 && ++ BX_SELECTED_CONTROLLER(channel).sector_count != 32 && ++ BX_SELECTED_CONTROLLER(channel).sector_count != 16 && ++ BX_SELECTED_CONTROLLER(channel).sector_count != 8 && ++ BX_SELECTED_CONTROLLER(channel).sector_count != 4 && ++ BX_SELECTED_CONTROLLER(channel).sector_count != 2) ++ command_aborted(channel, value); + +- if (BX_SELECTED_HD.device_type != IDE_DISK) ++ if (!BX_SELECTED_IS_HD(channel)) + BX_PANIC(("set multiple mode issued to non-disk")); + +- BX_SELECTED_CONTROLLER.sectors_per_block = BX_SELECTED_CONTROLLER.sector_count; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.write_fault = 0; +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).sectors_per_block = BX_SELECTED_CONTROLLER(channel).sector_count; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; + break; + + // ATAPI commands + case 0xa1: // IDENTIFY PACKET DEVICE +- if (BX_SELECTED_HD.device_type == IDE_CDROM) { +- BX_SELECTED_CONTROLLER.current_command = value; +- BX_SELECTED_CONTROLLER.error_register = 0; +- +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.write_fault = 0; +- BX_SELECTED_CONTROLLER.status.drq = 1; +- BX_SELECTED_CONTROLLER.status.err = 0; +- +- BX_SELECTED_CONTROLLER.status.seek_complete = 1; +- BX_SELECTED_CONTROLLER.status.corrected_data = 0; +- +- BX_SELECTED_CONTROLLER.buffer_index = 0; +- raise_interrupt(); +- identify_ATAPI_drive(BX_HD_THIS drive_select); ++ if (BX_SELECTED_IS_CD(channel)) { ++ BX_SELECTED_CONTROLLER(channel).current_command = value; ++ BX_SELECTED_CONTROLLER(channel).error_register = 0; ++ ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 1; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; ++ ++ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1; ++ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0; ++ ++ BX_SELECTED_CONTROLLER(channel).buffer_index = 0; ++ raise_interrupt(channel); ++ identify_ATAPI_drive(channel); + } else { +- command_aborted(0xa1); ++ command_aborted(channel, 0xa1); + } + break; + + case 0x08: // DEVICE RESET (atapi) +- if (BX_SELECTED_HD.device_type == IDE_CDROM) { +- BX_SELECTED_CONTROLLER.status.busy = 1; +- BX_SELECTED_CONTROLLER.error_register &= ~(1 << 7); ++ if (BX_SELECTED_IS_CD(channel)) { ++ BX_SELECTED_CONTROLLER(channel).status.busy = 1; ++ BX_SELECTED_CONTROLLER(channel).error_register &= ~(1 << 7); + + // device signature +- BX_SELECTED_CONTROLLER.head_no = 0; +- BX_SELECTED_CONTROLLER.sector_count = 1; +- BX_SELECTED_CONTROLLER.sector_no = 1; +- BX_SELECTED_CONTROLLER.cylinder_no = 0xeb14; +- +- BX_SELECTED_CONTROLLER.status.write_fault = 0; +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.corrected_data = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).head_no = 0; ++ BX_SELECTED_CONTROLLER(channel).sector_count = 1; ++ BX_SELECTED_CONTROLLER(channel).sector_no = 1; ++ BX_SELECTED_CONTROLLER(channel).cylinder_no = 0xeb14; ++ ++ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; + +- BX_SELECTED_CONTROLLER.status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; + + } else { + BX_DEBUG(("ATAPI Device Reset on non-cd device")); +- command_aborted(0x08); ++ command_aborted(channel, 0x08); + } + break; + + case 0xa0: // SEND PACKET (atapi) +- if (BX_SELECTED_HD.device_type == IDE_CDROM) { ++ if (BX_SELECTED_IS_CD(channel)) { + // PACKET +- if (BX_SELECTED_CONTROLLER.features & (1 << 0)) ++ if (BX_SELECTED_CONTROLLER(channel).features & (1 << 0)) + BX_PANIC(("PACKET-DMA not supported")); +- if (BX_SELECTED_CONTROLLER.features & (1 << 1)) ++ if (BX_SELECTED_CONTROLLER(channel).features & (1 << 1)) + BX_PANIC(("PACKET-overlapped not supported")); + + // We're already ready! +- BX_SELECTED_CONTROLLER.sector_count = 1; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.write_fault = 0; ++ BX_SELECTED_CONTROLLER(channel).sector_count = 1; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0; + // serv bit?? +- BX_SELECTED_CONTROLLER.status.drq = 1; +- BX_SELECTED_CONTROLLER.status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 1; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; + + // NOTE: no interrupt here +- BX_SELECTED_CONTROLLER.current_command = value; +- BX_SELECTED_CONTROLLER.buffer_index = 0; ++ BX_SELECTED_CONTROLLER(channel).current_command = value; ++ BX_SELECTED_CONTROLLER(channel).buffer_index = 0; + } else { +- command_aborted (0xa0); ++ command_aborted (channel, 0xa0); + } + break; + + case 0xa2: // SERVICE (atapi), optional +- if (BX_SELECTED_HD.device_type == IDE_CDROM) { ++ if (BX_SELECTED_IS_CD(channel)) { + BX_PANIC(("ATAPI SERVICE not implemented")); + } else { +- command_aborted (0xa2); ++ command_aborted (channel, 0xa2); + } + break; + + // power management + case 0xe5: // CHECK POWER MODE +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.write_fault = 0; +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; +- BX_SELECTED_CONTROLLER.sector_count = 0xff; // Active or Idle mode +- raise_interrupt(); ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).sector_count = 0xff; // Active or Idle mode ++ raise_interrupt(channel); + break; + + case 0x70: // SEEK (cgs) +- if (BX_SELECTED_HD.device_type == IDE_DISK) { ++ if (BX_SELECTED_IS_HD(channel)) { + BX_DEBUG(("write cmd 0x70 (SEEK) executing")); +- if (!calculate_logical_address(&logical_sector)) { ++ if (!calculate_logical_address(channel, &logical_sector)) { + BX_ERROR(("initial seek to sector %u out of bounds, aborting", logical_sector)); +- command_aborted(value); ++ command_aborted(channel, value); + break; + } +- BX_SELECTED_CONTROLLER.error_register = 0; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.seek_complete = 1; +- BX_SELECTED_CONTROLLER.status.drq = 1; +- BX_SELECTED_CONTROLLER.status.corrected_data = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; +- BX_SELECTED_CONTROLLER.buffer_index = 0; +- BX_DEBUG(("s[0].controller.control.disable_irq = %02x", (BX_HD_THIS s[0]).controller.control.disable_irq)); +- BX_DEBUG(("s[1].controller.control.disable_irq = %02x", (BX_HD_THIS s[1]).controller.control.disable_irq)); +- BX_DEBUG(("SEEK completed. error_register = %02x", BX_SELECTED_CONTROLLER.error_register)); +- raise_interrupt(); ++ BX_SELECTED_CONTROLLER(channel).error_register = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 1; ++ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer_index = 0; ++ BX_DEBUG(("s[0].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[0]).controller.control.disable_irq)); ++ BX_DEBUG(("s[1].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[1]).controller.control.disable_irq)); ++ BX_DEBUG(("SEEK completed. error_register = %02x", BX_SELECTED_CONTROLLER(channel).error_register)); ++ raise_interrupt(channel); + BX_DEBUG(("SEEK interrupt completed")); + } else { + BX_ERROR(("write cmd 0x70 (SEEK) not supported for non-disk")); +- command_aborted(0x70); ++ command_aborted(channel, 0x70); + } + break; + +@@ -1967,161 +2037,150 @@ + // List all the write operations that are defined in the ATA/ATAPI spec + // that we don't support. Commands that are listed here will cause a + // BX_ERROR, which is non-fatal, and the command will be aborted. +- case 0x22: BX_ERROR(("write cmd 0x22 (READ LONG) not supported")); command_aborted(0x22); break; +- case 0x23: BX_ERROR(("write cmd 0x23 (READ LONG NO RETRY) not supported")); command_aborted(0x23); break; +- case 0x24: BX_ERROR(("write cmd 0x24 (READ SECTORS EXT) not supported"));command_aborted(0x24); break; +- case 0x25: BX_ERROR(("write cmd 0x25 (READ DMA EXT) not supported"));command_aborted(0x25); break; +- case 0x26: BX_ERROR(("write cmd 0x26 (READ DMA QUEUED EXT) not supported"));command_aborted(0x26); break; +- case 0x27: BX_ERROR(("write cmd 0x27 (READ NATIVE MAX ADDRESS EXT) not supported"));command_aborted(0x27); break; +- case 0x29: BX_ERROR(("write cmd 0x29 (READ MULTIPLE EXT) not supported"));command_aborted(0x29); break; +- case 0x2A: BX_ERROR(("write cmd 0x2A (READ STREAM DMA) not supported"));command_aborted(0x2A); break; +- case 0x2B: BX_ERROR(("write cmd 0x2B (READ STREAM PIO) not supported"));command_aborted(0x2B); break; +- case 0x2F: BX_ERROR(("write cmd 0x2F (READ LOG EXT) not supported"));command_aborted(0x2F); break; +- case 0x31: BX_ERROR(("write cmd 0x31 (WRITE SECTORS NO RETRY) not supported")); command_aborted(0x31); break; +- case 0x32: BX_ERROR(("write cmd 0x32 (WRITE LONG) not supported")); command_aborted(0x32); break; +- case 0x33: BX_ERROR(("write cmd 0x33 (WRITE LONG NO RETRY) not supported")); command_aborted(0x33); break; +- case 0x34: BX_ERROR(("write cmd 0x34 (WRITE SECTORS EXT) not supported"));command_aborted(0x34); break; +- case 0x35: BX_ERROR(("write cmd 0x35 (WRITE DMA EXT) not supported"));command_aborted(0x35); break; +- case 0x36: BX_ERROR(("write cmd 0x36 (WRITE DMA QUEUED EXT) not supported"));command_aborted(0x36); break; +- case 0x37: BX_ERROR(("write cmd 0x37 (SET MAX ADDRESS EXT) not supported"));command_aborted(0x37); break; +- case 0x38: BX_ERROR(("write cmd 0x38 (CFA WRITE SECTORS W/OUT ERASE) not supported"));command_aborted(0x38); break; +- case 0x39: BX_ERROR(("write cmd 0x39 (WRITE MULTIPLE EXT) not supported"));command_aborted(0x39); break; +- case 0x3A: BX_ERROR(("write cmd 0x3A (WRITE STREAM DMA) not supported"));command_aborted(0x3A); break; +- case 0x3B: BX_ERROR(("write cmd 0x3B (WRITE STREAM PIO) not supported"));command_aborted(0x3B); break; +- case 0x3F: BX_ERROR(("write cmd 0x3F (WRITE LOG EXT) not supported"));command_aborted(0x3F); break; +- case 0x41: BX_ERROR(("write cmd 0x41 (READ VERIFY SECTORS NO RETRY) not supported")); command_aborted(0x41); break; +- case 0x42: BX_ERROR(("write cmd 0x42 (READ VERIFY SECTORS EXT) not supported"));command_aborted(0x42); break; +- case 0x50: BX_ERROR(("write cmd 0x50 (FORMAT TRACK) not supported")); command_aborted(0x50); break; +- case 0x51: BX_ERROR(("write cmd 0x51 (CONFIGURE STREAM) not supported"));command_aborted(0x51); break; +- case 0x87: BX_ERROR(("write cmd 0x87 (CFA TRANSLATE SECTOR) not supported"));command_aborted(0x87); break; +- case 0x92: BX_ERROR(("write cmd 0x92 (DOWNLOAD MICROCODE) not supported"));command_aborted(0x92); break; +- case 0x94: BX_ERROR(("write cmd 0x94 (STANDBY IMMEDIATE) not supported")); command_aborted(0x94); break; +- case 0x95: BX_ERROR(("write cmd 0x95 (IDLE IMMEDIATE) not supported")); command_aborted(0x95); break; +- case 0x96: BX_ERROR(("write cmd 0x96 (STANDBY) not supported")); command_aborted(0x96); break; +- case 0x97: BX_ERROR(("write cmd 0x97 (IDLE) not supported")); command_aborted(0x97); break; +- case 0x98: BX_ERROR(("write cmd 0x98 (CHECK POWER MODE) not supported")); command_aborted(0x98); break; +- case 0x99: BX_ERROR(("write cmd 0x99 (SLEEP) not supported")); command_aborted(0x99); break; +- case 0xB0: BX_ERROR(("write cmd 0xB0 (SMART commands) not supported"));command_aborted(0xB0); break; +- case 0xB1: BX_ERROR(("write cmd 0xB1 (DEVICE CONFIGURATION commands) not supported"));command_aborted(0xB1); break; +- case 0xC0: BX_ERROR(("write cmd 0xC0 (CFA ERASE SECTORS) not supported"));command_aborted(0xC0); break; +- case 0xC4: BX_ERROR(("write cmd 0xC4 (READ MULTIPLE) not supported"));command_aborted(0xC4); break; +- case 0xC5: BX_ERROR(("write cmd 0xC5 (WRITE MULTIPLE) not supported"));command_aborted(0xC5); break; +- case 0xC7: BX_ERROR(("write cmd 0xC7 (READ DMA QUEUED) not supported"));command_aborted(0xC7); break; +- case 0xC8: BX_ERROR(("write cmd 0xC8 (READ DMA) not supported"));command_aborted(0xC8); break; +- case 0xC9: BX_ERROR(("write cmd 0xC9 (READ DMA NO RETRY) not supported")); command_aborted(0xC9); break; +- case 0xCA: BX_ERROR(("write cmd 0xCA (WRITE DMA) not supported"));command_aborted(0xCA); break; +- case 0xCC: BX_ERROR(("write cmd 0xCC (WRITE DMA QUEUED) not supported"));command_aborted(0xCC); break; +- case 0xCD: BX_ERROR(("write cmd 0xCD (CFA WRITE MULTIPLE W/OUT ERASE) not supported"));command_aborted(0xCD); break; +- case 0xD1: BX_ERROR(("write cmd 0xD1 (CHECK MEDIA CARD TYPE) not supported"));command_aborted(0xD1); break; +- case 0xDA: BX_ERROR(("write cmd 0xDA (GET MEDIA STATUS) not supported"));command_aborted(0xDA); break; +- case 0xDE: BX_ERROR(("write cmd 0xDE (MEDIA LOCK) not supported"));command_aborted(0xDE); break; +- case 0xDF: BX_ERROR(("write cmd 0xDF (MEDIA UNLOCK) not supported"));command_aborted(0xDF); break; +- case 0xE0: BX_ERROR(("write cmd 0xE0 (STANDBY IMMEDIATE) not supported"));command_aborted(0xE0); break; +- case 0xE1: BX_ERROR(("write cmd 0xE1 (IDLE IMMEDIATE) not supported"));command_aborted(0xE1); break; +- case 0xE2: BX_ERROR(("write cmd 0xE2 (STANDBY) not supported"));command_aborted(0xE2); break; +- case 0xE3: BX_ERROR(("write cmd 0xE3 (IDLE) not supported"));command_aborted(0xE3); break; +- case 0xE4: BX_ERROR(("write cmd 0xE4 (READ BUFFER) not supported"));command_aborted(0xE4); break; +- case 0xE6: BX_ERROR(("write cmd 0xE6 (SLEEP) not supported"));command_aborted(0xE6); break; +- case 0xE7: BX_ERROR(("write cmd 0xE7 (FLUSH CACHE) not supported"));command_aborted(0xE7); break; +- case 0xE8: BX_ERROR(("write cmd 0xE8 (WRITE BUFFER) not supported"));command_aborted(0xE8); break; +- case 0xEA: BX_ERROR(("write cmd 0xEA (FLUSH CACHE EXT) not supported"));command_aborted(0xEA); break; +- case 0xED: BX_ERROR(("write cmd 0xED (MEDIA EJECT) not supported"));command_aborted(0xED); break; +- case 0xF1: BX_ERROR(("write cmd 0xF1 (SECURITY SET PASSWORD) not supported"));command_aborted(0xF1); break; +- case 0xF2: BX_ERROR(("write cmd 0xF2 (SECURITY UNLOCK) not supported"));command_aborted(0xF2); break; +- case 0xF3: BX_ERROR(("write cmd 0xF3 (SECURITY ERASE PREPARE) not supported"));command_aborted(0xF3); break; +- case 0xF4: BX_ERROR(("write cmd 0xF4 (SECURITY ERASE UNIT) not supported"));command_aborted(0xF4); break; +- case 0xF5: BX_ERROR(("write cmd 0xF5 (SECURITY FREEZE LOCK) not supported"));command_aborted(0xF5); break; +- case 0xF6: BX_ERROR(("write cmd 0xF6 (SECURITY DISABLE PASSWORD) not supported"));command_aborted(0xF6); break; +- case 0xF8: BX_ERROR(("write cmd 0xF8 (READ NATIVE MAX ADDRESS) not supported"));command_aborted(0xF8); break; +- case 0xF9: BX_ERROR(("write cmd 0xF9 (SET MAX ADDRESS) not supported"));command_aborted(0xF9); break; ++ case 0x22: BX_ERROR(("write cmd 0x22 (READ LONG) not supported")); command_aborted(channel, 0x22); break; ++ case 0x23: BX_ERROR(("write cmd 0x23 (READ LONG NO RETRY) not supported")); command_aborted(channel, 0x23); break; ++ case 0x24: BX_ERROR(("write cmd 0x24 (READ SECTORS EXT) not supported"));command_aborted(channel, 0x24); break; ++ case 0x25: BX_ERROR(("write cmd 0x25 (READ DMA EXT) not supported"));command_aborted(channel, 0x25); break; ++ case 0x26: BX_ERROR(("write cmd 0x26 (READ DMA QUEUED EXT) not supported"));command_aborted(channel, 0x26); break; ++ case 0x27: BX_ERROR(("write cmd 0x27 (READ NATIVE MAX ADDRESS EXT) not supported"));command_aborted(channel, 0x27); break; ++ case 0x29: BX_ERROR(("write cmd 0x29 (READ MULTIPLE EXT) not supported"));command_aborted(channel, 0x29); break; ++ case 0x2A: BX_ERROR(("write cmd 0x2A (READ STREAM DMA) not supported"));command_aborted(channel, 0x2A); break; ++ case 0x2B: BX_ERROR(("write cmd 0x2B (READ STREAM PIO) not supported"));command_aborted(channel, 0x2B); break; ++ case 0x2F: BX_ERROR(("write cmd 0x2F (READ LOG EXT) not supported"));command_aborted(channel, 0x2F); break; ++ case 0x31: BX_ERROR(("write cmd 0x31 (WRITE SECTORS NO RETRY) not supported")); command_aborted(channel, 0x31); break; ++ case 0x32: BX_ERROR(("write cmd 0x32 (WRITE LONG) not supported")); command_aborted(channel, 0x32); break; ++ case 0x33: BX_ERROR(("write cmd 0x33 (WRITE LONG NO RETRY) not supported")); command_aborted(channel, 0x33); break; ++ case 0x34: BX_ERROR(("write cmd 0x34 (WRITE SECTORS EXT) not supported"));command_aborted(channel, 0x34); break; ++ case 0x35: BX_ERROR(("write cmd 0x35 (WRITE DMA EXT) not supported"));command_aborted(channel, 0x35); break; ++ case 0x36: BX_ERROR(("write cmd 0x36 (WRITE DMA QUEUED EXT) not supported"));command_aborted(channel, 0x36); break; ++ case 0x37: BX_ERROR(("write cmd 0x37 (SET MAX ADDRESS EXT) not supported"));command_aborted(channel, 0x37); break; ++ case 0x38: BX_ERROR(("write cmd 0x38 (CFA WRITE SECTORS W/OUT ERASE) not supported"));command_aborted(channel, 0x38); break; ++ case 0x39: BX_ERROR(("write cmd 0x39 (WRITE MULTIPLE EXT) not supported"));command_aborted(channel, 0x39); break; ++ case 0x3A: BX_ERROR(("write cmd 0x3A (WRITE STREAM DMA) not supported"));command_aborted(channel, 0x3A); break; ++ case 0x3B: BX_ERROR(("write cmd 0x3B (WRITE STREAM PIO) not supported"));command_aborted(channel, 0x3B); break; ++ case 0x3F: BX_ERROR(("write cmd 0x3F (WRITE LOG EXT) not supported"));command_aborted(channel, 0x3F); break; ++ case 0x41: BX_ERROR(("write cmd 0x41 (READ VERIFY SECTORS NO RETRY) not supported")); command_aborted(channel, 0x41); break; ++ case 0x42: BX_ERROR(("write cmd 0x42 (READ VERIFY SECTORS EXT) not supported"));command_aborted(channel, 0x42); break; ++ case 0x50: BX_ERROR(("write cmd 0x50 (FORMAT TRACK) not supported")); command_aborted(channel, 0x50); break; ++ case 0x51: BX_ERROR(("write cmd 0x51 (CONFIGURE STREAM) not supported"));command_aborted(channel, 0x51); break; ++ case 0x87: BX_ERROR(("write cmd 0x87 (CFA TRANSLATE SECTOR) not supported"));command_aborted(channel, 0x87); break; ++ case 0x92: BX_ERROR(("write cmd 0x92 (DOWNLOAD MICROCODE) not supported"));command_aborted(channel, 0x92); break; ++ case 0x94: BX_ERROR(("write cmd 0x94 (STANDBY IMMEDIATE) not supported")); command_aborted(channel, 0x94); break; ++ case 0x95: BX_ERROR(("write cmd 0x95 (IDLE IMMEDIATE) not supported")); command_aborted(channel, 0x95); break; ++ case 0x96: BX_ERROR(("write cmd 0x96 (STANDBY) not supported")); command_aborted(channel, 0x96); break; ++ case 0x97: BX_ERROR(("write cmd 0x97 (IDLE) not supported")); command_aborted(channel, 0x97); break; ++ case 0x98: BX_ERROR(("write cmd 0x98 (CHECK POWER MODE) not supported")); command_aborted(channel, 0x98); break; ++ case 0x99: BX_ERROR(("write cmd 0x99 (SLEEP) not supported")); command_aborted(channel, 0x99); break; ++ case 0xB0: BX_ERROR(("write cmd 0xB0 (SMART commands) not supported"));command_aborted(channel, 0xB0); break; ++ case 0xB1: BX_ERROR(("write cmd 0xB1 (DEVICE CONFIGURATION commands) not supported"));command_aborted(channel, 0xB1); break; ++ case 0xC0: BX_ERROR(("write cmd 0xC0 (CFA ERASE SECTORS) not supported"));command_aborted(channel, 0xC0); break; ++ case 0xC4: BX_ERROR(("write cmd 0xC4 (READ MULTIPLE) not supported"));command_aborted(channel, 0xC4); break; ++ case 0xC5: BX_ERROR(("write cmd 0xC5 (WRITE MULTIPLE) not supported"));command_aborted(channel, 0xC5); break; ++ case 0xC7: BX_ERROR(("write cmd 0xC7 (READ DMA QUEUED) not supported"));command_aborted(channel, 0xC7); break; ++ case 0xC8: BX_ERROR(("write cmd 0xC8 (READ DMA) not supported"));command_aborted(channel, 0xC8); break; ++ case 0xC9: BX_ERROR(("write cmd 0xC9 (READ DMA NO RETRY) not supported")); command_aborted(channel, 0xC9); break; ++ case 0xCA: BX_ERROR(("write cmd 0xCA (WRITE DMA) not supported"));command_aborted(channel, 0xCA); break; ++ case 0xCC: BX_ERROR(("write cmd 0xCC (WRITE DMA QUEUED) not supported"));command_aborted(channel, 0xCC); break; ++ case 0xCD: BX_ERROR(("write cmd 0xCD (CFA WRITE MULTIPLE W/OUT ERASE) not supported"));command_aborted(channel, 0xCD); break; ++ case 0xD1: BX_ERROR(("write cmd 0xD1 (CHECK MEDIA CARD TYPE) not supported"));command_aborted(channel, 0xD1); break; ++ case 0xDA: BX_ERROR(("write cmd 0xDA (GET MEDIA STATUS) not supported"));command_aborted(channel, 0xDA); break; ++ case 0xDE: BX_ERROR(("write cmd 0xDE (MEDIA LOCK) not supported"));command_aborted(channel, 0xDE); break; ++ case 0xDF: BX_ERROR(("write cmd 0xDF (MEDIA UNLOCK) not supported"));command_aborted(channel, 0xDF); break; ++ case 0xE0: BX_ERROR(("write cmd 0xE0 (STANDBY IMMEDIATE) not supported"));command_aborted(channel, 0xE0); break; ++ case 0xE1: BX_ERROR(("write cmd 0xE1 (IDLE IMMEDIATE) not supported"));command_aborted(channel, 0xE1); break; ++ case 0xE2: BX_ERROR(("write cmd 0xE2 (STANDBY) not supported"));command_aborted(channel, 0xE2); break; ++ case 0xE3: BX_ERROR(("write cmd 0xE3 (IDLE) not supported"));command_aborted(channel, 0xE3); break; ++ case 0xE4: BX_ERROR(("write cmd 0xE4 (READ BUFFER) not supported"));command_aborted(channel, 0xE4); break; ++ case 0xE6: BX_ERROR(("write cmd 0xE6 (SLEEP) not supported"));command_aborted(channel, 0xE6); break; ++ case 0xE7: BX_ERROR(("write cmd 0xE7 (FLUSH CACHE) not supported"));command_aborted(channel, 0xE7); break; ++ case 0xE8: BX_ERROR(("write cmd 0xE8 (WRITE BUFFER) not supported"));command_aborted(channel, 0xE8); break; ++ case 0xEA: BX_ERROR(("write cmd 0xEA (FLUSH CACHE EXT) not supported"));command_aborted(channel, 0xEA); break; ++ case 0xED: BX_ERROR(("write cmd 0xED (MEDIA EJECT) not supported"));command_aborted(channel, 0xED); break; ++ case 0xF1: BX_ERROR(("write cmd 0xF1 (SECURITY SET PASSWORD) not supported"));command_aborted(channel, 0xF1); break; ++ case 0xF2: BX_ERROR(("write cmd 0xF2 (SECURITY UNLOCK) not supported"));command_aborted(channel, 0xF2); break; ++ case 0xF3: BX_ERROR(("write cmd 0xF3 (SECURITY ERASE PREPARE) not supported"));command_aborted(channel, 0xF3); break; ++ case 0xF4: BX_ERROR(("write cmd 0xF4 (SECURITY ERASE UNIT) not supported"));command_aborted(channel, 0xF4); break; ++ case 0xF5: BX_ERROR(("write cmd 0xF5 (SECURITY FREEZE LOCK) not supported"));command_aborted(channel, 0xF5); break; ++ case 0xF6: BX_ERROR(("write cmd 0xF6 (SECURITY DISABLE PASSWORD) not supported"));command_aborted(channel, 0xF6); break; ++ case 0xF8: BX_ERROR(("write cmd 0xF8 (READ NATIVE MAX ADDRESS) not supported"));command_aborted(channel, 0xF8); break; ++ case 0xF9: BX_ERROR(("write cmd 0xF9 (SET MAX ADDRESS) not supported"));command_aborted(channel, 0xF9); break; + + default: + BX_PANIC(("IO write(1f7h): command 0x%02x", (unsigned) value)); + // if user foolishly decides to continue, abort the command + // so that the software knows the drive didn't understand it. +- command_aborted(value); ++ command_aborted(channel, value); + } + break; + +- case 0x3f6: // hard disk adapter control ++ case 0x16: // hard disk adapter control 0x3f6 + // (mch) Even if device 1 was selected, a write to this register + // goes to device 0 (if device 1 is absent) + +- prev_control_reset = BX_SELECTED_CONTROLLER.control.reset; +- BX_HD_THIS s[0].controller.control.reset = value & 0x04; +- BX_HD_THIS s[1].controller.control.reset = value & 0x04; +- // CGS: was: BX_SELECTED_CONTROLLER.control.disable_irq = value & 0x02; +- BX_HD_THIS s[0].controller.control.disable_irq = value & 0x02; +- BX_HD_THIS s[1].controller.control.disable_irq = value & 0x02; +- //BX_DEBUG(( "adpater control reg: reset controller = %d", +- // (unsigned) (BX_SELECTED_CONTROLLER.control.reset) ? 1 : 0 )); +- //BX_DEBUG(( "adpater control reg: disable_irq(14) = %d", +- // (unsigned) (BX_SELECTED_CONTROLLER.control.disable_irq) ? 1 : 0 )); +- if (!prev_control_reset && BX_SELECTED_CONTROLLER.control.reset) { ++ prev_control_reset = BX_SELECTED_CONTROLLER(channel).control.reset; ++ BX_HD_THIS channels[channel].drives[0].controller.control.reset = value & 0x04; ++ BX_HD_THIS channels[channel].drives[1].controller.control.reset = value & 0x04; ++ // CGS: was: BX_SELECTED_CONTROLLER(channel).control.disable_irq = value & 0x02; ++ BX_HD_THIS channels[channel].drives[0].controller.control.disable_irq = value & 0x02; ++ BX_HD_THIS channels[channel].drives[1].controller.control.disable_irq = value & 0x02; ++ ++ BX_DEBUG(( "adpater control reg: reset controller = %d", ++ (unsigned) (BX_SELECTED_CONTROLLER(channel).control.reset) ? 1 : 0 )); ++ BX_DEBUG(( "adpater control reg: disable_irq(X) = %d", ++ (unsigned) (BX_SELECTED_CONTROLLER(channel).control.disable_irq) ? 1 : 0 )); ++ ++ if (!prev_control_reset && BX_SELECTED_CONTROLLER(channel).control.reset) { + // transition from 0 to 1 causes all drives to reset + BX_DEBUG(("hard drive: RESET")); + + // (mch) Set BSY, drive not ready + for (int id = 0; id < 2; id++) { +- BX_CONTROLLER(id).status.busy = 1; +- BX_CONTROLLER(id).status.drive_ready = 0; +- BX_CONTROLLER(id).reset_in_progress = 1; ++ BX_CONTROLLER(channel,id).status.busy = 1; ++ BX_CONTROLLER(channel,id).status.drive_ready = 0; ++ BX_CONTROLLER(channel,id).reset_in_progress = 1; + +- BX_CONTROLLER(id).status.write_fault = 0; +- BX_CONTROLLER(id).status.seek_complete = 1; +- BX_CONTROLLER(id).status.drq = 0; +- BX_CONTROLLER(id).status.corrected_data = 0; +- BX_CONTROLLER(id).status.err = 0; ++ BX_CONTROLLER(channel,id).status.write_fault = 0; ++ BX_CONTROLLER(channel,id).status.seek_complete = 1; ++ BX_CONTROLLER(channel,id).status.drq = 0; ++ BX_CONTROLLER(channel,id).status.corrected_data = 0; ++ BX_CONTROLLER(channel,id).status.err = 0; + +- BX_CONTROLLER(id).error_register = 0x01; // diagnostic code: no error ++ BX_CONTROLLER(channel,id).error_register = 0x01; // diagnostic code: no error + +- BX_CONTROLLER(id).current_command = 0x00; +- BX_CONTROLLER(id).buffer_index = 0; ++ BX_CONTROLLER(channel,id).current_command = 0x00; ++ BX_CONTROLLER(channel,id).buffer_index = 0; + +- BX_CONTROLLER(id).sectors_per_block = 0x80; +- BX_CONTROLLER(id).lba_mode = 0; ++ BX_CONTROLLER(channel,id).sectors_per_block = 0x80; ++ BX_CONTROLLER(channel,id).lba_mode = 0; + +- BX_CONTROLLER(id).control.disable_irq = 0; ++ BX_CONTROLLER(channel,id).control.disable_irq = 0; + } +- } else if (BX_SELECTED_CONTROLLER.reset_in_progress && +- !BX_SELECTED_CONTROLLER.control.reset) { ++ } else if (BX_SELECTED_CONTROLLER(channel).reset_in_progress && ++ !BX_SELECTED_CONTROLLER(channel).control.reset) { + // Clear BSY and DRDY +- BX_DEBUG(("Reset complete {%s}", DEVICE_TYPE_STRING)); ++ BX_DEBUG(("Reset complete {%s}", BX_SELECTED_TYPE_STRING(channel))); + for (int id = 0; id < 2; id++) { +- BX_CONTROLLER(id).status.busy = 0; +- BX_CONTROLLER(id).status.drive_ready = 1; +- BX_CONTROLLER(id).reset_in_progress = 0; ++ BX_CONTROLLER(channel,id).status.busy = 0; ++ BX_CONTROLLER(channel,id).status.drive_ready = 1; ++ BX_CONTROLLER(channel,id).reset_in_progress = 0; + + // Device signature +- if (BX_HD_THIS s[id].device_type == IDE_DISK) { +- BX_CONTROLLER(id).head_no = 0; +- BX_CONTROLLER(id).sector_count = 1; +- BX_CONTROLLER(id).sector_no = 1; +- BX_CONTROLLER(id).cylinder_no = 0; ++ if (BX_DRIVE_IS_HD(channel,id)) { ++ BX_CONTROLLER(channel,id).head_no = 0; ++ BX_CONTROLLER(channel,id).sector_count = 1; ++ BX_CONTROLLER(channel,id).sector_no = 1; ++ BX_CONTROLLER(channel,id).cylinder_no = 0; + } else { +- BX_CONTROLLER(id).head_no = 0; +- BX_CONTROLLER(id).sector_count = 1; +- BX_CONTROLLER(id).sector_no = 1; +- BX_CONTROLLER(id).cylinder_no = 0xeb14; ++ BX_CONTROLLER(channel,id).head_no = 0; ++ BX_CONTROLLER(channel,id).sector_count = 1; ++ BX_CONTROLLER(channel,id).sector_no = 1; ++ BX_CONTROLLER(channel,id).cylinder_no = 0xeb14; + } + } + } +- BX_DEBUG(("s[0].controller.control.disable_irq = %02x", (BX_HD_THIS s[0]).controller.control.disable_irq)); +- BX_DEBUG(("s[1].controller.control.disable_irq = %02x", (BX_HD_THIS s[1]).controller.control.disable_irq)); ++ BX_DEBUG(("s[0].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[0]).controller.control.disable_irq)); ++ BX_DEBUG(("s[1].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[1]).controller.control.disable_irq)); + break; +-#if 0 +- // you'll need these to support second IDE controller, not needed yet. +- case 0x170: +- case 0x171: +- case 0x172: +- case 0x173: +- case 0x174: +- case 0x175: +- case 0x176: +- case 0x177: +- BX_DEBUG(("ignoring write to 0x%04x", address)); +- break; +-#endif + + default: + BX_PANIC(("hard drive: io write to address %x = %02x", +@@ -2132,30 +2191,32 @@ + void + bx_hard_drive_c::close_harddrive(void) + { +- BX_HD_THIS s[0].hard_drive->close(); +- BX_HD_THIS s[1].hard_drive->close(); ++ for (Bit8u channel=0; channelclose(); ++ BX_HD_THIS channels[channel].drives[1].hard_drive->close(); ++ } + } + + + Boolean +-bx_hard_drive_c::calculate_logical_address(Bit32u *sector) ++bx_hard_drive_c::calculate_logical_address(Bit8u channel, Bit32u *sector) + { + Bit32u logical_sector; + +- if (BX_SELECTED_CONTROLLER.lba_mode) { +- //bx_printf ("disk: calculate: %d %d %d\n", ((Bit32u)BX_SELECTED_CONTROLLER.head_no), ((Bit32u)BX_SELECTED_CONTROLLER.cylinder_no), (Bit32u)BX_SELECTED_CONTROLLER.sector_no); +- logical_sector = ((Bit32u)BX_SELECTED_CONTROLLER.head_no) << 24 | +- ((Bit32u)BX_SELECTED_CONTROLLER.cylinder_no) << 8 | +- (Bit32u)BX_SELECTED_CONTROLLER.sector_no; ++ if (BX_SELECTED_CONTROLLER(channel).lba_mode) { ++ //bx_printf ("disk: calculate: %d %d %d\n", ((Bit32u)BX_SELECTED_CONTROLLER(channel).head_no), ((Bit32u)BX_SELECTED_CONTROLLER(channel).cylinder_no), (Bit32u)BX_SELECTED_CONTROLLER(channel).sector_no); ++ logical_sector = ((Bit32u)BX_SELECTED_CONTROLLER(channel).head_no) << 24 | ++ ((Bit32u)BX_SELECTED_CONTROLLER(channel).cylinder_no) << 8 | ++ (Bit32u)BX_SELECTED_CONTROLLER(channel).sector_no; + //bx_printf ("disk: result: %u\n", logical_sector); + } else +- logical_sector = (BX_SELECTED_CONTROLLER.cylinder_no * BX_SELECTED_HD.hard_drive->heads * +- BX_SELECTED_HD.hard_drive->sectors) + +- (BX_SELECTED_CONTROLLER.head_no * BX_SELECTED_HD.hard_drive->sectors) + +- (BX_SELECTED_CONTROLLER.sector_no - 1); ++ logical_sector = (BX_SELECTED_CONTROLLER(channel).cylinder_no * BX_SELECTED_DRIVE(channel).hard_drive->heads * ++ BX_SELECTED_DRIVE(channel).hard_drive->sectors) + ++ (BX_SELECTED_CONTROLLER(channel).head_no * BX_SELECTED_DRIVE(channel).hard_drive->sectors) + ++ (BX_SELECTED_CONTROLLER(channel).sector_no - 1); + + if (logical_sector >= +- (BX_SELECTED_HD.hard_drive->cylinders * BX_SELECTED_HD.hard_drive->heads * BX_SELECTED_HD.hard_drive->sectors)) { ++ (BX_SELECTED_DRIVE(channel).hard_drive->cylinders * BX_SELECTED_DRIVE(channel).hard_drive->heads * BX_SELECTED_DRIVE(channel).hard_drive->sectors)) { + BX_ERROR (("calc_log_addr: out of bounds")); + return false; + } +@@ -2164,246 +2225,238 @@ + } + + void +-bx_hard_drive_c::increment_address() ++bx_hard_drive_c::increment_address(Bit8u channel) + { +- BX_SELECTED_CONTROLLER.sector_count--; ++ BX_SELECTED_CONTROLLER(channel).sector_count--; + +- if (BX_SELECTED_CONTROLLER.lba_mode) { ++ if (BX_SELECTED_CONTROLLER(channel).lba_mode) { + Bit32u current_address; +- calculate_logical_address(¤t_address); ++ calculate_logical_address(channel, ¤t_address); + current_address++; +- BX_SELECTED_CONTROLLER.head_no = (current_address >> 24) & 0xf; +- BX_SELECTED_CONTROLLER.cylinder_no = (current_address >> 8) & 0xffff; +- BX_SELECTED_CONTROLLER.sector_no = (current_address) & 0xff; ++ BX_SELECTED_CONTROLLER(channel).head_no = (current_address >> 24) & 0xf; ++ BX_SELECTED_CONTROLLER(channel).cylinder_no = (current_address >> 8) & 0xffff; ++ BX_SELECTED_CONTROLLER(channel).sector_no = (current_address) & 0xff; + } else { +- BX_SELECTED_CONTROLLER.sector_no++; +- if (BX_SELECTED_CONTROLLER.sector_no > BX_SELECTED_HD.hard_drive->sectors) { +- BX_SELECTED_CONTROLLER.sector_no = 1; +- BX_SELECTED_CONTROLLER.head_no++; +- if (BX_SELECTED_CONTROLLER.head_no >= BX_SELECTED_HD.hard_drive->heads) { +- BX_SELECTED_CONTROLLER.head_no = 0; +- BX_SELECTED_CONTROLLER.cylinder_no++; +- if (BX_SELECTED_CONTROLLER.cylinder_no >= BX_SELECTED_HD.hard_drive->cylinders) +- BX_SELECTED_CONTROLLER.cylinder_no = BX_SELECTED_HD.hard_drive->cylinders - 1; ++ BX_SELECTED_CONTROLLER(channel).sector_no++; ++ if (BX_SELECTED_CONTROLLER(channel).sector_no > BX_SELECTED_DRIVE(channel).hard_drive->sectors) { ++ BX_SELECTED_CONTROLLER(channel).sector_no = 1; ++ BX_SELECTED_CONTROLLER(channel).head_no++; ++ if (BX_SELECTED_CONTROLLER(channel).head_no >= BX_SELECTED_DRIVE(channel).hard_drive->heads) { ++ BX_SELECTED_CONTROLLER(channel).head_no = 0; ++ BX_SELECTED_CONTROLLER(channel).cylinder_no++; ++ if (BX_SELECTED_CONTROLLER(channel).cylinder_no >= BX_SELECTED_DRIVE(channel).hard_drive->cylinders) ++ BX_SELECTED_CONTROLLER(channel).cylinder_no = BX_SELECTED_DRIVE(channel).hard_drive->cylinders - 1; + } + } + } + } + + void +-bx_hard_drive_c::identify_ATAPI_drive(unsigned drive) ++bx_hard_drive_c::identify_ATAPI_drive(Bit8u channel) + { + unsigned i; + +- if (drive != (unsigned)BX_HD_THIS drive_select) { +- BX_PANIC(("identify_drive panic (drive != drive_select)")); +- } +- +- BX_SELECTED_HD.id_drive[0] = (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0); // Removable CDROM, 50us response, 12 byte packets ++ BX_SELECTED_DRIVE(channel).id_drive[0] = (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0); // Removable CDROM, 50us response, 12 byte packets + + for (i = 1; i <= 9; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0"; + for (i = 0; i < 10; i++) { +- BX_SELECTED_HD.id_drive[10+i] = (serial_number[i*2] << 8) | ++ BX_SELECTED_DRIVE(channel).id_drive[10+i] = (serial_number[i*2] << 8) | + serial_number[i*2 + 1]; + } + + for (i = 20; i <= 22; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + const char* firmware = "ALPHA1 "; + for (i = 0; i < strlen(firmware)/2; i++) { +- BX_SELECTED_HD.id_drive[23+i] = (firmware[i*2] << 8) | ++ BX_SELECTED_DRIVE(channel).id_drive[23+i] = (firmware[i*2] << 8) | + firmware[i*2 + 1]; + } + BX_ASSERT((23+i) == 27); + +- for (i = 0; i < strlen((char *) model_no)/2; i++) { +- BX_SELECTED_HD.id_drive[27+i] = (model_no[i*2] << 8) | +- model_no[i*2 + 1]; ++ for (i = 0; i < strlen((char *) BX_SELECTED_MODEL(channel))/2; i++) { ++ BX_SELECTED_DRIVE(channel).id_drive[27+i] = (BX_SELECTED_MODEL(channel)[i*2] << 8) | ++ BX_SELECTED_MODEL(channel)[i*2 + 1]; + } + BX_ASSERT((27+i) == 47); + +- BX_SELECTED_HD.id_drive[47] = 0; +- BX_SELECTED_HD.id_drive[48] = 1; // 32 bits access ++ BX_SELECTED_DRIVE(channel).id_drive[47] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[48] = 1; // 32 bits access + +- BX_SELECTED_HD.id_drive[49] = (1 << 9); // LBA supported ++ BX_SELECTED_DRIVE(channel).id_drive[49] = (1 << 9); // LBA supported + +- BX_SELECTED_HD.id_drive[50] = 0; +- BX_SELECTED_HD.id_drive[51] = 0; +- BX_SELECTED_HD.id_drive[52] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[50] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[51] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[52] = 0; + +- BX_SELECTED_HD.id_drive[53] = 3; // words 64-70, 54-58 valid ++ BX_SELECTED_DRIVE(channel).id_drive[53] = 3; // words 64-70, 54-58 valid + + for (i = 54; i <= 62; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + // copied from CFA540A +- BX_SELECTED_HD.id_drive[63] = 0x0103; // variable (DMA stuff) +- BX_SELECTED_HD.id_drive[64] = 0x0001; // PIO +- BX_SELECTED_HD.id_drive[65] = 0x00b4; +- BX_SELECTED_HD.id_drive[66] = 0x00b4; +- BX_SELECTED_HD.id_drive[67] = 0x012c; +- BX_SELECTED_HD.id_drive[68] = 0x00b4; +- +- BX_SELECTED_HD.id_drive[69] = 0; +- BX_SELECTED_HD.id_drive[70] = 0; +- BX_SELECTED_HD.id_drive[71] = 30; // faked +- BX_SELECTED_HD.id_drive[72] = 30; // faked +- BX_SELECTED_HD.id_drive[73] = 0; +- BX_SELECTED_HD.id_drive[74] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[63] = 0x0103; // variable (DMA stuff) ++ BX_SELECTED_DRIVE(channel).id_drive[64] = 0x0001; // PIO ++ BX_SELECTED_DRIVE(channel).id_drive[65] = 0x00b4; ++ BX_SELECTED_DRIVE(channel).id_drive[66] = 0x00b4; ++ BX_SELECTED_DRIVE(channel).id_drive[67] = 0x012c; ++ BX_SELECTED_DRIVE(channel).id_drive[68] = 0x00b4; ++ ++ BX_SELECTED_DRIVE(channel).id_drive[69] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[70] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[71] = 30; // faked ++ BX_SELECTED_DRIVE(channel).id_drive[72] = 30; // faked ++ BX_SELECTED_DRIVE(channel).id_drive[73] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[74] = 0; + +- BX_SELECTED_HD.id_drive[75] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[75] = 0; + + for (i = 76; i <= 79; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + +- BX_SELECTED_HD.id_drive[80] = 0x1e; // supports up to ATA/ATAPI-4 +- BX_SELECTED_HD.id_drive[81] = 0; +- BX_SELECTED_HD.id_drive[82] = 0; +- BX_SELECTED_HD.id_drive[83] = 0; +- BX_SELECTED_HD.id_drive[84] = 0; +- BX_SELECTED_HD.id_drive[85] = 0; +- BX_SELECTED_HD.id_drive[86] = 0; +- BX_SELECTED_HD.id_drive[87] = 0; +- BX_SELECTED_HD.id_drive[88] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[80] = 0x1e; // supports up to ATA/ATAPI-4 ++ BX_SELECTED_DRIVE(channel).id_drive[81] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[82] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[83] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[84] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[85] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[86] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[87] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[88] = 0; + + for (i = 89; i <= 126; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + +- BX_SELECTED_HD.id_drive[127] = 0; +- BX_SELECTED_HD.id_drive[128] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[127] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[128] = 0; + + for (i = 129; i <= 159; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + for (i = 160; i <= 255; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + // now convert the id_drive array (native 256 word format) to + // the controller buffer (512 bytes) + Bit16u temp16; + for (i = 0; i <= 255; i++) { +- temp16 = BX_SELECTED_HD.id_drive[i]; +- BX_SELECTED_CONTROLLER.buffer[i*2] = temp16 & 0x00ff; +- BX_SELECTED_CONTROLLER.buffer[i*2+1] = temp16 >> 8; ++ temp16 = BX_SELECTED_DRIVE(channel).id_drive[i]; ++ BX_SELECTED_CONTROLLER(channel).buffer[i*2] = temp16 & 0x00ff; ++ BX_SELECTED_CONTROLLER(channel).buffer[i*2+1] = temp16 >> 8; + } + } + + void +-bx_hard_drive_c::identify_drive(unsigned drive) ++bx_hard_drive_c::identify_drive(Bit8u channel) + { + unsigned i; + Bit32u temp32; + Bit16u temp16; + +- if (drive != BX_HD_THIS drive_select) { +- BX_PANIC(("identify_drive panic (drive != drive_select)")); +- } +- + #if defined(CONNER_CFA540A) +- BX_SELECTED_HD.id_drive[0] = 0x0c5a; +- BX_SELECTED_HD.id_drive[1] = 0x0418; +- BX_SELECTED_HD.id_drive[2] = 0; +- BX_SELECTED_HD.id_drive[3] = BX_SELECTED_HD.hard_drive->heads; +- BX_SELECTED_HD.id_drive[4] = 0x9fb7; +- BX_SELECTED_HD.id_drive[5] = 0x0289; +- BX_SELECTED_HD.id_drive[6] = BX_SELECTED_HD.hard_drive->sectors; +- BX_SELECTED_HD.id_drive[7] = 0x0030; +- BX_SELECTED_HD.id_drive[8] = 0x000a; +- BX_SELECTED_HD.id_drive[9] = 0x0000; ++ BX_SELECTED_DRIVE(channel).id_drive[0] = 0x0c5a; ++ BX_SELECTED_DRIVE(channel).id_drive[1] = 0x0418; ++ BX_SELECTED_DRIVE(channel).id_drive[2] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[3] = BX_SELECTED_DRIVE(channel).hard_drive->heads; ++ BX_SELECTED_DRIVE(channel).id_drive[4] = 0x9fb7; ++ BX_SELECTED_DRIVE(channel).id_drive[5] = 0x0289; ++ BX_SELECTED_DRIVE(channel).id_drive[6] = BX_SELECTED_DRIVE(channel).hard_drive->sectors; ++ BX_SELECTED_DRIVE(channel).id_drive[7] = 0x0030; ++ BX_SELECTED_DRIVE(channel).id_drive[8] = 0x000a; ++ BX_SELECTED_DRIVE(channel).id_drive[9] = 0x0000; + + char* serial_number = " CA00GSQ\0\0\0\0\0\0\0\0\0\0\0\0"; + for (i = 0; i < 10; i++) { +- BX_SELECTED_HD.id_drive[10+i] = (serial_number[i*2] << 8) | ++ BX_SELECTED_DRIVE(channel).id_drive[10+i] = (serial_number[i*2] << 8) | + serial_number[i*2 + 1]; + } + +- BX_SELECTED_HD.id_drive[20] = 3; +- BX_SELECTED_HD.id_drive[21] = 512; // 512 Sectors = 256kB cache +- BX_SELECTED_HD.id_drive[22] = 4; ++ BX_SELECTED_DRIVE(channel).id_drive[20] = 3; ++ BX_SELECTED_DRIVE(channel).id_drive[21] = 512; // 512 Sectors = 256kB cache ++ BX_SELECTED_DRIVE(channel).id_drive[22] = 4; + + char* firmware = "8FT054 "; + for (i = 0; i < strlen(firmware)/2; i++) { +- BX_SELECTED_HD.id_drive[23+i] = (firmware[i*2] << 8) | ++ BX_SELECTED_DRIVE(channel).id_drive[23+i] = (firmware[i*2] << 8) | + firmware[i*2 + 1]; + } + BX_ASSERT((23+i) == 27); + + char* model = "Conner Peripherals 540MB - CFA540A "; + for (i = 0; i < strlen(model)/2; i++) { +- BX_SELECTED_HD.id_drive[27+i] = (model[i*2] << 8) | ++ BX_SELECTED_DRIVE(channel).id_drive[27+i] = (model[i*2] << 8) | + model[i*2 + 1]; + } + BX_ASSERT((27+i) == 47); + +- BX_SELECTED_HD.id_drive[47] = 0x8080; // multiple mode identification +- BX_SELECTED_HD.id_drive[48] = 0; +- BX_SELECTED_HD.id_drive[49] = 0x0f01; +- +- BX_SELECTED_HD.id_drive[50] = 0; +- +- BX_SELECTED_HD.id_drive[51] = 0; +- BX_SELECTED_HD.id_drive[52] = 0x0002; +- BX_SELECTED_HD.id_drive[53] = 0x0003; +- BX_SELECTED_HD.id_drive[54] = 0x0418; +- +- BX_SELECTED_HD.id_drive[55] = BX_SELECTED_HD.hard_drive->heads; +- BX_SELECTED_HD.id_drive[56] = BX_SELECTED_HD.hard_drive->sectors; +- +- BX_SELECTED_HD.id_drive[57] = 0x1e80; +- BX_SELECTED_HD.id_drive[58] = 0x0010; +- BX_SELECTED_HD.id_drive[59] = 0x0100 | BX_SELECTED_CONTROLLER.sectors_per_block; +- BX_SELECTED_HD.id_drive[60] = 0x20e0; +- BX_SELECTED_HD.id_drive[61] = 0x0010; +- +- BX_SELECTED_HD.id_drive[62] = 0; +- +- BX_SELECTED_HD.id_drive[63] = 0x0103; // variable (DMA stuff) +- BX_SELECTED_HD.id_drive[64] = 0x0001; // PIO +- BX_SELECTED_HD.id_drive[65] = 0x00b4; +- BX_SELECTED_HD.id_drive[66] = 0x00b4; +- BX_SELECTED_HD.id_drive[67] = 0x012c; +- BX_SELECTED_HD.id_drive[68] = 0x00b4; ++ BX_SELECTED_DRIVE(channel).id_drive[47] = 0x8080; // multiple mode identification ++ BX_SELECTED_DRIVE(channel).id_drive[48] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[49] = 0x0f01; ++ ++ BX_SELECTED_DRIVE(channel).id_drive[50] = 0; ++ ++ BX_SELECTED_DRIVE(channel).id_drive[51] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[52] = 0x0002; ++ BX_SELECTED_DRIVE(channel).id_drive[53] = 0x0003; ++ BX_SELECTED_DRIVE(channel).id_drive[54] = 0x0418; ++ ++ BX_SELECTED_DRIVE(channel).id_drive[55] = BX_SELECTED_DRIVE(channel).hard_drive->heads; ++ BX_SELECTED_DRIVE(channel).id_drive[56] = BX_SELECTED_DRIVE(channel).hard_drive->sectors; ++ ++ BX_SELECTED_DRIVE(channel).id_drive[57] = 0x1e80; ++ BX_SELECTED_DRIVE(channel).id_drive[58] = 0x0010; ++ BX_SELECTED_DRIVE(channel).id_drive[59] = 0x0100 | BX_SELECTED_CONTROLLER(channel).sectors_per_block; ++ BX_SELECTED_DRIVE(channel).id_drive[60] = 0x20e0; ++ BX_SELECTED_DRIVE(channel).id_drive[61] = 0x0010; ++ ++ BX_SELECTED_DRIVE(channel).id_drive[62] = 0; ++ ++ BX_SELECTED_DRIVE(channel).id_drive[63] = 0x0103; // variable (DMA stuff) ++ BX_SELECTED_DRIVE(channel).id_drive[64] = 0x0001; // PIO ++ BX_SELECTED_DRIVE(channel).id_drive[65] = 0x00b4; ++ BX_SELECTED_DRIVE(channel).id_drive[66] = 0x00b4; ++ BX_SELECTED_DRIVE(channel).id_drive[67] = 0x012c; ++ BX_SELECTED_DRIVE(channel).id_drive[68] = 0x00b4; + + for (i = 69; i <= 79; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + +- BX_SELECTED_HD.id_drive[80] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[80] = 0; + +- BX_SELECTED_HD.id_drive[81] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[81] = 0; + +- BX_SELECTED_HD.id_drive[82] = 0; +- BX_SELECTED_HD.id_drive[83] = 0; +- BX_SELECTED_HD.id_drive[84] = 0; +- BX_SELECTED_HD.id_drive[85] = 0; +- BX_SELECTED_HD.id_drive[86] = 0; +- BX_SELECTED_HD.id_drive[87] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[82] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[83] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[84] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[85] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[86] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[87] = 0; + + for (i = 88; i <= 127; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + +- BX_SELECTED_HD.id_drive[128] = 0x0418; +- BX_SELECTED_HD.id_drive[129] = 0x103f; +- BX_SELECTED_HD.id_drive[130] = 0x0418; +- BX_SELECTED_HD.id_drive[131] = 0x103f; +- BX_SELECTED_HD.id_drive[132] = 0x0004; +- BX_SELECTED_HD.id_drive[133] = 0xffff; +- BX_SELECTED_HD.id_drive[134] = 0; +- BX_SELECTED_HD.id_drive[135] = 0x5050; ++ BX_SELECTED_DRIVE(channel).id_drive[128] = 0x0418; ++ BX_SELECTED_DRIVE(channel).id_drive[129] = 0x103f; ++ BX_SELECTED_DRIVE(channel).id_drive[130] = 0x0418; ++ BX_SELECTED_DRIVE(channel).id_drive[131] = 0x103f; ++ BX_SELECTED_DRIVE(channel).id_drive[132] = 0x0004; ++ BX_SELECTED_DRIVE(channel).id_drive[133] = 0xffff; ++ BX_SELECTED_DRIVE(channel).id_drive[134] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[135] = 0x5050; + + for (i = 136; i <= 144; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + +- BX_SELECTED_HD.id_drive[145] = 0x302e; +- BX_SELECTED_HD.id_drive[146] = 0x3245; +- BX_SELECTED_HD.id_drive[147] = 0x2020; +- BX_SELECTED_HD.id_drive[148] = 0x2020; ++ BX_SELECTED_DRIVE(channel).id_drive[145] = 0x302e; ++ BX_SELECTED_DRIVE(channel).id_drive[146] = 0x3245; ++ BX_SELECTED_DRIVE(channel).id_drive[147] = 0x2020; ++ BX_SELECTED_DRIVE(channel).id_drive[148] = 0x2020; + + for (i = 149; i <= 255; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + #else + +@@ -2433,36 +2486,36 @@ + // bit 2: 1=soft sectored + // bit 1: 1=hard sectored + // bit 0: 0=reserved +- BX_SELECTED_HD.id_drive[0] = 0x0040; ++ BX_SELECTED_DRIVE(channel).id_drive[0] = 0x0040; + + // Word 1: number of user-addressable cylinders in + // default translation mode. If the value in words 60-61 + // exceed 16,515,072, this word shall contain 16,383. +- BX_SELECTED_HD.id_drive[1] = BX_SELECTED_HD.hard_drive->cylinders; ++ BX_SELECTED_DRIVE(channel).id_drive[1] = BX_SELECTED_DRIVE(channel).hard_drive->cylinders; + + // Word 2: reserved +- BX_SELECTED_HD.id_drive[2] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[2] = 0; + + // Word 3: number of user-addressable heads in default + // translation mode +- BX_SELECTED_HD.id_drive[3] = BX_SELECTED_HD.hard_drive->heads; ++ BX_SELECTED_DRIVE(channel).id_drive[3] = BX_SELECTED_DRIVE(channel).hard_drive->heads; + + // Word 4: # unformatted bytes per translated track in default xlate mode + // Word 5: # unformatted bytes per sector in default xlated mode + // Word 6: # user-addressable sectors per track in default xlate mode + // Note: words 4,5 are now "Vendor specific (obsolete)" +- BX_SELECTED_HD.id_drive[4] = (512 * BX_SELECTED_HD.hard_drive->sectors); +- BX_SELECTED_HD.id_drive[5] = 512; +- BX_SELECTED_HD.id_drive[6] = BX_SELECTED_HD.hard_drive->sectors; ++ BX_SELECTED_DRIVE(channel).id_drive[4] = (512 * BX_SELECTED_DRIVE(channel).hard_drive->sectors); ++ BX_SELECTED_DRIVE(channel).id_drive[5] = 512; ++ BX_SELECTED_DRIVE(channel).id_drive[6] = BX_SELECTED_DRIVE(channel).hard_drive->sectors; + + // Word 7-9: Vendor specific + for (i=7; i<=9; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + // Word 10-19: Serial number (20 ASCII characters, 0000h=not specified) + // This field is right justified and padded with spaces (20h). + for (i=10; i<=19; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + // Word 20: buffer type + // 0000h = not specified +@@ -2475,92 +2528,92 @@ + // simulatenous data xfers with a read caching + // capability. + // 0004h-ffffh = reserved +- BX_SELECTED_HD.id_drive[20] = 3; ++ BX_SELECTED_DRIVE(channel).id_drive[20] = 3; + + // Word 21: buffer size in 512 byte increments, 0000h = not specified +- BX_SELECTED_HD.id_drive[21] = 512; // 512 Sectors = 256kB cache ++ BX_SELECTED_DRIVE(channel).id_drive[21] = 512; // 512 Sectors = 256kB cache + + // Word 22: # of ECC bytes available on read/write long cmds + // 0000h = not specified +- BX_SELECTED_HD.id_drive[22] = 4; ++ BX_SELECTED_DRIVE(channel).id_drive[22] = 4; + + // Word 23..26: Firmware revision (8 ascii chars, 0000h=not specified) + // This field is left justified and padded with spaces (20h) + for (i=23; i<=26; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + // Word 27..46: Model number (40 ascii chars, 0000h=not specified) + // This field is left justified and padded with spaces (20h) + // for (i=27; i<=46; i++) +-// BX_SELECTED_HD.id_drive[i] = 0; ++// BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + for (i=0; i<20; i++) { +- BX_SELECTED_HD.id_drive[27+i] = (model_no[i*2] << 8) | +- model_no[i*2 + 1]; ++ BX_SELECTED_DRIVE(channel).id_drive[27+i] = (BX_SELECTED_MODEL(channel)[i*2] << 8) | ++ BX_SELECTED_MODEL(channel)[i*2 + 1]; + } + + // Word 47: 15-8 Vendor unique + // 7-0 00h= read/write multiple commands not implemented + // xxh= maximum # of sectors that can be transferred + // per interrupt on read and write multiple commands +- BX_SELECTED_HD.id_drive[47] = max_multiple_sectors; ++ BX_SELECTED_DRIVE(channel).id_drive[47] = max_multiple_sectors; + + // Word 48: 0000h = cannot perform dword IO + // 0001h = can perform dword IO +- BX_SELECTED_HD.id_drive[48] = 1; ++ BX_SELECTED_DRIVE(channel).id_drive[48] = 1; + + // Word 49: Capabilities + // 15-10: 0 = reserved + // 9: 1 = LBA supported + // 8: 1 = DMA supported + // 7-0: Vendor unique +- BX_SELECTED_HD.id_drive[49] = 1<<9; ++ BX_SELECTED_DRIVE(channel).id_drive[49] = 1<<9; + + // Word 50: Reserved +- BX_SELECTED_HD.id_drive[50] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[50] = 0; + + // Word 51: 15-8 PIO data transfer cycle timing mode + // 7-0 Vendor unique +- BX_SELECTED_HD.id_drive[51] = 0x200; ++ BX_SELECTED_DRIVE(channel).id_drive[51] = 0x200; + + // Word 52: 15-8 DMA data transfer cycle timing mode + // 7-0 Vendor unique +- BX_SELECTED_HD.id_drive[52] = 0x200; ++ BX_SELECTED_DRIVE(channel).id_drive[52] = 0x200; + + // Word 53: 15-1 Reserved + // 0 1=the fields reported in words 54-58 are valid + // 0=the fields reported in words 54-58 may be valid +- BX_SELECTED_HD.id_drive[53] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[53] = 0; + + // Word 54: # of user-addressable cylinders in curr xlate mode + // Word 55: # of user-addressable heads in curr xlate mode + // Word 56: # of user-addressable sectors/track in curr xlate mode +- BX_SELECTED_HD.id_drive[54] = BX_SELECTED_HD.hard_drive->cylinders; +- BX_SELECTED_HD.id_drive[55] = BX_SELECTED_HD.hard_drive->heads; +- BX_SELECTED_HD.id_drive[56] = BX_SELECTED_HD.hard_drive->sectors; ++ BX_SELECTED_DRIVE(channel).id_drive[54] = BX_SELECTED_DRIVE(channel).hard_drive->cylinders; ++ BX_SELECTED_DRIVE(channel).id_drive[55] = BX_SELECTED_DRIVE(channel).hard_drive->heads; ++ BX_SELECTED_DRIVE(channel).id_drive[56] = BX_SELECTED_DRIVE(channel).hard_drive->sectors; + + // Word 57-58: Current capacity in sectors + // Excludes all sectors used for device specific purposes. + temp32 = +- BX_SELECTED_HD.hard_drive->cylinders * +- BX_SELECTED_HD.hard_drive->heads * +- BX_SELECTED_HD.hard_drive->sectors; +- BX_SELECTED_HD.id_drive[57] = (temp32 & 0xffff); // LSW +- BX_SELECTED_HD.id_drive[58] = (temp32 >> 16); // MSW ++ BX_SELECTED_DRIVE(channel).hard_drive->cylinders * ++ BX_SELECTED_DRIVE(channel).hard_drive->heads * ++ BX_SELECTED_DRIVE(channel).hard_drive->sectors; ++ BX_SELECTED_DRIVE(channel).id_drive[57] = (temp32 & 0xffff); // LSW ++ BX_SELECTED_DRIVE(channel).id_drive[58] = (temp32 >> 16); // MSW + + // Word 59: 15-9 Reserved + // 8 1=multiple sector setting is valid + // 7-0 current setting for number of sectors that can be + // transferred per interrupt on R/W multiple commands +- BX_SELECTED_HD.id_drive[59] = 0x0000 | curr_multiple_sectors; ++ BX_SELECTED_DRIVE(channel).id_drive[59] = 0x0000 | curr_multiple_sectors; + + // Word 60-61: + // If drive supports LBA Mode, these words reflect total # of user + // addressable sectors. This value does not depend on the current + // drive geometry. If the drive does not support LBA mode, these + // words shall be set to 0. +- Bit32u num_sects = BX_SELECTED_HD.hard_drive->cylinders * BX_SELECTED_HD.hard_drive->heads * BX_SELECTED_HD.hard_drive->sectors; +- BX_SELECTED_HD.id_drive[60] = num_sects & 0xffff; // LSW +- BX_SELECTED_HD.id_drive[61] = num_sects >> 16; // MSW ++ Bit32u num_sects = BX_SELECTED_DRIVE(channel).hard_drive->cylinders * BX_SELECTED_DRIVE(channel).hard_drive->heads * BX_SELECTED_DRIVE(channel).hard_drive->sectors; ++ BX_SELECTED_DRIVE(channel).id_drive[60] = num_sects & 0xffff; // LSW ++ BX_SELECTED_DRIVE(channel).id_drive[61] = num_sects >> 16; // MSW + + // Word 62: 15-8 single word DMA transfer mode active + // 7-0 single word DMA transfer modes supported +@@ -2568,7 +2621,7 @@ + // supported e.g., if Mode 0 is supported bit 0 is set. + // The high order byte contains a single bit set to indiciate + // which mode is active. +- BX_SELECTED_HD.id_drive[62] = 0x0; ++ BX_SELECTED_DRIVE(channel).id_drive[62] = 0x0; + + // Word 63: 15-8 multiword DMA transfer mode active + // 7-0 multiword DMA transfer modes supported +@@ -2576,11 +2629,11 @@ + // supported e.g., if Mode 0 is supported bit 0 is set. + // The high order byte contains a single bit set to indiciate + // which mode is active. +- BX_SELECTED_HD.id_drive[63] = 0x0; ++ BX_SELECTED_DRIVE(channel).id_drive[63] = 0x0; + + // Word 64-79 Reserved + for (i=64; i<=79; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + // Word 80: 15-5 reserved + // 4 supports ATA/ATAPI-4 +@@ -2588,10 +2641,10 @@ + // 2 supports ATA-2 + // 1 supports ATA-1 + // 0 reserved +- BX_SELECTED_HD.id_drive[80] = (1 << 2) | (1 << 1); ++ BX_SELECTED_DRIVE(channel).id_drive[80] = (1 << 2) | (1 << 1); + + // Word 81: Minor version number +- BX_SELECTED_HD.id_drive[81] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[81] = 0; + + // Word 82: 15 obsolete + // 14 NOP command supported +@@ -2609,226 +2662,257 @@ + // 2 supports removable media feature set + // 1 supports securite mode feature set + // 0 support SMART feature set +- BX_SELECTED_HD.id_drive[82] = 1 << 14; +- BX_SELECTED_HD.id_drive[83] = 1 << 14; +- BX_SELECTED_HD.id_drive[84] = 1 << 14; +- BX_SELECTED_HD.id_drive[85] = 1 << 14; +- BX_SELECTED_HD.id_drive[86] = 0; +- BX_SELECTED_HD.id_drive[87] = 1 << 14; ++ BX_SELECTED_DRIVE(channel).id_drive[82] = 1 << 14; ++ BX_SELECTED_DRIVE(channel).id_drive[83] = 1 << 14; ++ BX_SELECTED_DRIVE(channel).id_drive[84] = 1 << 14; ++ BX_SELECTED_DRIVE(channel).id_drive[85] = 1 << 14; ++ BX_SELECTED_DRIVE(channel).id_drive[86] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[87] = 1 << 14; + + for (i=88; i<=127; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + // Word 128-159 Vendor unique + for (i=128; i<=159; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + // Word 160-255 Reserved + for (i=160; i<=255; i++) +- BX_SELECTED_HD.id_drive[i] = 0; ++ BX_SELECTED_DRIVE(channel).id_drive[i] = 0; + + #endif + +- BX_DEBUG(("Drive ID Info. initialized : %04d {%s}", 512, DEVICE_TYPE_STRING)); ++ BX_DEBUG(("Drive ID Info. initialized : %04d {%s}", 512, BX_SELECTED_TYPE_STRING(channel))); + + // now convert the id_drive array (native 256 word format) to + // the controller buffer (512 bytes) + for (i=0; i<=255; i++) { +- temp16 = BX_SELECTED_HD.id_drive[i]; +- BX_SELECTED_CONTROLLER.buffer[i*2] = temp16 & 0x00ff; +- BX_SELECTED_CONTROLLER.buffer[i*2+1] = temp16 >> 8; ++ temp16 = BX_SELECTED_DRIVE(channel).id_drive[i]; ++ BX_SELECTED_CONTROLLER(channel).buffer[i*2] = temp16 & 0x00ff; ++ BX_SELECTED_CONTROLLER(channel).buffer[i*2+1] = temp16 >> 8; + } + } + + void +-bx_hard_drive_c::init_send_atapi_command(Bit8u command, int req_length, int alloc_length, bool lazy) ++bx_hard_drive_c::init_send_atapi_command(Bit8u channel, Bit8u command, int req_length, int alloc_length, bool lazy) + { +- // BX_SELECTED_CONTROLLER.byte_count is a union of BX_SELECTED_CONTROLLER.cylinder_no; ++ // BX_SELECTED_CONTROLLER(channel).byte_count is a union of BX_SELECTED_CONTROLLER(channel).cylinder_no; + // lazy is used to force a data read in the buffer at the next read. + +- if (BX_SELECTED_CONTROLLER.byte_count == 0xffff) +- BX_SELECTED_CONTROLLER.byte_count = 0xfffe; ++ if (BX_SELECTED_CONTROLLER(channel).byte_count == 0xffff) ++ BX_SELECTED_CONTROLLER(channel).byte_count = 0xfffe; + +- if ((BX_SELECTED_CONTROLLER.byte_count & 1) +- && !(alloc_length <= BX_SELECTED_CONTROLLER.byte_count)) { ++ if ((BX_SELECTED_CONTROLLER(channel).byte_count & 1) ++ && !(alloc_length <= BX_SELECTED_CONTROLLER(channel).byte_count)) { + BX_INFO(("Odd byte count (0x%04x) to ATAPI command 0x%02x, using 0x%04x", +- BX_SELECTED_CONTROLLER.byte_count, command, BX_SELECTED_CONTROLLER.byte_count - 1)); +- BX_SELECTED_CONTROLLER.byte_count -= 1; ++ BX_SELECTED_CONTROLLER(channel).byte_count, command, BX_SELECTED_CONTROLLER(channel).byte_count - 1)); ++ BX_SELECTED_CONTROLLER(channel).byte_count -= 1; + } + +- if (BX_SELECTED_CONTROLLER.byte_count == 0) ++ if (BX_SELECTED_CONTROLLER(channel).byte_count == 0) + BX_PANIC(("ATAPI command with zero byte count")); + + if (alloc_length < 0) + BX_PANIC(("Allocation length < 0")); + if (alloc_length == 0) +- alloc_length = BX_SELECTED_CONTROLLER.byte_count; ++ alloc_length = BX_SELECTED_CONTROLLER(channel).byte_count; + +- BX_SELECTED_CONTROLLER.interrupt_reason.i_o = 1; +- BX_SELECTED_CONTROLLER.interrupt_reason.c_d = 0; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drq = 1; +- BX_SELECTED_CONTROLLER.status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 1; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; + + // no bytes transfered yet + if (lazy) +- BX_SELECTED_CONTROLLER.buffer_index = 2048; ++ BX_SELECTED_CONTROLLER(channel).buffer_index = 2048; + else +- BX_SELECTED_CONTROLLER.buffer_index = 0; +- BX_SELECTED_CONTROLLER.drq_index = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer_index = 0; ++ BX_SELECTED_CONTROLLER(channel).drq_index = 0; + +- if (BX_SELECTED_CONTROLLER.byte_count > req_length) +- BX_SELECTED_CONTROLLER.byte_count = req_length; ++ if (BX_SELECTED_CONTROLLER(channel).byte_count > req_length) ++ BX_SELECTED_CONTROLLER(channel).byte_count = req_length; + +- if (BX_SELECTED_CONTROLLER.byte_count > alloc_length) +- BX_SELECTED_CONTROLLER.byte_count = alloc_length; ++ if (BX_SELECTED_CONTROLLER(channel).byte_count > alloc_length) ++ BX_SELECTED_CONTROLLER(channel).byte_count = alloc_length; + +- BX_SELECTED_HD.atapi.command = command; +- BX_SELECTED_HD.atapi.drq_bytes = BX_SELECTED_CONTROLLER.byte_count; +- BX_SELECTED_HD.atapi.total_bytes_remaining = (req_length < alloc_length) ? req_length : alloc_length; ++ BX_SELECTED_DRIVE(channel).atapi.command = command; ++ BX_SELECTED_DRIVE(channel).atapi.drq_bytes = BX_SELECTED_CONTROLLER(channel).byte_count; ++ BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining = (req_length < alloc_length) ? req_length : alloc_length; + + // if (lazy) { + // // bias drq_bytes and total_bytes_remaining +- // BX_SELECTED_HD.atapi.drq_bytes += 2048; +- // BX_SELECTED_HD.atapi.total_bytes_remaining += 2048; ++ // BX_SELECTED_DRIVE(channel).atapi.drq_bytes += 2048; ++ // BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining += 2048; + // } + } + + void +-bx_hard_drive_c::atapi_cmd_error(sense_t sense_key, asc_t asc) ++bx_hard_drive_c::atapi_cmd_error(Bit8u channel, sense_t sense_key, asc_t asc) + { +- BX_SELECTED_CONTROLLER.error_register = sense_key << 4; +- BX_SELECTED_CONTROLLER.interrupt_reason.i_o = 1; +- BX_SELECTED_CONTROLLER.interrupt_reason.c_d = 1; +- BX_SELECTED_CONTROLLER.interrupt_reason.rel = 0; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.write_fault = 0; +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.err = 1; +- +- BX_SELECTED_HD.sense.sense_key = sense_key; +- BX_SELECTED_HD.sense.asc = asc; +- BX_SELECTED_HD.sense.ascq = 0; ++ BX_ERROR(("atapi_cmd_error channel=%02x key=%02x asc=%02x", channel, sense_key, asc)); ++ ++ BX_SELECTED_CONTROLLER(channel).error_register = sense_key << 4; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 1; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.rel = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.write_fault = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 1; ++ ++ BX_SELECTED_DRIVE(channel).sense.sense_key = sense_key; ++ BX_SELECTED_DRIVE(channel).sense.asc = asc; ++ BX_SELECTED_DRIVE(channel).sense.ascq = 0; + } + + void +-bx_hard_drive_c::atapi_cmd_nop() ++bx_hard_drive_c::atapi_cmd_nop(Bit8u channel) + { +- BX_SELECTED_CONTROLLER.interrupt_reason.i_o = 1; +- BX_SELECTED_CONTROLLER.interrupt_reason.c_d = 1; +- BX_SELECTED_CONTROLLER.interrupt_reason.rel = 0; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.err = 0; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 1; ++ BX_SELECTED_CONTROLLER(channel).interrupt_reason.rel = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.err = 0; + } + + void +-bx_hard_drive_c::init_mode_sense_single(const void* src, int size) ++bx_hard_drive_c::init_mode_sense_single(Bit8u channel, const void* src, int size) + { + // Header +- BX_SELECTED_CONTROLLER.buffer[0] = (size+6) >> 8; +- BX_SELECTED_CONTROLLER.buffer[1] = (size+6) & 0xff; +- BX_SELECTED_CONTROLLER.buffer[2] = 0x70; // no media present +- BX_SELECTED_CONTROLLER.buffer[3] = 0; // reserved +- BX_SELECTED_CONTROLLER.buffer[4] = 0; // reserved +- BX_SELECTED_CONTROLLER.buffer[5] = 0; // reserved +- BX_SELECTED_CONTROLLER.buffer[6] = 0; // reserved +- BX_SELECTED_CONTROLLER.buffer[7] = 0; // reserved ++ BX_SELECTED_CONTROLLER(channel).buffer[0] = (size+6) >> 8; ++ BX_SELECTED_CONTROLLER(channel).buffer[1] = (size+6) & 0xff; ++ BX_SELECTED_CONTROLLER(channel).buffer[2] = 0x70; // no media present ++ BX_SELECTED_CONTROLLER(channel).buffer[3] = 0; // reserved ++ BX_SELECTED_CONTROLLER(channel).buffer[4] = 0; // reserved ++ BX_SELECTED_CONTROLLER(channel).buffer[5] = 0; // reserved ++ BX_SELECTED_CONTROLLER(channel).buffer[6] = 0; // reserved ++ BX_SELECTED_CONTROLLER(channel).buffer[7] = 0; // reserved + + // Data +- memcpy(BX_SELECTED_CONTROLLER.buffer + 8, src, size); ++ memcpy(BX_SELECTED_CONTROLLER(channel).buffer + 8, src, size); + } + + void +-bx_hard_drive_c::ready_to_send_atapi() ++bx_hard_drive_c::ready_to_send_atapi(Bit8u channel) + { +- raise_interrupt(); ++ raise_interrupt(channel); + } + + void +-bx_hard_drive_c::raise_interrupt() ++bx_hard_drive_c::raise_interrupt(Bit8u channel) + { +- BX_DEBUG(("raise_interrupt called, disable_irq = %02x", BX_SELECTED_CONTROLLER.control.disable_irq)); +- if (!BX_SELECTED_CONTROLLER.control.disable_irq) { BX_DEBUG(("raising interrupt")); } else { BX_DEBUG(("Not raising interrupt")); } +- if (!BX_SELECTED_CONTROLLER.control.disable_irq) { +- Bit32u irq = 14; // always 1st IDE controller +- // for second controller, you would want irq 15 +- BX_DEBUG(("Raising interrupt %d {%s}", irq, DEVICE_TYPE_STRING)); ++ BX_DEBUG(("raise_interrupt called, disable_irq = %02x", BX_SELECTED_CONTROLLER(channel).control.disable_irq)); ++ if (!BX_SELECTED_CONTROLLER(channel).control.disable_irq) { BX_DEBUG(("raising interrupt")); } else { BX_DEBUG(("Not raising interrupt")); } ++ if (!BX_SELECTED_CONTROLLER(channel).control.disable_irq) { ++ Bit32u irq = BX_HD_THIS channels[channel].irq; ++ BX_DEBUG(("Raising interrupt %d {%s}", irq, BX_SELECTED_TYPE_STRING(channel))); + BX_HD_THIS devices->pic->raise_irq(irq); + } else { +- if (bx_dbg.disk || (CDROM_SELECTED && bx_dbg.cdrom)) +- BX_INFO(("Interrupt masked {%s}", DEVICE_TYPE_STRING)); ++ if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) ++ BX_INFO(("Interrupt masked {%s}", BX_SELECTED_TYPE_STRING(channel))); + } + } + + void +-bx_hard_drive_c::command_aborted(unsigned value) ++bx_hard_drive_c::command_aborted(Bit8u channel, unsigned value) + { +- BX_DEBUG(("aborting on command 0x%02x {%s}", value, DEVICE_TYPE_STRING)); +- BX_SELECTED_CONTROLLER.current_command = 0; +- BX_SELECTED_CONTROLLER.status.busy = 0; +- BX_SELECTED_CONTROLLER.status.drive_ready = 1; +- BX_SELECTED_CONTROLLER.status.err = 1; +- BX_SELECTED_CONTROLLER.error_register = 0x04; // command ABORTED +- BX_SELECTED_CONTROLLER.status.drq = 0; +- BX_SELECTED_CONTROLLER.status.seek_complete = 0; +- BX_SELECTED_CONTROLLER.status.corrected_data = 0; +- BX_SELECTED_CONTROLLER.buffer_index = 0; +- raise_interrupt(); ++ BX_DEBUG(("aborting on command 0x%02x {%s}", value, BX_SELECTED_TYPE_STRING(channel))); ++ BX_SELECTED_CONTROLLER(channel).current_command = 0; ++ BX_SELECTED_CONTROLLER(channel).status.busy = 0; ++ BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1; ++ BX_SELECTED_CONTROLLER(channel).status.err = 1; ++ BX_SELECTED_CONTROLLER(channel).error_register = 0x04; // command ABORTED ++ BX_SELECTED_CONTROLLER(channel).status.drq = 0; ++ BX_SELECTED_CONTROLLER(channel).status.seek_complete = 0; ++ BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0; ++ BX_SELECTED_CONTROLLER(channel).buffer_index = 0; ++ raise_interrupt(channel); ++} ++ ++ Bit32u ++bx_hard_drive_c::get_device_handle(Bit8u channel, Bit8u device) ++{ ++ BX_INFO(("get_device_handle %d %d",channel, device)); ++ if ((channel < BX_MAX_ATA_CHANNEL) && (device < 2)) { ++ return ((channel*2) + device); ++ } ++ ++ return BX_MAX_ATA_CHANNEL*2; ++} ++ ++ Bit32u ++bx_hard_drive_c::get_first_cd_handle(void) ++{ ++ for (Bit8u channel=0; channel= BX_MAX_ATA_CHANNEL*2 ) return 0; ++ ++ Bit8u channel = handle / 2; ++ Bit8u device = handle % 2; ++ return( BX_HD_THIS channels[channel].drives[device].cdrom.ready ); + } + + unsigned +-bx_hard_drive_c::set_cd_media_status(unsigned status) ++bx_hard_drive_c::set_cd_media_status(Bit32u handle, unsigned status) + { ++ if ( handle >= BX_MAX_ATA_CHANNEL*2 ) return 0; ++ ++ Bit8u channel = handle / 2; ++ Bit8u device = handle % 2; ++ + // if setting to the current value, nothing to do +- if (status == BX_HD_THIS s[1].cdrom.ready) ++ if (status == BX_HD_THIS channels[channel].drives[device].cdrom.ready) + return(status); + // return 0 if no cdromd is present +- if (!bx_options.cdromd.Opresent->get()) ++ if (!BX_DRIVE_IS_CD(channel,device)) + return(0); + + if (status == 0) { + // eject cdrom if not locked by guest OS +- if (BX_HD_THIS s[1].cdrom.locked) return(1); ++ if (BX_HD_THIS channels[channel].drives[device].cdrom.locked) return(1); + else { + #ifdef LOWLEVEL_CDROM +- BX_HD_THIS s[1].cdrom.cd->eject_cdrom(); ++ BX_HD_THIS channels[channel].drives[device].cdrom.cd->eject_cdrom(); + #endif +- BX_HD_THIS s[1].cdrom.ready = 0; +- bx_options.cdromd.Ostatus->set(BX_EJECTED); ++ BX_HD_THIS channels[channel].drives[device].cdrom.ready = 0; ++ bx_options.atadevice[channel][device].Ostatus->set(BX_EJECTED); + } + } + else { + // insert cdrom + #ifdef LOWLEVEL_CDROM +- if (BX_HD_THIS s[1].cdrom.cd->insert_cdrom(bx_options.cdromd.Opath->getptr())) { ++ if (BX_HD_THIS channels[channel].drives[device].cdrom.cd->insert_cdrom(bx_options.atadevice[channel][device].Opath->getptr())) { + BX_INFO(( "Media present in CD-ROM drive")); +- BX_HD_THIS s[1].cdrom.ready = 1; +- BX_HD_THIS s[1].cdrom.capacity = BX_HD_THIS s[1].cdrom.cd->capacity(); +- bx_options.cdromd.Ostatus->set(BX_INSERTED); +- BX_SELECTED_HD.sense.sense_key = SENSE_UNIT_ATTENTION; +- BX_SELECTED_HD.sense.asc = 0; +- BX_SELECTED_HD.sense.ascq = 0; +- raise_interrupt(); ++ BX_HD_THIS channels[channel].drives[device].cdrom.ready = 1; ++ BX_HD_THIS channels[channel].drives[device].cdrom.capacity = BX_HD_THIS channels[channel].drives[device].cdrom.cd->capacity(); ++ bx_options.atadevice[channel][device].Ostatus->set(BX_INSERTED); ++ BX_SELECTED_DRIVE(channel).sense.sense_key = SENSE_UNIT_ATTENTION; ++ BX_SELECTED_DRIVE(channel).sense.asc = 0; ++ BX_SELECTED_DRIVE(channel).sense.ascq = 0; ++ raise_interrupt(channel); + } + else { + #endif + BX_INFO(( "Could not locate CD-ROM, continuing with media not present")); +- BX_HD_THIS s[1].cdrom.ready = 0; +- bx_options.cdromd.Ostatus->set(BX_EJECTED); ++ BX_HD_THIS channels[channel].drives[device].cdrom.ready = 0; ++ bx_options.atadevice[channel][device].Ostatus->set(BX_EJECTED); + #ifdef LOWLEVEL_CDROM + } + #endif + } +- return( BX_HD_THIS s[1].cdrom.ready ); ++ return( BX_HD_THIS channels[channel].drives[device].cdrom.ready ); + } + + +Index: iodev/harddrv.h +=================================================================== +RCS file: /cvsroot/bochs/bochs/iodev/harddrv.h,v +retrieving revision 1.13 +diff -u -r1.13 harddrv.h +--- iodev/harddrv.h 12 Sep 2002 06:49:04 -0000 1.13 ++++ iodev/harddrv.h 14 Sep 2002 07:27:57 -0000 +@@ -184,7 +184,6 @@ + Boolean err; + } status; + Bit8u error_register; +- // Bit8u drive_select; this field was moved :^( + Bit8u head_no; + union { + Bit8u sector_count; +@@ -282,12 +281,8 @@ + # define BX_HD_THIS this-> + #endif + +-#define BX_SELECTED_HD BX_HD_THIS s[BX_HD_THIS drive_select] +-#define CDROM_SELECTED (BX_HD_THIS s[BX_HD_THIS drive_select].device_type == IDE_CDROM) +-#define DEVICE_TYPE_STRING ((CDROM_SELECTED) ? "CD-ROM" : "DISK") +- + typedef enum { +- IDE_DISK, IDE_CDROM ++ IDE_NONE, IDE_DISK, IDE_CDROM + } device_type_t; + + class bx_hard_drive_c : public logfunctions { +@@ -298,8 +293,10 @@ + BX_HD_SMF void close_harddrive(void); + BX_HD_SMF void init(bx_devices_c *d, bx_cmos_c *cmos); + BX_HD_SMF void reset(unsigned type); +- BX_HD_SMF unsigned get_cd_media_status(void); +- BX_HD_SMF unsigned set_cd_media_status(unsigned status); ++ BX_HD_SMF Bit32u get_device_handle(Bit8u channel, Bit8u device); ++ BX_HD_SMF Bit32u get_first_cd_handle(void); ++ BX_HD_SMF unsigned get_cd_media_status(Bit32u handle); ++ BX_HD_SMF unsigned set_cd_media_status(Bit32u handle, unsigned status); + + #if !BX_USE_HD_SMF + Bit32u read(Bit32u address, unsigned io_len); +@@ -311,36 +308,46 @@ + + private: + +- BX_HD_SMF Boolean calculate_logical_address(Bit32u *sector); +- BX_HD_SMF void increment_address(); +- BX_HD_SMF void identify_drive(unsigned drive); +- BX_HD_SMF void identify_ATAPI_drive(unsigned drive); +- BX_HD_SMF void command_aborted(unsigned command); +- +- BX_HD_SMF void init_send_atapi_command(Bit8u command, int req_length, int alloc_length, bool lazy = false); +- BX_HD_SMF void ready_to_send_atapi(); +- BX_HD_SMF void raise_interrupt(); +- BX_HD_SMF void atapi_cmd_error(sense_t sense_key, asc_t asc); +- BX_HD_SMF void init_mode_sense_single(const void* src, int size); +- BX_HD_SMF void atapi_cmd_nop(); +- +- struct sStruct { +- device_image_t* hard_drive; +- device_type_t device_type; +- // 512 byte buffer for ID drive command +- // These words are stored in native word endian format, as +- // they are fetched and returned via a return(), so +- // there's no need to keep them in x86 endian format. +- Bit16u id_drive[256]; +- +- controller_t controller; +- cdrom_t cdrom; +- sense_info_t sense; +- atapi_t atapi; +- +- } s[2]; ++ BX_HD_SMF Boolean calculate_logical_address(Bit8u channel, Bit32u *sector); ++ BX_HD_SMF void increment_address(Bit8u channel); ++ BX_HD_SMF void identify_drive(Bit8u channel); ++ BX_HD_SMF void identify_ATAPI_drive(Bit8u channel); ++ BX_HD_SMF void command_aborted(Bit8u channel, unsigned command); ++ ++ BX_HD_SMF void init_send_atapi_command(Bit8u channel, Bit8u command, int req_length, int alloc_length, bool lazy = false); ++ BX_HD_SMF void ready_to_send_atapi(Bit8u channel); ++ BX_HD_SMF void raise_interrupt(Bit8u channel); ++ BX_HD_SMF void atapi_cmd_error(Bit8u channel, sense_t sense_key, asc_t asc); ++ BX_HD_SMF void init_mode_sense_single(Bit8u channel, const void* src, int size); ++ BX_HD_SMF void atapi_cmd_nop(Bit8u channel); ++ ++ // FIXME: ++ // For each ATA channel we should have one controller struct ++ // and an array of two drive structs ++ struct channel_t { ++ struct drive_t { ++ device_image_t* hard_drive; ++ device_type_t device_type; ++ // 512 byte buffer for ID drive command ++ // These words are stored in native word endian format, as ++ // they are fetched and returned via a return(), so ++ // there's no need to keep them in x86 endian format. ++ Bit16u id_drive[256]; ++ ++ controller_t controller; ++ cdrom_t cdrom; ++ sense_info_t sense; ++ atapi_t atapi; ++ ++ Bit8u model_no[41]; ++ } drives[2]; ++ unsigned drive_select; ++ ++ Bit16u ioaddr1; ++ Bit16u ioaddr2; ++ Bit8u irq; + +- unsigned drive_select; ++ } channels[BX_MAX_ATA_CHANNEL]; + + bx_devices_c *devices; + };