ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

detect.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:       See COPYING in the top level directory
00003  * PROJECT:         ReactOS Serial enumerator driver
00004  * FILE:            drivers/bus/serenum/detect.c
00005  * PURPOSE:         Detection of serial devices
00006  *
00007  * PROGRAMMERS:     Jason Filby (jasonfilby@yahoo.com)
00008  *                  Filip Navara (xnavara@volny.cz)
00009  *                  Hervé Poussineau (hpoussin@reactos.org)
00010  */
00011 
00012 #include "serenum.h"
00013 
00014 static NTSTATUS
00015 DeviceIoControl(
00016     IN PDEVICE_OBJECT DeviceObject,
00017     IN ULONG CtlCode,
00018     IN PVOID InputBuffer OPTIONAL,
00019     IN ULONG_PTR InputBufferSize,
00020     IN OUT PVOID OutputBuffer OPTIONAL,
00021     IN OUT PULONG_PTR OutputBufferSize)
00022 {
00023     KEVENT Event;
00024     PIRP Irp;
00025     IO_STATUS_BLOCK IoStatus;
00026     NTSTATUS Status;
00027 
00028     KeInitializeEvent (&Event, NotificationEvent, FALSE);
00029 
00030     Irp = IoBuildDeviceIoControlRequest(CtlCode,
00031         DeviceObject,
00032         InputBuffer,
00033         InputBufferSize,
00034         OutputBuffer,
00035         (OutputBufferSize) ? *OutputBufferSize : 0,
00036         FALSE,
00037         &Event,
00038         &IoStatus);
00039     if (Irp == NULL)
00040     {
00041         WARN_(SERENUM, "IoBuildDeviceIoControlRequest() failed\n");
00042         return STATUS_INSUFFICIENT_RESOURCES;
00043     }
00044 
00045     Status = IoCallDriver(DeviceObject, Irp);
00046 
00047     if (Status == STATUS_PENDING)
00048     {
00049         INFO_(SERENUM, "Operation pending\n");
00050         KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
00051         Status = IoStatus.Status;
00052     }
00053 
00054     if (OutputBufferSize)
00055     {
00056         *OutputBufferSize = IoStatus.Information;
00057     }
00058 
00059     return Status;
00060 }
00061 
00062 static NTSTATUS
00063 ReadBytes(
00064     IN PDEVICE_OBJECT LowerDevice,
00065     OUT PUCHAR Buffer,
00066     IN ULONG BufferSize,
00067     OUT PULONG_PTR FilledBytes)
00068 {
00069     PIRP Irp;
00070     IO_STATUS_BLOCK ioStatus;
00071     KEVENT event;
00072     LARGE_INTEGER zero;
00073     NTSTATUS Status;
00074 
00075     KeInitializeEvent(&event, NotificationEvent, FALSE);
00076     zero.QuadPart = 0;
00077     Irp = IoBuildSynchronousFsdRequest(
00078         IRP_MJ_READ,
00079         LowerDevice,
00080         Buffer, BufferSize,
00081         &zero,
00082         &event,
00083         &ioStatus);
00084     if (!Irp)
00085         return FALSE;
00086 
00087     Status = IoCallDriver(LowerDevice, Irp);
00088     if (Status == STATUS_PENDING)
00089     {
00090         KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
00091         Status = ioStatus.Status;
00092     }
00093     INFO_(SERENUM, "Bytes received: %lu/%lu\n",
00094         ioStatus.Information, BufferSize);
00095     *FilledBytes = ioStatus.Information;
00096     return Status;
00097 }
00098 
00099 static NTSTATUS
00100 ReportDetectedDevice(
00101     IN PDEVICE_OBJECT DeviceObject,
00102     IN PUNICODE_STRING DeviceDescription,
00103     IN PUNICODE_STRING DeviceId,
00104     IN PUNICODE_STRING InstanceId,
00105     IN PUNICODE_STRING HardwareIds,
00106     IN PUNICODE_STRING CompatibleIds)
00107 {
00108     PDEVICE_OBJECT Pdo = NULL;
00109     PPDO_DEVICE_EXTENSION PdoDeviceExtension = NULL;
00110     PFDO_DEVICE_EXTENSION FdoDeviceExtension;
00111     NTSTATUS Status;
00112 
00113     TRACE_(SERENUM, "ReportDetectedDevice() called with %wZ (%wZ) detected\n", DeviceId, DeviceDescription);
00114 
00115     Status = IoCreateDevice(
00116         DeviceObject->DriverObject,
00117         sizeof(PDO_DEVICE_EXTENSION),
00118         NULL,
00119         FILE_DEVICE_CONTROLLER,
00120         FILE_AUTOGENERATED_DEVICE_NAME,
00121         FALSE,
00122         &Pdo);
00123     if (!NT_SUCCESS(Status)) goto ByeBye;
00124 
00125     Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
00126     Pdo->Flags |= DO_POWER_PAGABLE;
00127     PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
00128     FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
00129     RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
00130     PdoDeviceExtension->Common.IsFDO = FALSE;
00131     Status = DuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, DeviceDescription, &PdoDeviceExtension->DeviceDescription);
00132     if (!NT_SUCCESS(Status)) goto ByeBye;
00133     Status = DuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, DeviceId, &PdoDeviceExtension->DeviceId);
00134     if (!NT_SUCCESS(Status)) goto ByeBye;
00135     Status = DuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, InstanceId, &PdoDeviceExtension->InstanceId);
00136     if (!NT_SUCCESS(Status)) goto ByeBye;
00137     Status = DuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, HardwareIds, &PdoDeviceExtension->HardwareIds);
00138     if (!NT_SUCCESS(Status)) goto ByeBye;
00139     Status = DuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, CompatibleIds, &PdoDeviceExtension->CompatibleIds);
00140     if (!NT_SUCCESS(Status)) goto ByeBye;
00141 
00142     /* Device attached to serial port (Pdo) may delegate work to
00143      * serial port stack (Fdo = DeviceObject variable) */
00144     Pdo->StackSize = DeviceObject->StackSize + 1;
00145 
00146     FdoDeviceExtension->AttachedPdo = Pdo;
00147     PdoDeviceExtension->AttachedFdo = DeviceObject;
00148 
00149     Pdo->Flags |= DO_BUFFERED_IO;
00150     Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
00151 
00152     return STATUS_SUCCESS;
00153 
00154 ByeBye:
00155     if (Pdo)
00156     {
00157         ASSERT(PdoDeviceExtension);
00158         if (PdoDeviceExtension->DeviceDescription.Buffer)
00159             RtlFreeUnicodeString(&PdoDeviceExtension->DeviceDescription);
00160         if (PdoDeviceExtension->DeviceId.Buffer)
00161             RtlFreeUnicodeString(&PdoDeviceExtension->DeviceId);
00162         if (PdoDeviceExtension->InstanceId.Buffer)
00163             RtlFreeUnicodeString(&PdoDeviceExtension->InstanceId);
00164         if (PdoDeviceExtension->HardwareIds.Buffer)
00165             RtlFreeUnicodeString(&PdoDeviceExtension->HardwareIds);
00166         if (PdoDeviceExtension->CompatibleIds.Buffer)
00167             RtlFreeUnicodeString(&PdoDeviceExtension->CompatibleIds);
00168         IoDeleteDevice(Pdo);
00169     }
00170     return Status;
00171 }
00172 
00173 static BOOLEAN
00174 IsValidPnpIdString(
00175     IN PUCHAR Buffer,
00176     IN ULONG BufferLength)
00177 {
00178     ANSI_STRING String;
00179 
00180     /* FIXME: IsValidPnpIdString not implemented */
00181     UNIMPLEMENTED;
00182     String.Length = String.MaximumLength = BufferLength;
00183     String.Buffer = (PCHAR)Buffer;
00184     ERR_(SERENUM, "Buffer %Z\n", &String);
00185     return TRUE;
00186 }
00187 
00188 static NTSTATUS
00189 ReportDetectedPnpDevice(
00190     IN PUCHAR Buffer,
00191     IN ULONG BufferLength)
00192 {
00193     ANSI_STRING String;
00194 
00195     /* FIXME: ReportDetectedPnpDevice not implemented */
00196     UNIMPLEMENTED;
00197     String.Length = String.MaximumLength = BufferLength;
00198     String.Buffer = (PCHAR)Buffer;
00199     ERR_(SERENUM, "Buffer %Z\n", &String);
00200     /* Call ReportDetectedDevice */
00201     return STATUS_SUCCESS;
00202 }
00203 
00204 #define BEGIN_ID '('
00205 #define END_ID ')'
00206 
00207 static NTSTATUS
00208 Wait(
00209     IN ULONG milliseconds)
00210 {
00211     KTIMER Timer;
00212     LARGE_INTEGER DueTime;
00213 
00214     DueTime.QuadPart = milliseconds * -10;
00215     KeInitializeTimer(&Timer);
00216     KeSetTimer(&Timer, DueTime, NULL);
00217     return KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, NULL);
00218 }
00219 
00220 NTSTATUS
00221 SerenumDetectPnpDevice(
00222     IN PDEVICE_OBJECT DeviceObject,
00223     IN PDEVICE_OBJECT LowerDevice)
00224 {
00225     HANDLE Handle = NULL;
00226     UCHAR Buffer[256];
00227     ULONG BaudRate;
00228     ULONG_PTR TotalBytesReceived = 0;
00229     ULONG_PTR Size;
00230     ULONG Msr, Purge;
00231     ULONG i;
00232     BOOLEAN BufferContainsBeginId = FALSE;
00233     BOOLEAN BufferContainsEndId = FALSE;
00234     SERIAL_LINE_CONTROL Lcr;
00235     SERIAL_TIMEOUTS Timeouts;
00236     SERIALPERF_STATS PerfStats;
00237     NTSTATUS Status;
00238 
00239     /* Open port */
00240     Status = ObOpenObjectByPointer(
00241         LowerDevice,
00242         OBJ_KERNEL_HANDLE,
00243         NULL,
00244         0,
00245         NULL,
00246         KernelMode,
00247         &Handle);
00248     if (!NT_SUCCESS(Status)) goto ByeBye;
00249 
00250     /* 1. COM port initialization, check for device enumerate */
00251     TRACE_(SERENUM, "COM port initialization, check for device enumerate\n");
00252     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_DTR,
00253         NULL, 0, NULL, NULL);
00254     if (!NT_SUCCESS(Status)) goto ByeBye;
00255     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
00256         NULL, 0, NULL, NULL);
00257     if (!NT_SUCCESS(Status)) goto ByeBye;
00258     Wait(200);
00259     Size = sizeof(Msr);
00260     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_GET_MODEMSTATUS,
00261         NULL, 0, &Msr, &Size);
00262     if (!NT_SUCCESS(Status)) goto ByeBye;
00263     if ((Msr & SERIAL_DSR_STATE) == 0) goto DisconnectIdle;
00264 
00265     /* 2. COM port setup, 1st phase */
00266     TRACE_(SERENUM, "COM port setup, 1st phase\n");
00267     BaudRate = 1200;
00268     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
00269         &BaudRate, sizeof(BaudRate), NULL, 0);
00270     if (!NT_SUCCESS(Status)) goto ByeBye;
00271     Lcr.WordLength = 7;
00272     Lcr.Parity = NO_PARITY;
00273     Lcr.StopBits = STOP_BIT_1;
00274     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
00275         &Lcr, sizeof(Lcr), NULL, NULL);
00276     if (!NT_SUCCESS(Status)) goto ByeBye;
00277     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_DTR,
00278         NULL, 0, NULL, NULL);
00279     if (!NT_SUCCESS(Status)) goto ByeBye;
00280     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
00281         NULL, 0, NULL, NULL);
00282     if (!NT_SUCCESS(Status)) goto ByeBye;
00283     Wait(200);
00284     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
00285         NULL, 0, NULL, NULL);
00286     if (!NT_SUCCESS(Status)) goto ByeBye;
00287     Wait(200);
00288 
00289     /* 3. Wait for response, 1st phase */
00290     TRACE_(SERENUM, "Wait for response, 1st phase\n");
00291     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_RTS,
00292         NULL, 0, NULL, NULL);
00293     if (!NT_SUCCESS(Status)) goto ByeBye;
00294     Timeouts.ReadIntervalTimeout = 0;
00295     Timeouts.ReadTotalTimeoutMultiplier = 0;
00296     Timeouts.ReadTotalTimeoutConstant = 200;
00297     Timeouts.WriteTotalTimeoutMultiplier = Timeouts.WriteTotalTimeoutConstant = 0;
00298     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
00299         &Timeouts, sizeof(Timeouts), NULL, NULL);
00300     if (!NT_SUCCESS(Status)) goto ByeBye;
00301     Status = ReadBytes(LowerDevice, Buffer, sizeof(Buffer), &Size);
00302     if (!NT_SUCCESS(Status)) goto ByeBye;
00303     if (Size != 0) goto CollectPnpComDeviceId;
00304 
00305     /* 4. COM port setup, 2nd phase */
00306     TRACE_(SERENUM, "COM port setup, 2nd phase\n");
00307     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_DTR,
00308         NULL, 0, NULL, NULL);
00309     if (!NT_SUCCESS(Status)) goto ByeBye;
00310     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
00311         NULL, 0, NULL, NULL);
00312     if (!NT_SUCCESS(Status)) goto ByeBye;
00313     Purge = SERIAL_PURGE_RXABORT | SERIAL_PURGE_RXCLEAR;
00314     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_PURGE,
00315         &Purge, sizeof(ULONG), NULL, NULL);
00316     if (!NT_SUCCESS(Status)) goto ByeBye;
00317     Wait(200);
00318 
00319     /* 5. Wait for response, 2nd phase */
00320     TRACE_(SERENUM, "Wait for response, 2nd phase\n");
00321     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
00322         NULL, 0, NULL, NULL);
00323     if (!NT_SUCCESS(Status)) goto ByeBye;
00324     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_RTS,
00325         NULL, 0, NULL, NULL);
00326     if (!NT_SUCCESS(Status)) goto ByeBye;
00327     Status = ReadBytes(LowerDevice, Buffer, 1, &TotalBytesReceived);
00328     if (!NT_SUCCESS(Status)) goto ByeBye;
00329     if (TotalBytesReceived != 0) goto CollectPnpComDeviceId;
00330     Size = sizeof(Msr);
00331     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_GET_MODEMSTATUS,
00332         NULL, 0, &Msr, &Size);
00333     if (!NT_SUCCESS(Status)) goto ByeBye;
00334     if ((Msr & SERIAL_DSR_STATE) == 0) goto VerifyDisconnect; else goto ConnectIdle;
00335 
00336     /* 6. Collect PnP COM device ID */
00337 CollectPnpComDeviceId:
00338     TRACE_(SERENUM, "Collect PnP COM device ID\n");
00339     Timeouts.ReadIntervalTimeout = 200;
00340     Timeouts.ReadTotalTimeoutMultiplier = 0;
00341     Timeouts.ReadTotalTimeoutConstant = 2200;
00342     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
00343         &Timeouts, sizeof(Timeouts), NULL, NULL);
00344     if (!NT_SUCCESS(Status)) goto ByeBye;
00345     Status = ReadBytes(LowerDevice, &Buffer[TotalBytesReceived], sizeof(Buffer) - TotalBytesReceived, &Size);
00346     if (!NT_SUCCESS(Status)) goto ByeBye;
00347     TotalBytesReceived += Size;
00348     Size = sizeof(PerfStats);
00349     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_GET_STATS,
00350         NULL, 0, &PerfStats, &Size);
00351     if (!NT_SUCCESS(Status)) goto ByeBye;
00352     if (PerfStats.FrameErrorCount + PerfStats.ParityErrorCount != 0) goto ConnectIdle;
00353     for (i = 0; i < TotalBytesReceived; i++)
00354     {
00355         if (Buffer[i] == BEGIN_ID) BufferContainsBeginId = TRUE;
00356         if (Buffer[i] == END_ID) BufferContainsEndId = TRUE;
00357     }
00358     if (TotalBytesReceived == 1 || BufferContainsEndId)
00359     {
00360         if (IsValidPnpIdString(Buffer, TotalBytesReceived))
00361         {
00362             Status = ReportDetectedPnpDevice(Buffer, TotalBytesReceived);
00363             goto ByeBye;
00364         }
00365         goto ConnectIdle;
00366     }
00367     if (!BufferContainsBeginId) goto ConnectIdle;
00368     if (!BufferContainsEndId) goto ConnectIdle;
00369     Size = sizeof(Msr);
00370     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_GET_MODEMSTATUS,
00371         NULL, 0, &Msr, &Size);
00372     if (!NT_SUCCESS(Status)) goto ByeBye;
00373     if ((Msr & SERIAL_DSR_STATE) == 0) goto VerifyDisconnect;
00374 
00375     /* 7. Verify disconnect */
00376 VerifyDisconnect:
00377     TRACE_(SERENUM, "Verify disconnect\n");
00378     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
00379         NULL, 0, NULL, NULL);
00380     if (!NT_SUCCESS(Status)) goto ByeBye;
00381     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
00382         NULL, 0, NULL, NULL);
00383     if (!NT_SUCCESS(Status)) goto ByeBye;
00384     Wait(5000);
00385     goto DisconnectIdle;
00386 
00387     /* 8. Connect idle */
00388 ConnectIdle:
00389     TRACE_(SERENUM, "Connect idle\n");
00390     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
00391         NULL, 0, NULL, NULL);
00392     if (!NT_SUCCESS(Status)) goto ByeBye;
00393     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
00394         NULL, 0, NULL, NULL);
00395     if (!NT_SUCCESS(Status)) goto ByeBye;
00396     BaudRate = 300;
00397     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
00398         &BaudRate, sizeof(BaudRate), NULL, NULL);
00399     if (!NT_SUCCESS(Status)) goto ByeBye;
00400     Lcr.WordLength = 7;
00401     Lcr.Parity = NO_PARITY;
00402     Lcr.StopBits = STOP_BIT_1;
00403     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
00404         &Lcr, sizeof(Lcr), NULL, NULL);
00405     if (!NT_SUCCESS(Status)) goto ByeBye;
00406     if (TotalBytesReceived == 0)
00407         Status = STATUS_DEVICE_NOT_CONNECTED;
00408     else
00409         Status = STATUS_SUCCESS;
00410     goto ByeBye;
00411 
00412     /* 9. Disconnect idle */
00413 DisconnectIdle:
00414     TRACE_(SERENUM, "Disconnect idle\n");
00415     /* FIXME: report to OS device removal, if it was present */
00416     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
00417         NULL, 0, NULL, NULL);
00418     if (!NT_SUCCESS(Status)) goto ByeBye;
00419     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
00420         NULL, 0, NULL, NULL);
00421     if (!NT_SUCCESS(Status)) goto ByeBye;
00422     BaudRate = 300;
00423     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
00424         &BaudRate, sizeof(BaudRate), NULL, NULL);
00425     if (!NT_SUCCESS(Status)) goto ByeBye;
00426     Lcr.WordLength = 7;
00427     Lcr.Parity = NO_PARITY;
00428     Lcr.StopBits = STOP_BIT_1;
00429     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
00430         &Lcr, sizeof(Lcr), NULL, NULL);
00431     if (!NT_SUCCESS(Status)) goto ByeBye;
00432     Status = STATUS_DEVICE_NOT_CONNECTED;
00433 
00434 ByeBye:
00435     /* Close port */
00436     if (Handle)
00437         ZwClose(Handle);
00438     return Status;
00439 }
00440 
00441 NTSTATUS
00442 SerenumDetectLegacyDevice(
00443     IN PDEVICE_OBJECT DeviceObject,
00444     IN PDEVICE_OBJECT LowerDevice)
00445 {
00446     HANDLE Handle = NULL;
00447     ULONG Fcr, Mcr;
00448     ULONG BaudRate;
00449     ULONG Command;
00450     SERIAL_TIMEOUTS Timeouts;
00451     SERIAL_LINE_CONTROL LCR;
00452     ULONG i, Count = 0;
00453     UCHAR Buffer[16];
00454     UNICODE_STRING DeviceDescription;
00455     UNICODE_STRING DeviceId;
00456     UNICODE_STRING InstanceId;
00457     UNICODE_STRING HardwareIds;
00458     UNICODE_STRING CompatibleIds;
00459     NTSTATUS Status;
00460 
00461     TRACE_(SERENUM, "SerenumDetectLegacyDevice(DeviceObject %p, LowerDevice %p)\n",
00462         DeviceObject,
00463         LowerDevice);
00464 
00465     RtlZeroMemory(Buffer, sizeof(Buffer));
00466 
00467     /* Open port */
00468     Status = ObOpenObjectByPointer(
00469         LowerDevice,
00470         OBJ_KERNEL_HANDLE,
00471         NULL,
00472         0,
00473         NULL,
00474         KernelMode,
00475         &Handle);
00476     if (!NT_SUCCESS(Status)) return Status;
00477 
00478     /* Reset UART */
00479     TRACE_(SERENUM, "Reset UART\n");
00480     Mcr = 0; /* MCR: DTR/RTS/OUT2 off */
00481     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_MODEM_CONTROL,
00482         &Mcr, sizeof(Mcr), NULL, NULL);
00483     if (!NT_SUCCESS(Status)) goto ByeBye;
00484 
00485     /* Set communications parameters */
00486     TRACE_(SERENUM, "Set communications parameters\n");
00487     /* DLAB off */
00488     Fcr = 0;
00489     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_FIFO_CONTROL,
00490         &Fcr, sizeof(Fcr), NULL, NULL);
00491     if (!NT_SUCCESS(Status)) goto ByeBye;
00492     /* Set serial port speed */
00493     BaudRate = 1200;
00494     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
00495         &BaudRate, sizeof(BaudRate), NULL, NULL);
00496     if (!NT_SUCCESS(Status)) goto ByeBye;
00497     /* Set LCR */
00498     LCR.WordLength = 7;
00499     LCR.Parity = NO_PARITY;
00500     LCR.StopBits = STOP_BITS_2;
00501     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
00502         &LCR, sizeof(LCR), NULL, NULL);
00503     if (!NT_SUCCESS(Status)) goto ByeBye;
00504 
00505     /* Flush receive buffer */
00506     TRACE_(SERENUM, "Flush receive buffer\n");
00507     Command = SERIAL_PURGE_RXCLEAR;
00508     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_MODEM_CONTROL,
00509         &Command, sizeof(Command), NULL, NULL);
00510     if (!NT_SUCCESS(Status)) goto ByeBye;
00511     /* Wait 100 ms */
00512     Wait(100);
00513 
00514     /* Enable DTR/RTS */
00515     TRACE_(SERENUM, "Enable DTR/RTS\n");
00516     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
00517         NULL, 0, NULL, NULL);
00518     if (!NT_SUCCESS(Status)) goto ByeBye;
00519     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_RTS,
00520         NULL, 0, NULL, NULL);
00521     if (!NT_SUCCESS(Status)) goto ByeBye;
00522 
00523     /* Set timeout to 500 microseconds */
00524     TRACE_(SERENUM, "Set timeout to 500 microseconds\n");
00525     Timeouts.ReadIntervalTimeout = 100;
00526     Timeouts.ReadTotalTimeoutMultiplier = 0;
00527     Timeouts.ReadTotalTimeoutConstant = 500;
00528     Timeouts.WriteTotalTimeoutMultiplier = Timeouts.WriteTotalTimeoutConstant = 0;
00529     Status = DeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
00530         &Timeouts, sizeof(Timeouts), NULL, NULL);
00531     if (!NT_SUCCESS(Status)) goto ByeBye;
00532 
00533     /* Fill the read buffer */
00534     TRACE_(SERENUM, "Fill the read buffer\n");
00535     Status = ReadBytes(LowerDevice, Buffer, sizeof(Buffer)/sizeof(Buffer[0]), (PVOID)&Count);
00536     if (!NT_SUCCESS(Status)) goto ByeBye;
00537 
00538     RtlInitUnicodeString(&DeviceId, L"Serenum\\Mouse");
00539     RtlInitUnicodeString(&InstanceId, L"0000"); /* FIXME */
00540     for (i = 0; i < Count; i++)
00541     {
00542         if (Buffer[i] == 'B')
00543         {
00544             /* Sign for Microsoft Ballpoint */
00545             /* Hardware id: *PNP0F09
00546              * Compatible id: *PNP0F0F, SERIAL_MOUSE
00547              */
00548             RtlInitUnicodeString(&DeviceDescription, L"Microsoft Ballpoint device");
00549             SerenumInitMultiSzString(&HardwareIds, "*PNP0F09", NULL);
00550             SerenumInitMultiSzString(&CompatibleIds, "*PNP0F0F", "SERIAL_MOUSE", NULL);
00551             Status = ReportDetectedDevice(DeviceObject,
00552                 &DeviceDescription, &DeviceId, &InstanceId, &HardwareIds, &CompatibleIds);
00553             RtlFreeUnicodeString(&HardwareIds);
00554             RtlFreeUnicodeString(&CompatibleIds);
00555             goto ByeBye;
00556         }
00557         else if (Buffer[i] == 'M')
00558         {
00559             /* Sign for Microsoft Mouse protocol followed by button specifier */
00560             if (i == sizeof(Buffer) - 1)
00561             {
00562                 /* Overflow Error */
00563                 Status = STATUS_DEVICE_NOT_CONNECTED;
00564                 goto ByeBye;
00565             }
00566             switch (Buffer[i + 1])
00567             {
00568                 case '3':
00569                     /* Hardware id: *PNP0F08
00570                      * Compatible id: SERIAL_MOUSE
00571                      */
00572                     RtlInitUnicodeString(&DeviceDescription, L"Microsoft Mouse with 3-buttons");
00573                     SerenumInitMultiSzString(&HardwareIds, "*PNP0F08", NULL);
00574                     SerenumInitMultiSzString(&CompatibleIds, "SERIAL_MOUSE", NULL);
00575                     break;
00576                 default:
00577                     /* Hardware id: *PNP0F01
00578                      * Compatible id: SERIAL_MOUSE
00579                      */
00580                     RtlInitUnicodeString(&DeviceDescription, L"Microsoft Mouse with 2-buttons or Microsoft Wheel Mouse");
00581                     SerenumInitMultiSzString(&HardwareIds, "*PNP0F01", NULL);
00582                     SerenumInitMultiSzString(&CompatibleIds, "SERIAL_MOUSE", NULL);
00583                     break;
00584             }
00585             Status = ReportDetectedDevice(DeviceObject,
00586                 &DeviceDescription, &DeviceId, &InstanceId, &HardwareIds, &CompatibleIds);
00587             RtlFreeUnicodeString(&HardwareIds);
00588             RtlFreeUnicodeString(&CompatibleIds);
00589             goto ByeBye;
00590         }
00591     }
00592 
00593     Status = STATUS_DEVICE_NOT_CONNECTED;
00594 
00595 ByeBye:
00596     /* Close port */
00597     if (Handle)
00598         ZwClose(Handle);
00599     return Status;
00600 }

Generated on Sun May 27 2012 04:27:50 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.