Patch by tinus.Fix media change support for CDROMs. This fixes bug #471. Patch by tinus.
Modified: trunk/reactos/drivers/fs/cdfs/common.c
Modified: trunk/reactos/drivers/fs/cdfs/create.c
Modified: trunk/reactos/drivers/fs/cdfs/fsctl.c
Modified: trunk/reactos/drivers/storage/cdrom/cdrom.c
Modified: trunk/reactos/drivers/storage/class2/class2.c

Modified: trunk/reactos/drivers/fs/cdfs/common.c
--- trunk/reactos/drivers/fs/cdfs/common.c	2005-01-17 10:20:03 UTC (rev 13096)
+++ trunk/reactos/drivers/fs/cdfs/common.c	2005-01-17 14:30:31 UTC (rev 13097)
@@ -191,6 +191,19 @@
      *OutputBufferSize = IoStatus.Information;
     }
 
+  if (Status == STATUS_VERIFY_REQUIRED)
+    {
+      PDEVICE_OBJECT DeviceToVerify;
+      NTSTATUS NewStatus;
+
+      DPRINT1("STATUS_VERIFY_REQUIRED\n");
+      DeviceToVerify = IoGetDeviceToVerify(PsGetCurrentThread());
+      IoSetDeviceToVerify(PsGetCurrentThread(), NULL);
+
+      NewStatus = IoVerifyVolume(DeviceToVerify, FALSE);
+      DPRINT1("IoVerifyVolume() retuned (Status %lx)\n", NewStatus);
+    }
+
   DPRINT("Returning Status %x\n", Status);
 
   return Status;

Modified: trunk/reactos/drivers/fs/cdfs/create.c
--- trunk/reactos/drivers/fs/cdfs/create.c	2005-01-17 10:20:03 UTC (rev 13096)
+++ trunk/reactos/drivers/fs/cdfs/create.c	2005-01-17 14:30:31 UTC (rev 13097)
@@ -140,29 +140,10 @@
 				0,
 				NULL,
 				0,
-				TRUE);
+				FALSE);
   DPRINT ("Status %lx\n", Status);
-  if (Status == STATUS_VERIFY_REQUIRED)
+  if (!NT_SUCCESS(Status))
     {
-      PDEVICE_OBJECT DeviceToVerify;
-
-      DPRINT1 ("Media change detected!\n");
-      DPRINT1 ("Device %p\n", DeviceExt->VolumeDevice);
-
-      DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
-      IoSetDeviceToVerify (PsGetCurrentThread (),
-			   NULL);
-
-      Status = IoVerifyVolume (DeviceToVerify,
-			       FALSE);
-      if (!NT_SUCCESS(Status))
-	{
-	  DPRINT1 ("Status %lx\n", Status);
-	  return Status;
-	}
-    }
-  else if (!NT_SUCCESS(Status))
-    {
       DPRINT1 ("Status %lx\n", Status);
       return Status;
     }

Modified: trunk/reactos/drivers/fs/cdfs/fsctl.c
--- trunk/reactos/drivers/fs/cdfs/fsctl.c	2005-01-17 10:20:03 UTC (rev 13096)
+++ trunk/reactos/drivers/fs/cdfs/fsctl.c	2005-01-17 14:30:31 UTC (rev 13097)
@@ -345,6 +345,7 @@
     goto ByeBye;
 
   NewDeviceObject->Flags = NewDeviceObject->Flags | DO_DIRECT_IO;
+  NewDeviceObject->Flags &= ~DO_VERIFY_VOLUME;
   DeviceExt = (PVOID)NewDeviceObject->DeviceExtension;
   RtlZeroMemory(DeviceExt,
 		sizeof(DEVICE_EXTENSION));

Modified: trunk/reactos/drivers/storage/cdrom/cdrom.c
--- trunk/reactos/drivers/storage/cdrom/cdrom.c	2005-01-17 10:20:03 UTC (rev 13096)
+++ trunk/reactos/drivers/storage/cdrom/cdrom.c	2005-01-17 14:30:31 UTC (rev 13097)
@@ -134,7 +134,11 @@
 CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
 		  IN PVOID Context);
 
+VOID
+CdromWorkItem(IN PDEVICE_OBJECT DeviceObject,
+	      IN PVOID Context);
 
+
 /* FUNCTIONS ****************************************************************/
 
 /**********************************************************************
@@ -1203,7 +1207,10 @@
 	  Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
 
 	  /* FIXME: Update drive capacity */
-
+	  IoCompleteRequest (Irp,
+			     IO_DISK_INCREMENT);
+	  IoStartNextPacket (DeviceObject,
+			     FALSE);
 	  return;
 	}
     }
@@ -1614,11 +1621,68 @@
 
 
 VOID STDCALL
