Petr Tesarik : ntdll: Fix CDROM raw reads.

Alexandre Julliard julliard at wine.codeweavers.com
Wed Mar 29 06:21:18 CST 2006


Module: wine
Branch: refs/heads/master
Commit: 4c777d7466ea5fbe04899bf945f097bcc30a7dcb
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=4c777d7466ea5fbe04899bf945f097bcc30a7dcb

Author: Petr Tesarik <hat at tesarici.cz>
Date:   Mon Mar 27 10:20:39 2006 +0200

ntdll: Fix CDROM raw reads.

- Fix incorrect data sizes.
- Fix CDDA addressing.
- Implement XAForm2 mode on Linux.

---

 dlls/ntdll/cdrom.c |  152 ++++++++++++++++++++++++++++------------------------
 1 files changed, 82 insertions(+), 70 deletions(-)

diff --git a/dlls/ntdll/cdrom.c b/dlls/ntdll/cdrom.c
index a5cf6cd..8838949 100644
--- a/dlls/ntdll/cdrom.c
+++ b/dlls/ntdll/cdrom.c
@@ -1192,101 +1192,113 @@ static NTSTATUS CDROM_SetVolume(int fd, 
 /******************************************************************
  *		CDROM_RawRead
  *
+ * Some features of this IOCTL are rather poorly documented and
+ * not really intuitive either:
+ *
+ *   1. Although the DiskOffset parameter is meant to be a
+ *      byte offset into the disk, it is in fact the sector
+ *      number multiplied by 2048 regardless of the actual
+ *      sector size.
+ *
+ *   2. The least significant 11 bits of DiskOffset are ignored.
+ *
+ *   3. The TrackMode parameter has no effect on the sector
+ *      size. The entire raw sector (i.e. 2352 bytes of data)
+ *      is always returned. IMO the TrackMode is only used
+ *      to check the correct sector type.
  *
  */
 static NTSTATUS CDROM_RawRead(int fd, const RAW_READ_INFO* raw, void* buffer, DWORD len, DWORD* sz)
 {
-    int	        ret = STATUS_NOT_SUPPORTED;
+    int         ret = STATUS_NOT_SUPPORTED;
     int         io = -1;
-    DWORD       sectSize;
 
     TRACE("RAW_READ_INFO: DiskOffset=%li,%li SectorCount=%li TrackMode=%i\n buffer=%p len=%li sz=%p\n",
           raw->DiskOffset.u.HighPart, raw->DiskOffset.u.LowPart, raw->SectorCount, raw->TrackMode, buffer, len, sz);
 
+    if (len < raw->SectorCount * 2352) return STATUS_BUFFER_TOO_SMALL;
+
+#if defined(linux)
+    if (raw->DiskOffset.u.HighPart & ~2047) {
+        WARN("DiskOffset points to a sector >= 2**32\n");
+        return ret;
+    }
+
     switch (raw->TrackMode)
     {
-    case YellowMode2:   sectSize = 2336;        break;
-    case XAForm2:       sectSize = 2328;        break;
-    case CDDA:          sectSize = 2352;        break;
-    default:    return STATUS_INVALID_PARAMETER;
-    }
-    if (len < raw->SectorCount * sectSize) return STATUS_BUFFER_TOO_SMALL;
-    /* strangely enough, it seems that sector offsets are always indicated with a size of 2048,
-     * even if a larger size if read...
-     */
-#if defined(linux)
+    case YellowMode2:
+    case XAForm2:
     {
-        struct cdrom_read_audio cdra;
+        DWORD lba = raw->DiskOffset.QuadPart >> 11;
         struct cdrom_msf*       msf;
+        PBYTE                   *bp; /* current buffer pointer */
         int i;
-        LONGLONG t = ((LONGLONG)raw->DiskOffset.u.HighPart << 32) +
-                                raw->DiskOffset.u.LowPart + CD_MSF_OFFSET;
 
-        switch (raw->TrackMode)
+        if ((lba + raw->SectorCount) >
+            ((1 << 8*sizeof(msf->cdmsf_min0)) * CD_SECS * CD_FRAMES
+             - CD_MSF_OFFSET)) {
+            WARN("DiskOffset not accessible with MSF\n");
+            return ret;
+        }
+
+        /* Linux reads only one sector at a time.
+         * ioctl CDROMREADRAW takes struct cdrom_msf as an argument
+         * on the contrary to what header comments state.
+         */
+        lba += CD_MSF_OFFSET;
+        for (i = 0, bp = buffer; i < raw->SectorCount;
+             i++, lba++, bp += 2352)
         {
-        case YellowMode2:
-            /* Linux reads only one sector at a time.
-             * ioctl CDROMREADMODE2 takes struct cdrom_msf as an argument
-             * on the contrary to what header comments state.
-             */
-            for (i = 0; i < raw->SectorCount; i++, t += sectSize)
+            msf = (struct cdrom_msf*)bp;
+            msf->cdmsf_min0   = lba / CD_FRAMES / CD_SECS;
+            msf->cdmsf_sec0   = lba / CD_FRAMES % CD_SECS;
+            msf->cdmsf_frame0 = lba % CD_FRAMES;
+            io = ioctl(fd, CDROMREADRAW, msf);
+            if (io != 0)
             {
-                msf = (struct cdrom_msf*)buffer + i * sectSize;
-                msf->cdmsf_min0   = t / CD_FRAMES / CD_SECS;
-                msf->cdmsf_sec0   = t / CD_FRAMES % CD_SECS;
-                msf->cdmsf_frame0 = t % CD_FRAMES;
-                io = ioctl(fd, CDROMREADMODE2, msf);
-                if (io != 0)
-                {
-                    *sz = sectSize * i;
-                    return CDROM_GetStatusCode(io);
-                }
+                *sz = 2352 * i;
+                return CDROM_GetStatusCode(io);
             }
-            break;
-        case XAForm2:
-            FIXME("XAForm2: NIY\n");
-            return ret;
-        case CDDA:
-            /* FIXME: the output doesn't seem 100% correct... in fact output is shifted
-             * between by NT2K box and this... should check on the same drive...
-             * otherwise, I fear a 2352/2368 mismatch somewhere in one of the drivers
-             * (linux/NT).
-             * Anyway, that's not critical at all. We're talking of 16/32 bytes, we're
-             * talking of 0.2 ms of sound
-             */
-            /* 2048 = 2 ** 11 */
-            if (raw->DiskOffset.u.HighPart & ~2047) FIXME("Unsupported value\n");
-            cdra.addr.lba = ((raw->DiskOffset.u.LowPart >> 11) |
-                (raw->DiskOffset.u.HighPart << (32 - 11))) - 1;
-            FIXME("reading at %u\n", cdra.addr.lba);
-            cdra.addr_format = CDROM_LBA;
-            cdra.nframes = raw->SectorCount;
-            cdra.buf = buffer;
-            io = ioctl(fd, CDROMREADAUDIO, &cdra);
-            break;
-        default:
-            FIXME("NIY: %d\n", raw->TrackMode);
-            return ret;
         }
+        break;
+    }
+
+    case CDDA:
+    {
+        struct cdrom_read_audio cdra;
+
+        cdra.addr.lba = raw->DiskOffset.QuadPart >> 11;
+        TRACE("reading at %u\n", cdra.addr.lba);
+        cdra.addr_format = CDROM_LBA;
+        cdra.nframes = raw->SectorCount;
+        cdra.buf = buffer;
+        io = ioctl(fd, CDROMREADAUDIO, &cdra);
+        break;
+    }
+
+    default:
+        FIXME("NIY: %d\n", raw->TrackMode);
+        return STATUS_INVALID_PARAMETER;
     }
 #else
+    switch (raw->TrackMode)
     {
-        switch (raw->TrackMode)
-        {
-        case YellowMode2:
-            FIXME("YellowMode2: NIY\n");
-            return ret;
-        case XAForm2:
-            FIXME("XAForm2: NIY\n");
-            return ret;
-        case CDDA:
-            FIXME("CDDA: NIY\n");
-            return ret;
-        }
+    case YellowMode2:
+        FIXME("YellowMode2: NIY\n");
+        return ret;
+    case XAForm2:
+        FIXME("XAForm2: NIY\n");
+        return ret;
+    case CDDA:
+        FIXME("CDDA: NIY\n");
+        return ret;
+    default:
+        FIXME("NIY: %d\n", raw->TrackMode);
+        return STATUS_INVALID_PARAMETER;
     }
 #endif
 
-    *sz = sectSize * raw->SectorCount;
+    *sz = 2352 * raw->SectorCount;
     ret = CDROM_GetStatusCode(io);
     return ret;
 }




More information about the wine-cvs mailing list