From 5cc6105b392b202bbded1d39915742192c88fc95 Mon Sep 17 00:00:00 2001
From: Eric Pouech <eric.pouech@wanadoo.fr>
Date: Sun, 13 Jan 2002 01:44:00 +0000
Subject: [PATCH] Changed the Wine internal cdrom interface to the NT model.

---
 dlls/ntdll/Makefile.in |   1 +
 dlls/ntdll/cdrom.c     | 996 +++++++++++++++++++++++++++++++++++++++++
 files/drive.c          | 263 ++++++++++-
 files/file.c           |   5 +
 include/cdrom.h        | 109 -----
 include/file.h         |   6 +
 include/ntddcdrm.h     | 167 +++++++
 include/ntddstor.h     | 229 ++++++++++
 include/winioctl.h     |  79 +++-
 misc/Makefile.in       |   1 -
 misc/cdrom.c           | 908 -------------------------------------
 win32/device.c         |  53 ++-
 12 files changed, 1778 insertions(+), 1039 deletions(-)
 create mode 100644 dlls/ntdll/cdrom.c
 delete mode 100644 include/cdrom.h
 create mode 100644 include/ntddcdrm.h
 create mode 100644 include/ntddstor.h
 delete mode 100644 misc/cdrom.c

diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index a4bc895f59d..c48977f682c 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -6,6 +6,7 @@ MODULE    = ntdll
 EXTRALIBS = $(LIBUNICODE)
 
 C_SRCS = \
+	cdrom.c \
 	critsection.c \
 	debugtools.c \
 	exception.c \
