floppy.c

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

C
1,185
字号

  DPRINT("floppy: InitController: done initializing; returning STATUS_SUCCESS\n");

  return STATUS_SUCCESS;
}


static BOOLEAN NTAPI AddControllers(PDRIVER_OBJECT DriverObject)
/*
 * FUNCTION: Called on initialization to find our controllers and build device and controller objects for them
 * ARGUMENTS:
 *     DriverObject: Our driver's DriverObject (so we can create devices against it)
 * RETURNS:
 *     FALSE if we can't allocate a device, adapter, or interrupt object, or if we fail to find any controllers
 *     TRUE otherwise (i.e. we have at least one fully-configured controller)
 * NOTES:
 *     - Currently we only support ISA buses.
 *     - BUG: Windows 2000 seems to clobber the response from the IoQueryDeviceDescription callback, so now we
 *       just test a boolean value in the first object to see if it was completely populated.  The same value
 *       is tested for each controller before we build device objects for it.
 * TODO:
 *     - Report resource usage to the HAL
 */
{
  INTERFACE_TYPE InterfaceType = Isa;
  CONFIGURATION_TYPE ControllerType = DiskController;
  CONFIGURATION_TYPE PeripheralType = FloppyDiskPeripheral;
  KAFFINITY Affinity;
  DEVICE_DESCRIPTION DeviceDescription;
  UCHAR i;
  UCHAR j;

  PAGED_CODE();

  /* Find our controllers on all ISA buses */
  IoQueryDeviceDescription(&InterfaceType, 0, &ControllerType, 0, &PeripheralType, 0, ConfigCallback, 0);

  /*
   * w2k breaks the return val from ConfigCallback, so we have to hack around it, rather than just
   * looking for a return value from ConfigCallback.  We expect at least one controller.
   */
  if(!gControllerInfo[0].Populated)
    {
      DPRINT("floppy: AddControllers: failed to get controller info from registry\n");
      return FALSE;
    }

  /* Now that we have a controller, set it up with the system */
  for(i = 0; i < gNumberOfControllers; i++)
    {
      /* 0: Report resource usage to the kernel, to make sure they aren't assigned to anyone else */
      /* FIXME: Implement me. */

      /* 1: Set up interrupt */
      gControllerInfo[i].MappedVector = HalGetInterruptVector(gControllerInfo[i].InterfaceType, gControllerInfo[i].BusNumber,
                                                              gControllerInfo[i].Level, gControllerInfo[i].Vector,
                                                              &gControllerInfo[i].MappedLevel, &Affinity);

      /* Must set up the DPC before we connect the interrupt */
      KeInitializeDpc(&gControllerInfo[i].Dpc, DpcForIsr, &gControllerInfo[i]);

      DPRINT("floppy: Connecting interrupt %d to controller%d (object 0x%x)\n", gControllerInfo[i].MappedVector,
	       i, &gControllerInfo[i]);

      /* NOTE: We cannot share our interrupt, even on level-triggered buses.  See Isr() for details. */
      if(IoConnectInterrupt(&gControllerInfo[i].InterruptObject, Isr, &gControllerInfo[i], 0, gControllerInfo[i].MappedVector,
         gControllerInfo[i].MappedLevel, gControllerInfo[i].MappedLevel, gControllerInfo[i].InterruptMode,
         FALSE, Affinity, 0) != STATUS_SUCCESS)
        {
          DPRINT("floppy: AddControllers: unable to connect interrupt\n");
          continue;
        }

      /* 2: Set up DMA */
      memset(&DeviceDescription, 0, sizeof(DeviceDescription));
      DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
      DeviceDescription.DmaChannel = gControllerInfo[i].Dma;
      DeviceDescription.InterfaceType = gControllerInfo[i].InterfaceType;
      DeviceDescription.BusNumber = gControllerInfo[i].BusNumber;
      DeviceDescription.MaximumLength = 2*18*512; /* based on a 1.44MB floppy */

      /* DMA 0,1,2,3 are 8-bit; 4,5,6,7 are 16-bit (4 is chain i think) */
      DeviceDescription.DmaWidth = gControllerInfo[i].Dma > 3 ? Width16Bits: Width8Bits;

      gControllerInfo[i].AdapterObject = HalGetAdapter(&DeviceDescription, &gControllerInfo[i].MapRegisters);

      if(!gControllerInfo[i].AdapterObject)
        {
          DPRINT("floppy: AddControllers: unable to allocate an adapter object\n");
          IoDisconnectInterrupt(gControllerInfo[i].InterruptObject);
          continue;
        }

      /* 2b: Initialize the new controller */
      if(InitController(&gControllerInfo[i]) != STATUS_SUCCESS)
	{
	  DPRINT("floppy: AddControllers():Unable to set up controller %d - initialization failed\n", i);
          IoDisconnectInterrupt(gControllerInfo[i].InterruptObject);
	  continue;
	}

      /* 2c: Set the controller's initlized flag so we know to release stuff in Unload */
      gControllerInfo[i].Initialized = TRUE;

      /* 3: per-drive setup */
      for(j = 0; j < gControllerInfo[i].NumberOfDrives; j++)
        {
          WCHAR DeviceNameBuf[MAX_DEVICE_NAME];
          UNICODE_STRING DeviceName;
          UNICODE_STRING LinkName;
	  UNICODE_STRING ArcPath;
	  UCHAR DriveNumber;

	  DPRINT("floppy: AddControllers(): Configuring drive %d on controller %d\n", i, j);

	  /*
	   * 3a: create a device object for the drive
	   * Controllers and drives are 0-based, so the combos are:
	   * 0: 0,0
	   * 1: 0,1
	   * 2: 0,2
	   * 3: 0,3
	   * 4: 1,0
	   * 5: 1,1
	   * ...
	   * 14: 3,2
	   * 15: 3,3
	   */
	  DriveNumber = (UCHAR)(i*4 + j); /* loss of precision is OK; there are only 16 of 'em */

          swprintf(DeviceNameBuf, L"\\Device\\Floppy%d", DriveNumber);
          RtlInitUnicodeString(&DeviceName, DeviceNameBuf);

          if(IoCreateDevice(DriverObject, sizeof(PVOID), &DeviceName,
			    FILE_DEVICE_DISK, FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE, FALSE,
                            &gControllerInfo[i].DriveInfo[j].DeviceObject) != STATUS_SUCCESS)
            {
              DPRINT("floppy: AddControllers: unable to register a Device object\n");
              IoDisconnectInterrupt(gControllerInfo[i].InterruptObject);
              continue; /* continue on to next drive */
            }

	  DPRINT("floppy: AddControllers: New device: %S (0x%x)\n", DeviceNameBuf, gControllerInfo[i].DriveInfo[j].DeviceObject);

	  /* 3b.5: Create an ARC path in case we're booting from this drive */
	  swprintf(gControllerInfo[i].DriveInfo[j].ArcPathBuffer,
		   L"\\ArcName\\multi(%d)disk(%d)fdisk(%d)", gControllerInfo[i].BusNumber, i, DriveNumber);

	  RtlInitUnicodeString(&ArcPath, gControllerInfo[i].DriveInfo[j].ArcPathBuffer);
	  IoAssignArcName(&ArcPath, &DeviceName);

	  /* 3c: Set flags up */
	  gControllerInfo[i].DriveInfo[j].DeviceObject->Flags |= DO_DIRECT_IO;

	  /* 3d: Create a symlink */
	  swprintf(gControllerInfo[i].DriveInfo[j].SymLinkBuffer, L"\\DosDevices\\%c:", DriveNumber + 'A');
	  RtlInitUnicodeString(&LinkName, gControllerInfo[i].DriveInfo[j].SymLinkBuffer);
	  if(IoCreateSymbolicLink(&LinkName, &DeviceName) != STATUS_SUCCESS)
	    {
	      DPRINT("floppy: AddControllers: Unable to create a symlink for drive %d\n", DriveNumber);
	      IoDisconnectInterrupt(gControllerInfo[i].InterruptObject);
	      IoDeassignArcName(&ArcPath);
	      continue; /* continue to next drive */
	    }

	  /* 3e: Set up the DPC */
	  IoInitializeDpcRequest(gControllerInfo[i].DriveInfo[j].DeviceObject, DpcForIsr);

	  /* 3f: Point the device extension at our DriveInfo struct */
	  gControllerInfo[i].DriveInfo[j].DeviceObject->DeviceExtension = &gControllerInfo[i].DriveInfo[j];

	  /* 3g: neat comic strip */

	  /* 3h: set the initial media type to unknown */
	  memset(&gControllerInfo[i].DriveInfo[j].DiskGeometry, 0, sizeof(DISK_GEOMETRY));
	  gControllerInfo[i].DriveInfo[j].DiskGeometry.MediaType = Unknown;

	  /* 3i: Now that we're done, set the Initialized flag so we know to free this in Unload */
	  gControllerInfo[i].DriveInfo[j].Initialized = TRUE;
        }
    }

  DPRINT("floppy: AddControllers: --------------------------------------------> finished adding controllers\n");

  return TRUE;
}


