Change license from GPLv3 to LGPLv3.
[seabios.git] / src / disk.c
index 533c254f4e7ec7d874266a118054f17ff83d44b4..d5c7df2783198e25f755e6185f8a9e65d9cb4f37 100644 (file)
@@ -3,16 +3,16 @@
 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
 // Copyright (C) 2002  MandrakeSoft S.A.
 //
-// This file may be distributed under the terms of the GNU GPLv3 license.
+// This file may be distributed under the terms of the GNU LGPLv3 license.
 
 #include "disk.h" // floppy_13
 #include "biosvar.h" // SET_BDA
 #include "config.h" // CONFIG_*
 #include "util.h" // debug_enter
-#include "ata.h" // ATA_*
 #include "pic.h" // eoi_pic2
 #include "bregs.h" // struct bregs
 #include "pci.h" // pci_bdf_to_bus
+#include "atabits.h" // ATA_CB_STAT
 
 
 /****************************************************************
  ****************************************************************/
 
 void
-__disk_ret(const char *fname, int lineno, struct bregs *regs, u8 code)
+__disk_ret(struct bregs *regs, u32 linecode, const char *fname)
 {
+    u8 code = linecode;
     SET_BDA(disk_last_status, code);
     if (code)
-        __set_code_fail(fname, lineno, regs, code);
+        __set_code_fail(regs, linecode, fname);
     else
         set_code_success(regs);
 }
 
 static void
-__disk_stub(const char *fname, int lineno, struct bregs *regs)
+__disk_stub(struct bregs *regs, int lineno, const char *fname)
 {
-    __debug_stub(fname, lineno, regs);
-    __disk_ret(fname, lineno, regs, DISK_RET_SUCCESS);
+    __debug_stub(regs, lineno, fname);
+    __disk_ret(regs, DISK_RET_SUCCESS | (lineno << 8), fname);
 }
 
-#define DISK_STUB(regs) \
-    __disk_stub(__func__, __LINE__, (regs))
+#define DISK_STUB(regs)                         \
+    __disk_stub((regs), __LINE__, __func__)
+
+static int
+__send_disk_op(struct disk_op_s *op_p, u16 op_s)
+{
+    struct disk_op_s dop;
+    memcpy_far(MAKE_FARPTR(GET_SEG(SS), &dop)
+               , MAKE_FARPTR(op_s, op_p)
+               , sizeof(dop));
+
+    dprintf(DEBUG_HDL_13, "disk_op d=%d lba=%d buf=%p count=%d cmd=%d\n"
+            , dop.driveid, (u32)dop.lba, dop.far_buffer
+            , dop.count, dop.command);
+
+    irq_enable();
+
+    int status;
+    if (dop.command == CMD_CDEMU_READ)
+        status = cdrom_read_512(&dop);
+    else if (dop.command == CMD_CDROM_READ)
+        status = cdrom_read(&dop);
+    else
+        status = ata_cmd_data(&dop);
+
+    irq_disable();
+
+    return status;
+}
+
+static int
+send_disk_op(struct disk_op_s *op)
+{
+    return stack_hop((u32)op, GET_SEG(SS), 0, __send_disk_op);
+}
 
 static void
 basic_access(struct bregs *regs, u8 device, u16 command)
 {
+    struct disk_op_s dop;
+    dop.lba = 0;
+    dop.driveid = device;
     u8 type = GET_GLOBAL(ATA.devices[device].type);
     u16 nlc, nlh, nlspt;
     if (type == ATA_TYPE_ATA) {
         nlc   = GET_GLOBAL(ATA.devices[device].lchs.cylinders);
         nlh   = GET_GLOBAL(ATA.devices[device].lchs.heads);
         nlspt = GET_GLOBAL(ATA.devices[device].lchs.spt);
+        dop.command = command;
     } else {
         // Must be cd emulation.
-        nlc   = GET_GLOBAL(CDEMU.vdevice.cylinders);
-        nlh   = GET_GLOBAL(CDEMU.vdevice.heads);
-        nlspt = GET_GLOBAL(CDEMU.vdevice.spt);
+        u16 ebda_seg = get_ebda_seg();
+        nlc   = GET_EBDA2(ebda_seg, cdemu.cylinders);
+        nlh   = GET_EBDA2(ebda_seg, cdemu.heads);
+        nlspt = GET_EBDA2(ebda_seg, cdemu.spt);
+        dop.lba = GET_EBDA2(ebda_seg, cdemu.ilba) * 4;
+        dop.command = CMD_CDEMU_READ;
     }
 
-    u16 count       = regs->al;
+    dop.count       = regs->al;
     u16 cylinder    = regs->ch | ((((u16) regs->cl) << 2) & 0x300);
     u16 sector      = regs->cl & 0x3f;
     u16 head        = regs->dh;
 
-    if (count > 128 || count == 0 || sector == 0) {
+    if (dop.count > 128 || dop.count == 0 || sector == 0) {
         dprintf(1, "int13_harddisk: function %02x, parameter out of range!\n"
                 , regs->ah);
         disk_ret(regs, DISK_RET_EPARAM);
@@ -83,22 +124,14 @@ basic_access(struct bregs *regs, u8 device, u16 command)
     }
 
     // translate lchs to lba
-    u32 lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
-               + (u32)sector - 1);
+    dop.lba += (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
+                + (u32)sector - 1);
 
     u16 segment = regs->es;
     u16 offset  = regs->bx;
-    void *far_buffer = MAKE_FARPTR(segment, offset);
-
-    irq_enable();
-
-    int status;
-    if (type == ATA_TYPE_ATA)
-        status = ata_cmd_data(device, command, lba, count, far_buffer);
-    else
-        status = cdrom_read_emu(device, lba, count, far_buffer);
+    dop.far_buffer = MAKE_FARPTR(segment, offset);
 
-    irq_disable();
+    int status = send_disk_op(&dop);
 
     // Set nb of sector transferred
     regs->al = GET_EBDA(sector_count);
@@ -107,6 +140,7 @@ basic_access(struct bregs *regs, u8 device, u16 command)
         dprintf(1, "int13_harddisk: function %02x, error %d!\n"
                 , regs->ah, status);
         disk_ret(regs, DISK_RET_EBADTRACK);
+        return;
     }
     disk_ret(regs, DISK_RET_SUCCESS);
 }
