class2.c

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

C
2,461
字号
	  return(STATUS_BUFFER_TOO_SMALL);
	}
      DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;

      /* Initialize next stack location for call to the port driver */
      NextStack = IoGetNextIrpStackLocation(Irp);

      NextStack->Parameters = Stack->Parameters;
      NextStack->MajorFunction = Stack->MajorFunction;
      NextStack->MinorFunction = Stack->MinorFunction;

      /* Call port driver */
      return(IoCallDriver(DeviceExtension->PortDeviceObject,
			  Irp));
    }
  if (IoControlCode == IOCTL_SCSI_GET_ADDRESS)
    {
      PSCSI_ADDRESS ScsiAddress;

      if (OutputBufferLength < sizeof(SCSI_ADDRESS))
	{
	  Irp->IoStatus.Information = 0;
	  Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
	  IoCompleteRequest(Irp, IO_NO_INCREMENT);

	  return(STATUS_BUFFER_TOO_SMALL);
	}

      ScsiAddress = Irp->AssociatedIrp.SystemBuffer;
      ScsiAddress->Length = sizeof(SCSI_ADDRESS);
      ScsiAddress->PortNumber = DeviceExtension->PortNumber;
      ScsiAddress->PathId = DeviceExtension->PathId;
      ScsiAddress->TargetId = DeviceExtension->TargetId;
      ScsiAddress->Lun = DeviceExtension->Lun;

      Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
      Irp->IoStatus.Status = STATUS_SUCCESS;
      IoCompleteRequest(Irp, IO_NO_INCREMENT);

      return(STATUS_SUCCESS);
    }

  if (IoControlCode == IOCTL_SCSI_PASS_THROUGH ||
      IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)
    {
      PSCSI_PASS_THROUGH ScsiPassThrough;

      DPRINT("IOCTL_SCSI_PASS_THROUGH/IOCTL_SCSI_PASS_THROUGH_DIRECT\n");

      /* Check input size */
      if (InputBufferLength < sizeof(SCSI_PASS_THROUGH))
	{
	  Irp->IoStatus.Information = 0;
	  Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
	  IoCompleteRequest(Irp, IO_NO_INCREMENT);
	  return(STATUS_INVALID_PARAMETER);
	}

      /* Initialize next stack location for call to the port driver */
      NextStack = IoGetNextIrpStackLocation(Irp);

      ScsiPassThrough = Irp->AssociatedIrp.SystemBuffer;
      ScsiPassThrough->PathId = DeviceExtension->PathId;
      ScsiPassThrough->TargetId = DeviceExtension->TargetId;
      ScsiPassThrough->Lun = DeviceExtension->Lun;
      ScsiPassThrough->Cdb[1] |= DeviceExtension->Lun << 5;

      NextStack->Parameters = Stack->Parameters;
      NextStack->MajorFunction = Stack->MajorFunction;
      NextStack->MinorFunction = Stack->MinorFunction;

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

  /* Allocate and initialize an SRB */
  Srb = ExAllocateFromNPagedLookasideList(&DeviceExtension->SrbLookasideListHead);

  if (Srb == NULL)
    {
      Irp->IoStatus.Information = 0;
      Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
      IoCompleteRequest(Irp,
			IO_NO_INCREMENT);
      return(STATUS_INSUFFICIENT_RESOURCES);
    }

  /* Initialize the SRB */
  RtlZeroMemory(Srb,
		sizeof(SCSI_REQUEST_BLOCK));
  Cdb = (PCDB)Srb->Cdb;

  ModifiedControlCode = (IoControlCode & 0x0000FFFF) | (IOCTL_DISK_BASE << 16);
  switch (ModifiedControlCode)
    {
      case IOCTL_DISK_CHECK_VERIFY:
	DPRINT ("ScsiClassDeviceControl: IOCTL_DISK_CHECK_VERIFY\n");

	if (OutputBufferLength != 0)
	  {
	    if (OutputBufferLength < sizeof(ULONG))
	      {
		DPRINT ("ScsiClassDeviceControl: IOCTL_DISK_CHECK_VERIFY SMALL\n");
		Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
		Irp->IoStatus.Information = 0;
                /* Free the SRB */
                ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
			                    Srb);
		IoCompleteRequest (Irp,
				   IO_NO_INCREMENT);
		return STATUS_BUFFER_TOO_SMALL;
	      }

	    /* Allocate new IRP for TEST UNIT READY scsi command */
	    SubIrp = IoAllocateIrp ((CCHAR)DeviceObject->StackSize + 3,
				    FALSE);
	    if (SubIrp == NULL)
	      {
	        DPRINT ("ScsiClassDeviceControl: IOCTL_DISK_CHECK_VERIFY NotEnuf\n");
		Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
		Irp->IoStatus.Information = 0;
                /* Free the SRB */
                ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
			                    Srb);
		IoCompleteRequest (Irp,
				   IO_NO_INCREMENT);
		return STATUS_INSUFFICIENT_RESOURCES;
	      }

	    SubIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
	    IoSetNextIrpStackLocation (SubIrp);

	    NextStack = IoGetCurrentIrpStackLocation (SubIrp);
	    NextStack->Parameters.Others.Argument1 = Irp;
	    NextStack->DeviceObject = DeviceObject;

	    IoSetCompletionRoutine (SubIrp,
				    ScsiClassCheckVerifyCompletion,
				    NULL,
				    TRUE,
				    TRUE,
				    TRUE);

	DPRINT ("ScsiClassDeviceControl: IOCTL_DISK_CHECK_VERIFY IoSet\n");

	    IoSetNextIrpStackLocation (SubIrp);
	    NextStack = IoGetCurrentIrpStackLocation (SubIrp);
	    NextStack->DeviceObject = DeviceObject;

	    IoMarkIrpPending (Irp);

	    Irp = SubIrp;
	  }

	/* Initialize SRB operation */
	Srb->CdbLength = 6;
	Srb->TimeOutValue = DeviceExtension->TimeOutValue;
	Cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;

