Implemented IOCTL_SCSI_GET_ADDRESS for non true scsi cdrom drives
(only on linux).
Initialize registry under HKEY_LOCAL_MACHINE/HARDWARE/DEVICEMAP/Scsi.
Added IOCTL_CDROM_MEDIA_REMOVAL support.

diff --git a/configure b/configure
index cdf3eb8..8a29708 100755
--- a/configure
+++ b/configure
@@ -10467,6 +10467,9 @@
 
 
 
+
+
+
 for ac_header in \
 	arpa/inet.h \
 	arpa/nameser.h \
@@ -10479,8 +10482,10 @@
 	libutil.h \
 	link.h \
 	linux/cdrom.h \
+	linux/hdreg.h \
 	linux/input.h \
 	linux/joystick.h \
+	linux/major.h \
 	linux/param.h \
 	linux/serial.h \
 	linux/ucdrom.h \
@@ -10493,6 +10498,7 @@
 	pty.h \
 	resolv.h \
 	sched.h \
+	scsi/sg.h \
 	socket.h \
 	stdint.h \
 	strings.h \
@@ -10511,8 +10517,8 @@
 	sys/param.h \
 	sys/ptrace.h \
 	sys/reg.h \
-	sys/signal.h \
 	sys/shm.h \
+	sys/signal.h \
 	sys/socket.h \
 	sys/sockio.h \
 	sys/statfs.h \
@@ -10520,11 +10526,11 @@
 	sys/syscall.h \
 	sys/time.h \
 	sys/user.h \
-	sys/wait.h \
 	sys/v86.h \
 	sys/v86intr.h \
 	sys/vfs.h \
 	sys/vm86.h \
+	sys/wait.h \
 	syscall.h \
 	ucontext.h \
 	unistd.h \
diff --git a/configure.ac b/configure.ac
index b36fb68..bfd75cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -913,8 +913,10 @@
 	libutil.h \
 	link.h \
 	linux/cdrom.h \
+	linux/hdreg.h \
 	linux/input.h \
 	linux/joystick.h \
+	linux/major.h \
 	linux/param.h \
 	linux/serial.h \
 	linux/ucdrom.h \
@@ -927,6 +929,7 @@
 	pty.h \
 	resolv.h \
 	sched.h \
+	scsi/sg.h \
 	socket.h \
 	stdint.h \
 	strings.h \
@@ -945,8 +948,8 @@
 	sys/param.h \
 	sys/ptrace.h \
 	sys/reg.h \
-	sys/signal.h \
 	sys/shm.h \
+	sys/signal.h \
 	sys/socket.h \
 	sys/sockio.h \
 	sys/statfs.h \
@@ -954,11 +957,11 @@
 	sys/syscall.h \
 	sys/time.h \
 	sys/user.h \
-	sys/wait.h \
 	sys/v86.h \
 	sys/v86intr.h \
 	sys/vfs.h \
 	sys/vm86.h \
+	sys/wait.h \
 	syscall.h \
 	ucontext.h \
 	unistd.h \
diff --git a/dlls/ntdll/cdrom.c b/dlls/ntdll/cdrom.c
index 63360c8..19730cc 100644
--- a/dlls/ntdll/cdrom.c
+++ b/dlls/ntdll/cdrom.c
@@ -24,9 +24,13 @@
 
 #include <errno.h>
 #include <string.h>
+#include <stdio.h>
 #include <unistd.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"
@@ -36,6 +40,15 @@
 #include "file.h"
 #include "wine/debug.h"
 
+#ifdef HAVE_SCSI_SG_H
+# include <scsi/sg.h>
+#endif
+#ifdef HAVE_LINUX_MAJOR_H
+# include <linux/major.h>
+#endif
+#ifdef HAVE_LINUX_HDREG_H
+# include <linux/hdreg.h>
+#endif
 #ifdef HAVE_LINUX_PARAM_H
 # include <linux/param.h>
 #endif
@@ -61,6 +74,187 @@
 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
