cdrom.c

来自「一个类似windows」· C语言 代码 · 共 1,704 行 · 第 1/4 页

C
1,704
字号
	  Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
	  IoCompleteRequest (Irp,
			     IO_DISK_INCREMENT);
	  IoStartNextPacket (DeviceObject,
			     FALSE);
	  return;
	}

      /* Allocate an SRB */
      Srb = ExAllocatePool (NonPagedPool,
			    sizeof (SCSI_REQUEST_BLOCK));
      if (Srb == NULL)
	{
	  IoFreeIrp (SubIrp);
	  Irp->IoStatus.Information = 0;
	  Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
	  IoCompleteRequest (Irp,
			     IO_DISK_INCREMENT);
	  IoStartNextPacket (DeviceObject,
			     FALSE);
	  return;
	}

      /* Allocte a sense buffer */
      SenseBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
				    SENSE_BUFFER_SIZE);
      if (SenseBuffer == NULL)
	{
	  ExFreePool (Srb);
	  IoFreeIrp (SubIrp);
	  Irp->IoStatus.Information = 0;
	  Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
	  IoCompleteRequest (Irp,
			     IO_DISK_INCREMENT);
	  IoStartNextPacket (DeviceObject,
			     FALSE);
	  return;
	}

      /* Initialize the IRP */
      IoSetNextIrpStackLocation (SubIrp);
      SubIrp->IoStatus.Information = 0;
      SubIrp->IoStatus.Status = STATUS_SUCCESS;
      SubIrp->Flags = 0;
      SubIrp->UserBuffer = NULL;

      SubIrpStack = IoGetCurrentIrpStackLocation (SubIrp);
      SubIrpStack->DeviceObject = DeviceExtension->DeviceObject;
      SubIrpStack->Parameters.Others.Argument2 = (PVOID)Irp;

      /* Initialize next stack location */
      SubIrpStack = IoGetNextIrpStackLocation (SubIrp);
      SubIrpStack->MajorFunction = IRP_MJ_SCSI;
      SubIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
      SubIrpStack->Parameters.Scsi.Srb = Srb;

      /* Initialize the SRB */
      RtlZeroMemory(Srb,
		    sizeof (SCSI_REQUEST_BLOCK));
      Srb->Length = sizeof (SCSI_REQUEST_BLOCK);
      Srb->PathId = DeviceExtension->PathId;
      Srb->TargetId = DeviceExtension->TargetId;
      Srb->Lun = DeviceExtension->Lun;
      Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
      Srb->SrbStatus = SRB_STATUS_SUCCESS;
      Srb->ScsiStatus = 0;
      Srb->NextSrb = 0;
      Srb->OriginalRequest = SubIrp;
      Srb->SenseInfoBuffer = SenseBuffer;
      Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;

      /* Initialize the CDB */
      Cdb = (PCDB)Srb->Cdb;

      /* Set the completion routine */
      IoSetCompletionRoutine (SubIrp,
			      CdromDeviceControlCompletion,
			      Srb,
			      TRUE,
			      TRUE,
			      TRUE);

      switch (IrpStack->Parameters.DeviceIoControl.IoControlCode)
	{
	  case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
	    DPRINT ("CdromClassStartIo: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
	    Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
	    Srb->CdbLength = 10;
	    Srb->TimeOutValue = DeviceExtension->TimeOutValue;
	    Srb->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DATA_IN;
	    Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;

	    /* Allocate data buffer */
	    DataBuffer = ExAllocatePool (NonPagedPoolCacheAligned,
					 sizeof(READ_CAPACITY_DATA));
	    if (DataBuffer == NULL)
	      {
		Irp->IoStatus.Information = 0;
		Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
		IoCompleteRequest (Irp,
				   IO_DISK_INCREMENT);
		ExFreePool (SenseBuffer);
		ExFreePool (Srb);
		IoFreeIrp (SubIrp);
		IoStartNextPacket (DeviceObject,
				   FALSE);
		return;
	      }

	    /* Allocate an MDL for the data buffer */
	    SubIrp->MdlAddress = IoAllocateMdl (DataBuffer,
						sizeof(READ_CAPACITY_DATA),
						FALSE,
						FALSE,
						NULL);
	    if (SubIrp->MdlAddress == NULL)
	      {
		Irp->IoStatus.Information = 0;
		Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
		IoCompleteRequest (Irp,
				   IO_DISK_INCREMENT);
		ExFreePool (DataBuffer);
		ExFreePool (SenseBuffer);
		ExFreePool (Srb);
		IoFreeIrp (SubIrp);
		IoStartNextPacket (DeviceObject,
				   FALSE);
		return;
	      }

	    MmBuildMdlForNonPagedPool (SubIrp->MdlAddress);
	    Srb->DataBuffer = DataBuffer;

	    IoCallDriver (DeviceExtension->PortDeviceObject,
			  SubIrp);
	    return;

	  case IOCTL_CDROM_CHECK_VERIFY:
	    DPRINT ("CdromClassStartIo: IOCTL_CDROM_CHECK_VERIFY\n");
	    Srb->CdbLength = 6;
	    Srb->TimeOutValue = DeviceExtension->TimeOutValue * 2;
	    Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
	    Cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;

	    IoCallDriver (DeviceExtension->PortDeviceObject,
			  SubIrp);
	    return;

	  default:
	    IoCompleteRequest (Irp,
			       IO_NO_INCREMENT);
	    return;
	}
    }

  /* Call the SCSI port driver */
  IoCallDriver (DeviceExtension->PortDeviceObject,
		Irp);
}


