Store cdrom emulated driveid directly.
[seabios.git] / src / cdrom.c
index 8ccbeeab327e9626e418219080bfbb2e1d248301..8823f9b78ead5518ce04fc711c83c27ff04e3a39 100644 (file)
@@ -1,6 +1,6 @@
 // 16bit code to access cdrom drives.
 //
-// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
 // Copyright (C) 2002  MandrakeSoft S.A.
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
@@ -9,7 +9,7 @@
 #include "util.h" // memset
 #include "bregs.h" // struct bregs
 #include "biosvar.h" // GET_EBDA
-#include "atabits.h" // ATA_TYPE_ATAPI
+#include "ata.h" // ATA_CMD_REQUEST_SENSE
 
 
 /****************************************************************
 
 // read disk drive size
 static void
-cdrom_1315(struct bregs *regs, u8 device)
+cdrom_1315(struct bregs *regs, u8 driveid)
 {
     disk_ret(regs, DISK_RET_EADDRNOTFOUND);
 }
 
 // lock
 static void
-cdrom_134500(struct bregs *regs, u8 device)
+cdrom_134500(struct bregs *regs, u8 driveid)
 {
     u16 ebda_seg = get_ebda_seg();
-    u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[device]);
+    u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[driveid]);
     if (locks == 0xff) {
         regs->al = 1;
         disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
         return;
     }
-    SET_EBDA2(ebda_seg, cdrom_locks[device], locks + 1);
+    SET_EBDA2(ebda_seg, cdrom_locks[driveid], locks + 1);
     regs->al = 1;
     disk_ret(regs, DISK_RET_SUCCESS);
 }
 
 // unlock
 static void
-cdrom_134501(struct bregs *regs, u8 device)
+cdrom_134501(struct bregs *regs, u8 driveid)
 {
     u16 ebda_seg = get_ebda_seg();
-    u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[device]);
+    u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[driveid]);
     if (locks == 0x00) {
         regs->al = 0;
         disk_ret(regs, DISK_RET_ENOTLOCKED);
         return;
     }
     locks--;
-    SET_EBDA2(ebda_seg, cdrom_locks[device], locks);
+    SET_EBDA2(ebda_seg, cdrom_locks[driveid], locks);
     regs->al = (locks ? 1 : 0);
     disk_ret(regs, DISK_RET_SUCCESS);
 }
 
 // status
 static void
-cdrom_134502(struct bregs *regs, u8 device)
+cdrom_134502(struct bregs *regs, u8 driveid)
 {
-    u8 locks = GET_EBDA(cdrom_locks[device]);
+    u8 locks = GET_EBDA(cdrom_locks[driveid]);
     regs->al = (locks ? 1 : 0);
     disk_ret(regs, DISK_RET_SUCCESS);
 }
 
 static void
-cdrom_1345XX(struct bregs *regs, u8 device)
+cdrom_1345XX(struct bregs *regs, u8 driveid)
 {
     disk_ret(regs, DISK_RET_EPARAM);
 }
 
 // IBM/MS lock/unlock drive
 static void
-cdrom_1345(struct bregs *regs, u8 device)
+cdrom_1345(struct bregs *regs, u8 driveid)
 {
     switch (regs->al) {
-    case 0x00: cdrom_134500(regs, device); break;
-    case 0x01: cdrom_134501(regs, device); break;
-    case 0x02: cdrom_134502(regs, device); break;
-    default:   cdrom_1345XX(regs, device); break;
+    case 0x00: cdrom_134500(regs, driveid); break;
+    case 0x01: cdrom_134501(regs, driveid); break;
+    case 0x02: cdrom_134502(regs, driveid); break;
+    default:   cdrom_1345XX(regs, driveid); break;
     }
 }
 
 // IBM/MS eject media
 static void
-cdrom_1346(struct bregs *regs, u8 device)
+cdrom_1346(struct bregs *regs, u8 driveid)
 {
-    u8 locks = GET_EBDA(cdrom_locks[device]);
+    u8 locks = GET_EBDA(cdrom_locks[driveid]);
     if (locks != 0) {
         disk_ret(regs, DISK_RET_ELOCKED);
         return;
@@ -111,7 +111,7 @@ cdrom_1346(struct bregs *regs, u8 device)
 
 // IBM/MS extended media change
 static void
-cdrom_1349(struct bregs *regs, u8 device)
+cdrom_1349(struct bregs *regs, u8 driveid)
 {
     set_fail(regs);
     // always send changed ??
@@ -119,27 +119,27 @@ cdrom_1349(struct bregs *regs, u8 device)
 }
 
 static void
-cdrom_ok(struct bregs *regs, u8 device)
+cdrom_ok(struct bregs *regs, u8 driveid)
 {
     disk_ret(regs, DISK_RET_SUCCESS);
 }
 
 static void
-cdrom_wp(struct bregs *regs, u8 device)
+cdrom_wp(struct bregs *regs, u8 driveid)
 {
     disk_ret(regs, DISK_RET_EWRITEPROTECT);
 }
 
 void
-cdrom_13(struct bregs *regs, u8 device)
+cdrom_13(struct bregs *regs, u8 driveid)
 {
     //debug_stub(regs);
 
     switch (regs->ah) {
-    case 0x15: cdrom_1315(regs, device); break;
-    case 0x45: cdrom_1345(regs, device); break;
-    case 0x46: cdrom_1346(regs, device); break;
-    case 0x49: cdrom_1349(regs, device); break;
+    case 0x15: cdrom_1315(regs, driveid); break;
+    case 0x45: cdrom_1345(regs, driveid); break;
+    case 0x46: cdrom_1346(regs, driveid); break;
+    case 0x49: cdrom_1349(regs, driveid); break;
 
     // These functions are the same as for hard disks
     case 0x01:
@@ -149,7 +149,7 @@ cdrom_13(struct bregs *regs, u8 device)
     case 0x47:
     case 0x48:
     case 0x4e:
-        disk_13(regs, device);
+        disk_13(regs, driveid);
         break;
 
     // all these functions return SUCCESS
@@ -161,17 +161,17 @@ cdrom_13(struct bregs *regs, u8 device)
     case 0x11: // recalibrate
     case 0x14: // controller internal diagnostic
     case 0x16: // detect disk change
-        cdrom_ok(regs, device);
+        cdrom_ok(regs, driveid);
         break;
 
     // all these functions return disk write-protected
     case 0x03: // write disk sectors
     case 0x05: // format disk track
     case 0x43: // IBM/MS extended write
-        cdrom_wp(regs, device);
+        cdrom_wp(regs, driveid);
         break;
 
-    default:   disk_13XX(regs, device); break;
+    default:   disk_13XX(regs, driveid); break;
     }
 }
 
@@ -180,14 +180,26 @@ cdrom_13(struct bregs *regs, u8 device)
  * CD emulation
  ****************************************************************/
 