DPRINT ("ScsiClassDeviceControl: IOCTL_DISK_CHECK_VERIFY SrbAsync\n");

	return(ScsiClassSendSrbAsynchronous(DeviceObject,
					    Srb,
					    Irp,
					    NULL,
					    0,
					    FALSE));

      default:
	DPRINT("Unknown device io control code %lx\n",
		ModifiedControlCode);
        /* Free the SRB */
        ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
			            Srb);
	/* Pass the IOCTL down to the port driver */
	NextStack = IoGetNextIrpStackLocation(Irp);
	NextStack->Parameters = Stack->Parameters;
	NextStack->MajorFunction = Stack->MajorFunction;
	NextStack->MinorFunction = Stack->MinorFunction;

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

  Irp->IoStatus.Information = 0;
  Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  IoCompleteRequest(Irp, IO_NO_INCREMENT);

  return(STATUS_UNSUCCESSFUL);
}


/*
 * @implemented
 */
PVOID STDCALL
ScsiClassFindModePage(IN PCHAR ModeSenseBuffer,
		      IN ULONG Length,
		      IN UCHAR PageMode,
		      IN BOOLEAN Use6Byte)
{
  ULONG DescriptorLength;
  ULONG HeaderLength;
  PCHAR End;
  PCHAR Ptr;

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

  /* Get header length */
  HeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10);

  /* Check header length */
  if (Length < HeaderLength)
    return NULL;

  /* Get descriptor length */
  if (Use6Byte == TRUE)
    {
      DescriptorLength = ((PMODE_PARAMETER_HEADER)ModeSenseBuffer)->BlockDescriptorLength;
    }
  else
    {
      DescriptorLength = ((PMODE_PARAMETER_HEADER10)ModeSenseBuffer)->BlockDescriptorLength[1];
    }

  /* Set page pointers */
  Ptr = ModeSenseBuffer + HeaderLength + DescriptorLength;
  End = ModeSenseBuffer + Length;

  /* Search for page */
  while (Ptr < End)
    {
      /* Check page code */
      if (((PMODE_DISCONNECT_PAGE)Ptr)->PageCode == PageMode)
	return Ptr;

      /* Skip to next page */
      Ptr += ((PMODE_DISCONNECT_PAGE)Ptr)->PageLength;
    }

  return NULL;
}


/*
 * @implemented
 */
ULONG STDCALL
ScsiClassFindUnclaimedDevices(IN PCLASS_INIT_DATA InitializationData,
			      IN PSCSI_ADAPTER_BUS_INFO AdapterInformation)
{
  PSCSI_INQUIRY_DATA UnitInfo;
  PINQUIRYDATA InquiryData;
  PUCHAR Buffer;
  ULONG Bus;
  ULONG UnclaimedDevices = 0;

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

  DPRINT("NumberOfBuses: %lu\n",AdapterInformation->NumberOfBuses);
  Buffer = (PUCHAR)AdapterInformation;
  for (Bus = 0; Bus < (ULONG)AdapterInformation->NumberOfBuses; Bus++)
    {
      DPRINT("Searching bus %lu\n", Bus);

      UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterInformation->BusData[Bus].InquiryDataOffset);

      while (AdapterInformation->BusData[Bus].InquiryDataOffset)
	{
	  InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;

	  DPRINT("Device: '%.8s'\n", InquiryData->VendorId);

	  if ((InitializationData->ClassFindDeviceCallBack(InquiryData) == TRUE) &&
	      (UnitInfo->DeviceClaimed == FALSE))
	    {
	      UnclaimedDevices++;
	    }

	  if (UnitInfo->NextInquiryDataOffset == 0)
	    break;

	  UnitInfo = (PSCSI_INQUIRY_DATA) (Buffer + UnitInfo->NextInquiryDataOffset);
	}
    }

  return(UnclaimedDevices);
}


/*
 * @implemented
 */