-CdromTimerRoutine(PDEVICE_OBJECT DeviceObject,
-		  PVOID Context)
+CdromTimerRoutine(IN PDEVICE_OBJECT DeviceObject,
+		  IN PVOID Context)
 {
+  PIO_WORKITEM WorkItem;
+
   DPRINT ("CdromTimerRoutine() called\n");
+  WorkItem = IoAllocateWorkItem(DeviceObject);
+  if (!WorkItem)
+    {
+      return;
+    }
 
+  IoQueueWorkItem(WorkItem,
+		  CdromWorkItem,
+		  DelayedWorkQueue,
+		  WorkItem);
 }
 
+
+VOID
+CdromWorkItem(IN PDEVICE_OBJECT DeviceObject,
+	      IN PVOID Context)
+{
+  PIRP Irp;
+  KEVENT Event;
+  IO_STATUS_BLOCK IoStatus;
+  NTSTATUS Status;
+
+  DPRINT("CdromWorkItem() called\n");
+
+  IoFreeWorkItem((PIO_WORKITEM) Context);
+
+  KeInitializeEvent(&Event,
+		    NotificationEvent,
+		    FALSE);
+
+  Irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_CHECK_VERIFY,
+				      DeviceObject,
+				      NULL,
+				      0,
+				      NULL,
+				      0,
+				      FALSE,
+				      &Event,
+				      &IoStatus);
+  if (Irp == NULL)
+    {
+      DPRINT("IoBuildDeviceIoControlRequest failed\n");
+      return;
+    }
+
+  Status = IoCallDriver(DeviceObject, Irp);
+  DPRINT("Status: %x\n", Status);
+
+  if (Status == STATUS_PENDING)
+    {
+      KeWaitForSingleObject(&Event,
+			    Suspended,
+			    KernelMode,
+			    FALSE,
+			    NULL);
+    }
+}
+
 /* EOF */

Modified: trunk/reactos/drivers/storage/class2/class2.c
--- trunk/reactos/drivers/storage/class2/class2.c	2005-01-17 10:20:03 UTC (rev 13096)
+++ trunk/reactos/drivers/storage/class2/class2.c	2005-01-17 14:30:31 UTC (rev 13097)
@@ -1027,6 +1027,46 @@
 
 
 /*
+ * Implements part of the directives on:
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/kmarch/hh/kmarch/other_c694d732-fa95-4841-8d61-2a55ee787905.xml.asp
+ */
+static VOID
+ScsiClassInvalidateMedia(IN PDEVICE_OBJECT DeviceObject,
+			 OUT NTSTATUS *Status)
+{
+  PDEVICE_EXTENSION DeviceExtension;
+  PDEVICE_EXTENSION PhysicalExtension;
+
+  DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
+  PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;
+
+  if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
+    {
+      DPRINT("Invalidate: test char yields TRUE\n");
+    }
+  else
+    {
+      DPRINT("Invalidate: test char yields FALSE\n");
+    }
+
+  if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
+      (DeviceObject->Vpb->Flags & VPB_MOUNTED))
+    {
+      DPRINT("Set DO_VERIFY_VOLUME\n");
+      DeviceObject->Flags |= DO_VERIFY_VOLUME;
+      *Status = STATUS_VERIFY_REQUIRED;
+    }
+  else
+    {
+      *Status = STATUS_IO_DEVICE_ERROR;
+    }
+
+  /* Increment the media change count */
+  PhysicalExtension->MediaChangeCount++;
+}
+
+
+/*
  * @implemented
  */
 BOOLEAN STDCALL
@@ -1106,9 +1146,12 @@
 
 		case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
 		  DPRINT("SCSI_ADSENSE_NO_MEDIA_IN_DEVICE\n");
-	   	  *Status = STATUS_NO_MEDIA_IN_DEVICE;
+		  ScsiClassInvalidateMedia(DeviceObject,
+					   Status);
+
+		  *Status = STATUS_NO_MEDIA_IN_DEVICE;
 		  Retry = FALSE;
-		  
+
 		  if((DeviceExtension->MediaChangeEvent != NULL) &&
 		    (!DeviceExtension->MediaChangeEvent))
 		    {
@@ -1200,22 +1243,9 @@
 		  break;
 	      }
 
-	    if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
-		(DeviceObject->Vpb->Flags & VPB_MOUNTED))
-	      {
-	    DPRINT("SCSI_SENSE_UNIT_ATTENTION set DoVerifyVol\n");
-
-		DeviceObject->Flags |= DO_VERIFY_VOLUME;
-		*Status = STATUS_VERIFY_REQUIRED;
-		Retry = FALSE;
-	      }
-	    else
-	      {
-		*Status = STATUS_IO_DEVICE_ERROR;
-	      }
-
-	    /* Increment the media change count */
-	    PhysicalExtension->MediaChangeCount++;
+	    ScsiClassInvalidateMedia(DeviceObject,
+				     Status);
+	    Retry = FALSE;
 	    break;
 
 	  case SCSI_SENSE_DATA_PROTECT: