Cleanup cdrom emulation.
authorKevin O'Connor <kevin@koconnor.net>
Sun, 23 Mar 2008 03:13:24 +0000 (23:13 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Sun, 23 Mar 2008 03:13:24 +0000 (23:13 -0400)
Remove 'header' param for ata_cmd_packet - the only code that uses it
    is cdrom emulation.  So, bury this detail in ata.c.
Introduce new helpers cdrom_read_emu and cdrom_read_512 for working
    with emulated cdrom drives.
Unify basic_access() and emu_access() - now basic_access() can read
    from cdrom drives.

src/ata.c
src/ata.h
src/cdrom.c
src/disk.c
src/disk.h

index d628420..cfe4b1e 100644 (file)
--- a/src/ata.c
+++ b/src/ata.c
@@ -267,9 +267,9 @@ ata_transfer(struct ata_pio_command *cmd)
       // 2 : BUSY bit set
       // 3 : error
       // 4 : not ready
-int
-ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
-               , u16 header, u32 length, void *far_buffer)
+static inline int
+__ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
+                 , u16 header, u32 length, void *far_buffer)
 {
     DEBUGF("ata_cmd_packet d=%d cmdlen=%d h=%d l=%d buf=%p\n"
            , biosid, cmdlen, header, length, far_buffer);
@@ -422,24 +422,58 @@ ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
 }
 
 int
-cdrom_read(u16 biosid, u32 lba, u32 count, void *far_buffer, u16 skip)
+ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
+               , u32 length, void *far_buffer)
 {
-    u16 sectors = (count + 2048 - 1) / 2048;
+    return __ata_cmd_packet(biosid, cmdbuf, cmdlen, 0, length, far_buffer);
+}
 
-    u8 atacmd[12];
-    memset(atacmd, 0, sizeof(atacmd));
-    atacmd[0]=0x28;                      // READ command
-    atacmd[7]=(sectors & 0xff00) >> 8;   // Sectors
-    atacmd[8]=(sectors & 0x00ff);        // Sectors
-    atacmd[2]=(lba & 0xff000000) >> 24;  // LBA
+static void
+build_cdrom_cmd(u8 *atacmd, u32 lba, u16 count)
+{
+    memset(atacmd, 0, 12);
+    atacmd[0]=0x28;                     // READ command
+    atacmd[7]=(count & 0xff00) >> 8;    // Sectors
+    atacmd[8]=(count & 0x00ff);         // Sectors
+    atacmd[2]=(lba & 0xff000000) >> 24; // LBA
     atacmd[3]=(lba & 0x00ff0000) >> 16;
     atacmd[4]=(lba & 0x0000ff00) >> 8;
     atacmd[5]=(lba & 0x000000ff);
+}
 
+// Read sectors from the cdrom.
+int
+cdrom_read(u16 biosid, u32 lba, u32 count, void *far_buffer)
+{
+    u8 atacmd[12];
+    build_cdrom_cmd(atacmd, lba, count);
     return ata_cmd_packet(biosid, atacmd, sizeof(atacmd)
-                          , skip, count, far_buffer);
+                          , count*2048, far_buffer);
 }
 
+// Pretend the cdrom has 512 byte sectors (instead of 2048) and read
+// sectors.
+int
+cdrom_read_512(u16 biosid, u32 vlba, u32 count, void *far_buffer)
+{
+    u32 slba = vlba / 4;
+    u16 before = vlba % 4;
+    u32 elba = (vlba + count - 1) / 4;
+
+    u8 atacmd[12];
+    build_cdrom_cmd(atacmd, slba, elba - slba + 1);
+
+    int status = __ata_cmd_packet(biosid, atacmd, sizeof(atacmd)
+                                  , before*512, count*512, far_buffer);
+    if (status) {
+        SET_EBDA(ata.trsfsectors, 0);
+        return status;
+    }
+    SET_EBDA(ata.trsfsectors, count);
+    return 0;
+}
+
+
 // ---------------------------------------------------------------------------
 // ATA/ATAPI driver : device detection
 // ---------------------------------------------------------------------------
index 763dbf1..074ed55 100644 (file)
--- a/src/ata.h
+++ b/src/ata.h
@@ -33,9 +33,9 @@ struct ata_pio_command {
 void ata_reset(u16 device);
 int ata_transfer(struct ata_pio_command *cmd);
 int ata_cmd_packet(u16 device, u8 *cmdbuf, u8 cmdlen
-                   , u16 header, u32 length, void *far_buffer);
-int cdrom_read(u16 device, u32 lba, u32 count
-               , void *far_buffer, u16 skip);
+                   , u32 length, void *far_buffer);
+int cdrom_read(u16 device, u32 lba, u32 count, void *far_buffer);
+int cdrom_read_512(u16 device, u32 lba, u32 count, void *far_buffer);
 void ata_detect();
 
 static inline int
index fc616e1..875b9e3 100644 (file)
@@ -179,18 +179,13 @@ cdrom_13(struct bregs *regs, u8 device)
  * CD emulation
  ****************************************************************/
 
