[PATCH 3/3] winedos: better MSCDEX emulation

Petr Tesarik hat at tesarici.cz
Fri Mar 31 06:44:54 CST 2006


Hi,

while I was trying to make Kindler Literaturlexikon work in Wine, I
found out that this program uses a DOS program to access the CDROM,
and that it requires a real working MSCDEX device driver (and not only
that, the driver has to reside in a different segment than the DOS
core).

To make the patches as small as possible, I've split the patch into
several parts.

This part provides the actual code of the device driver.  For the most
part, this is the result of moving device driver code from
MSCDEX_Handler() to a new function MSCDEX_Request() which can be
called both from MSCDEX_Handler() and from the MSCDEX interrupt
routine.

I also had to patch module initialization, since device drivers can
not be initialized later, when a program is loaded already (in
particular, DPMI_AllocInternalRMCB() fails, so we cannot set up the
thunks correctly).

ChangeLog:

* dlls/winedos/in2f.c:
winedos: move most of MSCDEX stuff into a separate function

* dlls/winedos/in2f.c:
winedos: fix some minor bugs in MSCDEX code

* dlls/winedos/module.c, dlls/winedos/dosexe.h:
winedos: initialize MSCDEX after other device drivers
-------------- next part --------------
Index: dosexe.h
===================================================================
RCS file: /home/wine/wine/dlls/winedos/dosexe.h,v
retrieving revision 1.38
diff -u -r1.38 dosexe.h
--- dosexe.h	27 Mar 2006 11:30:41 -0000	1.38
+++ dosexe.h	31 Mar 2006 10:29:37 -0000
@@ -374,6 +482,7 @@
 
 /* int2f.c */
 extern void WINAPI DOSVM_Int2fHandler(CONTEXT86*);
+extern void MSCDEX_InstallCDROM(void);
 
 /* int31.c */
 extern void WINAPI DOSVM_Int31Handler(CONTEXT86*);
Index: int2f.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/int2f.c,v
retrieving revision 1.8
diff -u -r1.8 int2f.c
--- int2f.c	28 Nov 2005 20:10:42 -0000	1.8
+++ int2f.c	31 Mar 2006 10:29:37 -0000
@@ -24,6 +24,7 @@
 #include "config.h"
 
 #include <string.h>
+#include <stdlib.h>
 
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
@@ -42,6 +43,25 @@
 /* base WPROCS.DLL ordinal number for VxDs */
 #define VXD_BASE 400
 
+typedef struct
+{
+    DOS_DEVICE_HEADER hdr;
+
+    WORD  reserved;             /* must be 0 */
+    BYTE  drive;                /* drive letter (0=A:, 1=B:, ...) */
+    BYTE  units;                /* number of supported units */
+} CDROM_DEVICE_HEADER;
+
+typedef struct
+{
+    CDROM_DEVICE_HEADER hdr;
+    WINEDEV_THUNK thunk;
+
+    WORD  cdrom_segment;        /* Real mode segment for CDROM_HEAP */
+} CDROM_HEAP;
+
+static CDROM_HEAP *cdrom_heap;
+
 static void do_int2f_16( CONTEXT86 *context );
 static void MSCDEX_Handler( CONTEXT86 *context );
 
@@ -470,24 +490,542 @@
     return (GetDriveTypeA(root) == DRIVE_CDROM);
 }
 
