cdrom.c

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

C
1,704
字号
	    }
	  if (CapabilitiesData->Capabilities[2] & 0x08)
	    {
	      DbgPrint("  Drive can eject a disc or changer cartridge\n");
	    }
	  if (CapabilitiesData->Capabilities[2] & 0x10)
	    {
	      DbgPrint("  Drive supports C2 error pointers\n");
	    }
	  switch (CapabilitiesData->Capabilities[2] >> 5)
	    {
	      case 0:
	        DbgPrint("  Drive use a caddy type loading mechanism\n");
		break;
	      case 1:
	        DbgPrint("  Drive use a tray type loading mechanism\n");
		break;
	      case 2:
	        DbgPrint("  Drive use a pop-up type loading mechanism\n");
		break;
	      case 4:
	        DbgPrint("  Drive is a changer with individually changeable discs\n");
		break;
	      case 5:
	        DbgPrint("  Drive is a changer with cartridge mechanism\n");
		break;
	    }
	  DPRINT("CapabilitiesData.Capabilities[3] %x\n", CapabilitiesData->Capabilities[3]);
	  if (CapabilitiesData->Capabilities[3] & 0x01)
	    {
	      DbgPrint("  Audio level for each channel can be controlled independently\n");
	    }
	  if (CapabilitiesData->Capabilities[3] & 0x02)
	    {
	      DbgPrint("  Audio for each channel can be muted independently\n");
	    }
	  if (CapabilitiesData->Capabilities[3] & 0x04)
	    {
	      DbgPrint("  Changer can report exact contents of slots\n");
	    }
	  if (CapabilitiesData->Capabilities[3] & 0x08)
	    {
	      DbgPrint("  Drive supports software slot selection\n");
	    }
	  DbgPrint("  Maximum speed is %d kB/s\n",
	          (CapabilitiesData->MaximumSpeedSupported[0] << 8)
		  | CapabilitiesData->MaximumSpeedSupported[1]);
	  DbgPrint("  Current speed is %d kB/s\n",
	          (CapabilitiesData->CurrentSpeed[0] << 8)
		  | CapabilitiesData->CurrentSpeed[1]);
	  DbgPrint("  Number of discrete volume levels is %d\n",
	          (CapabilitiesData->Reserved3 << 8)
		  | CapabilitiesData->NumberVolumeLevels);
	  DbgPrint("  Buffer size is %d kB\n",
	          (CapabilitiesData->BufferSize[0] << 8)
		  | CapabilitiesData->BufferSize[1]);
#endif
	}
      else
	{
	  DPRINT("XA not supported\n");
	  CdromData->XaFlags |= XA_NOT_SUPPORTED;
	}

    }


  ExFreePool (Buffer);

  /* Initialize device timer */
  IoInitializeTimer(DiskDeviceObject,
		    CdromTimerRoutine,
		    NULL);
  IoStartTimer(DiskDeviceObject);

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

  return(STATUS_SUCCESS);
}


/**********************************************************************
 * NAME
 *	CdromClassReadTocEntry
 *
 * ARGUMENTS:
 *      DeviceObject
 *      TrackNo
 *      Buffer
 *      Length
 *
 * RETURNS:
 *	Status.
 */
static NTSTATUS
CdromClassReadTocEntry (PDEVICE_OBJECT DeviceObject,
			SIZE_T TrackNo,
			PVOID Buffer,
			SIZE_T Length)
{
  PDEVICE_EXTENSION DeviceExtension;
  SCSI_REQUEST_BLOCK Srb;
  PCDB Cdb;

  DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

  RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
  Srb.CdbLength = 10;
  Srb.TimeOutValue = DeviceExtension->TimeOutValue;

  Cdb = (PCDB)Srb.Cdb;
  Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
  Cdb->READ_TOC.StartingTrack = TrackNo;
  Cdb->READ_TOC.Format = 0;
  Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
  Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
  Cdb->READ_TOC.Msf = 1;

  return(ScsiClassSendSrbSynchronous(DeviceObject,
				     &Srb,
				     Buffer,
				     Length,
				     FALSE));
}