NTSTATUS STDCALL
CdromDeviceControlCompletion (IN PDEVICE_OBJECT DeviceObject,
			      IN PIRP Irp,
			      IN PVOID Context)
{
  PDEVICE_EXTENSION DeviceExtension;
  PDEVICE_EXTENSION PhysicalExtension;
  PIO_STACK_LOCATION IrpStack;
  PIO_STACK_LOCATION OrigCurrentIrpStack;
  PIO_STACK_LOCATION OrigNextIrpStack;
  PSCSI_REQUEST_BLOCK Srb;
  PIRP OrigIrp;
  BOOLEAN Retry;
  NTSTATUS Status;

  DPRINT ("CdromDeviceControlCompletion() called\n");

  DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;
  Srb = (PSCSI_REQUEST_BLOCK) Context;

  IrpStack = IoGetCurrentIrpStackLocation (Irp);

  /* Get the original IRP */
  OrigIrp = (PIRP)IrpStack->Parameters.Others.Argument2;
  OrigCurrentIrpStack = IoGetCurrentIrpStackLocation (OrigIrp);
  OrigNextIrpStack = IoGetNextIrpStackLocation (OrigIrp);

  if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
    {
      Status = STATUS_SUCCESS;
    }
  else
    {
      DPRINT ("SrbStatus %lx\n", Srb->SrbStatus);

      /* Interpret sense info */
      Retry = ScsiClassInterpretSenseInfo (DeviceObject,
					   Srb,
					   IrpStack->MajorFunction,
					   IrpStack->Parameters.DeviceIoControl.IoControlCode,
					   MAXIMUM_RETRIES - (ULONG)OrigNextIrpStack->Parameters.Others.Argument1,
					   &Status);
      DPRINT ("Retry %u\n", Retry);

      if (Retry == TRUE &&
	  (ULONG)OrigNextIrpStack->Parameters.Others.Argument1 > 0)
	{
	  DPRINT1 ("Try again (Retry count 0x%p)\n",
		   (ULONG)OrigNextIrpStack->Parameters.Others.Argument1);

	  OrigNextIrpStack->Parameters.Others.Argument1 = (PVOID)((ULONG_PTR)OrigNextIrpStack->Parameters.Others.Argument1 - 1);

	  /* Release 'old' buffers */
	  ExFreePool (Srb->SenseInfoBuffer);
	  if (Srb->DataBuffer)
	    ExFreePool(Srb->DataBuffer);
	  ExFreePool(Srb);

	  if (Irp->MdlAddress != NULL)
	    IoFreeMdl(Irp->MdlAddress);

	  IoFreeIrp(Irp);

	  /* Call the StartIo routine again */
	  CdromClassStartIo (DeviceObject,
			     OrigIrp);

	  return STATUS_MORE_PROCESSING_REQUIRED;
	}

      DPRINT ("Status %lx\n", Status);
    }

  if (NT_SUCCESS (Status))
    {
      switch (OrigCurrentIrpStack->Parameters.DeviceIoControl.IoControlCode)
	{
	  case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
	    {
	      PREAD_CAPACITY_DATA CapacityBuffer;
	      ULONG LastSector;
	      ULONG SectorSize;

	      DPRINT ("CdromClassControlCompletion: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");

	      CapacityBuffer = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
	      SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
			   (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
			   (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
			    ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];

	      LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
			   (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
			   (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
			    ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];

	      if (SectorSize == 0)
		SectorSize = 2048;
	      DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;

	      DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
	      WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
			DeviceExtension->SectorShift);
	      DeviceExtension->PartitionLength.QuadPart =
		(DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);

	      if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
		{
		  DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
		}
	      else
		{
		  DeviceExtension->DiskGeometry->MediaType = FixedMedia;
		}
	      DeviceExtension->DiskGeometry->Cylinders.QuadPart =
		(LONGLONG)((LastSector + 1)/(32 * 64));
	      DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
	      DeviceExtension->DiskGeometry->TracksPerCylinder = 64;

	      RtlCopyMemory (OrigIrp->AssociatedIrp.SystemBuffer,
			     DeviceExtension->DiskGeometry,
			     sizeof(DISK_GEOMETRY));
	      OrigIrp->IoStatus.Information = sizeof(DISK_GEOMETRY);
	    }
	    break;

	  case IOCTL_CDROM_CHECK_VERIFY:
	    DPRINT ("CdromDeviceControlCompletion: IOCTL_CDROM_CHECK_VERIFY\n");
	    if (OrigCurrentIrpStack->Parameters.DeviceIoControl.OutputBufferLength != 0)
	      {
		/* Return the media change counter */
		*((PULONG)(OrigIrp->AssociatedIrp.SystemBuffer)) =
		  PhysicalExtension->MediaChangeCount;
		OrigIrp->IoStatus.Information = sizeof(ULONG);
	      }
	    else
	      {
		OrigIrp->IoStatus.Information = 0;
	      }
	    break;

	  default:
	    OrigIrp->IoStatus.Information = 0;
	    Status = STATUS_INVALID_DEVICE_REQUEST;
	    break;
	}
    }

  /* Release the SRB and associated buffers */
  if (Srb != NULL)
    {
      DPRINT("Srb %p\n", Srb);

      if (Srb->DataBuffer != NULL)
	ExFreePool (Srb->DataBuffer);

      if (Srb->SenseInfoBuffer != NULL)
	ExFreePool (Srb->SenseInfoBuffer);

      ExFreePool (Srb);
    }

  if (OrigIrp->PendingReturned)
    {
      IoMarkIrpPending (OrigIrp);
    }

  /* Release the MDL */
  if (Irp->MdlAddress != NULL)
    {
      IoFreeMdl (Irp->MdlAddress);
    }

  /* Release the sub irp */
  IoFreeIrp (Irp);

  /* Set io status information */
  OrigIrp->IoStatus.Status = Status;
  if (!NT_SUCCESS(Status) && IoIsErrorUserInduced (Status))
    {
      IoSetHardErrorOrVerifyDevice (OrigIrp,
				    DeviceObject);
      OrigIrp->IoStatus.Information = 0;
    }

  /* Complete the original IRP */
  IoCompleteRequest (OrigIrp,
		     IO_DISK_INCREMENT);
  IoStartNextPacket (DeviceObject,
		     FALSE);

  DPRINT ("CdromDeviceControlCompletion() done\n");

  return STATUS_MORE_PROCESSING_REQUIRED;
}


VOID STDCALL
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 STDCALL
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 */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?