+ */
+void CDROM_InitRegistry(int dev)
+{
+    int portnum, targetid;
+    int dma;
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING nameW;
+    WCHAR dataW[50];
+    DWORD lenW;
+    char buffer[40];
+    DWORD value;
+    const char *data;
+    HKEY scsiKey;
+    HKEY portKey;
+    HKEY busKey;
+    HKEY targetKey;
+    DWORD disp;
+
+    attr.Length = sizeof(attr);
+    attr.RootDirectory = HKEY_LOCAL_MACHINE;
+    attr.ObjectName = &nameW;
+    attr.Attributes = 0;
+    attr.SecurityDescriptor = NULL;
+    attr.SecurityQualityOfService = NULL;
+
+    if ( ! CDROM_GetIdeInterface(dev, &portnum, &targetid))
+        return;
+
+    /* Ensure there is Scsi key */
+    if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "HARDWARE\\DEVICEMAP\\Scsi" ) ||
+        NtCreateKey( &scsiKey, KEY_ALL_ACCESS, &attr, 0,
+                     NULL, REG_OPTION_VOLATILE, &disp ))
+    {
+        ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
+        return;
+    }
+    RtlFreeUnicodeString( &nameW );
+
+    snprintf(buffer,40,"Scsi Port %d",portnum);
+    attr.RootDirectory = scsiKey;
+    if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
+        NtCreateKey( &portKey, KEY_ALL_ACCESS, &attr, 0,
+                     NULL, REG_OPTION_VOLATILE, &disp ))
+    {
+        ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
+        return;
+    }
+    RtlFreeUnicodeString( &nameW );
+
+    RtlCreateUnicodeStringFromAsciiz( &nameW, "Driver" );
+    data = "atapi";
+    RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
+    NtSetValueKey( portKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
+    RtlFreeUnicodeString( &nameW );
+    value = 10;
+    RtlCreateUnicodeStringFromAsciiz( &nameW, "FirstBusTimeScanInMs" );
+    NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
+    RtlFreeUnicodeString( &nameW );
+    value = 0;
+#ifdef HDIO_GET_DMA
+    if (ioctl(dev,HDIO_GET_DMA, &dma) != -1) {
+        value = dma;
+        TRACE("setting dma to %lx\n", value);
+    }
+#endif
+    RtlCreateUnicodeStringFromAsciiz( &nameW, "DMAEnabled" );
+    NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
+    RtlFreeUnicodeString( &nameW );
+
+    attr.RootDirectory = portKey;
+    if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Scsi Bus 0" ) ||
+        NtCreateKey( &busKey, KEY_ALL_ACCESS, &attr, 0,
+                     NULL, REG_OPTION_VOLATILE, &disp ))
+    {
+        ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
+        return;
+    }
+    RtlFreeUnicodeString( &nameW );
+
+    attr.RootDirectory = busKey;
+    if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Initiator Id 255" ) ||
+        NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
+                     NULL, REG_OPTION_VOLATILE, &disp ))
+    {
+        ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
+        return;
+    }
+    RtlFreeUnicodeString( &nameW );
+    NtClose( targetKey );
+
+    snprintf(buffer,40,"Target Id %d", targetid);
+    attr.RootDirectory = busKey;
+    if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
+        NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
+                     NULL, REG_OPTION_VOLATILE, &disp ))
+    {
+        ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
+        return;
+    }
+    RtlFreeUnicodeString( &nameW );
+
+    RtlCreateUnicodeStringFromAsciiz( &nameW, "Type" );
+    data = "CdRomPeripheral";
+    RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
+    NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
+    RtlFreeUnicodeString( &nameW );
+    /* FIXME - maybe read the real identifier?? */
+    RtlCreateUnicodeStringFromAsciiz( &nameW, "Identifier" );
+    data = "Wine CDROM";
+    RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
+    NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
+    RtlFreeUnicodeString( &nameW );
+    /* FIXME - we always use Cdrom0 - do not know about the nt behaviour */
+    RtlCreateUnicodeStringFromAsciiz( &nameW, "DeviceName" );
+    data = "Cdrom0";
+    RtlMultiByteToUnicodeN( dataW, 50, &lenW, data, strlen(data));
+    NtSetValueKey( targetKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
+    RtlFreeUnicodeString( &nameW );
+
+    NtClose( targetKey );
+    NtClose( busKey );
+    NtClose( portKey );
+    NtClose( scsiKey );
+}
+
+
+/******************************************************************
  *		CDROM_Open
  *
  *
@@ -969,20 +1163,22 @@
 }
 
 /******************************************************************
- *		CDROM_ScsiGetAddress
- *
- *
+ *		CDROM_GetAddress
+ * 
+ * implements IOCTL_SCSI_GET_ADDRESS
  */