VOID NTAPI SignalMediaChanged(PDEVICE_OBJECT DeviceObject,
                              PIRP Irp)
/*
 * FUNCTION: Process an IRP when the media has changed, and possibly notify the user
 * ARGUMENTS:
 *     DeviceObject: DeviceObject associated with the IRP
 *     Irp: IRP that we're failing due to change
 * NOTES:
 *     - This procedure is documented in the DDK by "Notifying the File System of Possible Media Changes",
 *       "IoSetHardErrorOrVerifyDevice", and by "Responding to Check-Verify Requests from the File System".
 *     - Callable at <= DISPATCH_LEVEL
 */
{
  PDRIVE_INFO DriveInfo = DeviceObject->DeviceExtension;

  DPRINT("floppy: SignalMediaChanged called\n");

  DriveInfo->DiskChangeCount++;

  /* If volume is not mounted, do NOT set verify and return STATUS_IO_DEVICE_ERROR */
  if(!(DeviceObject->Vpb->Flags & VPB_MOUNTED))
    {
      Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
      Irp->IoStatus.Information = 0;
      return;
    }

  /* Notify the filesystem that it will need to verify the volume */
  DeviceObject->Flags |= DO_VERIFY_VOLUME;
  Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
  Irp->IoStatus.Information = 0;

  /*
   * If this is a user-based, threaded request, let the IO manager know to pop up a box asking
   * the user to supply the correct media, but only if the error (which we just picked out above)
   * is deemed by the IO manager to be "user induced".  The reason we don't just unconditionally
   * call IoSetHardError... is because MS might change the definition of "user induced" some day,
   * and we don't want to have to remember to re-code this.
   */
  if(Irp->Tail.Overlay.Thread && IoIsErrorUserInduced(Irp->IoStatus.Status))
    IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
}