+static void
+cdemu_1302(struct bregs *regs, u8 driveid)
+{
+    cdemu_access(regs, driveid, CMD_READ);
+}
+
+static void
+cdemu_1304(struct bregs *regs, u8 driveid)
+{
+    cdemu_access(regs, driveid, CMD_VERIFY);
+}
+
 // read disk drive parameters
 static void
-cdemu_1308(struct bregs *regs, u8 device)
+cdemu_1308(struct bregs *regs, u8 driveid)
 {
     u16 ebda_seg = get_ebda_seg();
-    u16 nlc   = GET_EBDA2(ebda_seg, cdemu.cylinders) - 1;
-    u16 nlh   = GET_EBDA2(ebda_seg, cdemu.heads) - 1;
-    u16 nlspt = GET_EBDA2(ebda_seg, cdemu.spt);
+    u16 nlc   = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders) - 1;
+    u16 nlh   = GET_EBDA2(ebda_seg, cdemu.lchs.heads) - 1;
+    u16 nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
 
     regs->al = 0x00;
     regs->bl = 0x00;
@@ -213,15 +225,12 @@ cdemu_13(struct bregs *regs)
     //debug_stub(regs);
 
     u16 ebda_seg = get_ebda_seg();
-    u8 device  = GET_EBDA2(ebda_seg, cdemu.controller_index) * 2;
-    device += GET_EBDA2(ebda_seg, cdemu.device_spec);
+    u8 driveid = GET_EBDA2(ebda_seg, cdemu.emulated_driveid);
 
     switch (regs->ah) {
-    // These functions are the same as for hard disks
-    case 0x02:
-    case 0x04:
-        disk_13(regs, device);
-        break;
+    case 0x02: cdemu_1302(regs, driveid); break;
+    case 0x04: cdemu_1304(regs, driveid); break;
+    case 0x08: cdemu_1308(regs, driveid); break;
 
     // These functions are the same as standard CDROM.
     case 0x00:
@@ -236,12 +245,10 @@ cdemu_13(struct bregs *regs)
     case 0x14:
     case 0x15:
     case 0x16:
-        cdrom_13(regs, device);
+        cdrom_13(regs, driveid);
         break;
 
-    case 0x08: cdemu_1308(regs, device); break;
-
-    default:   disk_13XX(regs, device); break;
+    default:   disk_13XX(regs, driveid); break;
     }
 }
 
@@ -271,17 +278,19 @@ cdemu_134b(struct bregs *regs)
     u16 ebda_seg = get_ebda_seg();
     SET_INT13ET(regs, size, 0x13);
     SET_INT13ET(regs, media, GET_EBDA2(ebda_seg, cdemu.media));