-static DWORD CDROM_ScsiGetAddress(int dev, PSCSI_ADDRESS addr)
+static DWORD CDROM_GetAddress(int dev, SCSI_ADDRESS* address)
 {
-    FIXME("IOCTL_SCSI_GET_ADDRESS: stub\n");
+    int portnum, targetid;
 
-    addr->Length = sizeof(SCSI_ADDRESS);
-    addr->PortNumber = 0;
-    addr->PathId = 0;
-    addr->TargetId = 1;
-    addr->Lun = 0;
+    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;
 }
 
@@ -1050,11 +1246,6 @@
         break;
 
     case IOCTL_CDROM_MEDIA_REMOVAL:
-	FIXME("IOCTL_CDROM_MEDIA_REMOVAL: stub\n");
-        sz = 0;
-	error = 0;
-	break;
-
     case IOCTL_DISK_MEDIA_REMOVAL:
     case IOCTL_STORAGE_MEDIA_REMOVAL:
     case IOCTL_STORAGE_EJECTION_CONTROL:
@@ -1172,7 +1363,12 @@
         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 (lpOutBuffer == NULL) error = STATUS_INVALID_PARAMETER;
@@ -1185,12 +1381,6 @@
         else if (nOutBufferSize < sizeof(SCSI_PASS_THROUGH)) error = STATUS_BUFFER_TOO_SMALL;
         else error = CDROM_ScsiPassThrough(dev, (PSCSI_PASS_THROUGH)lpOutBuffer);
         break;
-    case IOCTL_SCSI_GET_ADDRESS:
-        sz = 0;
-        if (lpOutBuffer == NULL) error = STATUS_INVALID_PARAMETER;
-        else if (nOutBufferSize < sizeof(SCSI_ADDRESS)) error = STATUS_BUFFER_TOO_SMALL;
-        else error = CDROM_ScsiGetAddress(dev, (PSCSI_ADDRESS)lpOutBuffer);
-        break;
 
     default:
         FIXME("Unsupported IOCTL %lx\n", dwIoControlCode);
@@ -1208,4 +1398,3 @@
     CDROM_Close(clientID, dev);
     return TRUE;
 }
-                
diff --git a/files/drive.c b/files/drive.c
index 5f9b5e9..1d25e4e 100644
--- a/files/drive.c
+++ b/files/drive.c
@@ -133,6 +133,8 @@
     return p;
 }
 
+extern void CDROM_InitRegistry(int dev);
+
 /***********************************************************************
  *           DRIVE_GetDriveType
  */
@@ -250,9 +252,17 @@
                                       buffer, sizeof(buffer) );
             if (buffer[0])
 	    {
+		int cd_fd;
                 drive->device = heap_strdup( buffer );
 		if (PROFILE_GetWineIniBool( name, "ReadVolInfo", 1))
                     drive->flags |= DRIVE_READ_VOL_INFO;
+                if (drive->type == DRIVE_CDROM)
+                {
+                    if ((cd_fd = open(buffer,O_RDONLY|O_NONBLOCK)) != -1) {
+                        CDROM_InitRegistry(cd_fd);
+                        close(cd_fd);
+                    }
+                }
 	    }
 
             /* Get the FailReadOnly flag */
diff --git a/include/config.h.in b/include/config.h.in
index 4da1baf..4f1b63e 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -242,12 +242,18 @@
 /* Define if Linux-style gethostbyname_r and gethostbyaddr_r are available */
 #undef HAVE_LINUX_GETHOSTBYNAME_R_6
 
+/* Define to 1 if you have the <linux/hdreg.h> header file. */
+#undef HAVE_LINUX_HDREG_H
+
 /* Define to 1 if you have the <linux/input.h> header file. */
 #undef HAVE_LINUX_INPUT_H
 
 /* Define to 1 if you have the <linux/joystick.h> header file. */
 #undef HAVE_LINUX_JOYSTICK_H
 
+/* Define to 1 if you have the <linux/major.h> header file. */
+#undef HAVE_LINUX_MAJOR_H
+
 /* Define to 1 if you have the <linux/param.h> header file. */
 #undef HAVE_LINUX_PARAM_H
 
@@ -350,6 +356,9 @@
 /* Define to 1 if you have the <sched.h> header file. */
 #undef HAVE_SCHED_H
 
+/* Define to 1 if you have the <scsi/sg.h> header file. */
+#undef HAVE_SCSI_SG_H
+
 /* Define to 1 if you have the `select' function. */
 #undef HAVE_SELECT