⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 enum.c

📁 enumerates Plug-n-Play RS-232 devices that are compliant with the current revision of Plug and Play
💻 C
📖 第 1 页 / 共 4 页
字号:
/*++
Copyright (c) 1997  Microsoft Corporation

Module Name:

    ENUM.C

Abstract:

    This module contains the enumeration code needed to figure out
    whether or not a device is attached to the serial port.  If there
    is one, it will obtain the PNP COM ID (if the device is PNP) and
    parse out the relevant fields.


Environment:

    kernel mode only

Notes:



--*/

#include "pch.h"

#define MAX_DEVNODE_NAME        256 // Total size of Device ID

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGESENM, Serenum_ReenumerateDevices)
#pragma alloc_text(PAGESENM, SerenumScanOtherIdForMouse)
#pragma alloc_text(PAGESENM, Serenum_IoSyncReq)
#pragma alloc_text(PAGESENM, Serenum_IoSyncReqWithIrp)
#pragma alloc_text(PAGESENM, Serenum_IoSyncIoctlEx)
#pragma alloc_text(PAGESENM, Serenum_ReadSerialPort)
//#pragma alloc_text (PAGE, Serenum_PDO_EnumMarkMissing)
#pragma alloc_text(PAGESENM, Serenum_Wait)

#pragma alloc_text(PAGESENM, Serenum_PollingRoutine)

//#pragma alloc_text (PAGE, Serenum_GetRegistryKeyValue)
#endif

#if !defined(__isascii)
#define __isascii(_c)   ( (unsigned)(_c) < 0x80 )
#endif // !defined(__isascii)

void
SerenumScanOtherIdForMouse(IN PCHAR PBuffer, IN ULONG BufLen,
                           OUT PCHAR *PpMouseId)
/*++

Routine Description:

    This routines a PnP packet for a mouse ID up to the first PnP delimiter
    (i.e, '(').

Arguments:

   PBuffer - Pointer to the buffer to scan

   BufLen - Length of the buffer in bytes

   PpMouseId - Pointer to the pointer to the mouse ID (this will be set
               to point to the location in the buffer where the mouse ID
               was found)

Return value:

    void

--*/
{
   PAGED_CODE();

   *PpMouseId = PBuffer;

   while (BufLen--) {
      if (**PpMouseId == 'M' || **PpMouseId == 'B') {
         return;
      } else if (**PpMouseId == '(' || **PpMouseId == ('(' - 0x20)) {
         *PpMouseId = NULL;
         return;
      }
      (*PpMouseId)++;
   }

   *PpMouseId = NULL;
}

