[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