@@ -114,15 +148,21 @@ basic_access(struct bregs *regs, u8 device, u16 command)
 static void
 extended_access(struct bregs *regs, u8 device, u16 command)
 {
+    struct disk_op_s dop;
     // Get lba and check.
-    u64 lba = GET_INT13EXT(regs, lba);
+    dop.lba = GET_INT13EXT(regs, lba);
+    dop.command = command;
+    dop.driveid = device;
     u8 type = GET_GLOBAL(ATA.devices[device].type);
-    if (type == ATA_TYPE_ATA
-        && lba >= GET_GLOBAL(ATA.devices[device].sectors)) {
-        dprintf(1, "int13_harddisk: function %02x. LBA out of range\n"
-                , regs->ah);
-        disk_ret(regs, DISK_RET_EPARAM);
-        return;
+    if (type == ATA_TYPE_ATA) {
+        if (dop.lba >= GET_GLOBAL(ATA.devices[device].sectors)) {
+            dprintf(1, "int13_harddisk: function %02x. LBA out of range\n"
+                    , regs->ah);
+            disk_ret(regs, DISK_RET_EPARAM);
+            return;
+        }
+    } else {
+        dop.command = CMD_CDROM_READ;
     }
 
     if (!command) {
@@ -133,21 +173,10 @@ extended_access(struct bregs *regs, u8 device, u16 command)
 
     u16 segment = GET_INT13EXT(regs, segment);
     u16 offset = GET_INT13EXT(regs, offset);
-    void *far_buffer = MAKE_FARPTR(segment, offset);
-    u16 count = GET_INT13EXT(regs, count);
-
-    dprintf(DEBUG_HDL_13, "extacc lba=%d buf=%p count=%d\n"
-            , (u32)lba, far_buffer, count);
-
-    irq_enable();
+    dop.far_buffer = MAKE_FARPTR(segment, offset);
+    dop.count = GET_INT13EXT(regs, count);
 
-    int status;
-    if (type == ATA_TYPE_ATA)
-        status = ata_cmd_data(device, command, lba, count, far_buffer);
-    else
-        status = cdrom_read(device, lba, count, far_buffer);
-
-    irq_disable();
+    int status = send_disk_op(&dop);
 
     SET_INT13EXT(regs, count, GET_EBDA(sector_count));
 
@@ -219,7 +248,7 @@ disk_1308(struct bregs *regs, u8 device)
     u16 nlc = GET_GLOBAL(ATA.devices[device].lchs.cylinders);
     u16 nlh = GET_GLOBAL(ATA.devices[device].lchs.heads);
     u16 nlspt = GET_GLOBAL(ATA.devices[device].lchs.spt);
-    u16 count = GET_GLOBAL(ATA.hdcount);
+    u16 count = GET_BDA(hdcount);
 
     nlc = nlc - 2; /* 0 based , last sector not used */
     regs->al = 0;
@@ -407,9 +436,10 @@ disk_1348(struct bregs *regs, u8 device)
 
     // EDD 2.x
 
+    u16 ebda_seg = get_ebda_seg();
     SET_INT13DPT(regs, size, 30);
 
-    SET_INT13DPT(regs, dpte_segment, GET_BDA(ebda_seg));
+    SET_INT13DPT(regs, dpte_segment, ebda_seg);
     SET_INT13DPT(regs, dpte_offset
                  , offsetof(struct extended_bios_data_area_s, dpte));
 
@@ -440,22 +470,22 @@ disk_1348(struct bregs *regs, u8 device)
     if (mode == ATA_MODE_PIO32)
         options |= 1<<7;
 
-    SET_EBDA(dpte.iobase1, iobase1);
-    SET_EBDA(dpte.iobase2, iobase2 + ATA_CB_DC);
-    SET_EBDA(dpte.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
-                               | ATA_CB_DH_LBA));
-    SET_EBDA(dpte.unused, 0xcb);
-    SET_EBDA(dpte.irq, irq);
-    SET_EBDA(dpte.blkcount, 1);
-    SET_EBDA(dpte.dma, 0);
-    SET_EBDA(dpte.pio, 0);
-    SET_EBDA(dpte.options, options);
-    SET_EBDA(dpte.reserved, 0);
-    SET_EBDA(dpte.revision, 0x11);
-
-    u8 *p = MAKE_FARPTR(GET_BDA(ebda_seg)
+    SET_EBDA2(ebda_seg, dpte.iobase1, iobase1);
+    SET_EBDA2(ebda_seg, dpte.iobase2, iobase2 + ATA_CB_DC);
+    SET_EBDA2(ebda_seg, dpte.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
+                                      | ATA_CB_DH_LBA));
+    SET_EBDA2(ebda_seg, dpte.unused, 0xcb);
+    SET_EBDA2(ebda_seg, dpte.irq, irq);
+    SET_EBDA2(ebda_seg, dpte.blkcount, 1);
+    SET_EBDA2(ebda_seg, dpte.dma, 0);
+    SET_EBDA2(ebda_seg, dpte.pio, 0);
+    SET_EBDA2(ebda_seg, dpte.options, options);
+    SET_EBDA2(ebda_seg, dpte.reserved, 0);
+    SET_EBDA2(ebda_seg, dpte.revision, 0x11);
+
+    u8 *p = MAKE_FARPTR(ebda_seg
                         , offsetof(struct extended_bios_data_area_s, dpte));
-    SET_EBDA(dpte.checksum, -checksum(p, 15));
+    SET_EBDA2(ebda_seg, dpte.checksum, -checksum(p, 15));
 
     if (size < 66) {
         disk_ret(regs, DISK_RET_SUCCESS);
@@ -661,8 +691,9 @@ handle_13(struct bregs *regs)
             cdemu_134b(regs);
             return;
         }
-        if (GET_EBDA(cdemu_active)) {
-            if (drive == GET_GLOBAL(CDEMU.emulated_drive)) {
+        u16 ebda_seg = get_ebda_seg();
+        if (GET_EBDA2(ebda_seg, cdemu.active)) {
+            if (drive == GET_EBDA2(ebda_seg, cdemu.emulated_drive)) {
                 cdemu_13(regs);
                 return;
             }