static NTSTATUS
CdromClassReadLastSession (PDEVICE_OBJECT DeviceObject,
			   SIZE_T TrackNo,
			   PVOID Buffer,
			   SIZE_T Length)
{
  PDEVICE_EXTENSION DeviceExtension;
  SCSI_REQUEST_BLOCK Srb;
  PCDB Cdb;

  DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

  RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
  Srb.CdbLength = 10;
  Srb.TimeOutValue = DeviceExtension->TimeOutValue;

  Cdb = (PCDB)Srb.Cdb;
  Cdb->READ_TOC.OperationCode = SCSIOP_READ_TOC;
  Cdb->READ_TOC.StartingTrack = TrackNo;
  Cdb->READ_TOC.Format = 1;
  Cdb->READ_TOC.AllocationLength[0] = Length >> 8;
  Cdb->READ_TOC.AllocationLength[1] = Length & 0xff;
  Cdb->READ_TOC.Msf = 0;

  return(ScsiClassSendSrbSynchronous(DeviceObject,
				     &Srb,
				     Buffer,
				     Length,
				     FALSE));
}


/**********************************************************************
 * NAME							EXPORTED
 *	CdromClassDeviceControl
 *
 * DESCRIPTION:
 *	Answer requests for device control calls
 *
 * RUN LEVEL:
 *	PASSIVE_LEVEL
 *
 * ARGUMENTS:
 *	DeviceObject
 *	Irp
 *		Standard dispatch arguments
 *
 * RETURNS:
 *	Status.
 */

NTSTATUS STDCALL
CdromClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
			IN PIRP Irp)
{
  PDEVICE_EXTENSION DeviceExtension;
  PIO_STACK_LOCATION IrpStack;
  ULONG ControlCode, InputLength, OutputLength;
  PCDROM_DATA CdromData;
  ULONG Information;
  NTSTATUS Status;

  DPRINT("CdromClassDeviceControl() called!\n");

  Status = STATUS_INVALID_DEVICE_REQUEST;
  Information = 0;
  IrpStack = IoGetCurrentIrpStackLocation(Irp);
  ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
  InputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
  OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  CdromData = (PCDROM_DATA)(DeviceExtension + 1);

  switch (ControlCode)
    {
      case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
	DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_GET_DRIVE_GEOMETRY\n");
	if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
	  {
	    Status = STATUS_INFO_LENGTH_MISMATCH;
	    break;
	  }
	IoMarkIrpPending (Irp);
	IoStartPacket (DeviceObject,
		       Irp,
		       NULL,
		       NULL);
	return STATUS_PENDING;

      case IOCTL_CDROM_CHECK_VERIFY:
	DPRINT ("CdromClassDeviceControl: IOCTL_CDROM_CHECK_VERIFY\n");
	if (OutputLength != 0 && OutputLength < sizeof (ULONG))
	  {
	    DPRINT1("Buffer too small\n");
	    Status = STATUS_BUFFER_TOO_SMALL;
	    break;
	  }
	IoMarkIrpPending (Irp);
	IoStartPacket (DeviceObject,
		       Irp,
		       NULL,
		       NULL);
	return STATUS_PENDING;

      case IOCTL_CDROM_READ_TOC:
	DPRINT("IOCTL_CDROM_READ_TOC\n");
	if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(CDROM_TOC))
	  {
	    Status = STATUS_INFO_LENGTH_MISMATCH;
	  }
	else
	  {
	    PCDROM_TOC TocBuffer;
	    USHORT Length;

	    TocBuffer = Irp->AssociatedIrp.SystemBuffer;

	    /* First read the lead out */
	    Length = 4 + sizeof(TRACK_DATA);
	    Status = CdromClassReadTocEntry(DeviceObject,
					    0xAA,
					    TocBuffer,
					    Length);
	    if (NT_SUCCESS(Status))
	      {
		if (TocBuffer->FirstTrack == 0xaa)
		  {
		    /* there is an empty cd */
		    Information = Length;
		  }
		else
		  {
		    /* read the toc */
		    Length = 4 + sizeof(TRACK_DATA) * (TocBuffer->LastTrack - TocBuffer->FirstTrack + 2);
		    Status = CdromClassReadTocEntry(DeviceObject,
						    TocBuffer->FirstTrack,
						    TocBuffer, Length);
		    if (NT_SUCCESS(Status))
		      {
			Information = Length;
		      }
		  }
	      }
	  }
	break;

      case IOCTL_CDROM_GET_LAST_SESSION:
	DPRINT("IOCTL_CDROM_GET_LAST_SESSION\n");
	if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < 4 + sizeof(TRACK_DATA))
	  {
	    Status = STATUS_INFO_LENGTH_MISMATCH;
	  }
	else
	  {
	    PCDROM_TOC TocBuffer;
	    USHORT Length;

	    TocBuffer = Irp->AssociatedIrp.SystemBuffer;
	    Length = 4 + sizeof(TRACK_DATA);
	    Status = CdromClassReadLastSession(DeviceObject,
					       0,
					       TocBuffer,
					       Length);
	    if (NT_SUCCESS(Status))
	      {
		Information = Length;
	      }
	  }
	break;

      default:
	/* Call the common device control function */
	return(ScsiClassDeviceControl(DeviceObject, Irp));
    }

  /* Verify the device if the user caused the error */
  if (!NT_SUCCESS(Status) && IoIsErrorUserInduced(Status))
    {
      IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
    }

  Irp->IoStatus.Status = Status;
  Irp->IoStatus.Information = Information;
  IoCompleteRequest(Irp,
		    IO_DISK_INCREMENT);

  return Status;
}