-    SET_INT13ET(regs, emulated_drive, GET_EBDA2(ebda_seg, cdemu.emulated_drive));
-    SET_INT13ET(regs, controller_index
-                , GET_EBDA2(ebda_seg, cdemu.controller_index));
+    SET_INT13ET(regs, emulated_drive
+                , GET_EBDA2(ebda_seg, cdemu.emulated_extdrive));
+    u8 driveid = GET_EBDA2(ebda_seg, cdemu.emulated_driveid);
+    u8 cntl_id = GET_GLOBAL(Drives.drives[driveid].cntl_id);
+    SET_INT13ET(regs, controller_index, cntl_id / 2);
+    SET_INT13ET(regs, device_spec, cntl_id % 2);
     SET_INT13ET(regs, ilba, GET_EBDA2(ebda_seg, cdemu.ilba));
-    SET_INT13ET(regs, device_spec, GET_EBDA2(ebda_seg, cdemu.device_spec));
     SET_INT13ET(regs, buffer_segment, GET_EBDA2(ebda_seg, cdemu.buffer_segment));
     SET_INT13ET(regs, load_segment, GET_EBDA2(ebda_seg, cdemu.load_segment));
     SET_INT13ET(regs, sector_count, GET_EBDA2(ebda_seg, cdemu.sector_count));
