Index: dlls/ntdll/cdrom.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/cdrom.c,v
retrieving revision 1.7
diff -u -u -r1.7 cdrom.c
--- dlls/ntdll/cdrom.c	2 Apr 2002 19:19:49 -0000	1.7
+++ dlls/ntdll/cdrom.c	17 Apr 2002 23:20:41 -0000
@@ -25,16 +25,24 @@
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
+#include <stdio.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include "ntddk.h"
 #include "winioctl.h"
 #include "ntddstor.h"
 #include "ntddcdrm.h"
+#include "ntddscsi.h"
 #include "drive.h"
 #include "file.h"
 #include "wine/debug.h"
+#include "winreg.h"
 
+#include <scsi/sg.h>
+#include <linux/major.h>
+#include <linux/hdreg.h>
 #ifdef HAVE_LINUX_CDROM_H
 # include <linux/cdrom.h>
 #endif
@@ -57,6 +65,125 @@
 static struct cdrom_cache cdrom_cache[26];
 
 /******************************************************************
+ *		CDROM_GetIdeInterface
+ *
+ * Determines the ide interface (the number after the ide), and the 
+ * number of the device on that interface for ide cdroms.
+ * Returns false if the info could not be get
+ *
+ * NOTE: this function is used in CDROM_InitRegistry and CDROM_GetAddress
+ */
+    static int CDROM_GetIdeInterface(int dev, int* iface, int* device) {
+#if defined(linux)
+        {
+            struct stat st;
+            if (ioctl(dev, SG_EMULATED_HOST) != -1) {
+                FIXME("not implemented for true scsi drives\n");
+                return 0;
+            }
+            if ( fstat(dev, &st) == -1 || ! S_ISBLK(st.st_mode)) {
+                FIXME("cdrom not a block device!!!\n");
+                return 0;
+            }
+            switch (major(st.st_rdev)) {
+                case IDE0_MAJOR: *iface = 0; break;
+                case IDE1_MAJOR: *iface = 1; break;
+                case IDE2_MAJOR: *iface = 2; break;
+                case IDE3_MAJOR: *iface = 3; break;
+                case IDE4_MAJOR: *iface = 4; break;
+                case IDE5_MAJOR: *iface = 5; break;
+                case IDE6_MAJOR: *iface = 6; break;
+                case IDE7_MAJOR: *iface = 7; break;
+                default:
+                                 FIXME("major %d not supported\n", major(st.st_rdev));
+            }
+            *device = (minor(st.st_rdev) == 63 ? 1 : 0);
+            return 1;
+        }
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+        FIXME("not implemented for BSD\n");
+        return 0;
+#else
+        FIXME("not implemented for nonlinux\n");
+        return 0;
+#endif
+    }
+
+/******************************************************************
+ *		CDROM_InitRegistry
+ *
+ * Initializes registry to contain scsi info about the cdrom in NT.
+ * All devices (even not real scsi ones) have this info in NT.
+ * TODO: for now it only works for non scsi devices
+ * NOTE: programs usually read these registry entries after sending the 
+ *       IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
+ */
+static void CDROM_InitRegistry(int dev) {
+    int portnum, targetid;
+    int dma;
+    char buffer[40];
+    DWORD value;
+    HKEY scsiKey;
+    HKEY portKey;
+    HKEY busKey;
+    HKEY targetKey;
+
+    if ( ! CDROM_GetIdeInterface(dev, &portnum, &targetid))
+        return;
+
+    /* Ensure there is Scsi key */
+    if (RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DEVICEMAP\\Scsi", &scsiKey)) {
+        ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
+        return;
+    }
+
+    snprintf(buffer,40,"Scsi Port %d",portnum);
+    if (RegCreateKeyA( scsiKey, buffer, &portKey)) {
+        ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
+        return;
+    }
+
+    RegSetValueExA( portKey,"Driver", 0, REG_SZ, "atapi", strlen("atapi"));
+    value = 10;
+    RegSetValueExA( portKey,"FirstBusTimeScanInMs", 0, REG_DWORD, (char*)&value, sizeof(value));
+    value = 0;
+    if (ioctl(dev,HDIO_GET_DMA, &dma) != -1) {
+        value = dma;
+        TRACE("setting dma to %lx\n", value);
+    }
+    RegSetValueExA( portKey,"DMAEnabled", 0, REG_DWORD, (char*)&value, sizeof(value));
+
+    if (RegCreateKeyA( portKey, "Scsi Bus 0", &busKey)) {
+        ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
+        return;
+    }
+
+    if (RegCreateKeyA( busKey, "Initiator Id 255", &targetKey)) {
+        ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
+        return;
+    }
+    RegCloseKey( targetKey );
+
+    snprintf(buffer,40,"Target Id %d", targetid);
+    if (RegCreateKeyA( busKey, buffer, &targetKey)) {
+        ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
+        return;
+    }
+
+    RegSetValueExA( targetKey,"Type", 0, REG_SZ, "CdRomPeripheral", strlen("CdRomPeripheral"));
+    /* FIXME - maybe real identifier?? */
+    RegSetValueExA( targetKey,"Identifier", 0, REG_SZ, "Wine CDROM", strlen("Wine CDROM"));
+    /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */
+    RegSetValueExA( targetKey,"DeviceName", 0, REG_SZ, "Cdrom0", strlen("Cdrom0"));
+
+    RegCloseKey( targetKey );
+    RegCloseKey( busKey );
+    RegCloseKey( portKey );
+    RegCloseKey( scsiKey );
+}
+    
+
+/******************************************************************
  *		CDROM_Open
  *
  *
@@ -80,6 +207,7 @@
             FIXME("Can't open %s: %s\n", root, strerror(errno));
             return -1;
         }
+        CDROM_InitRegistry(cdrom_cache[dev].fd);
     }
     cdrom_cache[dev].count++;
     return cdrom_cache[dev].fd;
@@ -830,6 +958,41 @@
 }
 
 /******************************************************************
+ *		CDROM_GetAddress
+ * 
+ * implements IOCTL_SCSI_GET_ADDRESS
+ */
+static DWORD CDROM_GetAddress(int dev, SCSI_ADDRESS* address)
+{
+    int portnum, targetid;
+
+    address->Length = sizeof(SCSI_ADDRESS);
+    address->PathId = 0; /* bus number */
+    address->Lun = 0;
+    if ( ! CDROM_GetIdeInterface(dev, &portnum, &targetid))
+        return STATUS_NOT_SUPPORTED;
+
+    address->PortNumber = portnum;
+    address->TargetId = targetid;
+    return 0;
+}
+
+/******************************************************************
+ *		CDROM_ScsiPassThroughDirect
+ * 
+ * implements IOCTL_SCSI_PASS_THROUGH_DIRECT
+ */
+static DWORD CDROM_ScsiPassThroughDirect(int dev, SCSI_PASS_THROUGH_DIRECT* in, SCSI_PASS_THROUGH_DIRECT* out, DWORD len, DWORD* sz)
+{
+    FIXME("(%d, %lx, %lx, %ld, %lx) stub\n", dev, (DWORD)in, (DWORD)out, len, (DWORD)sz);
+    TRACE("in data: Length: %d, SenseInfoLength: %d, CdbLength: %d, DataTransferLength %ld"
+	    "DataBuffer: %lx\n",
+	    in->Length, in->SenseInfoLength,in->CdbLength, in->DataTransferLength,
+	    (DWORD)in->DataBuffer);
+    return STATUS_NOT_SUPPORTED;
+}
+
+/******************************************************************
  *		CDROM_DeviceIoControl
  *
  *
@@ -892,6 +1055,7 @@
         else error = CDROM_SetTray(dev, TRUE);
         break;
 
+    case IOCTL_CDROM_MEDIA_REMOVAL:
     case IOCTL_DISK_MEDIA_REMOVAL:
     case IOCTL_STORAGE_MEDIA_REMOVAL:
     case IOCTL_STORAGE_EJECTION_CONTROL:
@@ -1008,6 +1172,20 @@
         else if (lpOutBuffer == NULL) error = STATUS_BUFFER_TOO_SMALL;
         else error = CDROM_RawRead(dev, (const RAW_READ_INFO*)lpInBuffer, 
                                    lpOutBuffer, nOutBufferSize, &sz);
+        break;
+    case IOCTL_SCSI_GET_ADDRESS:
+        sz = sizeof(SCSI_ADDRESS);
+        if (lpInBuffer != NULL || nInBufferSize != 0) error = STATUS_INVALID_PARAMETER;
+        else if (nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_GetAddress(dev, (SCSI_ADDRESS*)lpOutBuffer);
+        break;
+    case IOCTL_SCSI_PASS_THROUGH_DIRECT:
+        sz = sizeof(SCSI_PASS_THROUGH_DIRECT);
+        if (lpInBuffer == NULL || nInBufferSize < sz) 
+            error = STATUS_INVALID_PARAMETER;
+        else if (lpOutBuffer == NULL || nOutBufferSize < sz) error = STATUS_BUFFER_TOO_SMALL;
+        else error = CDROM_ScsiPassThroughDirect(dev,(SCSI_PASS_THROUGH_DIRECT*)lpInBuffer,
+	       (SCSI_PASS_THROUGH_DIRECT*)lpOutBuffer, nOutBufferSize, &sz);
         break;
     default:
         FIXME("Unsupported IOCTL %lx\n", dwIoControlCode);