NTSTATUS
Serenum_ReenumerateDevices(IN PIRP Irp, IN PFDO_DEVICE_DATA FdoData)
/*++

Routine Description:

    This enumerates the serenum bus which is represented by Fdo (a pointer
    to the device object representing the serial bus). It creates new PDOs
    for any new devices which have been discovered since the last enumeration

Arguments:

    FdoData - Pointer to the fdo's device extension
                for the serial bus which needs to be enumerated
    Irp - Pointer to the Irp which was sent to reenumerate.

Return value:

    NTSTATUS

--*/
{
   PIRP NewIrp;
   NTSTATUS status;
   KEVENT event;
   KTIMER timer;

   IO_STATUS_BLOCK IoStatusBlock;
   UNICODE_STRING pdoUniName;
   PDEVICE_OBJECT pdo = FdoData->AttachedPDO;
   PPDO_DEVICE_DATA pdoData;
   PIO_STACK_LOCATION stack;

   UNICODE_STRING HardwareIDs;
   UNICODE_STRING CompIDs;
   UNICODE_STRING DeviceIDs;
   UNICODE_STRING DevDesc;

   LARGE_INTEGER defaultTime = RtlConvertLongToLargeInteger (-2000000);
   ULONG defaultSerialTime = 240;
   LARGE_INTEGER startingOffset = RtlConvertLongToLargeInteger (0);

   ULONG bitMask;
   SERIAL_BAUD_RATE baudRate;
   SERIAL_LINE_CONTROL lineControl;
   SERIAL_HANDFLOW handflow;

   BOOLEAN legacyPotential = FALSE;
   BOOLEAN legacyFound = FALSE;

   USHORT nActual = 0;
   ULONG i;

   PCHAR ReadBuffer = NULL;
   WCHAR pdoName[] = SERENUM_PDO_NAME_BASE;

   ULONG FdoFlags = FdoData->Self->Flags;

   SERIAL_BASIC_SETTINGS basicSettings;
   BOOLEAN basicSettingsDone = FALSE;
   SERIAL_TIMEOUTS timeouts, newTimeouts;

   PAGED_CODE();

   //
   // Initialization
   //

   RtlInitUnicodeString(&pdoUniName, pdoName);
   pdoName [((sizeof(pdoName)/sizeof(WCHAR)) - 2)] =
      L'0' + FdoData->PdoIndex++;
   KeInitializeEvent(&event, NotificationEvent, FALSE);
   KeInitializeTimer(&timer);

   RtlInitUnicodeString(&HardwareIDs, NULL);
   RtlInitUnicodeString(&CompIDs, NULL);
   RtlInitUnicodeString(&DeviceIDs, NULL);
   RtlInitUnicodeString(&DevDesc, NULL);

   //
   // If the current PDO should be marked missing, do so.
   //
   if (FdoData->PDOForcedRemove) {

       Serenum_PDO_EnumMarkMissing(FdoData, pdo->DeviceExtension);
       pdo = NULL;
   }

   //
   // Open the Serial port before sending Irps down
   // Use the Irp passed to us, and grab it on the way up.
   // Must save away the system buffer.  Use the stack space.
   //

   stack = IoGetCurrentIrpStackLocation( Irp );
   stack->Parameters.Others.Argument1 = Irp->AssociatedIrp.SystemBuffer;

   Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Opening the serial port...\n"));

   status = Serenum_IoSyncReqWithIrp(Irp, IRP_MJ_CREATE, &event,
                                     FdoData->TopOfStack);

   //
   // If we cannot open the stack, odd's are we have a live and started PDO on
   // it. Since enumeration might interfere with running devices, we do not
   // adjust our list of children if we cannot open the stack.
   //
   if (!NT_SUCCESS(status)) {
      Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE,
                      ("Failed to open the serial port...\n"));
      Irp->AssociatedIrp.SystemBuffer = stack->Parameters.Others.Argument1;
      return status;
   }

   //
   // Set up the COM port
   //

   Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Setting up port\n"));

   status = Serenum_IoSyncIoctlEx(IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS, TRUE,
                                  FdoData->TopOfStack, &event, &IoStatusBlock,
                                  NULL, 0, &basicSettings,
                                  sizeof(basicSettings));

   if (NT_SUCCESS(status)) {
      basicSettingsDone = TRUE;
   } else {
      Serenum_IoSyncIoctlEx(IOCTL_SERIAL_GET_TIMEOUTS, FALSE,
                            FdoData->TopOfStack, &event, &IoStatusBlock,
                            NULL, 0, &timeouts, sizeof(timeouts));

      RtlZeroMemory(&newTimeouts, sizeof(newTimeouts));

      Serenum_IoSyncIoctlEx(IOCTL_SERIAL_SET_TIMEOUTS, FALSE,
                            FdoData->TopOfStack, &event, &IoStatusBlock,
                            &newTimeouts, sizeof(newTimeouts), NULL, 0);
   }

   //
   // Set DTR
   //
   Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Setting DTR...\n"));
   status = Serenum_IoSyncIoctl(IOCTL_SERIAL_SET_DTR, FALSE,
                                FdoData->TopOfStack, &event, &IoStatusBlock);

   if (!NT_SUCCESS(status)) {
      goto EnumerationDone;
   }

   //
   // Clear RTS
   //
   Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Clearing RTS...\n"));
   status = Serenum_IoSyncIoctl(IOCTL_SERIAL_CLR_RTS, FALSE,
                                FdoData->TopOfStack, &event, &IoStatusBlock);

   if (!NT_SUCCESS(status)) {
      goto EnumerationDone;
   }

   //
   // Set a timer for 200 ms
   //

   status = Serenum_Wait(&timer, defaultTime);

   if (!NT_SUCCESS(status)) {
      Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
                      ("Timer failed with status %x\n", status ));

      goto EnumerationDone;
   }

   Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Checking DSR...\n"));

   status = Serenum_IoSyncIoctlEx(IOCTL_SERIAL_GET_MODEMSTATUS, FALSE,
                                  FdoData->TopOfStack, &event, &IoStatusBlock,
                                  NULL, 0, &bitMask, sizeof(ULONG));

   if (!NT_SUCCESS(status)) {
      goto EnumerationDone;
   }

   if ((SERIAL_DSR_STATE & bitMask) == 0) {
      Serenum_KdPrint (FdoData, SER_DBG_SS_TRACE,
                       ("No PNP device available - DSR not set.\n"));
      legacyPotential = TRUE;
   }

   //
   // Setup the serial port for 1200 bits/s, 7 data bits,
   // no parity, one stop bit
   //
   Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Setting baud rate to 1200..."
                                               "\n"));
   baudRate.BaudRate = 1200;
   status = Serenum_IoSyncIoctlEx(IOCTL_SERIAL_SET_BAUD_RATE, FALSE,
                                  FdoData->TopOfStack, &event, &IoStatusBlock,
                                  &baudRate, sizeof(SERIAL_BAUD_RATE), NULL, 0);
   if (!NT_SUCCESS(status)) {
      goto EnumerationDone;
   }

   Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE,
                   ("Setting the line control...\n"));

   lineControl.StopBits = STOP_BIT_1;
   lineControl.Parity = NO_PARITY;
   lineControl.WordLength = 7;

   status = Serenum_IoSyncIoctlEx(IOCTL_SERIAL_SET_LINE_CONTROL, FALSE,
                                  FdoData->TopOfStack, &event, &IoStatusBlock,
                                  &lineControl, sizeof(SERIAL_LINE_CONTROL),
                                  NULL, 0);

   if (!NT_SUCCESS(status)) {
      goto EnumerationDone;
   }



   ReadBuffer = ExAllocatePool(NonPagedPool, MAX_DEVNODE_NAME);

   if (ReadBuffer == NULL) {
      Irp->AssociatedIrp.SystemBuffer = stack->Parameters.Others.Argument1;
      return STATUS_INSUFFICIENT_RESOURCES;
   }

   //
   // loop twice
   // The first iteration is for reading the PNP ID string from modems
   // and mice.
   // The second iteration is for other devices.
   //
   for (i = 0; i < 2; i++) {
      //
      // Purge the buffers before reading
      //

      Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Purging all buffers...\n"));

      bitMask = SERIAL_PURGE_RXCLEAR;

      status = Serenum_IoSyncIoctlEx(IOCTL_SERIAL_PURGE, FALSE,
                                     FdoData->TopOfStack, &event,
                                     &IoStatusBlock, &bitMask, sizeof(ULONG),
                                     NULL, 0);

      if (!NT_SUCCESS(status)) {
         goto EnumerationDone;
      }

      //
      // Clear DTR
      //
      Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Clearing DTR...\n"));

      status = Serenum_IoSyncIoctl(IOCTL_SERIAL_CLR_DTR, FALSE,
                                   FdoData->TopOfStack, &event, &IoStatusBlock);

      if (!NT_SUCCESS(status)) {
         goto EnumerationDone;
      }

      //
      // Clear RTS
      //
      Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Clearing RTS...\n"));
      status = Serenum_IoSyncIoctl(IOCTL_SERIAL_CLR_RTS, FALSE,
                                   FdoData->TopOfStack, &event, &IoStatusBlock);

      if (!NT_SUCCESS(status)) {
         goto EnumerationDone;
      }

      //
      // Set a timer for 200 ms
      //

      Serenum_KdPrint(FdoData, SER_DBG_SS_TRACE, ("Waiting...\n"));

      status = Serenum_Wait(&timer, defaultTime);

      if (!NT_SUCCESS(status)) {
         Serenum_KdPrint(FdoData, SER_DBG_SS_ERROR,
                         ("Timer failed with status %x\n", status ));
         goto EnumerationDone;
      }

      //
      // set DTR
      //

⌨️ 快捷键说明

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