-    SET_INT13ET(regs, cylinders, GET_EBDA2(ebda_seg, cdemu.cylinders));
-    SET_INT13ET(regs, sectors, GET_EBDA2(ebda_seg, cdemu.spt));
-    SET_INT13ET(regs, heads, GET_EBDA2(ebda_seg, cdemu.heads));
+    SET_INT13ET(regs, cylinders, GET_EBDA2(ebda_seg, cdemu.lchs.cylinders));
+    SET_INT13ET(regs, sectors, GET_EBDA2(ebda_seg, cdemu.lchs.spt));
+    SET_INT13ET(regs, heads, GET_EBDA2(ebda_seg, cdemu.lchs.heads));
 
     // If we have to terminate emulation
     if (regs->al == 0x00) {
@@ -299,13 +308,13 @@ cdemu_134b(struct bregs *regs)
 
 // Request SENSE
 static int
-atapi_get_sense(int device, u8 *asc, u8 *ascq)
+atapi_get_sense(int driveid, u8 *asc, u8 *ascq)
 {
     u8 atacmd[12], buffer[18];
     memset(atacmd, 0, sizeof(atacmd));
     atacmd[0] = ATA_CMD_REQUEST_SENSE;
     atacmd[4] = sizeof(buffer);
-    int ret = ata_cmd_packet(device, atacmd, sizeof(atacmd), sizeof(buffer)
+    int ret = ata_cmd_packet(driveid, atacmd, sizeof(atacmd), sizeof(buffer)
                              , MAKE_FLATPTR(GET_SEG(SS), buffer));
     if (ret)
         return ret;
@@ -318,12 +327,12 @@ atapi_get_sense(int device, u8 *asc, u8 *ascq)
 
 // Request capacity
 static int
-atapi_read_capacity(int device, u32 *blksize, u32 *sectors)
+atapi_read_capacity(int driveid, u32 *blksize, u32 *sectors)
 {
     u8 packet[12], buf[8];
     memset(packet, 0, sizeof(packet));
     packet[0] = 0x25; /* READ CAPACITY */
-    int ret = ata_cmd_packet(device, packet, sizeof(packet), sizeof(buf)
+    int ret = ata_cmd_packet(driveid, packet, sizeof(packet), sizeof(buf)
                              , MAKE_FLATPTR(GET_SEG(SS), buf));
     if (ret)
         return ret;
@@ -337,9 +346,9 @@ atapi_read_capacity(int device, u32 *blksize, u32 *sectors)
 }
 
 static int
-atapi_is_ready(u16 device)
+atapi_is_ready(u16 driveid)
 {
-    dprintf(6, "atapi_is_ready (device=%d)\n", device);
+    dprintf(6, "atapi_is_ready (driveid=%d)\n", driveid);
 
     /* Retry READ CAPACITY for 5 seconds unless MEDIUM NOT PRESENT is
      * reported by the device.  If the device reports "IN PROGRESS",
@@ -353,13 +362,13 @@ atapi_is_ready(u16 device)
             return -1;
         }
 
-        int ret = atapi_read_capacity(device, &blksize, &sectors);
+        int ret = atapi_read_capacity(driveid, &blksize, &sectors);
         if (!ret)
             // Success
             break;
 
         u8 asc, ascq;
-        ret = atapi_get_sense(device, &asc, &ascq);
+        ret = atapi_get_sense(driveid, &asc, &ascq);
         if (ret)
             // Error - retry.
             continue;
@@ -379,7 +388,7 @@ atapi_is_ready(u16 device)
         }
     }
 
-    if (blksize != GET_GLOBAL(ATA.devices[device].blksize)) {
+    if (blksize != GET_GLOBAL(Drives.drives[driveid].blksize)) {
         printf("Unsupported sector size %u\n", blksize);
         return -1;
     }
@@ -393,11 +402,9 @@ int
 cdrom_boot(int cdid)
 {
     // Verify device is a cdrom.
-    if (cdid >= ATA.cdcount)
+    if (cdid >= Drives.cdcount)
         return 1;
-    int driveid = GET_GLOBAL(ATA.idmap[1][cdid]);
-    if (GET_GLOBAL(ATA.devices[driveid].device) != ATA_DEVICE_CDROM)
-        return 2;
+    int driveid = GET_GLOBAL(Drives.idmap[1][cdid]);
 
     int ret = atapi_is_ready(driveid);
     if (ret)
@@ -406,6 +413,7 @@ cdrom_boot(int cdid)
     // Read the Boot Record Volume Descriptor
     u8 buffer[2048];
     struct disk_op_s dop;
+    memset(&dop, 0, sizeof(dop));
     dop.driveid = driveid;
     dop.lba = 0x11;
     dop.count = 1;
@@ -447,8 +455,7 @@ cdrom_boot(int cdid)
     u8 media = buffer[0x21];
     SET_EBDA2(ebda_seg, cdemu.media, media);
 
-    SET_EBDA2(ebda_seg, cdemu.controller_index, driveid/2);
-    SET_EBDA2(ebda_seg, cdemu.device_spec, driveid%2);
+    SET_EBDA2(ebda_seg, cdemu.emulated_driveid, driveid);
 
     u16 boot_segment = *(u16*)&buffer[0x22];
     if (!boot_segment)
@@ -472,7 +479,7 @@ cdrom_boot(int cdid)
 
     if (media == 0) {
         // No emulation requested - return success.
-        SET_EBDA2(ebda_seg, cdemu.emulated_drive, 0xE0 + cdid);
+        SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0xE0 + cdid);
         return 0;
     }
 
@@ -484,29 +491,29 @@ cdrom_boot(int cdid)
     // number of devices
     if (media < 4) {
         // Floppy emulation
-        SET_EBDA2(ebda_seg, cdemu.emulated_drive, 0x00);
+        SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x00);
         SETBITS_BDA(equipment_list_flags, 0x41);
 
         switch (media) {
         case 0x01:  // 1.2M floppy
-            SET_EBDA2(ebda_seg, cdemu.spt, 15);
-            SET_EBDA2(ebda_seg, cdemu.cylinders, 80);
-            SET_EBDA2(ebda_seg, cdemu.heads, 2);
+            SET_EBDA2(ebda_seg, cdemu.lchs.spt, 15);
+            SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+            SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
             break;
         case 0x02:  // 1.44M floppy
-            SET_EBDA2(ebda_seg, cdemu.spt, 18);
-            SET_EBDA2(ebda_seg, cdemu.cylinders, 80);
-            SET_EBDA2(ebda_seg, cdemu.heads, 2);
+            SET_EBDA2(ebda_seg, cdemu.lchs.spt, 18);
+            SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+            SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
             break;
         case 0x03:  // 2.88M floppy
-            SET_EBDA2(ebda_seg, cdemu.spt, 36);
-            SET_EBDA2(ebda_seg, cdemu.cylinders, 80);
-            SET_EBDA2(ebda_seg, cdemu.heads, 2);
+            SET_EBDA2(ebda_seg, cdemu.lchs.spt, 36);
+            SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+            SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
             break;
         }
     } else {
         // Harddrive emulation
-        SET_EBDA2(ebda_seg, cdemu.emulated_drive, 0x80);
+        SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x80);
         SET_BDA(hdcount, GET_BDA(hdcount) + 1);
 
         // Peak at partition table to get chs.
@@ -515,9 +522,10 @@ cdrom_boot(int cdid)
         u8 cyllow = GET_FARVAR(boot_segment, mbr->partitions[0].last.cyllow);
         u8 heads = GET_FARVAR(boot_segment, mbr->partitions[0].last.heads);
 
-        SET_EBDA2(ebda_seg, cdemu.spt, sptcyl & 0x3f);
-        SET_EBDA2(ebda_seg, cdemu.cylinders, ((sptcyl<<2)&0x300) + cyllow + 1);
-        SET_EBDA2(ebda_seg, cdemu.heads, heads + 1);
+        SET_EBDA2(ebda_seg, cdemu.lchs.spt, sptcyl & 0x3f);
+        SET_EBDA2(ebda_seg, cdemu.lchs.cylinders
+                  , ((sptcyl<<2)&0x300) + cyllow + 1);
+        SET_EBDA2(ebda_seg, cdemu.lchs.heads, heads + 1);
     }
 
     // everything is ok, so from now on, the emulation is active