NTSTATUS STDCALL
ScsiClassGetCapabilities(IN PDEVICE_OBJECT PortDeviceObject,
			 OUT PIO_SCSI_CAPABILITIES *PortCapabilities)
{
  IO_STATUS_BLOCK IoStatusBlock;
  NTSTATUS Status;
  KEVENT Event;
  PIRP Irp;

  KeInitializeEvent(&Event,
		    NotificationEvent,
		    FALSE);

  Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
				      PortDeviceObject,
				      NULL,
				      0,
				      PortCapabilities,
				      sizeof(PVOID),
				      FALSE,
				      &Event,
				      &IoStatusBlock);
  if (Irp == NULL)
    {
      return(STATUS_INSUFFICIENT_RESOURCES);
    }

  Status = IoCallDriver(PortDeviceObject,
			Irp);
  if (Status == STATUS_PENDING)
    {
      KeWaitForSingleObject(&Event,
			    Suspended,
			    KernelMode,
			    FALSE,
			    NULL);
      Status = IoStatusBlock.Status;
    }

  DPRINT("PortCapabilities at %p\n", *PortCapabilities);

  return(Status);
}


/*
 * @implemented
 */
NTSTATUS STDCALL
ScsiClassGetInquiryData(IN PDEVICE_OBJECT PortDeviceObject,
			IN PSCSI_ADAPTER_BUS_INFO *ConfigInfo)
{
  PSCSI_ADAPTER_BUS_INFO Buffer;
  IO_STATUS_BLOCK IoStatusBlock;
  NTSTATUS Status;
  KEVENT Event;
  PIRP Irp;

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

  *ConfigInfo = NULL;
  Buffer = ExAllocatePool(NonPagedPool,
			  INQUIRY_DATA_SIZE);
  if (Buffer == NULL)
    {
      return(STATUS_INSUFFICIENT_RESOURCES);
    }

  KeInitializeEvent(&Event,
		    NotificationEvent,
		    FALSE);

  Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
				      PortDeviceObject,
				      NULL,
				      0,
				      Buffer,
				      INQUIRY_DATA_SIZE,
				      FALSE,
				      &Event,
				      &IoStatusBlock);
  if (Irp == NULL)
    {
      ExFreePool(Buffer);
      return(STATUS_INSUFFICIENT_RESOURCES);
    }

  Status = IoCallDriver(PortDeviceObject,
			Irp);
  if (Status == STATUS_PENDING)
    {
      KeWaitForSingleObject(&Event,
			    Suspended,
			    KernelMode,
			    FALSE,
			    NULL);
      Status = IoStatusBlock.Status;
    }

  if (!NT_SUCCESS(Status))
    {
      ExFreePool(Buffer);
    }
  else
    {
      *ConfigInfo = Buffer;
    }

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

  return(Status);
}


/*
 * @implemented
 */
ULONG STDCALL
ScsiClassInitialize(IN PVOID Argument1,
		    IN PVOID Argument2,
		    IN PCLASS_INIT_DATA InitializationData)
{
  PCONFIGURATION_INFORMATION ConfigInfo;
  PDRIVER_OBJECT DriverObject = Argument1;
  WCHAR NameBuffer[80];
  UNICODE_STRING PortName;
  ULONG PortNumber;
  PDEVICE_OBJECT PortDeviceObject;
  PFILE_OBJECT FileObject;
  BOOLEAN DiskFound = FALSE;
  NTSTATUS Status;

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

  DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiClassCreateClose;
  DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose;
  DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite;
  DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite;
  DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl;
  DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceDispatch;
  DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
  DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;
  if (InitializationData->ClassStartIo)
    {
      DriverObject->DriverStartIo = InitializationData->ClassStartIo;
    }

  ConfigInfo = IoGetConfigurationInformation();

  DPRINT("ScsiPorts: %lu\n", ConfigInfo->ScsiPortCount);

  /* look for ScsiPortX scsi port devices */
  for (PortNumber = 0; PortNumber < ConfigInfo->ScsiPortCount; PortNumber++)
    {
      swprintf(NameBuffer,
	       L"\\Device\\ScsiPort%lu",
	        PortNumber);
      RtlInitUnicodeString(&PortName,
			   NameBuffer);
      DPRINT("Checking scsi port %ld\n", PortNumber);
      Status = IoGetDeviceObjectPointer(&PortName,
					FILE_READ_ATTRIBUTES,
					&FileObject,
					&PortDeviceObject);
      DPRINT("Status 0x%08lX\n", Status);
      if (NT_SUCCESS(Status))
	{
	  DPRINT("ScsiPort%lu found.\n", PortNumber);

	  /* check scsi port for attached disk drives */
	  if (InitializationData->ClassFindDevices(DriverObject,
						   Argument2,
						   InitializationData,
						   PortDeviceObject,
						   PortNumber))
	    {
	      DiskFound = TRUE;
	    }
	}
      else
	{
	  DbgPrint("Couldn't find ScsiPort%lu (Status %lx)\n", PortNumber, Status);
	}
    }

  DPRINT("ScsiClassInitialize() done!\n");

  return((DiskFound == TRUE) ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE);
}


/**********************************************************************
 * NAME							EXPORTED
 *	ScsiClassInitializeSrbLookasideList
 *
 * DESCRIPTION
 *	Initializes a lookaside list for SRBs.
 *

⌨️ 快捷键说明

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