diff --git a/dlls/ntdll/cdrom.c b/dlls/ntdll/cdrom.c
new file mode 100644
index 00000000000..1d56296ee87
--- /dev/null
+++ b/dlls/ntdll/cdrom.c
@@ -0,0 +1,996 @@
+/* -*- tab-width: 8; c-basic-offset: 4 -*- */
+/* Main file for CD-ROM support
+ *
+ * Copyright 1994 Martin Ayotte
+ * Copyright 1999, 2001 Eric Pouech
+ * Copyright 2000 Andreas Mohr
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ntddk.h"
+#include "winioctl.h"
+#include "ntddstor.h"
+#include "ntddcdrm.h"
+#include "drive.h"
+#include "file.h"
+#include "debugtools.h"
+
+#ifdef HAVE_LINUX_CDROM_H
+# include <linux/cdrom.h>
+#endif
+#ifdef HAVE_LINUX_UCDROM_H
+# include <linux/ucdrom.h>
+#endif
+#ifdef HAVE_SYS_CDIO_H
+# include <sys/cdio.h>
+#endif
+
+DEFAULT_DEBUG_CHANNEL(cdrom);
+
+/* FIXME: this is needed because we can't open simultaneously several times /dev/cdrom 
+ * this should be removed when a proper device interface is implemented
+ */
+struct cdrom_cache {
+    int fd;
+    int count;
+};
+static struct cdrom_cache cdrom_cache[26];
+
+/******************************************************************
+ *		CDROM_Open
+ *
+ *
+ */
+static int CDROM_Open(HANDLE hDevice, DWORD clientID)
+{
+    int dev = LOWORD(clientID);
+
+    if (dev >= 26) return -1;
+
+    if (!cdrom_cache[dev].count)
+    {
+        char root[4];
+
+        strcpy(root, "A:\\");
+        root[0] += dev;
+        if (GetDriveTypeA(root) != DRIVE_CDROM) return -1;
+        cdrom_cache[dev].fd = open(DRIVE_GetDevice(dev), O_RDONLY|O_NONBLOCK);
+        if (cdrom_cache[dev].fd == -1)
+        {
+            FIXME("Can't open %s: %s\n", root, strerror(errno));
+            return -1;
+        }
+    }
+    cdrom_cache[dev].count++;
+    return cdrom_cache[dev].fd;
+}
+
+/******************************************************************
+ *		CDROM_Close
+ *
+ *
+ */
+static void CDROM_Close(DWORD clientID, int fd)
+{
+    int dev = LOWORD(clientID);
+    
+    if (dev >= 26 || fd != cdrom_cache[dev].fd) FIXME("how come\n");
+    if (--cdrom_cache[dev].count == 0)
+        close(cdrom_cache[dev].fd);
+}
+
+/******************************************************************
+ *		CDROM_GetStatusCode
+ *
+ *
+ */
+static DWORD CDROM_GetStatusCode(int io)
+{
+    if (io == 0) return 0;
+    switch (errno)
+    {
+    case EIO:   return STATUS_NO_MEDIA_IN_DEVICE;
+    }
+    FIXME("Unmapped error code %d: %s\n", errno, strerror(errno));
+    return STATUS_IO_DEVICE_ERROR;
+}
+
+static DWORD CDROM_GetControl(int dev, CDROM_AUDIO_CONTROL* cac)
+{
+    cac->LbaFormat = 0; /* FIXME */
+    cac->LogicalBlocksPerSecond = 1; /* FIXME */
+    return  STATUS_NOT_SUPPORTED;
+}
+
+static DWORD CDROM_GetDeviceNumber(int dev, STORAGE_DEVICE_NUMBER* devnum)
+{
+    return STATUS_NOT_SUPPORTED;
+}
+
+static DWORD CDROM_GetDriveGeometry(int dev, DISK_GEOMETRY* dg)
+{
+#if 0
+    dg->Cylinders.s.LowPart = 1; /* FIXME */
+    dg->Cylinders.s.HighPart = 0; /* FIXME */
+    dg->MediaType = 1; /* FIXME */
+    dg->TracksPerCylinder = 1; /* FIXME */
+    dg->SectorsPerTrack = 1; /* FIXME */
+    dg->BytesPerSector= 1; /* FIXME */
+#endif
+    return STATUS_NOT_SUPPORTED;
+}
+
+/**************************************************************************
+ *                              CDROM_Reset                     [internal]
+ */
+static DWORD CDROM_ResetAudio(int dev)
+{
+#if defined(linux)
+    return CDROM_GetStatusCode(ioctl(dev, CDROMRESET));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    return CDROM_GetStatusCode(ioctl(dev, CDIOCRESET, NULL));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}  
+
+/******************************************************************
+ *		CDROM_SetTray
+ *
+ *
+ */
+static DWORD CDROM_SetTray(int dev, BOOL doEject)
+{
+#if defined(linux)
+    return CDROM_GetStatusCode(ioctl(dev, doEject ? CDROMEJECT : CDROMCLOSETRAY));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    return CDROM_GetStatusCode((ioctl(dev, CDIOCALLOW, NULL)) || 
+                               (ioctl(dev, doEject ? CDIOCEJECT : CDIOCCLOSE, NULL)) ||
+                               (ioctl(dev, CDIOCPREVENT, NULL)));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_ControlEjection
+ *
+ *
+ */
+static DWORD CDROM_ControlEjection(int dev, const PREVENT_MEDIA_REMOVAL* rmv)
+{
+    int val = rmv->PreventMediaRemoval;
+#if defined(linux)
+    return CDROM_GetStatusCode(ioctl(dev, CDROM_LOCKDOOR, val));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    return CDROM_GetStatusCode(ioctl(dev, (val) ? CDIOPREVENT : CDIOCALLOW, NULL));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_ReadTOC
+ *
+ *
+ */
+static DWORD CDROM_ReadTOC(int dev, CDROM_TOC* toc)
+{
+    DWORD       ret = STATUS_NOT_SUPPORTED;
+
+#if defined(linux)
+    int                         i, io = -1;
+    struct cdrom_tochdr		hdr;
+    struct cdrom_tocentry	entry;
+
+    io = ioctl(dev, CDROMREADTOCHDR, &hdr);
+    if (io == -1) 
+    {
+        WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
+        goto end;
+    }
+    toc->FirstTrack = hdr.cdth_trk0;
+    toc->LastTrack  = hdr.cdth_trk1;
+
+    TRACE("from=%d to=%d\n", toc->FirstTrack, toc->LastTrack);
+
+    for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
+    {
+	if (i == toc->LastTrack + 1)
+        {
+	    entry.cdte_track = CDROM_LEADOUT;
+        } else {
+            entry.cdte_track = i;
+        }
+	entry.cdte_format = CDROM_MSF;
+	io = ioctl(dev, CDROMREADTOCENTRY, &entry);
+	if (io == -1) {
+	    WARN("error read entry (%s)\n", strerror(errno));
+	    goto end;
+	}
+        toc->TrackData[i - toc->FirstTrack].Control = entry.cdte_ctrl;
+        toc->TrackData[i - toc->FirstTrack].Adr = entry.cdte_adr;
+        /* marking last track with leadout value as index */
+        toc->TrackData[i - toc->FirstTrack].TrackNumber = entry.cdte_track;
+        toc->TrackData[i - toc->FirstTrack].Address[0] = 0;
+        toc->TrackData[i - toc->FirstTrack].Address[1] = entry.cdte_addr.msf.minute;
+        toc->TrackData[i - toc->FirstTrack].Address[2] = entry.cdte_addr.msf.second;
+        toc->TrackData[i - toc->FirstTrack].Address[3] = entry.cdte_addr.msf.frame;
+    }
+end:
+    ret = CDROM_GetStatusCode(io);
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    int                         i, io = -1;
+    struct ioc_toc_header	hdr;
+    struct ioc_read_toc_entry	entry;
+    struct cd_toc_entry         toc_buffer;
+
+    io = ioctl(dev, CDIOREADTOCHEADER, &hdr);
+    if (io == -1) 
+    {
+        WARN("(%d) -- Error occurred (%s)!\n", dev, strerror(errno));
+        goto end;
+    }
+    toc->FirstTrack = hdr.starting_track;
+    toc->LastTrack  = hdr.ending_track;
+
+    TRACE("from=%d to=%d\n", toc->FirstTrack, toc->LastTrack);
+
+    for (i = toc->FirstTrack; i <= toc->LastTrack + 1; i++)
+    {
+	if (i == toc->LastTrack + 1)
+        {
+#define LEADOUT 0xaa
+	    entry.starting_track = LEADOUT;
+        } else {
+            entry.starting_track = i;
+        }
+	memset((char *)&toc_buffer, 0, sizeof(toc_buffer));
+	entry.address_format = CD_MSF_FORMAT;
+	entry.data_len = sizeof(toc_buffer);
+	entry.data = &toc_buffer;
+	io = ioctl(dev, CDIOREADTOCENTRYS, &entry);
+	if (io == -1) {
+	    WARN("error read entry (%s)\n", strerror(errno));
+	    goto end;
+	}
+        toc->TrackData[i - toc->FirstTrack].Control = toc_buffer.control;
+        toc->TrackData[i - toc->FirstTrack].Adr = toc_buffer.addr_type;
+        /* marking last track with leadout value as index */
+        toc->TrackData[i - toc->FirstTrack].TrackNumber = entry.starting_track;
+        toc->TrackData[i - toc->FirstTrack].Address[0] = 0;
+        toc->TrackData[i - toc->FirstTrack].Address[1] = toc_buffer.addr.msf.minute;
+        toc->TrackData[i - toc->FirstTrack].Address[2] = toc_buffer.addr.msf.second;
+        toc->TrackData[i - toc->FirstTrack].Address[3] = toc_buffer.addr.msf.frame;
+    }
+end:
+    ret = CDROM_GetStatusCode(io);
+#else
+    ret = STATUS_NOT_SUPPORTED;
+#endif
+    return ret;
+}
+
+/******************************************************************
+ *		CDROM_GetDiskData
+ *
+ *
+ */
+static DWORD CDROM_GetDiskData(int dev, CDROM_DISK_DATA* data)
+{
+    CDROM_TOC   toc;
+    DWORD       ret;
+    int         i;
+
+    if ((ret = CDROM_ReadTOC(dev, &toc)) != 0) return ret;
+    data->DiskData = 0;
+    for (i = toc.FirstTrack; i <= toc.LastTrack; i++) {
+        if (toc.TrackData[i].Control & 0x04)
+            data->DiskData |= CDROM_DISK_DATA_TRACK;
+        else
+            data->DiskData |= CDROM_DISK_AUDIO_TRACK;
+    }
+    return 0;
+}
+
+/******************************************************************
+ *		CDROM_ReadQChannel
+ *
+ *
+ */
+static DWORD CDROM_ReadQChannel(int dev, const CDROM_SUB_Q_DATA_FORMAT* fmt, 
+                                SUB_Q_CHANNEL_DATA* data)
+{
+    DWORD               ret = STATUS_NOT_SUPPORTED;
+    unsigned            size;
+    SUB_Q_HEADER*       hdr = (SUB_Q_HEADER*)data;
+    int                 io;
+
+#ifdef linux
+    struct cdrom_subchnl	sc;
+    sc.cdsc_format = CDROM_MSF;
+
+    io = ioctl(dev, CDROMSUBCHNL, &sc);
+    if (io == -1)
+    {
+	TRACE("opened or no_media (%s)!\n", strerror(errno));
+	hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
+	goto end;
+    }
+
+    hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
+
+    switch (sc.cdsc_audiostatus) {
+    case CDROM_AUDIO_INVALID:
+	hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
+	break;
+    case CDROM_AUDIO_NO_STATUS: 
+	hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
+	break;
+    case CDROM_AUDIO_PLAY:
+        hdr->AudioStatus = AUDIO_STATUS_IN_PROGRESS;
+        break;
+    case CDROM_AUDIO_PAUSED:
+        hdr->AudioStatus = AUDIO_STATUS_PAUSED;
+        break;
+    case CDROM_AUDIO_COMPLETED:
+        hdr->AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
+        break;
+    case CDROM_AUDIO_ERROR:
+        hdr->AudioStatus = AUDIO_STATUS_PLAY_ERROR;
+        break;
+    default:
+	TRACE("status=%02X !\n", sc.cdsc_audiostatus);
+        break;
+    }
+    switch (fmt->Format)
+    {
+    case IOCTL_CDROM_CURRENT_POSITION:
+        size = sizeof(SUB_Q_CURRENT_POSITION);
+        data->CurrentPosition.FormatCode = sc.cdsc_format;
+        data->CurrentPosition.Control = sc.cdsc_ctrl;
+        data->CurrentPosition.ADR = sc.cdsc_adr;
+        data->CurrentPosition.TrackNumber = sc.cdsc_trk;
+        data->CurrentPosition.IndexNumber = sc.cdsc_ind;
+
+        data->CurrentPosition.AbsoluteAddress[0] = 0;
+        data->CurrentPosition.AbsoluteAddress[1] = sc.cdsc_absaddr.msf.minute;
+        data->CurrentPosition.AbsoluteAddress[2] = sc.cdsc_absaddr.msf.second;
+        data->CurrentPosition.AbsoluteAddress[3] = sc.cdsc_absaddr.msf.frame;
+
+        data->CurrentPosition.TrackRelativeAddress[0] = 0;
+        data->CurrentPosition.TrackRelativeAddress[1] = sc.cdsc_reladdr.msf.minute;
+        data->CurrentPosition.TrackRelativeAddress[2] = sc.cdsc_reladdr.msf.second;
+        data->CurrentPosition.TrackRelativeAddress[3] = sc.cdsc_reladdr.msf.frame;
+        break;
+    case IOCTL_CDROM_MEDIA_CATALOG:
+        size = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
+        data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
+        {
+            struct cdrom_mcn mcn;
+            if ((io = ioctl(dev, CDROM_GET_MCN, &mcn)) == -1) goto end;
+
+            data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
+            data->MediaCatalog.Mcval = 0; /* FIXME */
+            memcpy(data->MediaCatalog.MediaCatalog, mcn.medium_catalog_number, 14);
+            data->MediaCatalog.MediaCatalog[14] = 0;
+        }
+        break;
+    case IOCTL_CDROM_TRACK_ISRC:
+        size = sizeof(SUB_Q_CURRENT_POSITION);
+        FIXME("TrackIsrc: NIY on linux");
+        data->TrackIsrc.FormatCode = IOCTL_CDROM_TRACK_ISRC;
+        data->TrackIsrc.Tcval = 0;
+        io = 0;
+        break;
+    }
+
+ end:
+    ret = CDROM_GetStatusCode(io);
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    struct ioc_read_subchannel	read_sc;
+    struct cd_sub_channel_info	sc;
+
+    read_sc.address_format = CD_MSF_FORMAT;
+    read_sc.track          = 0;
+    read_sc.data_len       = sizeof(sc);
+    read_sc.data           = &sc;
+    switch (fmt->Format)
+    {
+    case IOCTL_CDROM_CURRENT_POSITION:
+        read_sc.data_format    = CD_CURRENT_POSITION;
+        break;
+    case IOCTL_CDROM_MEDIA_CATALOG:
+        read_sc.data_format    = CD_MEDIA_CATALOG;
+        break;
+    case IOCTL_CDROM_TRACK_ISRC:
+        read_sc.data_format    = CD_TRACK_INFO;
+        sc.track_info.track_number = data->TrackIsrc.Track;
+        break;
+    }
+    io = ioctl(dev, CDIOCREADSUBCHANNEL, &read_sc);
+    if (io == -1)
+    {
+	TRACE("opened or no_media (%s)!\n", strerror(errno));
+	hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
+	goto end;
+    }
+
+    hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
+
+    switch (sc.header.audio_status) {
+    case CD_AS_AUDIO_INVALID:
+	hdr->AudioStatus = AUDIO_STATUS_NOT_SUPPORTED;
+	break;
+    case CD_AS_NO_STATUS:
+	hdr->AudioStatus = AUDIO_STATUS_NO_STATUS;
+        break;
+    case CD_AS_PLAY_IN_PROGRESS:
+        hdr->AudioStatus = AUDIO_STATUS_IN_PROGRESS;
+        break;
+    case CD_AS_PLAY_PAUSED:
+        hdr->AudioStatus = AUDIO_STATUS_IN_PAUSED;
+        break;
+    case CD_AS_PLAY_AUDIO_COMPLETED:
+        hdr->AudioStatus = AUDIO_STATUS_PLAY_COMPLETE;
+        break;
+    case CD_AS_PLAY_ERROR:
+        hdr->AudioStatus = AUDIO_STATUS_PLAY_ERROR;
+        break;
+    default:
+	TRACE("status=%02X !\n", sc.header.audio_status);
+    }
+    switch (fmt->Format)
+    {
+    case IOCTL_CDROM_CURRENT_POSITION:
+        size = sizeof(SUB_Q_CURRENT_POSITION);
+        data->CurrentPosition.FormatCode = sc.position.data_format;
+        data->CurrentPosition.Control = sc.position.control;
+        data->CurrentPosition.ADR = sc.position.addr_type;
+        data->CurrentPosition.TrackNumber = sc.position.track_number;
+        data->CurrentPosition.IndexNumber = sc.position.index_number;
+
+        data->CurrentPosition.AbsoluteAddress[0] = 0;
+        data->CurrentPosition.AbsoluteAddress[1] = sc.position.absaddr.msf.minute;
+        data->CurrentPosition.AbsoluteAddress[2] = sc.position.absaddr.msf.second;
+        data->CurrentPosition.AbsoluteAddress[3] = sc.position.absaddr.msf.frame;
+        data->CurrentPosition.TrackRelativeAddress[0] = 0;
+        data->CurrentPosition.TrackRelativeAddress[1] = sc.position.reladdr.msf.minute;
+        data->CurrentPosition.TrackRelativeAddress[2] = sc.position.reladdr.msf.second;
+        data->CurrentPosition.TrackRelativeAddress[3] = sc.position.reladdr.msf.frame;
+        break;
+    case IOCTL_CDROM_MEDIA_CATALOG:
+        size = sizeof(SUB_Q_MEDIA_CATALOG_NUMBER);
+        data->MediaCatalog.FormatCode = IOCTL_CDROM_MEDIA_CATALOG;
+        data->MediaCatalog.FormatCode = sc.media_catalog.data_format;
+        data->MediaCatalog.Mcval = sc.media_catalog.mc_valid;
+        memcpy(data->MediaCatalog.MediaCatalog, sc.media_catalog.mc_number, 15);
+        break;
+    case IOCTL_CDROM_TRACK_ISRC:
+        size = sizeof(SUB_Q_CURRENT_POSITION);
+        data->TrackIsrc.Tcval = sc.track_info.ti_valid;
+        memcpy(data->TrackIsrc.TrackIsrc, sc.track_info.ti_number, 15);
+        break;
+    }
+
+ end:
+    ret = CDROM_GetStatusCode(io);
+#endif
+    return ret;
+}
+
+/******************************************************************
+ *		CDROM_Verify
+ *
+ *
+ */
+static DWORD CDROM_Verify(int dev)
+{
+    /* quick implementation */
+    CDROM_SUB_Q_DATA_FORMAT     fmt;
+    SUB_Q_CHANNEL_DATA          data;
+
+    fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
+    return CDROM_ReadQChannel(dev, &fmt, &data) ? 0 : 1;
+}
+
+/******************************************************************
+ *		CDROM_PlayAudioMSF
+ *
+ *
+ */
+static DWORD CDROM_PlayAudioMSF(int dev, const CDROM_PLAY_AUDIO_MSF* audio_msf)
+{
+    DWORD       ret = STATUS_NOT_SUPPORTED;
+#ifdef linux
+    struct 	cdrom_msf	msf;
+    int         io;
+
+    msf.cdmsf_min0   = audio_msf->StartingM;
+    msf.cdmsf_sec0   = audio_msf->StartingS;
+    msf.cdmsf_frame0 = audio_msf->StartingF;
+    msf.cdmsf_min1   = audio_msf->EndingM;
+    msf.cdmsf_sec1   = audio_msf->EndingS;
+    msf.cdmsf_frame1 = audio_msf->EndingF;
+
+    io = ioctl(dev, CDROMSTART);
+    if (io == -1)
+    {
+	WARN("motor doesn't start !\n");
+	goto end;
+    }
+    io = ioctl(dev, CDROMPLAYMSF, &msf);
+    if (io == -1)
+    {
+	WARN("device doesn't play !\n");
+	goto end;
+    }
+    TRACE("msf = %d:%d:%d %d:%d:%d\n",
+	  msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
+	  msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
+ end:
+    ret = CDROM_GetStatusCode(io);
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    struct	ioc_play_msf	msf;
+    int         io;
+
+    msf.start_m      = audio_msf->StartingM;
+    msf.start_s      = audio_msf->StartingS;
+    msf.start_f      = audio_msf->StartingF;
+    msf.end_m        = audio_msf->EndingM;
+    msf.end_s        = audio_msf->EndingS;
+    msf.end_f        = audio_msf->EndingF;
+
+    io = ioctl(dev, CDIOCSTART, NULL);
+    if (io == -1)
+    {
+	WARN("motor doesn't start !\n");
+	goto end;
+    }
+    io = ioctl(dev, CDIOCPLAYMSF, &msf);
+    if (io == -1)
+    {
+	WARN("device doesn't play !\n");
+	goto end;
+    }
+    TRACE("msf = %d:%d:%d %d:%d:%d\n",
+	  msf.start_m, msf.start_s, msf.start_f,
+	  msf.end_m,   msf.end_s,   msf.end_f);
+end:
+    ret = CDROM_GetStatusCode(io);
+#endif
+    return ret;
+}
+
+/******************************************************************
+ *		CDROM_SeekAudioMSF
+ *
+ *
+ */
+static DWORD CDROM_SeekAudioMSF(int dev, const CDROM_SEEK_AUDIO_MSF* audio_msf)
+{
+#if defined(linux)
+    struct cdrom_msf0	msf;
+    msf.minute = audio_msf->M;
+    msf.second = audio_msf->S;
+    msf.frame  = audio_msf->F;
+
+    return CDROM_GetStatusCode(ioctl(dev, CDROMSEEK, &msf));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    FIXME("Could a BSD expert implement the seek function ?\n");
+    return STATUS_NOT_SUPPORTED;
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_PauseAudio
+ *
+ *
+ */
+static DWORD CDROM_PauseAudio(int dev)
+{
+#if defined(linux)
+    return CDROM_GetStatusCode(ioctl(dev, CDROMPAUSE));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    return CDROM_GetStatusCode(ioctl(dev, CDIOCPAUSE, NULL));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_ResumeAudio
+ *
+ *
+ */
+static DWORD CDROM_ResumeAudio(int dev)
+{
+#if defined(linux)
+    return CDROM_GetStatusCode(ioctl(dev, CDROMRESUME));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    return CDROM_GetStatusCode(ioctl(dev, CDIOCRESUME, NULL));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_StopAudio
+ *
+ *
+ */
+static DWORD CDROM_StopAudio(int dev)
+{
+#if defined(linux)
+    return CDROM_GetStatusCode(ioctl(dev, CDROMSTOP));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    return CDROM_GetStatusCode(ioctl(dev, CDIOCSTOP, NULL));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_GetVolume
+ *
+ *
+ */
+static DWORD CDROM_GetVolume(int dev, VOLUME_CONTROL* vc)
+{
+#if defined(linux)
+    struct cdrom_volctrl volc;
+    int io;
+    
+    io = ioctl(dev, CDROMVOLREAD, &volc);
+    if (io != -1)
+    {
+        vc->PortVolume[0] = volc.channel0;
+        vc->PortVolume[1] = volc.channel1;
+        vc->PortVolume[2] = volc.channel2;
+        vc->PortVolume[3] = volc.channel3;
+    }
+    return CDROM_GetStatusCode(io);
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    struct  ioc_vol     volc;
+    int io;
+    
+    io = ioctl(dev, CDIOCGETVOL, &volc);
+    if (io != -1)
+    {
+        vc->PortVolume[0] = volc.vol[0];
+        vc->PortVolume[1] = volc.vol[1];
+        vc->PortVolume[2] = volc.vol[2];
+        vc->PortVolume[3] = volc.vol[3];
+    } 
+    return CDROM_GetStatusCode(io);
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_SetVolume
+ *
+ *
+ */
+static DWORD CDROM_SetVolume(int dev, const VOLUME_CONTROL* vc)
+{
+#if defined(linux)
+    struct cdrom_volctrl volc;
+
+    volc.channel0 = vc->PortVolume[0];
+    volc.channel1 = vc->PortVolume[1];
+    volc.channel2 = vc->PortVolume[2];
+    volc.channel3 = vc->PortVolume[3];
+   
+    return CDROM_GetStatusCode(ioctl(dev, CDROMVOLCTRL, &volc));
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    struct  ioc_vol     volc;
+
+    volc.vol[0] = vc->PortVolume[0];
+    volc.vol[1] = vc->PortVolume[1];
+    volc.vol[2] = vc->PortVolume[2];
+    volc.vol[3] = vc->PortVolume[3];
+
+    return CDROM_GetStatusCode(ioctl(dev, CDIOCSETVOL, &volc));
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/******************************************************************
+ *		CDROM_RawRead
+ *
+ *
+ */
+static DWORD CDROM_RawRead(int dev, const RAW_READ_INFO* raw, void* buffer, DWORD len, DWORD* sz)
+{
+    int	        ret = STATUS_NOT_SUPPORTED;
+    int         io = -1;
+    DWORD       sectSize;
+
+    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)
+    {
+        struct cdrom_read       cdr;
+        struct cdrom_read_audio cdra;
+
+        switch (raw->TrackMode)
+        {
+        case YellowMode2:
+            if (raw->DiskOffset.s.HighPart) FIXME("Unsupported value\n");
+            cdr.cdread_lba = raw->DiskOffset.s.LowPart; /* FIXME ? */
+            cdr.cdread_bufaddr = buffer;
+            cdr.cdread_buflen = raw->SectorCount * sectSize;
+            io = ioctl(dev, CDROMREADMODE2, &cdr);
+            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.s.HighPart & ~2047) FIXME("Unsupported value\n");
+            cdra.addr.lba = ((raw->DiskOffset.s.LowPart >> 11) |
+                (raw->DiskOffset.s.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(dev, CDROMREADAUDIO, &cdra);
+            break;
+        }
+    }
+    *sz = sectSize * raw->SectorCount;
+    ret = CDROM_GetStatusCode(io);
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+    {
+        struct ioc_read_audio   ira;
+
+        switch (raw->TrackMode)
+        {
+        case YellowMode2:
+            FIXME("YellowMode2: NIY\n");
+            return ret;
+        case XAForm2:
+            FIXME("XAForm2: NIY\n");
+            return ret;
+        case CDDA:
+            /* 2048 = 2 ** 11 */
+            if (raw->DiskOffset.s.HighPart & ~2047) FIXME("Unsupported value\n");
+            ira.address.lba = ((raw->DiskOffset.s.LowPart >> 11) |
+                raw->DiskOffset.s.HighPart << (32 - 11)) - 1;
+            ira.address_format = CD_LBA_FORMAT;
+            ira.nframes = raw->SectorCount;
+            ira.buffer = buffer;
+            io = ioctl(dev, CDIOCREADAUDIO, &ira);
+            break;
+        }
+    }
+    *sz = sectSize * raw->SectorCount;
+    ret = CDROM_GetStatusCode(io);
+#endif
+    return ret;
+}
+
+/******************************************************************
+ *		CDROM_DeviceIoControl
+ *
+ *
+ */
+BOOL CDROM_DeviceIoControl(DWORD clientID, HANDLE hDevice, DWORD dwIoControlCode, 
+                           LPVOID lpInBuffer, DWORD nInBufferSize, 
+                           LPVOID lpOutBuffer, DWORD nOutBufferSize,
+                           LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
+{
+    DWORD       sz;
+    DWORD       error = 0;
+    int         dev;
+
+    TRACE("%lx[%c] %lx %lx %ld %lx %ld %lx %lx\n", 
+          (DWORD)hDevice, 'A' + LOWORD(clientID), dwIoControlCode, (DWORD)lpInBuffer, nInBufferSize, 
+          (DWORD)lpOutBuffer, nOutBufferSize, (DWORD)lpBytesReturned, (DWORD)lpOverlapped);
+
+    if (lpBytesReturned) *lpBytesReturned = 0;
+    if (lpOverlapped)
+    {
+        FIXME("Overlapped isn't implemented yet\n");
+        SetLastError(STATUS_NOT_SUPPORTED);
+        return FALSE;
+    }
+
+    SetLastError(0);
+    dev = CDROM_Open(hDevice, clientID);
+    if (dev == -1)
+    {
+        CDROM_GetStatusCode(-1);
+        return FALSE;
+    }
+
+    switch (dwIoControlCode)
+    {
+    case IOCTL_STORAGE_CHECK_VERIFY:
+    case IOCTL_CDROM_CHECK_VERIFY:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_Verify(dev);
+        break;
+
+/* EPP     case IOCTL_STORAGE_CHECK_VERIFY2: */
+
+/* EPP     case IOCTL_STORAGE_FIND_NEW_DEVICES: */
+/* EPP     case IOCTL_CDROM_FIND_NEW_DEVICES: */
+
+    case IOCTL_STORAGE_LOAD_MEDIA:
+    case IOCTL_CDROM_LOAD_MEDIA:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_SetTray(dev, FALSE);
+        break;
+     case IOCTL_STORAGE_EJECT_MEDIA:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_SetTray(dev, TRUE);
+        break;
+
+    case IOCTL_DISK_MEDIA_REMOVAL:
+    case IOCTL_STORAGE_MEDIA_REMOVAL:
+    case IOCTL_STORAGE_EJECTION_CONTROL:
+        /* FIXME the last ioctl:s is not the same as the two others... 
+         * lockcount/owner should be handled */
+        sz = 0;
+        if (lpOutBuffer != NULL || nOutBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nInBufferSize < sizeof(PREVENT_MEDIA_REMOVAL)) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_ControlEjection(dev, (const PREVENT_MEDIA_REMOVAL*)lpInBuffer);
+        break;
+
+/* EPP     case IOCTL_STORAGE_GET_MEDIA_TYPES: */
+
+    case IOCTL_STORAGE_GET_DEVICE_NUMBER:
+        sz = sizeof(STORAGE_DEVICE_NUMBER);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_GetDeviceNumber(dev, (STORAGE_DEVICE_NUMBER*)lpOutBuffer);
+        break;
+
+    case IOCTL_STORAGE_RESET_DEVICE:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_ResetAudio(dev);
+        break;
+
+    case IOCTL_CDROM_GET_CONTROL:
+        sz = sizeof(CDROM_AUDIO_CONTROL);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_GetControl(dev, (CDROM_AUDIO_CONTROL*)lpOutBuffer);
+        break;
+
+    case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
+        sz = sizeof(DISK_GEOMETRY);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_GetDriveGeometry(dev, (DISK_GEOMETRY*)lpOutBuffer);
+        break;
+
+    case IOCTL_CDROM_DISK_TYPE:
+        sz = sizeof(CDROM_DISK_DATA);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_GetDiskData(dev, (CDROM_DISK_DATA*)lpOutBuffer);
+        break;
+
+/* EPP     case IOCTL_CDROM_GET_LAST_SESSION: */
+
+    case IOCTL_CDROM_READ_Q_CHANNEL:
+        sz = sizeof(SUB_Q_CHANNEL_DATA);
+        if (lpInBuffer == NULL || nInBufferSize < sizeof(CDROM_SUB_Q_DATA_FORMAT)) 
+            error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_ReadQChannel(dev, (const CDROM_SUB_Q_DATA_FORMAT*)lpInBuffer,
+                                        (SUB_Q_CHANNEL_DATA*)lpOutBuffer);
+        break;
+
+    case IOCTL_CDROM_READ_TOC:
+        sz = sizeof(CDROM_TOC);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_ReadTOC(dev, (CDROM_TOC*)lpOutBuffer);
+        break;
+
+/* EPP     case IOCTL_CDROM_READ_TOC_EX: */
+
+    case IOCTL_CDROM_PAUSE_AUDIO:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_PauseAudio(dev);
+        break;
+    case IOCTL_CDROM_PLAY_AUDIO_MSF:
+        sz = 0;
+        if (lpOutBuffer != NULL || nOutBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nInBufferSize < sizeof(CDROM_PLAY_AUDIO_MSF)) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_PlayAudioMSF(dev, (const CDROM_PLAY_AUDIO_MSF*)lpInBuffer);
+        break;
+    case IOCTL_CDROM_RESUME_AUDIO:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_ResumeAudio(dev);
+        break;
+    case IOCTL_CDROM_SEEK_AUDIO_MSF:
+        sz = 0;
+        if (lpOutBuffer != NULL || nOutBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nInBufferSize < sizeof(CDROM_SEEK_AUDIO_MSF)) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_SeekAudioMSF(dev, (const CDROM_SEEK_AUDIO_MSF*)lpInBuffer);
+        break;
+    case IOCTL_CDROM_STOP_AUDIO:
+        sz = 0;
+        if (lpInBuffer != NULL || nInBufferSize != 0 || lpOutBuffer != NULL || nOutBufferSize != 0)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_StopAudio(dev);
+        break;
+    case IOCTL_CDROM_GET_VOLUME:
+        sz = sizeof(VOLUME_CONTROL);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_GetVolume(dev, (VOLUME_CONTROL*)lpOutBuffer);
+        break;
+    case IOCTL_CDROM_SET_VOLUME:
+        sz = 0;
+        if (lpInBuffer == NULL || nInBufferSize < sizeof(VOLUME_CONTROL) || lpOutBuffer != NULL)
+            error = STATUS_INVALID_PARAMETER;
+        else error = CDROM_SetVolume(dev, (const VOLUME_CONTROL*)lpInBuffer);
+        break;
+    case IOCTL_CDROM_RAW_READ:
+        sz = 0;
+        if (nInBufferSize < sizeof(RAW_READ_INFO)) error = STATUS_INVALID_PARAMETER;
+        else if (lpOutBuffer == NULL) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_RawRead(dev, (const RAW_READ_INFO*)lpInBuffer, 
+                                   lpOutBuffer, nOutBufferSize, &sz);
+        break;
+    default:
+        FIXME("Unsupported IOCTL %lx\n", dwIoControlCode);
+        sz = 0;
+        error = STATUS_INVALID_PARAMETER;
+        break;
+    }
+
+    if (lpBytesReturned) *lpBytesReturned = sz;
+    if (error) 
+    {
+        SetLastError(error);
+        return FALSE;
+    }
+    CDROM_Close(clientID, dev);
+    return TRUE;
+}
+                
diff --git a/files/drive.c b/files/drive.c
index 809e536f005..91607248cd2 100644
--- a/files/drive.c
+++ b/files/drive.c
@@ -44,7 +44,6 @@
 #include "wine/winbase16.h"   /* for GetCurrentTask */
 #include "winerror.h"
 #include "drive.h"
-#include "cdrom.h"
 #include "file.h"
 #include "heap.h"
 #include "msdos.h"
@@ -52,6 +51,9 @@
 #include "task.h"
 #include "debugtools.h"
 #include "wine/server.h"
+#include "winioctl.h"
+#include "ntddstor.h"
+#include "ntddcdrm.h"
 
 DEFAULT_DEBUG_CHANNEL(dosfs);
 DECLARE_DEBUG_CHANNEL(file);
@@ -459,6 +461,40 @@ const char * DRIVE_GetDevice( int drive )
     return (DRIVE_IsValid( drive )) ? DOSDrives[drive].device : NULL;
 }
 
+/******************************************************************
+ *		static WORD CDROM_Data_FindBestVoldesc
+ *
+ *
+ */
+static WORD CDROM_Data_FindBestVoldesc(int fd)
+{
+    BYTE cur_vd_type, max_vd_type = 0;
+    unsigned int offs, best_offs = 0, extra_offs = 0;
+    char sig[3];
+
+    for (offs = 0x8000; offs <= 0x9800; offs += 0x800)
+    {
+        /* if 'CDROM' occurs at position 8, this is a pre-iso9660 cd, and
+         * the volume label is displaced forward by 8
+         */
+        lseek(fd, offs + 11, SEEK_SET); /* check for non-ISO9660 signature */
+        read(fd, &sig, 3);
+        if ((sig[0] == 'R') && (sig[1] == 'O') && (sig[2]=='M'))
+        {
+            extra_offs = 8;
+        }
+        lseek(fd, offs + extra_offs, SEEK_SET);
+        read(fd, &cur_vd_type, 1);
+        if (cur_vd_type == 0xff) /* voldesc set terminator */
+            break;
+        if (cur_vd_type > max_vd_type)
+        {
+            max_vd_type = cur_vd_type;
+            best_offs = offs + extra_offs;
+        }
+    }
+    return best_offs;
+}
 
 /***********************************************************************
  *           DRIVE_ReadSuperblock
@@ -567,8 +603,103 @@ int DRIVE_WriteSuperblockEntry (int drive, off_t ofs, size_t len, char * buff)
     return close (fd);
 }
 
+/******************************************************************
+ *		static HANDLE   CDROM_Open
+ *
+ *
+ */
+static HANDLE   CDROM_Open(int drive)
+{
+    char       root[6];
+
+    strcpy(root, "\\\\.\\A:");
+    root[4] += drive;
+
+    return CreateFileA(root, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
+}
+
+/**************************************************************************
+ *                              CDROM_Data_GetLabel             [internal]
+ */
+DWORD CDROM_Data_GetLabel(int drive, char *label)
+{
+#define LABEL_LEN       32+1
+    int dev = open(DOSDrives[drive].device, O_RDONLY|O_NONBLOCK);
+    WORD offs = CDROM_Data_FindBestVoldesc(dev);
+    WCHAR label_read[LABEL_LEN]; /* Unicode possible, too */
+    DWORD unicode_id = 0;
+ 
+    if (offs)
+    {
+        if ((lseek(dev, offs+0x58, SEEK_SET) == offs+0x58)
+        &&  (read(dev, &unicode_id, 3) == 3))
+        {
+            int ver = (unicode_id & 0xff0000) >> 16;
+ 
+            if ((lseek(dev, offs+0x28, SEEK_SET) != offs+0x28)
+            ||  (read(dev, &label_read, LABEL_LEN) != LABEL_LEN))
+                goto failure;
+ 
+            close(dev);
+            if ((LOWORD(unicode_id) == 0x2f25) /* Unicode ID */
+            &&  ((ver == 0x40) || (ver == 0x43) || (ver == 0x45)))
+            { /* yippee, unicode */
+                int i;
+                WORD ch;
+                for (i=0; i<LABEL_LEN;i++)
+                { /* Motorola -> Intel Unicode conversion :-\ */
+                     ch = label_read[i];
+                     label_read[i] = (ch << 8) | (ch >> 8);
+                }
+                WideCharToMultiByte( CP_ACP, 0, label_read, -1, label, 12, NULL, NULL );
+                label[11] = 0;
+            }
+            else
+            {
+                strncpy(label, (LPSTR)label_read, 11);
+                label[11] = '\0';
+            }
+            return 1;
+        }
+    }
+failure:
+    close(dev);
+    ERR("error reading label !\n");
+    return 0;
+}
 
+/**************************************************************************
+ *				CDROM_GetLabel			[internal]
+ */
+static DWORD CDROM_GetLabel(int drive, char *label)
+{
+    HANDLE              h = CDROM_Open(drive);
+    CDROM_DISK_DATA     cdd;
+    DWORD               br;
+    DWORD               ret = 1;
 
+    if (!h || !DeviceIoControl(h, IOCTL_CDROM_DISK_TYPE, NULL, 0, &cdd, sizeof(cdd), &br, 0))
+        return 0;
+
+    switch (cdd.DiskData & 0x03)
+    {
+    case CDROM_DISK_DATA_TRACK:
+        if (!CDROM_Data_GetLabel(drive, label))
+            ret = 0;
+    case CDROM_DISK_AUDIO_TRACK:
+        strcpy(label, "Audio CD   ");
+        break;
+    case CDROM_DISK_DATA_TRACK|CDROM_DISK_AUDIO_TRACK:
+        FIXME("Need to get the label of a mixed mode CD: not implemented yet !\n");
+        /* fall through */
+    case 0:
+        ret = 0;
+        break;
+    }
+    TRACE("CD: label is '%s'.\n", label);
+
+    return ret;
+}
 /***********************************************************************
  *           DRIVE_GetLabel
  */
@@ -605,6 +736,132 @@ const char * DRIVE_GetLabel( int drive )
 	DOSDrives[drive].label_read : DOSDrives[drive].label_conf;
 }
 
+#define CDFRAMES_PERSEC                 75
+#define CDFRAMES_PERMIN                 (CDFRAMES_PERSEC * 60)
+#define FRAME_OF_ADDR(a) ((a)[0] * CDFRAMES_PERMIN + (a)[1] * CDFRAMES_PERSEC + (a)[2])
+#define FRAME_OF_TOC(toc, idx)  FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
+
+/**************************************************************************
+ *                              CDROM_Audio_GetSerial           [internal]
+ */
+static DWORD CDROM_Audio_GetSerial(HANDLE h)
+{
+    unsigned long serial = 0;
+    int i;
+    WORD wMagic;
+    DWORD dwStart, dwEnd, br;
+    CDROM_TOC toc;
+
+    if (!DeviceIoControl(h, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(toc), &br, 0))
+        return 0;
+
+    /*
+     * wMagic collects the wFrames from track 1
+     * dwStart, dwEnd collect the beginning and end of the disc respectively, in
+     * frames.
+     * There it is collected for correcting the serial when there are less than
+     * 3 tracks.
+     */
+    wMagic = toc.TrackData[0].Address[2];
+    dwStart = FRAME_OF_TOC(toc, toc.FirstTrack);
+
+    for (i = 0; i <= toc.LastTrack - toc.FirstTrack; i++) {
+        serial += (toc.TrackData[i].Address[0] << 16) | 
+            (toc.TrackData[i].Address[1] << 8) | toc.TrackData[i].Address[2];
+    }
+    dwEnd = FRAME_OF_TOC(toc, toc.LastTrack + 1);
+ 
+    if (toc.LastTrack - toc.FirstTrack + 1 < 3)
+        serial += wMagic + (dwEnd - dwStart);
+
+    return serial;
+}
+
+/**************************************************************************
+ *                              CDROM_Data_GetSerial            [internal]
+ */
+static DWORD CDROM_Data_GetSerial(int drive)
+{
+    int dev = open(DOSDrives[drive].device, O_RDONLY|O_NONBLOCK);
+    WORD offs;
+    union {
+        unsigned long val;
+        unsigned char p[4];
+    } serial;
+    BYTE b0 = 0, b1 = 1, b2 = 2, b3 = 3;
+ 
+
+    if (dev == -1) return 0;
+    offs = CDROM_Data_FindBestVoldesc(dev);
+
+    serial.val = 0;
+    if (offs)
+    {
+        BYTE buf[2048];
+        OSVERSIONINFOA ovi;
+        int i;
+ 
+        lseek(dev, offs, SEEK_SET);
+        read(dev, buf, 2048);
+        /*
+         * OK, another braindead one... argh. Just believe it.
+         * Me$$ysoft chose to reverse the serial number in NT4/W2K.
+         * It's true and nobody will ever be able to change it.
+         */
+        ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
+        GetVersionExA(&ovi);
+        if ((ovi.dwPlatformId == VER_PLATFORM_WIN32_NT) &&  (ovi.dwMajorVersion >= 4))
+        {
+            b0 = 3; b1 = 2; b2 = 1; b3 = 0;
+        }
+        for (i = 0; i < 2048; i += 4)
+        {
+            /* DON'T optimize this into DWORD !! (breaks overflow) */
+            serial.p[b0] += buf[i+b0];
+            serial.p[b1] += buf[i+b1];
+            serial.p[b2] += buf[i+b2];
+            serial.p[b3] += buf[i+b3];
+        }
+    }
+    close(dev);
+    return serial.val;
+}
+        
+/**************************************************************************
+ *				CDROM_GetSerial			[internal]
+ */
+static DWORD CDROM_GetSerial(int drive)
+{
+    DWORD               serial = 0;
+    HANDLE              h = CDROM_Open(drive);
+    CDROM_DISK_DATA     cdd;
+    DWORD               br;
+
+    if (!h || ! !DeviceIoControl(h, IOCTL_CDROM_DISK_TYPE, NULL, 0, &cdd, sizeof(cdd), &br, 0))
+        return 0;
+
+    switch (cdd.DiskData & 0x03)
+    {
+    case CDROM_DISK_DATA_TRACK:
+        /* hopefully a data CD */
+        serial = CDROM_Data_GetSerial(drive);
+        break;
+    case CDROM_DISK_AUDIO_TRACK:
+        /* fall thru */
+    case CDROM_DISK_DATA_TRACK|CDROM_DISK_AUDIO_TRACK:
+        serial = CDROM_Audio_GetSerial(h);
+        break;
+    case 0:
+        break;
+    }
+    
+    if (serial)
+        TRACE("CD serial number is %04x-%04x.\n", HIWORD(serial), LOWORD(serial));
+
+    CloseHandle(h);
+
+    return serial;
+}
 
 /***********************************************************************
  *           DRIVE_GetSerialNumber
@@ -612,7 +869,7 @@ const char * DRIVE_GetLabel( int drive )
 DWORD DRIVE_GetSerialNumber( int drive )
 {
     DWORD serial = 0;
-char buff[DRIVE_SUPER];
+    char buff[DRIVE_SUPER];
 
     if (!DRIVE_IsValid( drive )) return 0;
     
@@ -938,7 +1195,7 @@ static UINT DRIVE_GetCurrentDirectory( UINT buflen, LPSTR buf )
     assert(s);
     ret = strlen(s) + 3; /* length of WHOLE current directory */
     if (ret >= buflen) return ret + 1;
-    lstrcpynA( buf, "A:\\", min( 4, buflen ) );
+    lstrcpynA( buf, "A:\\", min( 4u, buflen ) );
     if (buflen) buf[0] += DRIVE_GetCurrentDrive();
     if (buflen > 3) lstrcpynA( buf + 3, s, buflen - 3 );
     return ret;
diff --git a/files/file.c b/files/file.c
index 06ea389c758..9cca77758bc 100644
--- a/files/file.c
+++ b/files/file.c
@@ -449,6 +449,11 @@ HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
             ret = FILE_OpenPipe(filename,access);
             goto done;
         }
+        else if (isalpha(filename[4]) && filename[5] == ':' && filename[6] == '\0')
+        {
+            ret = FILE_CreateDevice( (toupper(filename[4]) - 'A') | 0x20000, access, sa );
+            goto done;
+        }
         else if (!DOSFS_GetDevice( filename ))
         {
             ret = DEVICE_Open( filename+4, access, sa );
diff --git a/include/cdrom.h b/include/cdrom.h
deleted file mode 100644
index e7c42187689..00000000000
--- a/include/cdrom.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/* -*- tab-width: 8; c-basic-offset: 4 -*- */
-/*
- * Header file for CD-ROM support
- *
- * Copyright 1994 Martin Ayotte
- * Copyright 1999 Eric Pouech
- * Copyright 2000 Andreas Mohr
- */
-
-#ifndef __WINE_CDROM_H__
-#define __WINE_CDROM_H__
-
-#ifndef __WINE_CONFIG_H 
-# error You must include config.h to use this header 
-#endif 
-
-#include <stdlib.h>
-#include <unistd.h>
-#include "windef.h"
-#include "wine/windef16.h"
-
-#ifdef HAVE_LINUX_CDROM_H
-# include <linux/cdrom.h>
-#endif
-#ifdef HAVE_LINUX_UCDROM_H
-# include <linux/ucdrom.h>
-#endif
-#ifdef HAVE_SYS_CDIO_H
-# include <sys/cdio.h>
-#endif
-
-typedef struct {
-    const char			*devname;
-#if defined(linux)
-    struct cdrom_subchnl	sc;
-#elif defined(__FreeBSD__) || defined(__NetBSD__)
-    struct cd_sub_channel_info	sc;
-#endif
-    /* those data reflect the cdaudio structure and
-     * don't change while playing
-     */
-    UINT16			nTracks;
-    UINT16			nFirstTrack;
-    UINT16			nLastTrack;
-    LPDWORD			lpdwTrackLen;
-    LPDWORD			lpdwTrackPos;
-    LPBYTE			lpbTrackFlags;
-    DWORD			dwFirstFrame;
-    DWORD			dwLastFrame;
-    /* those data change while playing */
-    int				cdaMode;
-    UINT16			nCurTrack;
-    DWORD			dwCurFrame;
-} WINE_CDAUDIO;
-
-#define	WINE_CDA_DONTKNOW		0x00
-#define	WINE_CDA_NOTREADY		0x01
-#define	WINE_CDA_OPEN			0x02
-#define	WINE_CDA_PLAY			0x03
-#define	WINE_CDA_STOP			0x04
-#define	WINE_CDA_PAUSE			0x05
-
-int	CDROM_Open(WINE_CDAUDIO* wcda, int drive);
-int	CDROM_OpenDev(WINE_CDAUDIO* wcda);
-int	CDROM_GetMediaType(WINE_CDAUDIO* wcda, int parentdev);
-int	CDROM_CloseDev(int dev);
-int	CDROM_Close(WINE_CDAUDIO* wcda);
-int	CDROM_Reset(WINE_CDAUDIO* wcda, int parentdev);
-int	CDROM_Audio_Play(WINE_CDAUDIO* wcda, DWORD start, DWORD stop, int parentdev);
-int	CDROM_Audio_Stop(WINE_CDAUDIO* wcda, int parentdev);
-int	CDROM_Audio_Pause(WINE_CDAUDIO* wcda, int pauseOn, int parentdev);
-int	CDROM_Audio_Seek(WINE_CDAUDIO* wcda, DWORD at, int parentdev);
-int	CDROM_SetDoor(WINE_CDAUDIO* wcda, int open, int parentdev);
-UINT16 	CDROM_Audio_GetNumberOfTracks(WINE_CDAUDIO* wcda, int parentdev);
-BOOL 	CDROM_Audio_GetTracksInfo(WINE_CDAUDIO* wcda, int parentdev);
-BOOL	CDROM_Audio_GetCDStatus(WINE_CDAUDIO* wcda, int parentdev);
-WORD	CDROM_Data_FindBestVoldesc(int fd);
-DWORD	CDROM_Audio_GetSerial(WINE_CDAUDIO* wcda);
-DWORD	CDROM_Data_GetSerial(WINE_CDAUDIO* wcda, int parentdev);
-DWORD	CDROM_GetSerial(int drive);
-DWORD	CDROM_GetLabel(int drive, char *label);
-
-#define CDFRAMES_PERSEC 		75
-#define SECONDS_PERMIN	 		60
-#define CDFRAMES_PERMIN 		((CDFRAMES_PERSEC) * (SECONDS_PERMIN))
-
-#ifndef CDROM_DATA_TRACK
-#define CDROM_DATA_TRACK 0x04
-#endif
-
-#define CDROM_MSF_MINUTE(msf)           ((BYTE)(msf))
-#define CDROM_MSF_SECOND(msf)           ((BYTE)(((WORD)(msf)) >> 8))
-#define CDROM_MSF_FRAME(msf)            ((BYTE)((msf)>>16))
-
-#define CDROM_MAKE_MSF(m, s, f)         ((DWORD)(((BYTE)(m) | \
-                                                  ((WORD)(s)<<8)) | \
-                                                 (((DWORD)(BYTE)(f))<<16)))
-
-/* values borrowed from Linux 2.2.x cdrom.h */
-#define CDS_NO_INFO			0
-#define CDS_AUDIO			100
-#define CDS_DATA_1                      101
-#define CDS_DATA_2                      102
-#define CDS_XA_2_1                      103
-#define CDS_XA_2_2                      104
-#define CDS_MIXED                       105
-
-#endif
-
diff --git a/include/file.h b/include/file.h
index 45a37d92ef1..815501efb04 100644
--- a/include/file.h
+++ b/include/file.h
@@ -115,4 +115,10 @@ extern int DOSFS_FindNext( const char *path, const char *short_mask,
 /* win32/device.c */
 extern HANDLE DEVICE_Open( LPCSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa );
 
+/* ntdll/cdrom.c.c */
+extern BOOL CDROM_DeviceIoControl(DWORD clientID, HANDLE hDevice, DWORD dwIoControlCode, 
+                                  LPVOID lpInBuffer, DWORD nInBufferSize, 
+                                  LPVOID lpOutBuffer, DWORD nOutBufferSize,
+                                  LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped);
+
 #endif  /* __WINE_FILE_H */
diff --git a/include/ntddcdrm.h b/include/ntddcdrm.h
new file mode 100644
index 00000000000..cd3f3f3dea3
--- /dev/null
+++ b/include/ntddcdrm.h
@@ -0,0 +1,167 @@
+/* DDK information for CD ROM */
+
+#ifndef __NTDDCDRM_H
+#define __NTDDCDRM_H
+
+#define IOCTL_CDROM_BASE                FILE_DEVICE_CD_ROM
+#define IOCTL_CDROM_UNLOAD_DRIVER       CTL_CODE(IOCTL_CDROM_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_READ_TOC            CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_GET_CONTROL         CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_PLAY_AUDIO_MSF      CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_SEEK_AUDIO_MSF      CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_STOP_AUDIO          CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_PAUSE_AUDIO         CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_RESUME_AUDIO        CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_GET_VOLUME          CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_SET_VOLUME          CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_READ_Q_CHANNEL      CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_GET_LAST_SESSION    CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_RAW_READ            CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT,  FILE_READ_ACCESS)
+#define IOCTL_CDROM_DISK_TYPE           CTL_CODE(IOCTL_CDROM_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_CDROM_GET_DRIVE_GEOMETRY  CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_CHECK_VERIFY        CTL_CODE(IOCTL_CDROM_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_MEDIA_REMOVAL       CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_EJECT_MEDIA         CTL_CODE(IOCTL_CDROM_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_LOAD_MEDIA          CTL_CODE(IOCTL_CDROM_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_RESERVE             CTL_CODE(IOCTL_CDROM_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_RELEASE             CTL_CODE(IOCTL_CDROM_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_FIND_NEW_DEVICES    CTL_CODE(IOCTL_CDROM_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#include "ntddstor.h"
+
+#define MAXIMUM_NUMBER_TRACKS 100
+#define MAXIMUM_CDROM_SIZE 804
+
+typedef struct _TRACK_DATA {
+    UCHAR               Reserved;
+    UCHAR               Control : 4;
+    UCHAR               Adr : 4;
+    UCHAR               TrackNumber;
+    UCHAR               Reserved1;
+    UCHAR               Address[4];
+} TRACK_DATA, *PTRACK_DATA;
+
+typedef struct _CDROM_TOC {
+    UCHAR               Length[2];
+    UCHAR               FirstTrack;
+    UCHAR               LastTrack;
+    TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
+} CDROM_TOC, *PCDROM_TOC;
+
+#define CDROM_TOC_SIZE sizeof(CDROM_TOC)
+
+typedef struct _CDROM_PLAY_AUDIO_MSF {
+    UCHAR               StartingM;
+    UCHAR               StartingS;
+    UCHAR               StartingF;
+    UCHAR               EndingM;
+    UCHAR               EndingS;
+    UCHAR               EndingF;
+} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF;
+
+typedef struct _CDROM_SEEK_AUDIO_MSF {
+    UCHAR               M;
+    UCHAR               S;
+    UCHAR               F;
+} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF;
+
+typedef struct _CDROM_DISK_DATA {
+    ULONG               DiskData;
+} CDROM_DISK_DATA, *PCDROM_DISK_DATA;
+
+#define CDROM_DISK_AUDIO_TRACK      (0x00000001)
+#define CDROM_DISK_DATA_TRACK       (0x00000002)
+
+#define IOCTL_CDROM_SUB_Q_CHANNEL    0x00
+#define IOCTL_CDROM_CURRENT_POSITION 0x01
+#define IOCTL_CDROM_MEDIA_CATALOG    0x02
+#define IOCTL_CDROM_TRACK_ISRC       0x03
+
+typedef struct _CDROM_SUB_Q_DATA_FORMAT {
+    UCHAR               Format;
+    UCHAR               Track;
+} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT;
+
+typedef struct _SUB_Q_HEADER {
+    UCHAR               Reserved;
+    UCHAR               AudioStatus;
+    UCHAR               DataLength[2];
+} SUB_Q_HEADER, *PSUB_Q_HEADER;
+
+typedef struct _SUB_Q_CURRENT_POSITION {
+    SUB_Q_HEADER        Header;
+    UCHAR               FormatCode;
+    UCHAR               Control : 4;
+    UCHAR               ADR : 4;
+    UCHAR               TrackNumber;
+    UCHAR               IndexNumber;
+    UCHAR               AbsoluteAddress[4];
+    UCHAR               TrackRelativeAddress[4];
+} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION;
+
+typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER {
+    SUB_Q_HEADER        Header;
+    UCHAR               FormatCode;
+    UCHAR               Reserved[3];
+    UCHAR               Reserved1 : 7;
+    UCHAR               Mcval : 1;
+    UCHAR               MediaCatalog[15];
+} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER;
+
+typedef struct _SUB_Q_TRACK_ISRC {
+    SUB_Q_HEADER        Header;
+    UCHAR               FormatCode;
+    UCHAR               Reserved0;
+    UCHAR               Track;
+    UCHAR               Reserved1;
+    UCHAR               Reserved2 : 7;
+    UCHAR               Tcval : 1;
+    UCHAR               TrackIsrc[15];
+} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC;
+
+typedef union _SUB_Q_CHANNEL_DATA {
+    SUB_Q_CURRENT_POSITION      CurrentPosition;
+    SUB_Q_MEDIA_CATALOG_NUMBER  MediaCatalog;
+    SUB_Q_TRACK_ISRC            TrackIsrc;
+} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA;
+
+#define AUDIO_STATUS_NOT_SUPPORTED      0x00
+#define AUDIO_STATUS_IN_PROGRESS        0x11
+#define AUDIO_STATUS_PAUSED             0x12
+#define AUDIO_STATUS_PLAY_COMPLETE      0x13
+#define AUDIO_STATUS_PLAY_ERROR         0x14
+#define AUDIO_STATUS_NO_STATUS          0x15
+
+#define ADR_NO_MODE_INFORMATION         0x0
+#define ADR_ENCODES_CURRENT_POSITION    0x1
+#define ADR_ENCODES_MEDIA_CATALOG       0x2
+#define ADR_ENCODES_ISRC                0x3
+
+#define AUDIO_WITH_PREEMPHASIS          0x0
+#define DIGITAL_COPY_PERMITTED          0x2
+#define AUDIO_DATA_TRACK                0x4
+#define TWO_FOUR_CHANNEL_AUDIO          0x8
+
+typedef struct _CDROM_AUDIO_CONTROL {
+    UCHAR               LbaFormat;
+    USHORT              LogicalBlocksPerSecond;
+} CDROM_AUDIO_CONTROL, *PCDROM_AUDIO_CONTROL;
+
+typedef struct _VOLUME_CONTROL {
+    UCHAR               PortVolume[4];
+} VOLUME_CONTROL, *PVOLUME_CONTROL;
+
+typedef enum _TRACK_MODE_TYPE {
+    YellowMode2,
+    XAForm2,
+    CDDA
+} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE;
+
+typedef struct __RAW_READ_INFO {
+    LARGE_INTEGER       DiskOffset;
+    ULONG               SectorCount;
+    TRACK_MODE_TYPE     TrackMode;
+} RAW_READ_INFO, *PRAW_READ_INFO;
+
+#endif /* __NTDDCDRM_H */
diff --git a/include/ntddstor.h b/include/ntddstor.h
new file mode 100644
index 00000000000..cbc9b5d2214
--- /dev/null
+++ b/include/ntddstor.h
@@ -0,0 +1,229 @@
+/* DDK definitions for storage media access */
+
+#ifndef _NTDDSTOR_H_
+#define _NTDDSTOR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE
+
+#define IOCTL_STORAGE_CHECK_VERIFY      CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_MEDIA_REMOVAL     CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_EJECT_MEDIA       CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_LOAD_MEDIA        CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RESERVE           CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RELEASE           CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_FIND_NEW_DEVICES  CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_GET_MEDIA_TYPES   CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_RESET_BUS         CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RESET_DEVICE      CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_GET_DEVICE_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_QUERY_PROPERTY    CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+typedef struct _STORAGE_DEVICE_NUMBER {
+    DEVICE_TYPE         DeviceType;
+    ULONG               DeviceNumber;
+    ULONG               PartitionNumber;
+} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER;
+
+typedef struct _STORAGE_BUS_RESET_REQUEST {
+    UCHAR               PathId;
+} STORAGE_BUS_RESET_REQUEST, *PSTORAGE_BUS_RESET_REQUEST;
+
+typedef struct _PREVENT_MEDIA_REMOVAL {
+    BOOLEAN             PreventMediaRemoval;
+} PREVENT_MEDIA_REMOVAL, *PPREVENT_MEDIA_REMOVAL;
+
+typedef struct _TAPE_STATISTICS {
+    ULONG               Version;
+    ULONG               Flags;
+    LARGE_INTEGER       RecoveredWrites;
+    LARGE_INTEGER       UnrecoveredWrites;
+    LARGE_INTEGER       RecoveredReads;
+    LARGE_INTEGER       UnrecoveredReads;
+    UCHAR               CompressionRatioReads;
+    UCHAR               CompressionRatioWrites;
+} TAPE_STATISTICS, *PTAPE_STATISTICS;
+
+#define RECOVERED_WRITES_VALID          0x00000001
+#define UNRECOVERED_WRITES_VALID        0x00000002
+#define RECOVERED_READS_VALID           0x00000004
+#define UNRECOVERED_READS_VALID         0x00000008
+#define WRITE_COMPRESSION_INFO_VALID    0x00000010
+#define READ_COMPRESSION_INFO_VALID     0x00000020
+
+typedef struct _TAPE_GET_STATISTICS {
+    ULONG               Operation;
+} TAPE_GET_STATISTICS, *PTAPE_GET_STATISTICS;
+
+#define TAPE_RETURN_STATISTICS          0L
+#define TAPE_RETURN_ENV_INFO            1L
+#define TAPE_RESET_STATISTICS           2L
+
+typedef enum _STORAGE_MEDIA_TYPE {
+    /* see also defines in ntdddisk.h */
+
+    DDS_4mm = 0x20,
+    MiniQic,
+    Travan,
+    QIC,
+    MP_8mm,
+    AME_8mm,
+    AIT1_8mm,
+    DLT,
+    NCTP,
+    IBM_3480,
+    IBM_3490E,
+    IBM_Magstar_3590,
+    IBM_Magstar_MP,
+    STK_DATA_D3,
+    SONY_DTF,
+    DV_6mm,
+    DMI,
+    SONY_D2,
+    CLEANER_CARTRIDGE,
+    CD_ROM,
+    CD_R,
+    CD_RW,
+    DVD_ROM,
+    DVD_R,
+    DVD_RW,
+    MO_3_RW,
+    MO_5_WO,
+    MO_5_RW,
+    MO_5_LIMDOW,
+    PC_5_WO,
+    PC_5_RW,
+    PD_5_RW,
+    ABL_5_WO,
+    PINNACLE_APEX_5_RW,
+    SONY_12_WO,
+    PHILIPS_12_WO,
+    HITACHI_12_WO,
+    CYGNET_12_WO,
+    KODAK_14_WO,
+    MO_NFR_525,
+    NIKON_12_RW,
+    IOMEGA_ZIP,
+    IOMEGA_JAZ,
+    SYQUEST_EZ135,
+    SYQUEST_EZFLYER,
+    SYQUEST_SYJET,
+    AVATAR_F2,
+    MP2_8mm 
+} STORAGE_MEDIA_TYPE, *PSTORAGE_MEDIA_TYPE;
+
+#define MEDIA_ERASEABLE         0x00000001
+#define MEDIA_WRITE_ONCE        0x00000002
+#define MEDIA_READ_ONLY         0x00000004
+#define MEDIA_READ_WRITE        0x00000008
+#define MEDIA_WRITE_PROTECTED   0x00000100
+#define MEDIA_CURRENTLY_MOUNTED 0x80000000
+
+typedef struct _DEVICE_MEDIA_INFO {
+    union {
+        struct {
+            LARGE_INTEGER       Cylinders;
+            STORAGE_MEDIA_TYPE  MediaType;
+            ULONG               TracksPerCylinder;
+            ULONG               SectorsPerTrack;
+            ULONG               BytesPerSector;
+            ULONG               NumberMediaSides;
+            ULONG               MediaCharacteristics;
+        } DiskInfo;
+        struct {
+            LARGE_INTEGER       Cylinders;
+            STORAGE_MEDIA_TYPE  MediaType;
+            ULONG               TracksPerCylinder;
+            ULONG               SectorsPerTrack;
+            ULONG               BytesPerSector;
+            ULONG               NumberMediaSides;
+            ULONG               MediaCharacteristics;
+        } RemovableDiskInfo;
+        struct {
+            STORAGE_MEDIA_TYPE  MediaType;
+            ULONG               MediaCharacteristics;
+            ULONG               CurrentBlockSize;
+        } TapeInfo;
+    } DeviceSpecific;
+} DEVICE_MEDIA_INFO, *PDEVICE_MEDIA_INFO;
+
+typedef struct _GET_MEDIA_TYPES {
+    ULONG               DeviceType;
+    ULONG               MediaInfoCount;
+    DEVICE_MEDIA_INFO   MediaInfo[1];
+} GET_MEDIA_TYPES, *PGET_MEDIA_TYPES;
+
+typedef enum _STORAGE_QUERY_TYPE {
+    PropertyStandardQuery = 0,
+    PropertyExistsQuery,
+    PropertyMaskQuery,
+    PropertyQueryMaxDefined 
+} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;
+
+typedef enum _STORAGE_PROPERTY_ID {
+    StorageDeviceProperty = 0,
+    StorageAdapterProperty
+} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
+
+typedef struct _STORAGE_PROPERTY_QUERY {
+    STORAGE_PROPERTY_ID         PropertyId;
+    STORAGE_QUERY_TYPE          QueryType;
+    UCHAR                       AdditionalParameters[1];
+} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
+
+typedef struct _STORAGE_DESCRIPTOR_HEADER {
+    ULONG                       Version;
+    ULONG                       Size;
+} STORAGE_DESCRIPTOR_HEADER, *PSTORAGE_DESCRIPTOR_HEADER;
+
+typedef enum _STORAGE_BUS_TYPE {
+    BusTypeUnknown = 0x00,
+    BusTypeScsi,
+    BusTypeAtapi,
+    BusTypeAta,
+    BusType1394,
+    BusTypeSsa,
+    BusTypeFibre,
+    BusTypeMaxReserved = 0x7F
+} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;
+
+typedef struct _STORAGE_DEVICE_DESCRIPTOR {
+    ULONG                       Version;
+    ULONG                       Size;
+    UCHAR                       DeviceType;
+    UCHAR                       DeviceTypeModifier;
+    BOOLEAN                     RemovableMedia;
+    BOOLEAN                     CommandQueueing;
+    ULONG                       VendorIdOffset;
+    ULONG                       ProductIdOffset;
+    ULONG                       ProductRevisionOffset;
+    ULONG                       SerialNumberOffset;
+    STORAGE_BUS_TYPE            BusType;
+    ULONG                       RawPropertiesLength;
+    UCHAR                       RawDeviceProperties[1];
+} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;
+
+typedef struct _STORAGE_ADAPTER_DESCRIPTOR {
+    ULONG                       Version;
+    ULONG                       Size;
+    ULONG                       MaximumTransferLength;
+    ULONG                       MaximumPhysicalPages;
+    ULONG                       AlignmentMask;
+    BOOLEAN                     AdapterUsesPio;
+    BOOLEAN                     AdapterScansDown;
+    BOOLEAN                     CommandQueueing;
+    BOOLEAN                     AcceleratedTransfer;
+    BOOLEAN                     BusType;
+    USHORT                      BusMajorVersion;
+    USHORT                      BusMinorVersion;
+} STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NTDDSTOR_H_ */
diff --git a/include/winioctl.h b/include/winioctl.h
index d7a3d718d84..8ac269fd51d 100644
--- a/include/winioctl.h
+++ b/include/winioctl.h
@@ -150,7 +150,9 @@
 #define IOCTL_STORAGE_RESERVE            CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS)
 #define IOCTL_STORAGE_RELEASE            CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS)
 #define IOCTL_STORAGE_FIND_NEW_DEVICES   CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
-
+#define IOCTL_STORAGE_EJECTION_CONTROL   CTL_CODE(IOCTL_STORAGE_BASE, 0x0250, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_MCN_CONTROL        CTL_CODE(IOCTL_STORAGE_BASE, 0x0251, METHOD_BUFFERED, FILE_ANY_ACCESS)
+ 
 #define IOCTL_STORAGE_GET_MEDIA_TYPES    CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS)
 #define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS)
 
@@ -213,6 +215,81 @@
 #define PARTITION_LDM                   0x42      /* Logical Disk Manager partition */
 #define PARTITION_UNIX                  0x63      /* Unix */
 
+typedef enum _MEDIA_TYPE {
+    Unknown, F5_1Pt2_512, F3_1Pt44_512, F3_2Pt88_512, F3_20Pt8_512, F3_720_512, F5_360_512,
+    F5_320_512, F5_320_1024, F5_180_512, F5_160_512, RemovableMedia, FixedMedia, F3_120M_512,
+    F3_640_512, F5_640_512, F5_720_512, F3_1Pt2_512, F3_1Pt23_1024, F5_1Pt23_1024, F3_128Mb_512,
+    F3_230Mb_512, F8_256_128 
+} MEDIA_TYPE, *PMEDIA_TYPE;
+
+typedef struct _FORMAT_PARAMETERS {
+   MEDIA_TYPE           MediaType;
+   DWORD                StartCylinderNumber;
+   DWORD                EndCylinderNumber;
+   DWORD                StartHeadNumber;
+   DWORD                EndHeadNumber;
+} FORMAT_PARAMETERS, *PFORMAT_PARAMETERS;
+ 
+typedef WORD   BAD_TRACK_NUMBER;
+typedef WORD   *PBAD_TRACK_NUMBER;
+ 
+typedef struct _FORMAT_EX_PARAMETERS {
+   MEDIA_TYPE           MediaType;
+   DWORD                StartCylinderNumber;
+   DWORD                EndCylinderNumber;
+   DWORD                StartHeadNumber;
+   DWORD                EndHeadNumber;
+   WORD                 FormatGapLength;
+   WORD                 SectorsPerTrack;
+   WORD                 SectorNumber[1];
+} FORMAT_EX_PARAMETERS, *PFORMAT_EX_PARAMETERS;
+ 
+typedef struct _DISK_GEOMETRY {
+    LARGE_INTEGER       Cylinders;
+    MEDIA_TYPE          MediaType;
+    DWORD               TracksPerCylinder;
+    DWORD               SectorsPerTrack;
+    DWORD               BytesPerSector;
+} DISK_GEOMETRY, *PDISK_GEOMETRY;
+ 
+typedef struct _PARTITION_INFORMATION {
+    LARGE_INTEGER       StartingOffset;
+    LARGE_INTEGER       PartitionLength;
+    DWORD               HiddenSectors;
+    DWORD               PartitionNumber;
+    BYTE                PartitionType;
+    BOOLEAN             BootIndicator;
+    BOOLEAN             RecognizedPartition;
+    BOOLEAN             RewritePartition;
+} PARTITION_INFORMATION, *PPARTITION_INFORMATION;
+ 
+typedef struct _SET_PARTITION_INFORMATION {
+    BYTE                PartitionType;
+} SET_PARTITION_INFORMATION, *PSET_PARTITION_INFORMATION;
+ 
+typedef struct _DRIVE_LAYOUT_INFORMATION {
+    DWORD               PartitionCount;
+    DWORD               Signature;
+    PARTITION_INFORMATION PartitionEntry[1];
+} DRIVE_LAYOUT_INFORMATION, *PDRIVE_LAYOUT_INFORMATION;
+ 
+typedef struct _VERIFY_INFORMATION {
+    LARGE_INTEGER       StartingOffset;
+    DWORD               Length;
+} VERIFY_INFORMATION, *PVERIFY_INFORMATION;
+ 
+typedef struct _REASSIGN_BLOCKS {
+    WORD                Reserved;
+    WORD                Count;
+    DWORD               BlockNumber[1];
+} REASSIGN_BLOCKS, *PREASSIGN_BLOCKS;
+ 
+#if(_WIN32_WINNT >= 0x0400)
+typedef struct _DISK_CONTROLLER_NUMBER {
+    DWORD               ControllerNumber;
+    DWORD               DiskNumber;
+} DISK_CONTROLLER_NUMBER, *PDISK_CONTROLLER_NUMBER;
+#endif /* _WIN32_WINNT >= 0x0400 */
 
 /* Device Io Stuff - Most VxD support.
  * NOTE: All VxD messages seem to start with a hiword or 0
diff --git a/misc/Makefile.in b/misc/Makefile.in
index 5565a0df2bf..2ebc27672cc 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -7,7 +7,6 @@ VPATH     = @srcdir@
 MODULE    = misc
 
 C_SRCS = \
-	cdrom.c \
 	cpu.c \
 	error.c \
 	main.c \
diff --git a/misc/cdrom.c b/misc/cdrom.c
deleted file mode 100644
index ec89b8a7adf..00000000000
--- a/misc/cdrom.c
+++ /dev/null
@@ -1,908 +0,0 @@
-/* -*- tab-width: 8; c-basic-offset: 4 -*- */
-/*
- * Main file for CD-ROM support
- *
- * Copyright 1994 Martin Ayotte
- * Copyright 1999 Eric Pouech
- * Copyright 2000 Andreas Mohr
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include "winnls.h"
-#include "cdrom.h"
-#include "drive.h"
-#include "debugtools.h"
-#include "winbase.h"
-
-DEFAULT_DEBUG_CHANNEL(cdrom);
-
-#define MAX_CDAUDIO_TRACKS 	256
-
-#define CDROM_OPEN(wcda,parentdev) \
-    (((parentdev) == -1) ? CDROM_OpenDev(wcda) : (parentdev))
-
-#define CDROM_CLOSE(dev,parentdev) \
-    (((parentdev) == -1) ? CDROM_CloseDev(dev) : 0)
-
-/**************************************************************************
- * 				CDROM_Open			[internal]
- *
- * drive = 0, 1, ...
- *      or -1 (figure it out)
- */
-int	CDROM_Open(WINE_CDAUDIO* wcda, int drive)
-{
-    int i, dev;
-    BOOL avail = FALSE;
-
-    if (drive == -1)
-    {
-        char root[] = "A:\\";
-	for (i=0; i < MAX_DOS_DRIVES; i++, root[0]++)
-            if (GetDriveTypeA(root) == DRIVE_CDROM)
-	    {
-		drive = i;
-		avail = TRUE;
-		break;
-	    }
-    }
-    else
-	avail = TRUE;
-    
-    if (avail == FALSE)
-    {
-	WARN("No CD-ROM #%d found !\n", drive);
-	return -1;
-    }
-    if ((wcda->devname = DRIVE_GetDevice(drive)) == NULL)
-{
-	WARN("No device entry for CD-ROM #%d (drive %c:) found !\n",
-		drive, 'A' + drive);
-	return -1;
-    }
-
-    /* Test whether device can be opened */
-    dev = CDROM_OpenDev(wcda);
-    if (dev == -1)
-	return -1;
-    else
-        CDROM_CloseDev(dev);
-
-    wcda->cdaMode = WINE_CDA_OPEN;	/* to force reading tracks info */
-    wcda->nCurTrack = 0;
-    wcda->nTracks = 0;
-    wcda->dwFirstFrame = 0;
-    wcda->dwLastFrame = 0;
-    wcda->lpdwTrackLen = NULL;
-    wcda->lpdwTrackPos = NULL;
-    wcda->lpbTrackFlags = NULL;
-    TRACE("opened drive %c: (device %s)\n", 'A' + drive, wcda->devname);
-    return 0;
-}
-
-/**************************************************************************
- * 				CDROM_OpenDev			[internal]
- *
- */
-int	CDROM_OpenDev(WINE_CDAUDIO* wcda)
-{
-    int dev = open(wcda->devname, O_RDONLY | O_NONBLOCK, 0);
-    if (dev == -1)
-	WARN("can't open device '%s'! (%s)\n", wcda->devname, strerror(errno));
-
-    TRACE("-> %d\n", dev);
-    return dev;
-}
-
-/**************************************************************************
- * 				CDROM_GetMediaType		[internal]
- */
-int	CDROM_GetMediaType(WINE_CDAUDIO* wcda, int parentdev)
-{
-    int type = -1;
-#ifdef linux
-    int dev = CDROM_OPEN( wcda, parentdev );
-    type = ioctl(dev, CDROM_DISC_STATUS);
-    CDROM_CLOSE( dev, parentdev );
-#endif
-    TRACE("-> %d\n", type);
-    return type;
-}
-
-/**************************************************************************
- * 				CDROM_Close			[internal]
- */
-int	CDROM_CloseDev(int dev)
-{
-    TRACE("%d\n", dev);
-    return close(dev);
-}
-
-/**************************************************************************
- * 				CDROM_Close			[internal]
- */
-int	CDROM_Close(WINE_CDAUDIO* wcda)
-{
-#if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
-    if (wcda->lpdwTrackLen != NULL) free(wcda->lpdwTrackLen);
-    if (wcda->lpdwTrackPos != NULL) free(wcda->lpdwTrackPos);
-    if (wcda->lpbTrackFlags != NULL) free(wcda->lpbTrackFlags);
-    TRACE("%s\n", wcda->devname);
-    return 0;
-#else
-    return -1;
-#endif
-}
-
-/**************************************************************************
- *				CDROM_Get_UPC			[internal]
- *
- * upc has to be 14 bytes long
- */
-int CDROM_Get_UPC(WINE_CDAUDIO* wcda, LPSTR upc, int parentdev)
-{
-#ifdef linux
-    struct cdrom_mcn mcn;
-    int dev = CDROM_OPEN( wcda, parentdev );
-    int status = ioctl(dev, CDROM_GET_MCN, &mcn);
-    CDROM_CLOSE( dev, parentdev );
-    if (status)
-{
-	ERR("ioctl() failed with code %d\n",status);
-	return -1;
-    }
-    strcpy(upc, mcn.medium_catalog_number);
-    return 0;
-#else
-    return -1;
-#endif
-}
-
-/**************************************************************************
- * 				CDROM_Audio_GetNumberOfTracks	[internal]
- */
-UINT16 CDROM_Audio_GetNumberOfTracks(WINE_CDAUDIO* wcda, int parentdev)
-{
-    UINT16 ret = (UINT16)-1;
-#if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
-#ifdef linux
-    struct cdrom_tochdr		hdr;
-#else
-    struct ioc_toc_header	hdr;
-#endif
-    int dev = CDROM_OPEN( wcda, parentdev );
-
-    if (wcda->nTracks == 0) {
-#ifdef linux
-	if (ioctl(dev, CDROMREADTOCHDR, &hdr))
-#else
-	if (ioctl(dev, CDIOREADTOCHEADER, &hdr))
-#endif
-	{
-	    WARN("(%p) -- Error occurred (%s)!\n", wcda, strerror(errno));
-	    goto end;
-	}
-#ifdef linux
-	wcda->nFirstTrack = hdr.cdth_trk0;
-	wcda->nLastTrack  = hdr.cdth_trk1;
-#else	
-	wcda->nFirstTrack = hdr.starting_track;
-	wcda->nLastTrack  = hdr.ending_track;
-#endif
-	wcda->nTracks = wcda->nLastTrack - wcda->nFirstTrack + 1;
-    }
-    ret = wcda->nTracks;
-end:
-    CDROM_CLOSE( dev, parentdev );
-#endif
-    return ret;
-}
-
-/**************************************************************************
- * 			CDROM_Audio_GetTracksInfo		[internal]
- */
-BOOL CDROM_Audio_GetTracksInfo(WINE_CDAUDIO* wcda, int parentdev)
-{
-    BOOL ret = FALSE;
-#if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
-    int		i, length;
-    int		start, last_start = 0;
-    int		total_length = 0;
-#ifdef linux
-    struct cdrom_tocentry	entry;
-#else
-    struct ioc_read_toc_entry	entry;
-    struct cd_toc_entry         toc_buffer;
-#endif
-    int dev = CDROM_OPEN( wcda, parentdev );
-    
-    if (wcda->nTracks == 0) {
-	if (CDROM_Audio_GetNumberOfTracks(wcda, dev) == (WORD)-1)
-	goto end;
-    }
-    TRACE("nTracks=%u\n", wcda->nTracks);
-    
-    if (wcda->lpdwTrackLen != NULL) 
-	free(wcda->lpdwTrackLen);
-    wcda->lpdwTrackLen = (LPDWORD)malloc((wcda->nTracks + 1) * sizeof(DWORD));
-    if (wcda->lpdwTrackPos != NULL) 
-	free(wcda->lpdwTrackPos);
-    wcda->lpdwTrackPos = (LPDWORD)malloc((wcda->nTracks + 1) * sizeof(DWORD));
-    if (wcda->lpbTrackFlags != NULL)
-	free(wcda->lpbTrackFlags);
-    wcda->lpbTrackFlags = (LPBYTE)malloc((wcda->nTracks + 1) * sizeof(BYTE));
-    if (wcda->lpdwTrackLen == NULL || wcda->lpdwTrackPos == NULL ||
-	wcda->lpbTrackFlags == NULL) {
-	WARN("error allocating track table !\n");
-	goto end;
-    }
-    memset(wcda->lpdwTrackLen, 0, (wcda->nTracks + 1) * sizeof(DWORD));
-    memset(wcda->lpdwTrackPos, 0, (wcda->nTracks + 1) * sizeof(DWORD));
-    memset(wcda->lpbTrackFlags, 0, (wcda->nTracks + 1) * sizeof(BYTE));
-    for (i = 0; i <= wcda->nTracks; i++) {
-	if (i == wcda->nTracks)
-#ifdef linux
-	    entry.cdte_track = CDROM_LEADOUT;
-#else
-#define LEADOUT 0xaa
-	entry.starting_track = LEADOUT; /* FIXME */
-#endif
-	else
-#ifdef linux
-	entry.cdte_track = i + 1;
-#else
-	entry.starting_track = i + 1;
-#endif
-#ifdef linux
-	entry.cdte_format = CDROM_MSF;
-#else
-	memset((char *)&toc_buffer, 0, sizeof(toc_buffer));
-	entry.address_format = CD_MSF_FORMAT;
-	entry.data_len = sizeof(toc_buffer);
-	entry.data = &toc_buffer;
-#endif
-#ifdef linux
-	if (ioctl(dev, CDROMREADTOCENTRY, &entry))
-#else
-	if (ioctl(dev, CDIOREADTOCENTRYS, &entry))
-#endif
-	{
-	    WARN("error read entry (%s)\n", strerror(errno));
-	    /* update status according to new status */
-	    CDROM_Audio_GetCDStatus(wcda, dev);
-
-	    goto end;
-	}
-#ifdef linux
-	start = CDFRAMES_PERSEC * (SECONDS_PERMIN * 
-				   entry.cdte_addr.msf.minute + entry.cdte_addr.msf.second) + 
-	    entry.cdte_addr.msf.frame;
-#else
-	start = CDFRAMES_PERSEC * (SECONDS_PERMIN *
-				   toc_buffer.addr.msf.minute + toc_buffer.addr.msf.second) +
-	    toc_buffer.addr.msf.frame;
-#endif
-	if (i == 0) {
-	    last_start = start;
-	    wcda->dwFirstFrame = start;
-	    TRACE("dwFirstOffset=%u\n", start);
-	} else {
-	    length = start - last_start;
-	    last_start = start;
-	    start = last_start - length;
-	    total_length += length;
-	    wcda->lpdwTrackLen[i - 1] = length;
-	    wcda->lpdwTrackPos[i - 1] = start;
-	    TRACE("track #%u start=%u len=%u\n", i, start, length);
-	}
-#ifdef linux
-	wcda->lpbTrackFlags[i] =
-	    (entry.cdte_adr << 4) | (entry.cdte_ctrl & 0x0f);
-#else
-	wcda->lpbTrackFlags[i] =
-	    (toc_buffer.addr_type << 4) | (toc_buffer.control & 0x0f);
-#endif 
-	TRACE("track #%u flags=%02x\n", i + 1, wcda->lpbTrackFlags[i]);
-    }
-    wcda->dwLastFrame = last_start;
-    TRACE("total_len=%u\n", total_length);
-    ret = TRUE;
-end:
-    CDROM_CLOSE( dev, parentdev );
-#endif
-    return ret;
-}
-
-/**************************************************************************
- * 				CDROM_Audio_GetCDStatus		[internal]
- */
-BOOL CDROM_Audio_GetCDStatus(WINE_CDAUDIO* wcda, int parentdev)
-{
-#if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
-    int oldmode = wcda->cdaMode;
-    int ret = FALSE;
-    int dev = CDROM_OPEN( wcda, parentdev );
-#ifdef linux
-    wcda->sc.cdsc_format = CDROM_MSF;
-#else
-    struct ioc_read_subchannel	read_sc;
-    
-    read_sc.address_format = CD_MSF_FORMAT;
-    read_sc.data_format    = CD_CURRENT_POSITION;
-    read_sc.track          = 0;
-    read_sc.data_len       = sizeof(wcda->sc);
-    read_sc.data	   = (struct cd_sub_channel_info *)&wcda->sc;
-#endif
-#ifdef linux
-    if (ioctl(dev, CDROMSUBCHNL, &wcda->sc))
-#else
-    if (ioctl(dev, CDIOCREADSUBCHANNEL, &read_sc))
-#endif
-    {
-	TRACE("opened or no_media (%s)!\n", strerror(errno));
-	wcda->cdaMode = WINE_CDA_OPEN; /* was NOT_READY */
-	goto end;
-    }
-    switch (
-#ifdef linux
-	    wcda->sc.cdsc_audiostatus
-#else
-	    wcda->sc.header.audio_status
-#endif
-	    ) {
-#ifdef linux
-    case CDROM_AUDIO_INVALID:
-#else
-    case CD_AS_AUDIO_INVALID:
-#endif
-	/* seems that this means stop for ide drives */
-	wcda->cdaMode = WINE_CDA_STOP;
-	TRACE("AUDIO_INVALID -> WINE_CDA_STOP\n");
-	break;
-#ifdef linux
-    case CDROM_AUDIO_NO_STATUS: 
-#else
-    case CD_AS_NO_STATUS:
-#endif
-	wcda->cdaMode = WINE_CDA_STOP;
-	TRACE("WINE_CDA_STOP !\n");
-	break;
-#ifdef linux
-    case CDROM_AUDIO_PLAY: 
-#else
-    case CD_AS_PLAY_IN_PROGRESS:
-#endif
-	wcda->cdaMode = WINE_CDA_PLAY;
-	break;
-#ifdef linux
-    case CDROM_AUDIO_PAUSED:
-#else
-    case CD_AS_PLAY_PAUSED:
-#endif
-	wcda->cdaMode = WINE_CDA_PAUSE;
-	TRACE("WINE_CDA_PAUSE !\n");
-	break;
-    default:
-#ifdef linux
-	TRACE("status=%02X !\n",
-	      wcda->sc.cdsc_audiostatus);
-#else
-	TRACE("status=%02X !\n",
-	      wcda->sc.header.audio_status);
-#endif
-    }
-#ifdef linux
-    wcda->nCurTrack = wcda->sc.cdsc_trk;
-    wcda->dwCurFrame = 
-	CDFRAMES_PERMIN * wcda->sc.cdsc_absaddr.msf.minute +
-	CDFRAMES_PERSEC * wcda->sc.cdsc_absaddr.msf.second +
-	wcda->sc.cdsc_absaddr.msf.frame;
-#else
-    wcda->nCurTrack = wcda->sc.what.position.track_number;
-    wcda->dwCurFrame = 
-	CDFRAMES_PERMIN * wcda->sc.what.position.absaddr.msf.minute +
-	CDFRAMES_PERSEC * wcda->sc.what.position.absaddr.msf.second +
-	wcda->sc.what.position.absaddr.msf.frame;
-#endif
-#ifdef linux
-    TRACE("%02u-%02u:%02u:%02u\n",
-	  wcda->sc.cdsc_trk,
-	  wcda->sc.cdsc_absaddr.msf.minute,
-	  wcda->sc.cdsc_absaddr.msf.second,
-	  wcda->sc.cdsc_absaddr.msf.frame);
-#else
-    TRACE("%02u-%02u:%02u:%02u\n",
-	  wcda->sc.what.position.track_number,
-	  wcda->sc.what.position.absaddr.msf.minute,
-	  wcda->sc.what.position.absaddr.msf.second,
-	  wcda->sc.what.position.absaddr.msf.frame);
-#endif
-    
-    if (oldmode != wcda->cdaMode && oldmode == WINE_CDA_OPEN) {
-	if (!CDROM_Audio_GetTracksInfo(wcda, dev)) {
-	    WARN("error updating TracksInfo !\n");
-	    goto end;
-	}
-    }
-    if (wcda->cdaMode != WINE_CDA_OPEN)
-        ret = TRUE;
-end:
-    CDROM_CLOSE( dev, parentdev );
-    return ret;
-#else
-    return FALSE;
-#endif
-}
-
-/**************************************************************************
- * 				CDROM_Audio_Play		[internal]
- */
-int	CDROM_Audio_Play(WINE_CDAUDIO* wcda, DWORD start, DWORD end, int parentdev)
-{
-    int ret = -1;
-#if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
-#ifdef linux
-    struct 	cdrom_msf	msf;
-#else
-    struct	ioc_play_msf	msf;
-#endif
-    int dev = CDROM_OPEN( wcda, parentdev );
-
-#ifdef linux
-    msf.cdmsf_min0 = start / CDFRAMES_PERMIN;
-    msf.cdmsf_sec0 = (start % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
-    msf.cdmsf_frame0 = start % CDFRAMES_PERSEC;
-    msf.cdmsf_min1 = end / CDFRAMES_PERMIN;
-    msf.cdmsf_sec1 = (end % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
-    msf.cdmsf_frame1 = end % CDFRAMES_PERSEC;
-#else
-    msf.start_m     = start / CDFRAMES_PERMIN;
-    msf.start_s     = (start % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
-    msf.start_f     = start % CDFRAMES_PERSEC;
-    msf.end_m       = end / CDFRAMES_PERMIN;
-    msf.end_s       = (end % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
-    msf.end_f       = end % CDFRAMES_PERSEC;
-#endif
-#ifdef linux
-    if (ioctl(dev, CDROMSTART))
-#else
-    if (ioctl(dev, CDIOCSTART, NULL))
-#endif
-    {
-	WARN("motor doesn't start !\n");
-	goto end;
-    }
-#ifdef linux
-    if (ioctl(dev, CDROMPLAYMSF, &msf))
-#else
-    if (ioctl(dev, CDIOCPLAYMSF, &msf))
-#endif
-    {
-	WARN("device doesn't play !\n");
-	goto end;
-    }
-#ifdef linux
-    TRACE("msf = %d:%d:%d %d:%d:%d\n",
-	  msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
-	  msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
-#else
-    TRACE("msf = %d:%d:%d %d:%d:%d\n",
-	  msf.start_m, msf.start_s, msf.start_f,
-	  msf.end_m,   msf.end_s,   msf.end_f);
-#endif
-    ret = 0;
-end:
-    CDROM_CLOSE( dev, parentdev );
-#endif
-    return ret;
-}
-
-/**************************************************************************
- * 				CDROM_Audio_Stop		[internal]
- */
-int	CDROM_Audio_Stop(WINE_CDAUDIO* wcda, int parentdev)
-{
-    int	ret = -1;
-#if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
-    int dev = CDROM_OPEN( wcda, parentdev );
-#ifdef linux
-    ret = ioctl(dev, CDROMSTOP);
-#else
-    ret = ioctl(dev, CDIOCSTOP, NULL);
-#endif
-    CDROM_CLOSE( dev, parentdev );
-#endif
-    return ret;
-}
-
-/**************************************************************************
- * 				CDROM_Audio_Pause		[internal]
- */
-int	CDROM_Audio_Pause(WINE_CDAUDIO* wcda, int pauseOn, int parentdev)
-{
-    int	ret = -1;
-#if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
-    int dev = CDROM_OPEN( wcda, parentdev );
-#ifdef linux
-    ret = ioctl(dev, pauseOn ? CDROMPAUSE : CDROMRESUME);
-#else
-    ret = ioctl(dev, pauseOn ? CDIOCPAUSE : CDIOCRESUME, NULL);
-#endif
-    CDROM_CLOSE( dev, parentdev );
-#endif
-    return ret;
-}
-
-/**************************************************************************
- * 				CDROM_Audio_Seek		[internal]
- */
-int	CDROM_Audio_Seek(WINE_CDAUDIO* wcda, DWORD at, int parentdev)
-{
-    int	ret = -1;
-#if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
-    int dev = CDROM_OPEN( wcda, parentdev );
-#ifdef linux
-    struct cdrom_msf0		msf;
-    msf.minute = at / CDFRAMES_PERMIN;
-    msf.second = (at % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
-    msf.frame  = at % CDFRAMES_PERSEC;
-
-    ret = ioctl(dev, CDROMSEEK, &msf);
-#else
-   /* FIXME: the current end for play is lost 
-    * use end of CD ROM instead
-    */
-   FIXME("Could a BSD expert implement the seek function ?\n");
-   CDROM_Audio_Play(wcda, at, wcda->lpdwTrackPos[wcda->nTracks] + wcda->lpdwTrackLen[wcda->nTracks], dev);
-#endif
-    CDROM_CLOSE( dev, parentdev );
-#endif
-    return ret;
-}
-
-/**************************************************************************
- * 				CDROM_SetDoor			[internal]
- */
-int	CDROM_SetDoor(WINE_CDAUDIO* wcda, int open, int parentdev)
-{
-    int	ret = -1;
-#if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
-    int dev = CDROM_OPEN( wcda, parentdev );
-
-    TRACE("%d\n", open);
-#ifdef linux
-    if (open) {
-	ret = ioctl(dev, CDROMEJECT);
-    } else {
- 	ret = ioctl(dev, CDROMCLOSETRAY);
-    }
-#else
-    ret = (ioctl(dev, CDIOCALLOW, NULL)) || 
-	(ioctl(dev, open ? CDIOCEJECT : CDIOCCLOSE, NULL)) ||
-	(ioctl(dev, CDIOCPREVENT, NULL));
-#endif
-    wcda->nTracks = 0;
-    if (ret == -1)
-        WARN("failed (%s)\n", strerror(errno));
-    CDROM_CLOSE( dev, parentdev );
-#endif
-    return ret;
-}
-
-/**************************************************************************
- * 				CDROM_Reset			[internal]
- */
-int	CDROM_Reset(WINE_CDAUDIO* wcda, int parentdev)
-{
-    int	ret = -1;
-#if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
-    int dev = CDROM_OPEN( wcda, parentdev );
-#ifdef linux
-    ret = ioctl(dev, CDROMRESET);
-#else
-    ret = ioctl(dev, CDIOCRESET, NULL);
-#endif
-    CDROM_CLOSE( dev, parentdev );
-#endif
-    return ret;
-}
-
-/**************************************************************************
- *                             CDROM_Data_FindBestVoldesc       [internal]
- */
-WORD CDROM_Data_FindBestVoldesc(int fd)
-{
-    BYTE cur_vd_type, max_vd_type = 0;
-    unsigned int offs, best_offs=0, extra_offs = 0;
-    char sig[3];
-
-
-    for (offs=0x8000; offs <= 0x9800; offs += 0x800)
-    {
-	/* if 'CDROM' occurs at position 8, this is a pre-iso9660 cd, and 
-	 * the volume label is displaced forward by 8
-	 */
-	lseek(fd, offs+11, SEEK_SET); /* check for non-ISO9660 signature */
-	read(fd, &sig, 3);
-	if ((sig[0]=='R')&&(sig[1]=='O')&&(sig[2]=='M'))
-	{
-	    extra_offs=8;
-	}
-        lseek(fd, offs+extra_offs, SEEK_SET);
-        read(fd, &cur_vd_type, 1);
-        if (cur_vd_type == 0xff) /* voldesc set terminator */
-            break;
-        if (cur_vd_type > max_vd_type)
-        {
-            max_vd_type = cur_vd_type;
-            best_offs = offs + extra_offs;
-        }
-    }
-    return best_offs;
-}
-
-/**************************************************************************
- *				CDROM_Audio_GetSerial		[internal]
- */
-DWORD CDROM_Audio_GetSerial(WINE_CDAUDIO* wcda)
-{
-    unsigned long serial = 0;
-    int i;
-    DWORD dwFrame, msf;
-    WORD wMinutes, wSeconds, wFrames;
-	WORD wMagic;
-	DWORD dwStart, dwEnd;
-
-	/*
-	 * wMagic collects the wFrames from track 1
-	 * dwStart, dwEnd collect the beginning and end of the disc respectively, in
-	 * frames.
-	 * There it is collected for correcting the serial when there are less than
-	 * 3 tracks.
-	 */
-	wMagic = 0;
-	dwStart = dwEnd = 0;
-
-    for (i = 0; i < wcda->nTracks; i++) {
-	dwFrame = wcda->lpdwTrackPos[i];
-	wMinutes = dwFrame / CDFRAMES_PERMIN;
-	wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
-	wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
-	msf = CDROM_MAKE_MSF(wMinutes, wSeconds, wFrames);
-
-	serial += (CDROM_MSF_MINUTE(msf) << 16) +
-	(CDROM_MSF_SECOND(msf) << 8) +
-	(CDROM_MSF_FRAME(msf));
-
-	if (i==0)
-	{
-		wMagic = wFrames;
-		dwStart = dwFrame;
-	}
-	dwEnd = dwFrame + wcda->lpdwTrackLen[i];
-	
-	}
-
-	if (wcda->nTracks < 3)
-	{
-		serial += wMagic + (dwEnd - dwStart);
-	}
-    return serial;
-}
-
-/**************************************************************************
- *				CDROM_Data_GetSerial		[internal]
- */
-DWORD CDROM_Data_GetSerial(WINE_CDAUDIO* wcda, int parentdev)
-{
-    int dev = CDROM_OPEN( wcda, parentdev );
-    WORD offs = CDROM_Data_FindBestVoldesc(dev);
-    union {
-	unsigned long val;
-	unsigned char p[4];
-    } serial;
-    BYTE b0 = 0, b1 = 1, b2 = 2, b3 = 3;
-    
-    serial.val = 0;
-    if (offs)
-    {
-	BYTE buf[2048];
-	OSVERSIONINFOA ovi;
-	int i;
-
-	lseek(dev,offs,SEEK_SET);
-	read(dev,buf,2048);
-	/*
-	 * OK, another braindead one... argh. Just believe it.
-	 * Me$$ysoft chose to reverse the serial number in NT4/W2K.
-	 * It's true and nobody will ever be able to change it.
-	 */
-	ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
-	GetVersionExA(&ovi);
-	if ((ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
-	&&  (ovi.dwMajorVersion >= 4))
-	{
-	    b0 = 3; b1 = 2; b2 = 1; b3 = 0;
-	}
-	for(i=0; i<2048; i+=4)
-	{
-	    /* DON'T optimize this into DWORD !! (breaks overflow) */
-	    serial.p[b0] += buf[i+b0];
-	    serial.p[b1] += buf[i+b1];
-	    serial.p[b2] += buf[i+b2];
-	    serial.p[b3] += buf[i+b3];
-	}
-    }
-    CDROM_CLOSE( dev, parentdev );
-    return serial.val;
-}
-
-/**************************************************************************
- *				CDROM_GetSerial			[internal]
- */
-DWORD CDROM_GetSerial(int drive)
-{
-    WINE_CDAUDIO wcda;
-    DWORD serial = 0;
-
-    /* EXPIRES 01.01.2002 */
-    WARN("CD-ROM serial number calculation might fail.\n");
-    WARN("Please test with as many exotic CDs as possible !\n");
-
-    if (!(CDROM_Open(&wcda, drive)))
-    {
-	int dev = CDROM_OpenDev(&wcda);
-	int media = CDROM_GetMediaType(&wcda, dev);
-
-	switch (media)
-	{
-	    case CDS_AUDIO:
-	    case CDS_MIXED: /* mixed is basically a mountable audio CD */
-		if (!(CDROM_Audio_GetCDStatus(&wcda, dev))) {
-		    ERR("couldn't get CD status !\n");
-		    goto end;
-		}
-		serial = CDROM_Audio_GetSerial(&wcda);
-		break;
-	    case CDS_DATA_1:
-	    case CDS_DATA_2:
-	    case CDS_XA_2_1:
-	    case CDS_XA_2_2:
-	    case -1: /* ioctl() error: ISO9660 image file given ? */
-		/* hopefully a data CD */
-		serial = CDROM_Data_GetSerial(&wcda, dev);
-		break;
-	    default:
-		WARN("Strange CD type (%d) or empty ?\n", media);
-	}
-	if (serial)
-	    TRACE("CD serial number is %04x-%04x.\n",
-		HIWORD(serial), LOWORD(serial));
-	else
-	    if (media >= CDS_AUDIO)
-		ERR("couldn't get CD serial !\n");
-end:
-	CDROM_CloseDev(dev);
-	CDROM_Close(&wcda);
-    }
-    return serial;
-}
-
-/**************************************************************************
- *				CDROM_Data_GetLabel		[internal]
- */
-DWORD CDROM_Data_GetLabel(WINE_CDAUDIO* wcda, char *label, int parentdev)
-{
-#define LABEL_LEN	32+1
-    int dev = CDROM_OPEN( wcda, parentdev );
-    WORD offs = CDROM_Data_FindBestVoldesc(dev);
-    WCHAR label_read[LABEL_LEN]; /* Unicode possible, too */
-    DWORD unicode_id = 0;
-
-    if (offs)
-    {
-	if ((lseek(dev, offs+0x58, SEEK_SET) == offs+0x58)
-	&&  (read(dev, &unicode_id, 3) == 3))
-	{
-	    int ver = (unicode_id & 0xff0000) >> 16;
-
-	    if ((lseek(dev, offs+0x28, SEEK_SET) != offs+0x28)
-	    ||  (read(dev, &label_read, LABEL_LEN) != LABEL_LEN))
-		goto failure;
-
-	    CDROM_CLOSE( dev, parentdev );
-	    if ((LOWORD(unicode_id) == 0x2f25) /* Unicode ID */
-	    &&  ((ver == 0x40) || (ver == 0x43) || (ver == 0x45)))
-	    { /* yippee, unicode */
-		int i;
-		WORD ch;
-		for (i=0; i<LABEL_LEN;i++)
-		{ /* Motorola -> Intel Unicode conversion :-\ */
-		     ch = label_read[i];
-		     label_read[i] = (ch << 8) | (ch >> 8);
-		}
-                WideCharToMultiByte( CP_ACP, 0, label_read, -1, label, 12, NULL, NULL );
-                label[11] = 0;
-	    }
-	    else
-	    {
-		strncpy(label, (LPSTR)label_read, 11);
-		label[11] = '\0';
-	    }
-	    return 1;
-	}
-    }
-failure:
-    CDROM_CLOSE( dev, parentdev );
-    ERR("error reading label !\n");
-    return 0;
-}
-
-/**************************************************************************
- *				CDROM_GetLabel			[internal]
- */
-DWORD CDROM_GetLabel(int drive, char *label)
-{
-    WINE_CDAUDIO wcda;
-    DWORD ret = 1;
-
-    if (!(CDROM_Open(&wcda, drive)))
-    {
-	int dev = CDROM_OpenDev(&wcda);
-	int media = CDROM_GetMediaType(&wcda, dev);
-	LPSTR cdname = NULL;
-
-	switch (media)
-	{
-	    case CDS_AUDIO:
-		cdname = "Audio";
-		strcpy(label, "Audio CD   ");
-		break;
-
-	    case CDS_DATA_1: /* fall through for all data CD types !! */
-		if (!cdname) cdname = "Data_1";
-	    case CDS_DATA_2:
-		if (!cdname) cdname = "Data_2";
-	    case CDS_XA_2_1:
-		if (!cdname) cdname = "XA 2.1";
-	    case CDS_XA_2_2:
-		if (!cdname) cdname = "XA 2.2";
-	    case CDS_MIXED:
-		if (!cdname) cdname = "Mixed mode";
-	    case -1:
-		if (!cdname) cdname = "Unknown/ISO file";
-
-		/* common code *here* !! */
-		/* hopefully a data CD */
-		if (!CDROM_Data_GetLabel(&wcda, label, dev))
-			ret = 0;
-		break;
-
-	    case CDS_NO_INFO:
-		if (!cdname) cdname = "No_info";
-		ret = 0;
-		break;
-
-	    default:
-                WARN("Strange CD type (%d) or empty ?\n", media);
-		cdname = "Strange/empty";
-	        ret = 0;
-		break;
-	}
-	
-	CDROM_CloseDev(dev);
-	CDROM_Close(&wcda);
-	TRACE("%s CD: label is '%s'.\n",
-	    cdname, label);
-    }
-    else
-        ret = 0;
-
-    return ret;
-}
-
diff --git a/win32/device.c b/win32/device.c
index 0856d9780a1..ce88d8f6176 100644
--- a/win32/device.c
+++ b/win32/device.c
@@ -319,8 +319,7 @@ LPCSTR VMM_Service_Name[N_VMM_SERVICE] =
 
 
 
-HANDLE DEVICE_Open( LPCSTR filename, DWORD access,
-                      LPSECURITY_ATTRIBUTES sa )
+HANDLE DEVICE_Open( LPCSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa )
 {
     const struct VxDInfo *info;
 
@@ -333,21 +332,28 @@ HANDLE DEVICE_Open( LPCSTR filename, DWORD access,
     return 0;
 }
 
-static const struct VxDInfo *DEVICE_GetInfo( HANDLE handle )
+static DWORD DEVICE_GetClientID( HANDLE handle )
 {
-    const struct VxDInfo *info = NULL;
+    DWORD       ret = 0;
     SERVER_START_REQ( get_file_info )
     {
         req->handle = handle;
-        if (!wine_server_call( req ) &&
-            (reply->type == FILE_TYPE_UNKNOWN) &&
-            (reply->attr & 0x10000))
-        {
-            for (info = VxDList; info->name; info++)
-                if (info->id == LOWORD(reply->attr)) break;
-        }
+        if (!wine_server_call( req ) && (reply->type == FILE_TYPE_UNKNOWN))
+            ret = reply->attr;
     }
     SERVER_END_REQ;
+    return ret;
+}
+
+static const struct VxDInfo *DEVICE_GetInfo( DWORD clientID )
+{
+    const struct VxDInfo *info = NULL;
+    
+    if (clientID & 0x10000)
+    {
+        for (info = VxDList; info->name; info++)
+            if (info->id == LOWORD(clientID)) break;
+    }
     return info;
 }
 
@@ -366,13 +372,13 @@ BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
 			      LPDWORD lpcbBytesReturned,
 			      LPOVERLAPPED lpOverlapped)
 {
-        const struct VxDInfo *info;
+        DWORD clientID;
 
         TRACE( "(%d,%ld,%p,%ld,%p,%ld,%p,%p)\n",
                hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer,
                lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped	);
 
-	if (!(info = DEVICE_GetInfo( hDevice )))
+	if (!(clientID = DEVICE_GetClientID( hDevice )))
 	{
 		SetLastError( ERROR_INVALID_PARAMETER );
 		return FALSE;
@@ -381,7 +387,12 @@ BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
 	/* Check if this is a user defined control code for a VxD */
 	if( HIWORD( dwIoControlCode ) == 0 )
 	{
-		if ( info->deviceio )
+                const struct VxDInfo *info;
+                if (!(info = DEVICE_GetInfo( clientID )))
+                {
+                        FIXME( "No device found for id %lx\n", clientID);
+                }
+                else if ( info->deviceio )
 		{
 			return info->deviceio( dwIoControlCode, 
                                         lpvInBuffer, cbInBuffer, 
@@ -400,7 +411,15 @@ BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
 	}
 	else
 	{
-		switch( dwIoControlCode )
+                char str[3];
+
+                strcpy(str,  "A:");
+                str[0] += LOBYTE(clientID);
+                if (GetDriveTypeA(str) == DRIVE_CDROM)
+                    return CDROM_DeviceIoControl(clientID, hDevice, dwIoControlCode, lpvInBuffer, cbInBuffer,
+                                                 lpvOutBuffer, cbOutBuffer, lpcbBytesReturned,
+                                                 lpOverlapped);
+                else switch( dwIoControlCode )
 		{
 		case FSCTL_DELETE_REPARSE_POINT:
 		case FSCTL_DISMOUNT_VOLUME:
@@ -1135,7 +1154,7 @@ static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
     case VWIN32_DIOC_DOS_INT13:
     case VWIN32_DIOC_DOS_INT25:
     case VWIN32_DIOC_DOS_INT26:
-	case VWIN32_DIOC_DOS_DRIVEINFO:
+    case VWIN32_DIOC_DOS_DRIVEINFO:
     {
         CONTEXT86 cxt;
         DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
@@ -1160,7 +1179,7 @@ static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
         case VWIN32_DIOC_DOS_INT13: INT_Int13Handler( &cxt ); break;
         case VWIN32_DIOC_DOS_INT25: INT_Int25Handler( &cxt ); break;
         case VWIN32_DIOC_DOS_INT26: INT_Int26Handler( &cxt ); break;
-		case VWIN32_DIOC_DOS_DRIVEINFO:	DOS3Call( &cxt ); break; /* Call int 21h 730x */
+        case VWIN32_DIOC_DOS_DRIVEINFO:	DOS3Call( &cxt ); break; /* Call int 21h 730x */
         }
 
         CONTEXT_2_DIOCRegs( &cxt, pOut );
-- 
GitLab