static VOID NTAPI QueueThread(PVOID Context)
/*
 * FUNCTION: Thread that manages the queue and dispatches any queued requests
 * ARGUMENTS:
 *     Context: unused
 */
{
  PIRP Irp;
  PIO_STACK_LOCATION Stack;
  PDEVICE_OBJECT DeviceObject;
  PVOID Objects[2];

  PAGED_CODE();
  UNREFERENCED_PARAMETER(Context);

  Objects[0] = &QueueSemaphore;
  Objects[1] = &QueueThreadTerminate;

  for(;;)
    {
      KeWaitForMultipleObjects(2, Objects, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);

      if(KeReadStateEvent(&QueueThreadTerminate))
	{
	  DPRINT("floppy: QueueThread terminating\n");
          return;
	}

      DPRINT("floppy: QueueThread: servicing an IRP\n");

      Irp = IoCsqRemoveNextIrp(&Csq, 0);

      /* we won't get an irp if it was canceled */
      if(!Irp)
	{
	  DPRINT("floppy: QueueThread: IRP queue empty\n");
          continue;
	}

      DeviceObject = (PDEVICE_OBJECT)Irp->Tail.Overlay.DriverContext[0];

      ASSERT(DeviceObject);

      Stack = IoGetCurrentIrpStackLocation(Irp);

      /* Decide what to do with the IRP */
      switch(Stack->MajorFunction)
	{
	case IRP_MJ_READ:
	case IRP_MJ_WRITE:
          ReadWritePassive(DeviceObject->DeviceExtension, Irp);
	  break;

	case IRP_MJ_DEVICE_CONTROL:
	  DeviceIoctlPassive(DeviceObject->DeviceExtension, Irp);
	  break;

	default:
	  DPRINT("floppy: QueueThread(): Unrecognized irp: mj: 0x%x\n", Stack->MajorFunction);
	  Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
	  Irp->IoStatus.Information = 0;
	  IoCompleteRequest(Irp, IO_NO_INCREMENT);
	}
    }
}


NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject,
                           PUNICODE_STRING RegistryPath)
/*
 * FUNCTION: Entry-point for the driver
 * ARGUMENTS:
 *     DriverObject: Our driver object
 *     RegistryPath: Unused
 * RETURNS:
 *     STATUS_SUCCESS on successful initialization of at least one drive
 *     STATUS_NO_SUCH_DEVICE if we didn't find even one drive
 *     STATUS_UNSUCCESSFUL otherwise
 */
{
  HANDLE ThreadHandle;

  UNREFERENCED_PARAMETER(RegistryPath);

  /*
   * Set up dispatch routines
   */
  DriverObject->MajorFunction[IRP_MJ_CREATE]         = (PDRIVER_DISPATCH)CreateClose;
  DriverObject->MajorFunction[IRP_MJ_CLOSE]          = (PDRIVER_DISPATCH)CreateClose;
  DriverObject->MajorFunction[IRP_MJ_READ]           = (PDRIVER_DISPATCH)ReadWrite;
  DriverObject->MajorFunction[IRP_MJ_WRITE]          = (PDRIVER_DISPATCH)ReadWrite;
  DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)DeviceIoctl;

  DriverObject->DriverUnload = Unload;

  /*
   * We depend on some zeroes in these structures.  I know this is supposed to be
   * initialized to 0 by the complier but this makes me feel beter.
   */
  memset(&gControllerInfo, 0, sizeof(gControllerInfo));

  /*
   * Set up queue.  This routine cannot fail (trust me, I wrote it).
   */
  IoCsqInitialize(&Csq, CsqInsertIrp, CsqRemoveIrp, CsqPeekNextIrp,
                  CsqAcquireLock, CsqReleaseLock, CsqCompleteCanceledIrp);

  /*
   * ...and its lock
   */
  KeInitializeSpinLock(&IrpQueueLock);

  /*
   * ...and the queue list itself
   */
  InitializeListHead(&IrpQueue);

  /*
   * The queue is counted by a semaphore.  The queue management thread
   * blocks on this semaphore, so if requests come in faster than the queue
   * thread can handle them, the semaphore count goes up.
   */
  KeInitializeSemaphore(&QueueSemaphore, 0, 0x7fffffff);

  /*
   * Event to terminate that thread
   */
  KeInitializeEvent(&QueueThreadTerminate, NotificationEvent, FALSE);

  /*
   * Create the queue processing thread.  Save its handle in the global variable
   * ThreadHandle so we can wait on its termination during Unload.
   */
  if(PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0, QueueThread, 0) != STATUS_SUCCESS)
    {
      DPRINT("floppy: Unable to create system thread; failing init\n");
      return STATUS_INSUFFICIENT_RESOURCES;
    }

  if(ObReferenceObjectByHandle(ThreadHandle, STANDARD_RIGHTS_ALL, NULL, KernelMode, &QueueThreadObject, NULL) != STATUS_SUCCESS)
    {
      DPRINT("floppy: Unable to reference returned thread handle; failing init\n");
      return STATUS_UNSUCCESSFUL;
    }

  /*
   * Close the handle, now that we have the object pointer and a reference of our own.
   * The handle will certainly not be valid in the context of the caller next time we
   * need it, as handles are process-specific.
   */
  ZwClose(ThreadHandle);

  /*
   * Start the device discovery proces.  Returns STATUS_SUCCESS if
   * it finds even one drive attached to one controller.
   */
  if(!AddControllers(DriverObject))
    return STATUS_NO_SUCH_DEVICE;

  return STATUS_SUCCESS;
}

⌨️ 快捷键说明

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