-// read disk sectors
-static void
-cdemu_1302(struct bregs *regs, u8 device)
-{
-    emu_access(regs, device, ATA_CMD_READ_SECTORS);
-}
-
-// verify disk sectors
-static void
-cdemu_1304(struct bregs *regs, u8 device)
+// Read a series of 512 byte sectors from the cdrom starting at the
+// image offset.
+inline int
+cdrom_read_emu(u16 biosid, u32 vlba, u32 count, void *far_buffer)
 {
-    emu_access(regs, device, 0);
+    u32 ilba = GET_EBDA(cdemu.ilba);
+    return cdrom_read_512(biosid, ilba * 4 + vlba, count, far_buffer);
 }
 
 // read disk drive parameters
@@ -228,9 +223,14 @@ cdemu_13(struct bregs *regs)
     device += GET_EBDA(cdemu.device_spec);
 
     switch (regs->ah) {
-    case 0x02: cdemu_1302(regs, device); break;
-    case 0x04: cdemu_1304(regs, device); break;
+    // These functions are the same as for hard disks
+    case 0x02:
+    case 0x04:
+        disk_13(regs, device);
+        break;
+
     case 0x08: cdemu_1308(regs, device); break;
+
     // XXX - All other calls get passed to standard CDROM functions.
     default: cdrom_13(regs, device); break;
     }
@@ -295,8 +295,7 @@ atapi_get_sense(u16 device, u8 *asc, u8 *ascq)
     memset(atacmd, 0, sizeof(atacmd));
     atacmd[0] = ATA_CMD_REQUEST_SENSE;
     atacmd[4] = sizeof(buffer);
-    u16 ret = ata_cmd_packet(device, atacmd, sizeof(atacmd)
-                             , 0, sizeof(buffer)
+    u16 ret = ata_cmd_packet(device, atacmd, sizeof(atacmd), sizeof(buffer)
                              , MAKE_FARPTR(GET_SEG(SS), (u32)buffer));
     if (ret != 0)
         return 0x0002;
@@ -332,8 +331,7 @@ atapi_is_ready(u16 device)
             DEBUGF("read capacity failed\n");
             return -1;
         }
-        u16 ret = ata_cmd_packet(device, packet, sizeof(packet)
-                                 , 0, sizeof(buf)
+        u16 ret = ata_cmd_packet(device, packet, sizeof(packet), sizeof(buf)
                                  , MAKE_FARPTR(GET_SEG(SS), (u32)buf));
         if (ret == 0)
             break;
@@ -431,8 +429,8 @@ cdrom_boot()
 
     // Read the Boot Record Volume Descriptor
     u8 buffer[2048];
-    ret = cdrom_read(device, 0x11, 2048
-                     , MAKE_FARPTR(GET_SEG(SS), (u32)buffer), 0);
+    ret = cdrom_read(device, 0x11, 1
+                     , MAKE_FARPTR(GET_SEG(SS), (u32)buffer));
     if (ret)
         return 3;
 
@@ -446,8 +444,8 @@ cdrom_boot()
     u32 lba = *(u32*)&buffer[0x47];
 
     // And we read the Boot Catalog
-    ret = cdrom_read(device, lba, 2048
-                     , MAKE_FARPTR(GET_SEG(SS), (u32)buffer), 0);
+    ret = cdrom_read(device, lba, 1
+                     , MAKE_FARPTR(GET_SEG(SS), (u32)buffer));
     if (ret)
         return 7;
 
@@ -484,8 +482,7 @@ cdrom_boot()
     SET_EBDA(cdemu.ilba, lba);
 
     // And we read the image in memory
-    ret = cdrom_read(device, lba, nbsectors*512
-                     , MAKE_FARPTR(boot_segment, 0), 0);
+    ret = cdrom_read_emu(device, 0, nbsectors, MAKE_FARPTR(boot_segment, 0));
     if (ret)
         return 12;
 
index 2312792..bc20b12 100644 (file)
@@ -51,9 +51,18 @@ basic_access(struct bregs *regs, u8 device, u16 command)
         return;
     }
 
-    u16 nlc   = GET_EBDA(ata.devices[device].lchs.cylinders);
-    u16 nlh   = GET_EBDA(ata.devices[device].lchs.heads);
-    u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
+    u8 type = GET_EBDA(ata.devices[device].type);
+    u16 nlc, nlh, nlspt;
+    if (type == ATA_TYPE_ATA) {
+        nlc   = GET_EBDA(ata.devices[device].lchs.cylinders);
+        nlh   = GET_EBDA(ata.devices[device].lchs.heads);
+        nlspt = GET_EBDA(ata.devices[device].lchs.spt);
+    } else {
+        // Must be cd emulation.
+        nlc   = GET_EBDA(cdemu.vdevice.cylinders);
+        nlh   = GET_EBDA(cdemu.vdevice.heads);
+        nlspt = GET_EBDA(cdemu.vdevice.spt);
+    }
 
     // sanity check on cyl heads, sec
     if (cylinder >= nlc || head >= nlh || sector > nlspt) {
@@ -70,84 +79,32 @@ basic_access(struct bregs *regs, u8 device, u16 command)
         return;
     }
 