/**********************************************************************
 * NAME
 *	CdromClassStartIo
 *
 * DESCRIPTION:
 *	Starts IRP processing.
 *
 * RUN LEVEL:
 *	PASSIVE_LEVEL
 *
 * ARGUMENTS:
 *	DeviceObject
 *	Irp
 *		Standard dispatch arguments
 *
 * RETURNS:
 *	None.
 */
VOID STDCALL
CdromClassStartIo (IN PDEVICE_OBJECT DeviceObject,
		   IN PIRP Irp)
{
  PDEVICE_EXTENSION DeviceExtension;
  PIO_STACK_LOCATION IrpStack;
  PIO_STACK_LOCATION SubIrpStack;
  ULONG MaximumTransferLength;
  ULONG TransferPages;
  PSCSI_REQUEST_BLOCK Srb;
  PIRP SubIrp;
  PUCHAR SenseBuffer;
  PVOID DataBuffer;
  PCDB Cdb;

  DPRINT("CdromClassStartIo() called!\n");

  IoMarkIrpPending (Irp);

  DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  IrpStack = IoGetCurrentIrpStackLocation (Irp);

  MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;

  if (DeviceObject->Flags & DO_VERIFY_VOLUME)
    {
      if (!(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
	{
	  DPRINT1 ("Verify required\n");

	  if (Irp->Tail.Overlay.Thread)
	    {
	      IoSetHardErrorOrVerifyDevice (Irp,
					    DeviceObject);
	    }
	  Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;

	  /* FIXME: Update drive capacity */
	  IoCompleteRequest (Irp,
			     IO_DISK_INCREMENT);
	  IoStartNextPacket (DeviceObject,
			     FALSE);
	  return;
	}
    }

  if (IrpStack->MajorFunction == IRP_MJ_READ)
    {
      DPRINT ("CdromClassStartIo: IRP_MJ_READ\n");

      TransferPages =
	ADDRESS_AND_SIZE_TO_SPAN_PAGES (MmGetMdlVirtualAddress(Irp->MdlAddress),
					IrpStack->Parameters.Read.Length);

      /* Check transfer size */
      if ((IrpStack->Parameters.Read.Length > MaximumTransferLength) ||
	  (TransferPages > DeviceExtension->PortCapabilities->MaximumPhysicalPages))
	{
	  /* Transfer size is too large - split it */
	  TransferPages =
	    DeviceExtension->PortCapabilities->MaximumPhysicalPages - 1;

	  /* Adjust transfer size */
	  if (MaximumTransferLength > TransferPages * PAGE_SIZE)
	    MaximumTransferLength = TransferPages * PAGE_SIZE;

	  if (MaximumTransferLength == 0)
	    MaximumTransferLength = PAGE_SIZE;

	  /* Split the transfer */
	  ScsiClassSplitRequest (DeviceObject,
				 Irp,
				 MaximumTransferLength);
	  return;
	}
      else
	{
	  /* Build SRB */
	  ScsiClassBuildRequest (DeviceObject,
				 Irp);
	}
    }
  else if (IrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
    {
      DPRINT ("CdromClassStartIo: IRP_MJ_IRP_MJ_DEVICE_CONTROL\n");

      /* Allocate an IRP for sending requests to the port driver */
      SubIrp = IoAllocateIrp ((CCHAR)(DeviceObject->StackSize + 1),
			      FALSE);
      if (SubIrp == NULL)
	{
	  Irp->IoStatus.Information = 0;

⌨️ 快捷键说明

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