+/* Returns 255 if successful, device driver error code otherwise */
+static BYTE MSCDEX_ReadTOC(HANDLE h, CDROM_TOC *toc)
+{
+    DWORD br;
+
+    if (!DeviceIoControl(h, IOCTL_CDROM_READ_TOC, NULL, 0,
+                         toc, sizeof(CDROM_TOC), &br, NULL))
+        return GetLastError() == STATUS_NO_MEDIA_IN_DEVICE
+            ? 2                 /* drive not ready */
+            : 1;                /* unknown unit */
+
+    return 255;
+}
+
+/* Returns 255 if successful, device driver error code otherwise */
+static BYTE MSCDEX_ReadQChannel(HANDLE h, SUB_Q_CHANNEL_DATA *qdata)
+{
+    CDROM_SUB_Q_DATA_FORMAT     fmt;
+    DWORD                       br;
+ 
+    fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
+    if (!DeviceIoControl(h, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt),
+                         qdata, sizeof(SUB_Q_CHANNEL_DATA), &br, NULL))
+        return GetLastError() == STATUS_NO_MEDIA_IN_DEVICE
+            ? 2                 /* drive not ready */
+            : 1;                /* unknown unit */
+
+    return 255;
+}
+
+/* Returns 255 if successful, device driver error code otherwise */
+static BYTE MSCDEX_ReadLong(HANDLE h, DWORD at, WORD num,
+                            BYTE addrmode, BYTE format, LPBYTE dst)
+{
+    RAW_READ_INFO       rri;
+    DWORD               br;
+
+    TRACE("Read long (%s): %d sectors from %ld\n",
+          format ? "raw" : "cooked", num, at);
+
+    switch (addrmode) {
+    case 1: /* Red book addressing mode = 0:m:s:f */
+        /* FIXME : frame <=> msf conversion routines could be shared
+         * between mscdex and mcicda
+         */
+        at = LOBYTE(HIWORD(at)) * CDFRAMES_PERMIN +
+            HIBYTE(LOWORD(at)) * CDFRAMES_PERSEC +
+            LOBYTE(LOWORD(at));
+        /* fall through */
+    case 0: /* HSG addressing mode */
+        switch (format)
+        {
+        case 0: /* cooked */
+            {
+                /* Some copy-protection schemes use non-standard
+                 * sectors, so a normal read will fail on them,
+                 * but a raw read is OK. Now, the Windows API does
+                 * not provide a way to read only 2048 bytes of
+                 * data in raw mode, so we have to read the entire
+                 * raw sector into a temporary buffer and copy out
+                 * the data portion.
+                 */
+                PBYTE rawdata;
+                int i;
+
+                if (! (rawdata = malloc(2352)) )
+                    return 0x0c; /* FIXME? */
+
+                for (i = 0; i < num; ++i, ++at, dst += 2048)
+                    {
+                        rri.DiskOffset.u.HighPart = at >> (32-11);
+                        rri.DiskOffset.u.LowPart = at << 11;
+                        rri.TrackMode = YellowMode2;
+                        rri.SectorCount = 1;
+                        if(!DeviceIoControl(h, IOCTL_CDROM_RAW_READ,
+                                            &rri, sizeof(rri),
+                                            rawdata, 2352, &br, NULL)) {
+                            free(rawdata);
+                            return GetLastError() == STATUS_NO_MEDIA_IN_DEVICE
+                                ? 0x02  /* drive not ready */
+                                : 0x0b; /* read fault */
+                        }
+
+                        /* FIXME: For now, we assume that data mode 2 means
+                         * always XA Mode 2 Form 1.  But what about Yellow
+                         * Mode 2 and XA Mode 2 Form 2 sectors?
+                         */
+                        if( rawdata[15] == 2)
+                            memcpy(dst, rawdata + 24, 2048);
+                        else
+                            memcpy(dst, rawdata + 16, 2048);
+                    }
+
+                free(rawdata);
+            }
+            break;
+
+        case 1:
+            rri.DiskOffset.u.HighPart = at >> (32-11);
+            rri.DiskOffset.u.LowPart = at << 11;
+            rri.TrackMode = YellowMode2;
+            rri.SectorCount = num;
+            DeviceIoControl(h, IOCTL_CDROM_RAW_READ, &rri, sizeof(rri),
+                            dst, num * 2352, &br, NULL);
+            break;
+
+        default:
+            ERR("Unsupported read mode !!\n");
+            return 0x0c;
+        }
+        break;
+    default:
+        ERR("Unsupported address mode !!\n");
+        return 0x0c;
+    }
+
+    return 255;
+}
+
+static void MSCDEX_Request(REQUEST_HEADER *request, BOOL dorealmode)
+{
+    BYTE*               io_stru;
+    BYTE                Error = 255; /* No Error */
+    char                devName[] = "\\\\.\\@:";
+    HANDLE              h;
+    CDROM_TOC           toc;
+    SUB_Q_CHANNEL_DATA  qdata;
+    DWORD               br;
+
+    TRACE("CDROM device driver -> command <%d>\n", request->command);
+
+    MSCDEX_Dump("Beg", request, dorealmode);
+
+    /* set status to 0 */
+    request->status = 0;
+    devName[4] = 'A' +  cdrom_heap->hdr.drive + request->unit;
+    h = CreateFileA(devName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
+    if (!h) {
+        WARN("Couldn't open cdrom handle\n");
+        request->status = STAT_ERROR | 1; /* unknown unit */
+        return;
+    }
+
+    /* This is checked at the end of MSCDEX_Request */
+    qdata.CurrentPosition.Header.AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
+
+    switch (request->command) {
+    case CMD_INIOCTL:
+        io_stru = dorealmode
+            ? PTR_REAL_TO_LIN( SELECTOROF(((REQ_IO*)request)->buffer),
+                               OFFSETOF(((REQ_IO*)request)->buffer) )
+            : MapSL(((REQ_IO*)request)->buffer);
+
+        TRACE(" --> IOCTL INPUT <%d>\n", io_stru[0]);
+        switch (io_stru[0]) {
+        case 0: /* Get device Header */
+            PTR_AT(io_stru, 0, WORD) = FIELD_OFFSET(CDROM_HEAP, hdr);
+            PTR_AT(io_stru, 2, WORD) = cdrom_heap->cdrom_segment;
+            Error = 255;        /* No Error */
+            break;
+
+        case 1: /* location of head */
+            if( (Error = MSCDEX_ReadQChannel(h, &qdata)) < 255)
+                break;
+
+            switch (io_stru[1]) {
+            case 0:
+                PTR_AT(io_stru, 2, DWORD) =
+                    FRAME_OF_ADDR(qdata.CurrentPosition.AbsoluteAddress);
+                break;
+            case 1:
+                MSCDEX_StoreMSF(FRAME_OF_ADDR(qdata.CurrentPosition.AbsoluteAddress),
+                                io_stru + 2);
+                break;
+            default:
+                ERR("CD-ROM driver: unsupported addressing mode !!\n");
+                Error = 0x0c;
+            }
+            TRACE(" ----> HEAD LOCATION <%ld>\n", PTR_AT(io_stru, 2, DWORD));
+            break;
+
+        case 4: /* Audio channel info */
+            if( (Error = MSCDEX_ReadQChannel(h, &qdata)) < 255)
+                break;
+
+            io_stru[1] = 0;
+            io_stru[2] = 0xff;
+            io_stru[3] = 1;
+            io_stru[4] = 0xff;
+            io_stru[5] = 2;
+            io_stru[6] = 0;
+            io_stru[7] = 3;
+            io_stru[8] = 0;
+            TRACE(" ----> AUDIO CHANNEL INFO\n");
+            break;
+
+        case 6: /* device status */
+            Error = MSCDEX_ReadQChannel(h, &qdata);
+            if(Error < 255 && Error != 2)
+                break;
+
+            PTR_AT(io_stru, 1, DWORD) = 0x00000290;
+            /* 290 =>
+             * 1        Supports HSG and Red Book addressing modes
+             * 0        Supports audio channel manipulation
+             *
+             * 1        Supports prefetching requests
+             * 0        Reserved
+             * 0        No interleaving
+             * 1        Data read and plays audio/video tracks
+             *
+             * 0        Read only
+             * 0        Supports only cooked reading
+             * 0        Door locked
+             * 0        see below (Door closed/opened)
+             */
+            if (Error == 2) {
+                PTR_AT(io_stru, 1, DWORD) |= 1;
+                Error = 255;    /* No Error */
+            }
+            TRACE(" ----> DEVICE STATUS <0x%08lx>\n", PTR_AT(io_stru, 1, DWORD));
+            break;
+
+        case 8: /* Volume size */
+            if( (Error = MSCDEX_ReadTOC(h, &toc)) < 255)
+                break;
+            if( (Error = MSCDEX_ReadQChannel(h, &qdata)) < 255)
+                break;
+
+            PTR_AT(io_stru, 1, DWORD) = FRAME_OF_TOC(toc, toc.LastTrack + 1) -
+                FRAME_OF_TOC(toc, toc.FirstTrack) - 1;
+            TRACE(" ----> VOLUME SIZE <%ld>\n", PTR_AT(io_stru, 1, DWORD));
+            break;
+
+        case 9: /* media changed ? */
+            if( (Error = MSCDEX_ReadQChannel(h, &qdata)) < 255)
+                break;
+            /* answers don't know... -1/1 for yes/no would be better */
+            io_stru[1] = 0; /* FIXME? 1? */
+            TRACE(" ----> MEDIA CHANGED <%d>\n", io_stru[1]);
+            break;
+
+        case 10: /* audio disk info */
+            if( (Error = MSCDEX_ReadTOC(h, &toc)) < 255)
+                break;
+            if( (Error = MSCDEX_ReadQChannel(h, &qdata)) < 255)
+                break;
+            io_stru[1] = toc.FirstTrack; /* starting track of the disc */
+            io_stru[2] = toc.LastTrack;  /* ending track */
+            MSCDEX_StoreMSF(FRAME_OF_TOC(toc, toc.LastTrack + 1) -
+                            FRAME_OF_TOC(toc, toc.FirstTrack) - 1, io_stru + 3);
+
+            TRACE(" ----> AUDIO DISK INFO <%d-%d/%08lx>\n",
+                  io_stru[1], io_stru[2], PTR_AT(io_stru, 3, DWORD));
+            break;
+
+        case 11: /* audio track info */
+            if( (Error = MSCDEX_ReadTOC(h, &toc)) < 255)
+                break;
+            if( (Error = MSCDEX_ReadQChannel(h, &qdata)) < 255)
+                break;
+
+            if (io_stru[1] >= toc.FirstTrack && io_stru[1] <= toc.LastTrack) {
+                MSCDEX_StoreMSF(FRAME_OF_TOC(toc, io_stru[1]), io_stru + 2);
+                /* starting point of the track */
+                io_stru[6] = CTRL_OF_TOC(toc, io_stru[1]);
+            } else {
+                PTR_AT(io_stru, 2, DWORD) = 0;
+                io_stru[6] = 0;
+            }
+            TRACE(" ----> AUDIO TRACK INFO[%d] = [%08lx:%d]\n",
+                  io_stru[1], PTR_AT(io_stru, 2, DWORD), io_stru[6]);
+            break;
+
+        case 12: /* get Q-Channel info */
+            if( (Error = MSCDEX_ReadTOC(h, &toc)) < 255)
+                break;
+            if( (Error = MSCDEX_ReadQChannel(h, &qdata)) < 255)
+                break;
+
+            io_stru[1] = CTRL_OF_TOC(toc, qdata.CurrentPosition.TrackNumber);
+            io_stru[2] = qdata.CurrentPosition.TrackNumber;
+            io_stru[3] = 0; /* FIXME ?? */
+
+            /* why the heck did MS use another format for 0MSF information... sigh */
+            {
+                BYTE    bTmp[4];
+
+                MSCDEX_StoreMSF(FRAME_OF_ADDR(qdata.CurrentPosition.TrackRelativeAddress), bTmp);
+                io_stru[ 4] = bTmp[2];
+                io_stru[ 5] = bTmp[1];
+                io_stru[ 6] = bTmp[0];
+                io_stru[ 7] = 0;
+
+                MSCDEX_StoreMSF(FRAME_OF_ADDR(qdata.CurrentPosition.AbsoluteAddress), bTmp);
+                io_stru[ 8] = bTmp[2];
+                io_stru[ 9] = bTmp[1];
+                io_stru[10] = bTmp[0];
+                io_stru[11] = 0;
+            }
+            TRACE("Q-Channel info: Ctrl/adr=%02x TNO=%02x X=%02x rtt=%02x:%02x:%02x rtd=%02x:%02x:%02x (cf=%08x, tp=%08x)\n",
+                  io_stru[ 1], io_stru[ 2], io_stru[ 3],
+                  io_stru[ 4], io_stru[ 5], io_stru[ 6],
+                  io_stru[ 8], io_stru[ 9], io_stru[10],
+                  FRAME_OF_ADDR(qdata.CurrentPosition.AbsoluteAddress),
+                  FRAME_OF_TOC(toc, qdata.CurrentPosition.TrackNumber));
+            break;
+
+        case 15: /* Audio status info */
+            Error = MSCDEX_ReadTOC(h, &toc);
+            if(Error < 255 && Error != 2)
+                break;
+            Error = MSCDEX_ReadQChannel(h, &qdata);
+            if(Error < 255 && Error != 2)
+                break;
+
+            /* !!!! FIXME FIXME FIXME !! */
+            PTR_AT(io_stru, 1,  WORD) = 2 | ((qdata.CurrentPosition.Header.AudioStatus == AUDIO_STATUS_PAUSED) ? 1 : 0);
+            if (Error == 2) {
+                PTR_AT(io_stru, 3, DWORD) = 0;
+                PTR_AT(io_stru, 7, DWORD) = 0;
+                Error = 255;    /* No Error */
+            } else {
+                PTR_AT(io_stru, 3, DWORD) = FRAME_OF_TOC(toc, toc.FirstTrack);
+                PTR_AT(io_stru, 7, DWORD) = FRAME_OF_TOC(toc, toc.LastTrack + 1);
+            }
+            TRACE("Audio status info: status=%04x startLoc=%ld endLoc=%ld\n",
+                  PTR_AT(io_stru, 1, WORD), PTR_AT(io_stru, 3, DWORD), PTR_AT(io_stru, 7, DWORD));
+            break;
+
+        default:
+            FIXME("IOCTL INPUT: Unimplemented <%d>!!\n", io_stru[0]);
+            Error = 0x0c;
+            break;
+        }
+        break;
+
+    case CMD_OUTIOCTL:
+        io_stru = dorealmode
+            ? PTR_REAL_TO_LIN( SELECTOROF(((REQ_IO*)request)->buffer),
+                               OFFSETOF(((REQ_IO*)request)->buffer) )
+            : MapSL(((REQ_IO*)request)->buffer);
+
+        TRACE(" --> IOCTL OUTPUT <%d>\n", io_stru[0]);
+        switch (io_stru[0]) {
+        case 0: /* eject */
+            DeviceIoControl(h, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &br, NULL);
+            TRACE(" ----> EJECT\n");
+            break;
+        case 2: /* reset drive */
+            DeviceIoControl(h, IOCTL_STORAGE_RESET_DEVICE, NULL, 0, NULL, 0, &br, NULL);
+            TRACE(" ----> RESET\n");
+            break;
+        case 3: /* Audio Channel Control */
+            FIXME(" ----> AUDIO CHANNEL CONTROL (NIY)\n");
+            break;
+        case 5: /* close tray */
+            DeviceIoControl(h, IOCTL_STORAGE_LOAD_MEDIA, NULL, 0, NULL, 0, &br, NULL);
+            TRACE(" ----> CLOSE TRAY\n");
+            break;
+        default:
+            FIXME(" IOCTL OUTPUT: Unimplemented <%d>!!\n", io_stru[0]);
+            Error = 0x0c;
+            break;
+        }
+        break;
+
+    case 128: /* read long */
+        Error = MSCDEX_ReadLong(h,
+                                PTR_AT(request, 20, DWORD), /* at */
+                                PTR_AT(request, 18, WORD), /* num */
+                                PTR_AT(request, 13, BYTE), /* addrmode */
+                                PTR_AT(request, 24, BYTE), /* format */
+                                dorealmode
+                                ? PTR_REAL_TO_LIN( PTR_AT(request, 16, WORD),
+                                                   PTR_AT(request, 14, WORD))
+                                : MapSL(MAKESEGPTR(PTR_AT(request, 16, WORD),
+                                                   PTR_AT(request, 14, WORD))));
+        break;
+
+    case 131: /* seek */
+        {
+            DWORD                       at;
+            CDROM_SEEK_AUDIO_MSF        seek;
+
+            at = PTR_AT(request, 20, DWORD);
+
+            TRACE(" --> SEEK AUDIO mode :<0x%02X>, [%ld]\n",
+                  PTR_AT(request, 13, BYTE), at);
+
+            if(Error < 255)
+                break;
+
+            switch (PTR_AT(request, 13, BYTE)) {
+            case 1: /* Red book addressing mode = 0:m:s:f */
+                /* FIXME : frame <=> msf conversion routines could be shared
+                 * between mscdex and mcicda
+                 */
+                at = LOBYTE(HIWORD(at)) * CDFRAMES_PERMIN +
+                    HIBYTE(LOWORD(at)) * CDFRAMES_PERSEC +
+                    LOBYTE(LOWORD(at));
+                /* fall through */
+            case 0: /* HSG addressing mode */
+                seek.M = at / CDFRAMES_PERMIN;
+                seek.S = (at / CDFRAMES_PERSEC) % 60;
+                seek.F = at % CDFRAMES_PERSEC;
+                DeviceIoControl(h, IOCTL_CDROM_SEEK_AUDIO_MSF,
+                                &seek, sizeof(seek), NULL, 0, &br, NULL);
+                break;
+            default:
+                ERR("Unsupported address mode !!\n");
+                Error = 0x0c;
+                break;
+            }
+
+            if( (Error = MSCDEX_ReadQChannel(h, &qdata)) < 255)
+                break;
+        }
+        break;
+
+    case 132: /* play */
+        {
+            DWORD                       beg, end;
+            CDROM_PLAY_AUDIO_MSF        play;
+
+            beg = end = PTR_AT(request, 14, DWORD);
+            end += PTR_AT(request, 18, DWORD);
+
+            TRACE(" --> PLAY AUDIO mode :<0x%02X>, [%ld-%ld]\n",
+                  PTR_AT(request, 13, BYTE), beg, end);
+
+            switch (PTR_AT(request, 13, BYTE)) {
+            case 1:
+                /* Red book addressing mode = 0:m:s:f */
+                /* FIXME : frame <=> msf conversion routines could be shared
+                 * between mscdex and mcicda
+                 */
+                beg = LOBYTE(LOWORD(beg)) * CDFRAMES_PERMIN +
+                    HIBYTE(LOWORD(beg)) * CDFRAMES_PERSEC +
+                    LOBYTE(HIWORD(beg));
+                end = LOBYTE(LOWORD(end)) * CDFRAMES_PERMIN +
+                    HIBYTE(LOWORD(end)) * CDFRAMES_PERSEC +
+                    LOBYTE(HIWORD(end));
+                /* fall through */
+            case 0: /* HSG addressing mode */
+                play.StartingM = beg / CDFRAMES_PERMIN;
+                play.StartingS = (beg / CDFRAMES_PERSEC) % 60;
+                play.StartingF = beg % CDFRAMES_PERSEC;
+                play.EndingM   = end / CDFRAMES_PERMIN;
+                play.EndingS   = (end / CDFRAMES_PERSEC) % 60;
+                play.EndingF   = end % CDFRAMES_PERSEC;
+                DeviceIoControl(h, IOCTL_CDROM_PLAY_AUDIO_MSF,
+                                &play, sizeof(play), NULL, 0, &br, NULL);
+                break;
+            default:
+                ERR("Unsupported address mode !!\n");
+                Error = 0x0c;
+                break;
+            }
+
+            if( (Error = MSCDEX_ReadQChannel(h, &qdata)) < 255)
+                break;
+        }
+        break;
+
+    case 133:
+        if(Error < 255)
+            break;
+
+        if (qdata.CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
+            DeviceIoControl(h, IOCTL_CDROM_PAUSE_AUDIO, NULL, 0, NULL, 0, &br, NULL);
+            TRACE(" --> STOP AUDIO (Paused)\n");
+        } else {
+            DeviceIoControl(h, IOCTL_CDROM_STOP_AUDIO, NULL, 0, NULL, 0, &br, NULL);
+            TRACE(" --> STOP AUDIO (Stopped)\n");
+        }
+        break;
+
+    case 136:
+        if(Error < 255 )
+            break;
+
+        TRACE(" --> RESUME AUDIO\n");
+        DeviceIoControl(h, IOCTL_CDROM_RESUME_AUDIO, NULL, 0, NULL, 0, &br, NULL);
+        break;
+
+    default:
+        FIXME(" ioctl unimplemented <%d>\n", request->command);
+        Error = 0x03;           /* unknown command */
+    }
+
+    /* setting error codes if any */
+    if (Error < 255)
+        request->status = STAT_ERROR | Error;
+
+    CloseHandle(h);
+
+    request->status |= STAT_DONE;
+    if (qdata.CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS)
+        request->status |= STAT_BUSY;
+
+    MSCDEX_Dump("End", request, dorealmode);
+}
+
 static void MSCDEX_Handler(CONTEXT86* context)
 {
-    int        drive, count;
+    int        drive;
     char*      p;
 
     switch (LOBYTE(context->Eax)) {
     case 0x00: /* Installation check */
-       /* Count the number of contiguous CDROM drives
-        */
-       for (drive = count = 0; drive < 26; drive++) {
-           if (is_cdrom(drive)) {
-               while (is_cdrom(drive + count)) count++;
-               break;
+       {
+           CDROM_DEVICE_HEADER* dev = &cdrom_heap->hdr;
+
+           TRACE("Installation check: %d cdroms, starting at %d\n",
+                 dev->units, dev->drive);
+           SET_BX( context, dev->units );
+           SET_CX( context, dev->drive );
+       }
+       break;
+
+    case 0x01: /* get drive device list */
+       {
+           CDROM_DEVICE_HEADER* dev = &cdrom_heap->hdr;
+           SEGPTR ptr_dev = MAKESEGPTR( cdrom_heap->cdrom_segment,
+                                        FIELD_OFFSET(CDROM_HEAP, hdr) );
+
+           p = CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Ebx);
+           for (drive = 0; drive < dev->units; drive++) {
+               *p = drive; /* subunit */
+               ++p;
+               *(DWORD*)p = ptr_dev;
+               p += sizeof(DWORD);
            }
+           TRACE("Get drive device list\n");
        }
-       TRACE("Installation check: %d cdroms, starting at %d\n", count, drive);
-       SET_BX( context, count );
-       SET_CX( context, (drive < 26) ? drive : 0 );
        break;
 
     case 0x0B: /* drive check */
@@ -511,438 +1049,104 @@
 
     case 0x10: /* direct driver access */
        {
-           BYTE*       driver_request;
-           BYTE*       io_stru;
-           BYTE        Error = 255; /* No Error */
-           int         dorealmode = ISV86(context);
-            char        devName[] = "\\\\.\\@:";
-           HANDLE      h;
-            CDROM_TOC                   toc;
-            CDROM_SUB_Q_DATA_FORMAT     fmt;
-            SUB_Q_CHANNEL_DATA          data;
-            DWORD                       br;
-            DWORD                       present = TRUE;
-
-           driver_request = CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Ebx);
-
-           if (!driver_request) {
-               /* FIXME - to be deleted ?? */
-               ERR("ES:BX==0 ! SEGFAULT ?\n");
-               ERR("-->BX=0x%04x, ES=0x%04lx, DS=0x%04lx, CX=0x%04x\n",
-                   BX_reg(context), context->SegEs, context->SegDs, CX_reg(context));
-               driver_request[4] |= 0x80;
-               driver_request[3] = 5;  /* bad request length */
-               return;
-           }
-           /* FIXME
-             * the following tests are wrong because lots of functions don't require the
-             * tray to be closed with a CD inside
-            */
-           TRACE("CDROM device driver -> command <%d>\n", (unsigned char)driver_request[2]);
+           REQUEST_HEADER *request;
 
            if (!is_cdrom(CX_reg(context))) {
                WARN("Request made doesn't match a CD ROM drive (%d)\n", CX_reg(context));
-               driver_request[4] |= 0x80;
-               driver_request[3] = 1;  /* unknown unit */
+               SET_CFLAG( context );
+               SET_AX( context, 0x000f ); /* invalid drive */
                return;
            }
 
-           MSCDEX_Dump("Beg", driver_request, dorealmode);
+           request = CTX_SEG_OFF_TO_LIN(context, context->SegEs, context->Ebx);
+           request->unit = CX_reg(context) - cdrom_heap->hdr.drive;
+           MSCDEX_Request(request, ISV86(context));
+           RESET_CFLAG( context );
+       }
+       break;
 
-           /* set status to 0 */
-           PTR_AT(driver_request, 3, WORD) = 0;
-            devName[4] = 'A' + CX_reg(context);
-            h = CreateFileA(devName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
-            if (!h) {
-               WARN("Couldn't open cdrom handle\n");
-               driver_request[4] |= 0x80;
-               driver_request[3] = 1;  /* unknown unit */
-               return;
-           }
+    default:
+       FIXME("Unimplemented MSCDEX function 0x%02X.\n", LOBYTE(context->Eax));
+       break;
+    }
+}
 
-            fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
-            if (!DeviceIoControl(h, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(toc), &br, NULL) ||
-                !DeviceIoControl(h, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt),
-                                 &data, sizeof(data), &br, NULL)) {
-                if (GetLastError() == STATUS_NO_MEDIA_IN_DEVICE)
-                {
-                    if (driver_request[2] != 6 && driver_request[2] != 15)
-                    {
-                        driver_request[4] |= 0x80;
-                        driver_request[3] = 2; /* drive not ready */
-                        CloseHandle(h);
-                        return;
-                    }
-                    present = FALSE;
-                }
-                else
-                {
-                    driver_request[4] |= 0x80;
-                    driver_request[3] = 1;     /* unknown unit */
-                    CloseHandle(h);
-                    return;
-                }
-            }
+/* prototypes */
+static void WINAPI cdrom_strategy(CONTEXT86*ctx);
+static void WINAPI cdrom_interrupt(CONTEXT86*ctx);
+static void cdrom_init(SEGPTR ptr_dev);
 
-           switch (driver_request[2]) {
-           case 3:
-               io_stru = (dorealmode) ?
-                    PTR_REAL_TO_LIN( PTR_AT(driver_request, 16, WORD), PTR_AT(driver_request, 14, WORD) ) :
-                       MapSL( MAKESEGPTR(PTR_AT(driver_request, 16, WORD), PTR_AT(driver_request, 14, WORD)));
+static const WINEDEV cdromdev =
+{
+    "WINE_CD_",
+    ATTR_CHAR|ATTR_REMOVABLE|ATTR_IOCTL,
+    cdrom_strategy, cdrom_interrupt, cdrom_init
+};
 
-               TRACE(" --> IOCTL INPUT <%d>\n", io_stru[0]);
-               switch (io_stru[0]) {
-#if 0
-               case 0: /* Get device Header */
-                   {
-                       static  LPSTR ptr = 0;
-                       if (ptr == 0)   {
-                           ptr = SEGPTR_ALLOC(22);
-                           PTR_AT(ptr,  0, DWORD) = ~1;        /* Next Device Driver */
-                           PTR_AT(ptr,  4,  WORD) = 0xC800;    /* Device attributes  */
-                           PTR_AT(ptr,  6,  WORD) = 0x1234;    /* Pointer to device strategy routine: FIXME */
-                           PTR_AT(ptr,  8,  WORD) = 0x3142;    /* Pointer to device interrupt routine: FIXME */
-                           PTR_AT(ptr, 10,  char) = 'W';       /* 8-byte character device name field */
-                           PTR_AT(ptr, 11,  char) = 'I';
-                           PTR_AT(ptr, 12,  char) = 'N';
-                           PTR_AT(ptr, 13,  char) = 'E';
-                           PTR_AT(ptr, 14,  char) = '_';
-                           PTR_AT(ptr, 15,  char) = 'C';
-                           PTR_AT(ptr, 16,  char) = 'D';
-                           PTR_AT(ptr, 17,  char) = '_';
-                           PTR_AT(ptr, 18,  WORD) = 0;         /* Reserved (must be zero) */
-                           PTR_AT(ptr, 20,  BYTE) = 0;         /* Drive letter (must be zero) */
-                           PTR_AT(ptr, 21,  BYTE) = 1;         /* Number of units supported (one or more) FIXME*/
-                       }
-                       PTR_AT(io_stru, DWORD,  0) = SEGPTR_GET(ptr);
-                   }
-                   break;
-#endif
+static REQUEST_HEADER *cdrom_driver_request;
 
-               case 1: /* location of head */
-                   switch (io_stru[1]) {
-                   case 0:
-                       PTR_AT(io_stru, 2, DWORD) =
-                            FRAME_OF_ADDR(data.CurrentPosition.AbsoluteAddress);
-                       break;
-                   case 1:
-                       MSCDEX_StoreMSF(FRAME_OF_ADDR(data.CurrentPosition.AbsoluteAddress),
-                                        io_stru + 2);
-                       break;
-                   default:
-                       ERR("CD-ROM driver: unsupported addressing mode !!\n");
-                       Error = 0x0c;
-                   }
-                   TRACE(" ----> HEAD LOCATION <%ld>\n", PTR_AT(io_stru, 2, DWORD));
-                   break;
-
-               case 4: /* Audio channel info */
-                   io_stru[1] = 0;
-                   io_stru[2] = 0xff;
-                   io_stru[3] = 1;
-                   io_stru[4] = 0xff;
-                   io_stru[5] = 2;
-                   io_stru[6] = 0;
-                   io_stru[7] = 3;
-                   io_stru[8] = 0;
-                   TRACE(" ----> AUDIO CHANNEL INFO\n");
-                   break;
-
-               case 6: /* device status */
-                   PTR_AT(io_stru, 1, DWORD) = 0x00000290;
-                   /* 290 =>
-                    * 1        Supports HSG and Red Book addressing modes
-                    * 0        Supports audio channel manipulation
-                    *
-                    * 1        Supports prefetching requests
-                    * 0        Reserved
-                    * 0        No interleaving
-                    * 1        Data read and plays audio/video tracks
-                    *
-                    * 0        Read only
-                    * 0        Supports only cooked reading
-                    * 0        Door locked
-                    * 0        see below (Door closed/opened)
-                    */
-                   if (!present) PTR_AT(io_stru, 1, DWORD) |= 1;
-                   TRACE(" ----> DEVICE STATUS <0x%08lx>\n", PTR_AT(io_stru, 1, DWORD));
-                   break;
-
-               case 8: /* Volume size */
-                   PTR_AT(io_stru, 1, DWORD) = FRAME_OF_TOC(toc, toc.LastTrack + 1) -
-                        FRAME_OF_TOC(toc, toc.FirstTrack) - 1;
-                   TRACE(" ----> VOLUME SIZE <%ld>\n", PTR_AT(io_stru, 1, DWORD));
-                   break;
-
-               case 9: /* media changed ? */
-                   /* answers don't know... -1/1 for yes/no would be better */
-                   io_stru[1] = 0; /* FIXME? 1? */
-                   TRACE(" ----> MEDIA CHANGED <%d>\n", io_stru[1]);
-                   break;
-
-               case 10: /* audio disk info */
-                   io_stru[1] = toc.FirstTrack; /* starting track of the disc */
-                   io_stru[2] = toc.LastTrack;  /* ending track */
-                   MSCDEX_StoreMSF(FRAME_OF_TOC(toc, toc.LastTrack + 1) -
-                                    FRAME_OF_TOC(toc, toc.FirstTrack) - 1, io_stru + 3);
-
-                   TRACE(" ----> AUDIO DISK INFO <%d-%d/%08lx>\n",
-                         io_stru[1], io_stru[2], PTR_AT(io_stru, 3, DWORD));
-                   break;
-
-               case 11: /* audio track info */
-                   if (io_stru[1] >= toc.FirstTrack && io_stru[1] <= toc.LastTrack) {
-                       MSCDEX_StoreMSF(FRAME_OF_TOC(toc, io_stru[1]), io_stru + 2);
-                       /* starting point if the track */
-                       io_stru[6] = CTRL_OF_TOC(toc, io_stru[1]);
-                   } else {
-                       PTR_AT(io_stru, 2, DWORD) = 0;
-                       io_stru[6] = 0;
-                   }
-                   TRACE(" ----> AUDIO TRACK INFO[%d] = [%08lx:%d]\n",
-                         io_stru[1], PTR_AT(io_stru, 2, DWORD), io_stru[6]);
-                   break;
-
-               case 12: /* get Q-Channel info */
-                   io_stru[1] = CTRL_OF_TOC(toc, data.CurrentPosition.TrackNumber);
-                   io_stru[2] = data.CurrentPosition.TrackNumber;
-                   io_stru[3] = 0; /* FIXME ?? */
-
-                   /* why the heck did MS use another format for 0MSF information... sigh */
-                   {
-                       BYTE    bTmp[4];
-
-                       MSCDEX_StoreMSF(FRAME_OF_ADDR(data.CurrentPosition.TrackRelativeAddress), bTmp);
-                       io_stru[ 4] = bTmp[2];
-                       io_stru[ 5] = bTmp[1];
-                       io_stru[ 6] = bTmp[0];
-                       io_stru[ 7] = 0;
-
-                       MSCDEX_StoreMSF(FRAME_OF_ADDR(data.CurrentPosition.AbsoluteAddress), bTmp);
-                       io_stru[ 8] = bTmp[2];
-                       io_stru[ 9] = bTmp[1];
-                       io_stru[10] = bTmp[0];
-                       io_stru[11] = 0;
-                   }
-                   TRACE("Q-Channel info: Ctrl/adr=%02x TNO=%02x X=%02x rtt=%02x:%02x:%02x rtd=%02x:%02x:%02x (cf=%08x, tp=%08x)\n",
-                         io_stru[ 1], io_stru[ 2], io_stru[ 3],
-                         io_stru[ 4], io_stru[ 5], io_stru[ 6],
-                         io_stru[ 8], io_stru[ 9], io_stru[10],
-                         FRAME_OF_ADDR(data.CurrentPosition.AbsoluteAddress),
-                          FRAME_OF_TOC(toc, data.CurrentPosition.TrackNumber));
-                   break;
-
-               case 15: /* Audio status info */
-                   /* !!!! FIXME FIXME FIXME !! */
-                   PTR_AT(io_stru, 1,  WORD) = 2 | ((data.CurrentPosition.Header.AudioStatus == AUDIO_STATUS_PAUSED) ? 1 : 0);
-                   if (!present) {
-                       PTR_AT(io_stru, 3, DWORD) = 0;
-                       PTR_AT(io_stru, 7, DWORD) = 0;
-                   } else {
-                       PTR_AT(io_stru, 3, DWORD) = FRAME_OF_TOC(toc, toc.FirstTrack);
-                       PTR_AT(io_stru, 7, DWORD) = FRAME_OF_TOC(toc, toc.LastTrack + 1);
-                   }
-                   TRACE("Audio status info: status=%04x startLoc=%ld endLoc=%ld\n",
-                         PTR_AT(io_stru, 1, WORD), PTR_AT(io_stru, 3, DWORD), PTR_AT(io_stru, 7, DWORD));
-                   break;
-
-               default:
-                   FIXME("IOCTL INPUT: Unimplemented <%d>!!\n", io_stru[0]);
-                   Error = 0x0c;
-                   break;
-               }
-               break;
+/* Return to caller */
+static void do_lret(CONTEXT86*ctx)
+{
+    WORD *stack = CTX_SEG_OFF_TO_LIN(ctx, ctx->SegSs, ctx->Esp);
 
-           case 12:
-               io_stru = (dorealmode) ?
-                   PTR_REAL_TO_LIN( PTR_AT(driver_request, 16, WORD), PTR_AT(driver_request, 14, WORD)) :
-                       MapSL( MAKESEGPTR(PTR_AT(driver_request, 16, WORD), PTR_AT(driver_request, 14, WORD)));
-
-               TRACE(" --> IOCTL OUTPUT <%d>\n", io_stru[0]);
-               switch (io_stru[0]) {
-               case 0: /* eject */
-                    DeviceIoControl(h, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &br, NULL);
-                   TRACE(" ----> EJECT\n");
-                   break;
-               case 2: /* reset drive */
-                   DeviceIoControl(h, IOCTL_STORAGE_RESET_DEVICE, NULL, 0, NULL, 0, &br, NULL);
-                   TRACE(" ----> RESET\n");
-                   break;
-               case 3: /* Audio Channel Control */
-                   FIXME(" ----> AUDIO CHANNEL CONTROL (NIY)\n");
-                   break;
-               case 5: /* close tray */
-                    DeviceIoControl(h, IOCTL_STORAGE_LOAD_MEDIA, NULL, 0, NULL, 0, &br, NULL);
-                   TRACE(" ----> CLOSE TRAY\n");
-                   break;
-               default:
-                   FIXME(" IOCTL OUTPUT: Unimplemented <%d>!!\n", io_stru[0]);
-                   Error = 0x0c;
-                   break;
-               }
-               break;
+    ctx->Eip   = *(stack++);
+    ctx->SegCs = *(stack++);
+    ctx->Esp  += 2*sizeof(WORD);
+}
 
-            case 128: /* read long */
-                {
-                    LPVOID              dst = MapSL(MAKESEGPTR(PTR_AT(driver_request, 16, WORD),
-                                                               PTR_AT(driver_request, 14, WORD)));
-                    DWORD               at = PTR_AT(driver_request, 20, DWORD);
-                    WORD                num = PTR_AT(driver_request, 18, WORD);
-                    RAW_READ_INFO       rri;
-
-                   switch (driver_request[13]) {
-                   case 1: /* Red book addressing mode = 0:m:s:f */
-                       /* FIXME : frame <=> msf conversion routines could be shared
-                        * between mscdex and mcicda
-                        */
-                       at = LOBYTE(HIWORD(at)) * CDFRAMES_PERMIN +
-                           HIBYTE(LOWORD(at)) * CDFRAMES_PERSEC +
-                           LOBYTE(LOWORD(at));
-                       /* fall through */
-                   case 0: /* HSG addressing mode */
-                        switch (PTR_AT(driver_request, 24, BYTE))
-                        {
-                        case 0: /* cooked */
-                            ReadFile(h, dst, num * 2048, &br, NULL);
-                            break;
-                        case 1:
-                            /* FIXME: computation is wrong */
-                            rri.DiskOffset.u.HighPart = 0;
-                            rri.DiskOffset.u.LowPart = at << 11;
-                            rri.TrackMode = YellowMode2;
-                            rri.SectorCount = num;
-                            DeviceIoControl(h, IOCTL_CDROM_RAW_READ, &rri, sizeof(rri),
-                                            dst, num * 2352, &br, NULL);
-                       break;
-                        default:
-                            ERR("Unsupported read mode !!\n");
-                            Error = 0x0c;
-                            break;
-                        }
-                        break;
-                   default:
-                       ERR("Unsupported address mode !!\n");
-                       Error = 0x0c;
-                       break;
-                   }
-                }
-                break;
-
-           case 131: /* seek */
-               {
-                   DWORD                       at;
-                    CDROM_SEEK_AUDIO_MSF        seek;
-
-                   at = PTR_AT(driver_request, 20, DWORD);
-
-                   TRACE(" --> SEEK AUDIO mode :<0x%02X>, [%ld]\n",
-                         (BYTE)driver_request[13], at);
-
-                   switch (driver_request[13]) {
-                   case 1: /* Red book addressing mode = 0:m:s:f */
-                       /* FIXME : frame <=> msf conversion routines could be shared
-                        * between mscdex and mcicda
-                        */
-                       at = LOBYTE(HIWORD(at)) * CDFRAMES_PERMIN +
-                           HIBYTE(LOWORD(at)) * CDFRAMES_PERSEC +
-                           LOBYTE(LOWORD(at));
-                       /* fall through */
-                   case 0: /* HSG addressing mode */
-                        seek.M = at / CDFRAMES_PERMIN;
-                        seek.S = (at / CDFRAMES_PERSEC) % 60;
-                        seek.F = at % CDFRAMES_PERSEC;
-                        DeviceIoControl(h, IOCTL_CDROM_SEEK_AUDIO_MSF, &seek, sizeof(seek),
-                                        NULL, 0, &br, NULL);
-                       break;
-                   default:
-                       ERR("Unsupported address mode !!\n");
-                       Error = 0x0c;
-                       break;
-                   }
-               }
-               break;
+static void WINAPI cdrom_strategy(CONTEXT86*ctx)
+{
+    cdrom_driver_request = CTX_SEG_OFF_TO_LIN(ctx, ctx->SegEs, ctx->Ebx);
+    do_lret( ctx );
+}
 
-           case 132: /* play */
-               {
-                   DWORD                       beg, end;
-                    CDROM_PLAY_AUDIO_MSF        play;
-
-                   beg = end = PTR_AT(driver_request, 14, DWORD);
-                   end += PTR_AT(driver_request, 18, DWORD);
-
-                   TRACE(" --> PLAY AUDIO mode :<0x%02X>, [%ld-%ld]\n",
-                         (BYTE)driver_request[13], beg, end);
-
-                   switch (driver_request[13]) {
-                   case 1:
-                       /* Red book addressing mode = 0:m:s:f */
-                       /* FIXME : frame <=> msf conversion routines could be shared
-                        * between mscdex and mcicda
-                        */
-                       beg = LOBYTE(LOWORD(beg)) * CDFRAMES_PERMIN +
-                           HIBYTE(LOWORD(beg)) * CDFRAMES_PERSEC +
-                           LOBYTE(HIWORD(beg));
-                       end = LOBYTE(LOWORD(end)) * CDFRAMES_PERMIN +
-                           HIBYTE(LOWORD(end)) * CDFRAMES_PERSEC +
-                           LOBYTE(HIWORD(end));
-                       /* fall through */
-                   case 0: /* HSG addressing mode */
-                        play.StartingM = beg / CDFRAMES_PERMIN;
-                        play.StartingS = (beg / CDFRAMES_PERSEC) % 60;
-                        play.StartingF = beg % CDFRAMES_PERSEC;
-                        play.EndingM   = end / CDFRAMES_PERMIN;
-                        play.EndingS   = (end / CDFRAMES_PERSEC) % 60;
-                        play.EndingF   = end % CDFRAMES_PERSEC;
-                        DeviceIoControl(h, IOCTL_CDROM_PLAY_AUDIO_MSF, &play, sizeof(play),
-                                        NULL, 0, &br, NULL);
-                       break;
-                   default:
-                       ERR("Unsupported address mode !!\n");
-                       Error = 0x0c;
-                       break;
-                   }
-               }
-               break;
+static void WINAPI cdrom_interrupt(CONTEXT86*ctx)
+{
+    if (cdrom_driver_request->unit > cdrom_heap->hdr.units)
+        cdrom_driver_request->status = STAT_ERROR | 1; /* unknown unit */
+    else
+        MSCDEX_Request(cdrom_driver_request, ISV86(ctx));
 
-           case 133:
-               if (data.CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) {
-                    DeviceIoControl(h, IOCTL_CDROM_PAUSE_AUDIO, NULL, 0, NULL, 0, &br, NULL);
-                   TRACE(" --> STOP AUDIO (Paused)\n");
-               } else {
-                    DeviceIoControl(h, IOCTL_CDROM_STOP_AUDIO, NULL, 0, NULL, 0, &br, NULL);
-                   TRACE(" --> STOP AUDIO (Stopped)\n");
-               }
-               break;
+    do_lret( ctx );
+}
 
-           case 136:
-               TRACE(" --> RESUME AUDIO\n");
-                DeviceIoControl(h, IOCTL_CDROM_PAUSE_AUDIO, NULL, 0, NULL, 0, &br, NULL);
-               break;
+static void cdrom_init(SEGPTR ptr_dev)
+{
+    CDROM_DEVICE_HEADER *dev = PTR_REAL_TO_LIN( SELECTOROF(ptr_dev),
+                                                OFFSETOF(ptr_dev) );
+    int drive, count;
+
+    /* Count the number of contiguous CDROM drives
+     */
+    count = 0;
+    for (drive = 0; drive < 26; drive++) {
+        while (is_cdrom( drive )) {
+            count++;
+            drive++;
+        }
+        if (count)
+            break;
+    }
 
-           default:
-               FIXME(" ioctl unimplemented <%d>\n", driver_request[2]);
-               Error = 0x0c;
-           }
+    if (!count)
+        drive = 0;
 
-           /* setting error codes if any */
-           if (Error < 255) {
-               driver_request[4] |= 0x80;
-               driver_request[3] = Error;
-           }
+    dev->drive = drive - count;
+    dev->units = count;
+    dev->reserved = 0;
+}
 
-           CloseHandle(h);
-           /* setting status bits
-            * 3 == playing && done
-            * 1 == done
-            */
-           driver_request[4] |=
-                (data.CurrentPosition.Header.AudioStatus == AUDIO_STATUS_IN_PROGRESS) ? 3 : 1;
+void MSCDEX_InstallCDROM(void)
+{
+    WORD seg;
 
-           MSCDEX_Dump("End", driver_request, dorealmode);
-       }
-       break;
-    default:
-       FIXME("Unimplemented MSCDEX function 0x%02X.\n", LOBYTE(context->Eax));
-       break;
-    }
+    /* allocate a new DOS data segment */
+    cdrom_heap = DOSVM_AllocDataUMB( sizeof(CDROM_HEAP), &seg, NULL );
+    cdrom_heap->cdrom_segment = seg;
+
+    DOSDEV_SetupDevice( &cdromdev,
+                        seg,
+                        FIELD_OFFSET(CDROM_HEAP, hdr),
+                        FIELD_OFFSET(CDROM_HEAP, thunk) );
 }
Index: module.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/module.c,v
retrieving revision 1.52
diff -u -r1.52 module.c
--- module.c	3 Oct 2005 10:15:32 -0000	1.52
+++ module.c	31 Mar 2006 10:29:37 -0000
@@ -197,6 +197,7 @@
     TRACE("Initializing DOS memory structures\n");
     DOSMEM_MapDosLayout();
     DOSDEV_InstallDOSDevices();
+    MSCDEX_InstallCDROM();
 
     return TRUE;
 }


More information about the wine-patches mailing list