-    u16 segment = regs->es;
-    u16 offset  = regs->bx;
-
     // translate lchs to lba
     u32 lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
                + (u32)sector - 1);
-    irq_enable();
-    u8 status = ata_cmd_data(device, command, lba, count
-                             , MAKE_FARPTR(segment, offset));
-    irq_disable();
-
-    // Set nb of sector transferred
-    regs->al = GET_EBDA(ata.trsfsectors);
-
-    if (status != 0) {
-        BX_INFO("int13_harddisk: function %02x, error %02x !\n",regs->ah,status);
-        disk_ret(regs, DISK_RET_EBADTRACK);
-    }
-    disk_ret(regs, DISK_RET_SUCCESS);
-}
-
-void
-emu_access(struct bregs *regs, u8 device, u16 command)
-{
-    u16 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)) {
-        BX_INFO("int13_harddisk: function %02x, parameter out of range!\n"
-                , regs->ah);
-        disk_ret(regs, DISK_RET_EPARAM);
-        return;
-    }
-
-    u16 nlc   = GET_EBDA(cdemu.vdevice.cylinders);
-    u16 nlh   = GET_EBDA(cdemu.vdevice.heads);
-    u16 nlspt = GET_EBDA(cdemu.vdevice.spt);
-
-    // sanity check on cyl heads, sec
-    if ( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
-        BX_INFO("int13_harddisk: function %02x, parameters out of"
-                " range %04x/%04x/%04x!\n"
-                , regs->ah, cylinder, head, sector);
-        disk_ret(regs, DISK_RET_EPARAM);
-        return;
-    }
-
-    if (!command) {
-        // If verify or seek
-        disk_ret(regs, DISK_RET_SUCCESS);
-        return;
-    }
-
-    u32 ilba = GET_EBDA(cdemu.ilba);
-    // calculate the virtual lba inside the image
-    u32 vlba= (((((u32)cylinder*(u32)nlh)+(u32)head)*(u32)nlspt)
-               +((u32)(sector-1)));
-    // start lba on cd
-    u32 slba  = (u32)vlba/4;
-    u16 before= (u16)vlba%4;
-    u32 lba = ilba + slba;
 
     u16 segment = regs->es;
     u16 offset  = regs->bx;
+    void *far_buffer = MAKE_FARPTR(segment, offset);
 
     irq_enable();
-    u8 status = cdrom_read(device, lba, count*512
-                           , MAKE_FARPTR(segment, offset), before*512);
+
+    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);
+
     irq_disable();
+
+    // Set nb of sector transferred
+    regs->al = GET_EBDA(ata.trsfsectors);
+
     if (status != 0) {
         BX_INFO("int13_harddisk: function %02x, error %02x !\n"
                 , regs->ah, status);
-        regs->al = 0;
         disk_ret(regs, DISK_RET_EBADTRACK);
     }
-    regs->al = count;
     disk_ret(regs, DISK_RET_SUCCESS);
 }
 
@@ -155,8 +112,6 @@ static void
 extended_access(struct bregs *regs, u8 device, u16 command)
 {
     u16 count = GET_INT13EXT(regs, count);
-    u16 segment = GET_INT13EXT(regs, segment);
-    u16 offset = GET_INT13EXT(regs, offset);
 
     // Can't use 64 bits lba
     u32 lba = GET_INT13EXT(regs, lba2);
@@ -184,15 +139,17 @@ extended_access(struct bregs *regs, u8 device, u16 command)
         return;
     }
 
+    u16 segment = GET_INT13EXT(regs, segment);
+    u16 offset = GET_INT13EXT(regs, offset);
+    void *far_buffer = MAKE_FARPTR(segment, offset);
+
     irq_enable();
 
     u8 status;
     if (type == ATA_TYPE_ATA)
-        status = ata_cmd_data(device, command, lba, count
-                              , MAKE_FARPTR(segment, offset));
+        status = ata_cmd_data(device, command, lba, count, far_buffer);
     else
-        status = cdrom_read(device, lba, count*2048
-                            , MAKE_FARPTR(segment, offset), 0);
+        status = cdrom_read(device, lba, count, far_buffer);
 
     irq_disable();
 
index 0f92b1e..e7514be 100644 (file)
@@ -111,11 +111,11 @@ void floppy_13(struct bregs *regs, u8 drive);
 void floppy_tick();
 
 // disk.c
-void emu_access(struct bregs *regs, u8 device, u16 command);
 void disk_13(struct bregs *regs, u8 device);
 void disk_13XX(struct bregs *regs, u8 device);
 
 // cdrom.c
+int cdrom_read_emu(u16 device, u32 lba, u32 count, void *far_buffer);
 void cdrom_13(struct bregs *regs, u8 device);
 void cdemu_13(struct bregs *regs);
 void cdemu_134b(struct bregs *regs);