2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Serial enumerator driver
4 * FILE: drivers/bus/serenum/detect.c
5 * PURPOSE: Detection of serial devices
7 * PROGRAMMERS: Jason Filby (jasonfilby@yahoo.com)
8 * Filip Navara (xnavara@volny.cz)
9 * Hervé Poussineau (hpoussin@reactos.com)
16 SerenumDeviceIoControl(
17 IN PDEVICE_OBJECT DeviceObject
,
19 IN PVOID InputBuffer OPTIONAL
,
20 IN ULONG InputBufferSize
,
21 IN OUT PVOID OutputBuffer OPTIONAL
,
22 IN OUT PULONG OutputBufferSize
)
26 IO_STATUS_BLOCK IoStatus
;
29 KeInitializeEvent (&Event
, NotificationEvent
, FALSE
);
31 Irp
= IoBuildDeviceIoControlRequest(CtlCode
,
36 (OutputBufferSize
) ? *OutputBufferSize
: 0,
42 DPRINT("Serenum: IoBuildDeviceIoControlRequest() failed\n");
43 return STATUS_INSUFFICIENT_RESOURCES
;
46 Status
= IoCallDriver(DeviceObject
, Irp
);
48 if (Status
== STATUS_PENDING
)
50 DPRINT("Serenum: Operation pending\n");
51 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
52 Status
= IoStatus
.Status
;
57 *OutputBufferSize
= IoStatus
.Information
;
65 IN PDEVICE_OBJECT DeviceObject
,
66 IN ULONG MajorFunction
)
70 IO_STATUS_BLOCK IoStatus
;
73 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
75 Irp
= IoBuildSynchronousFsdRequest(
85 DPRINT("Serenum: IoBuildSynchronousFsdRequest() failed\n");
86 return STATUS_INSUFFICIENT_RESOURCES
;
89 Status
= IoCallDriver(DeviceObject
, Irp
);
91 if (Status
== STATUS_PENDING
)
93 DPRINT("Serenum: Operation pending\n");
94 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
95 Status
= IoStatus
.Status
;
103 IN PDEVICE_OBJECT LowerDevice
,
106 OUT PULONG FilledBytes
)
109 IO_STATUS_BLOCK ioStatus
;
114 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
116 Irp
= IoBuildSynchronousFsdRequest(
126 Status
= IoCallDriver(LowerDevice
, Irp
);
127 if (Status
== STATUS_PENDING
)
129 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
130 Status
= ioStatus
.Status
;
132 DPRINT("Serenum: bytes received: %lu/%lu\n",
133 ioStatus
.Information
, BufferSize
);
134 *FilledBytes
= ioStatus
.Information
;
139 ReportDetectedDevice(
140 IN PDEVICE_OBJECT DeviceObject
,
141 IN PUNICODE_STRING DeviceDescription
,
142 IN PUNICODE_STRING DeviceId
,
143 IN PUNICODE_STRING InstanceId
,
144 IN PUNICODE_STRING HardwareIds
,
145 IN PUNICODE_STRING CompatibleIds
)
147 PDEVICE_OBJECT Pdo
= NULL
;
148 PPDO_DEVICE_EXTENSION PdoDeviceExtension
= NULL
;
149 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
152 DPRINT("Serenum: ReportDetectedDevice() called with %wZ (%wZ) detected\n", DeviceId
, DeviceDescription
);
154 Status
= IoCreateDevice(
155 DeviceObject
->DriverObject
,
156 sizeof(PDO_DEVICE_EXTENSION
),
158 FILE_DEVICE_CONTROLLER
,
159 FILE_AUTOGENERATED_DEVICE_NAME
,
162 if (!NT_SUCCESS(Status
)) goto ByeBye
;
164 Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
165 Pdo
->Flags
|= DO_POWER_PAGABLE
;
166 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Pdo
->DeviceExtension
;
167 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
168 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
169 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
170 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->DeviceDescription
, DeviceDescription
, PagedPool
);
171 if (!NT_SUCCESS(Status
)) goto ByeBye
;
172 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->DeviceId
, DeviceId
, PagedPool
);
173 if (!NT_SUCCESS(Status
)) goto ByeBye
;
174 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->InstanceId
, InstanceId
, PagedPool
);
175 if (!NT_SUCCESS(Status
)) goto ByeBye
;
176 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->HardwareIds
, HardwareIds
, PagedPool
);
177 if (!NT_SUCCESS(Status
)) goto ByeBye
;
178 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->CompatibleIds
, CompatibleIds
, PagedPool
);
179 if (!NT_SUCCESS(Status
)) goto ByeBye
;
181 /* Device attached to serial port (Pdo) may delegate work to
182 * serial port stack (Fdo = DeviceObject variable) */
183 Pdo
->StackSize
= DeviceObject
->StackSize
+ 1;
185 FdoDeviceExtension
->AttachedPdo
= Pdo
;
186 PdoDeviceExtension
->AttachedFdo
= DeviceObject
;
188 Pdo
->Flags
|= DO_BUFFERED_IO
;
189 Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
191 return STATUS_SUCCESS
;
196 ASSERT(PdoDeviceExtension
);
197 if (PdoDeviceExtension
->DeviceDescription
.Buffer
)
198 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceDescription
);
199 if (PdoDeviceExtension
->DeviceId
.Buffer
)
200 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceId
);
201 if (PdoDeviceExtension
->InstanceId
.Buffer
)
202 RtlFreeUnicodeString(&PdoDeviceExtension
->InstanceId
);
203 if (PdoDeviceExtension
->HardwareIds
.Buffer
)
204 RtlFreeUnicodeString(&PdoDeviceExtension
->HardwareIds
);
205 if (PdoDeviceExtension
->CompatibleIds
.Buffer
)
206 RtlFreeUnicodeString(&PdoDeviceExtension
->CompatibleIds
);
213 SerenumIsValidPnpIdString(
215 IN ULONG BufferLength
)
217 /* FIXME: SerenumIsValidPnpIdString not implemented */
218 DPRINT1("Serenum: SerenumIsValidPnpIdString() unimplemented\n");
219 return STATUS_SUCCESS
;
223 ReportDetectedPnpDevice(
225 IN ULONG BufferLength
)
228 /* FIXME: ReportDetectedPnpDevice not implemented */
229 DPRINT1("Serenum: ReportDetectedPnpDevice() unimplemented\n");
231 for (i
= 0; i
< BufferLength
; i
++)
232 DbgPrint("%c", Buffer
[i
]);
234 /* Call ReportDetectedDevice */
235 return STATUS_SUCCESS
;
242 SerenumWait(ULONG milliseconds
)
245 LARGE_INTEGER DueTime
;
247 DueTime
.QuadPart
= milliseconds
* -10;
248 KeInitializeTimer(&Timer
);
249 KeSetTimer(&Timer
, DueTime
, NULL
);
250 return KeWaitForSingleObject(&Timer
, Executive
, KernelMode
, FALSE
, NULL
);
254 SerenumDetectPnpDevice(
255 IN PDEVICE_OBJECT DeviceObject
,
256 IN PDEVICE_OBJECT LowerDevice
)
260 ULONG TotalBytesReceived
= 0;
264 BOOLEAN BufferContainsBeginId
= FALSE
;
265 BOOLEAN BufferContainsEndId
= FALSE
;
266 SERIAL_LINE_CONTROL Lcr
;
267 SERIAL_TIMEOUTS Timeouts
;
268 SERIALPERF_STATS PerfStats
;
272 Status
= SerenumSendIrp(LowerDevice
, IRP_MJ_CREATE
);
273 if (!NT_SUCCESS(Status
)) goto ByeBye
;
275 /* 1. COM port initialization, check for device enumerate */
277 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_DTR
,
278 NULL
, 0, NULL
, NULL
);
279 if (!NT_SUCCESS(Status
)) goto ByeBye
;
280 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
281 NULL
, 0, NULL
, NULL
);
282 if (!NT_SUCCESS(Status
)) goto ByeBye
;
285 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_GET_MODEMSTATUS
,
286 NULL
, 0, &Msr
, &Size
);
287 if (!NT_SUCCESS(Status
)) goto ByeBye
;
288 if ((Msr
& SERIAL_DSR_STATE
) == 0) goto SerenumDisconnectIdle
;
290 /* 2. COM port setup, 1st phase */
293 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
294 &BaudRate
, sizeof(BaudRate
), NULL
, 0);
295 if (!NT_SUCCESS(Status
)) goto ByeBye
;
297 Lcr
.Parity
= NO_PARITY
;
298 Lcr
.StopBits
= STOP_BIT_1
;
299 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
300 &Lcr
, sizeof(Lcr
), NULL
, NULL
);
301 if (!NT_SUCCESS(Status
)) goto ByeBye
;
302 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_DTR
,
303 NULL
, 0, NULL
, NULL
);
304 if (!NT_SUCCESS(Status
)) goto ByeBye
;
305 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
306 NULL
, 0, NULL
, NULL
);
307 if (!NT_SUCCESS(Status
)) goto ByeBye
;
309 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
310 NULL
, 0, NULL
, NULL
);
311 if (!NT_SUCCESS(Status
)) goto ByeBye
;
314 /* 3. Wait for response, 1st phase */
316 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_RTS
,
317 NULL
, 0, NULL
, NULL
);
318 if (!NT_SUCCESS(Status
)) goto ByeBye
;
319 Timeouts
.ReadIntervalTimeout
= 0;
320 Timeouts
.ReadTotalTimeoutMultiplier
= 0;
321 Timeouts
.ReadTotalTimeoutConstant
= 200;
322 Timeouts
.WriteTotalTimeoutMultiplier
= Timeouts
.WriteTotalTimeoutConstant
= 0;
323 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_TIMEOUTS
,
324 &Timeouts
, sizeof(Timeouts
), NULL
, NULL
);
325 if (!NT_SUCCESS(Status
)) goto ByeBye
;
326 Status
= ReadBytes(LowerDevice
, Buffer
, sizeof(Buffer
), &Size
);
327 if (!NT_SUCCESS(Status
)) goto ByeBye
;
328 if (Size
!= 0) goto SerenumCollectPnpComDeviceId
;
330 /* 4. COM port setup, 2nd phase */
332 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_DTR
,
333 NULL
, 0, NULL
, NULL
);
334 if (!NT_SUCCESS(Status
)) goto ByeBye
;
335 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
336 NULL
, 0, NULL
, NULL
);
337 if (!NT_SUCCESS(Status
)) goto ByeBye
;
338 Purge
= SERIAL_PURGE_RXABORT
| SERIAL_PURGE_RXCLEAR
;
339 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_PURGE
,
340 &Purge
, 0, NULL
, NULL
);
341 if (!NT_SUCCESS(Status
)) goto ByeBye
;
344 /* 5. Wait for response, 2nd phase */
346 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
347 NULL
, 0, NULL
, NULL
);
348 if (!NT_SUCCESS(Status
)) goto ByeBye
;
349 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_RTS
,
350 NULL
, 0, NULL
, NULL
);
351 if (!NT_SUCCESS(Status
)) goto ByeBye
;
352 Status
= ReadBytes(LowerDevice
, Buffer
, 1, &TotalBytesReceived
);
353 if (!NT_SUCCESS(Status
)) goto ByeBye
;
354 if (TotalBytesReceived
!= 0) goto SerenumCollectPnpComDeviceId
;
356 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_GET_MODEMSTATUS
,
357 NULL
, 0, &Msr
, &Size
);
358 if (!NT_SUCCESS(Status
)) goto ByeBye
;
359 if ((Msr
& SERIAL_DSR_STATE
) == 0) goto SerenumVerifyDisconnect
; else goto SerenumConnectIdle
;
361 /* 6. Collect PnP COM device ID */
362 SerenumCollectPnpComDeviceId
:
364 Timeouts
.ReadIntervalTimeout
= 200;
365 Timeouts
.ReadTotalTimeoutMultiplier
= 0;
366 Timeouts
.ReadTotalTimeoutConstant
= 2200;
367 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_TIMEOUTS
,
368 &Timeouts
, sizeof(Timeouts
), NULL
, NULL
);
369 if (!NT_SUCCESS(Status
)) goto ByeBye
;
370 Status
= ReadBytes(LowerDevice
, &Buffer
[TotalBytesReceived
], sizeof(Buffer
) - TotalBytesReceived
, &Size
);
371 if (!NT_SUCCESS(Status
)) goto ByeBye
;
372 TotalBytesReceived
+= Size
;
373 Size
= sizeof(PerfStats
);
374 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_GET_STATS
,
375 NULL
, 0, &PerfStats
, &Size
);
376 if (!NT_SUCCESS(Status
)) goto ByeBye
;
377 if (PerfStats
.FrameErrorCount
+ PerfStats
.ParityErrorCount
!= 0) goto SerenumConnectIdle
;
378 for (i
= 0; i
< TotalBytesReceived
; i
++)
380 if (Buffer
[i
] == BEGIN_ID
) BufferContainsBeginId
= TRUE
;
381 if (Buffer
[i
] == END_ID
) BufferContainsEndId
= TRUE
;
383 if (TotalBytesReceived
== 1 || BufferContainsEndId
)
385 if (SerenumIsValidPnpIdString(Buffer
, TotalBytesReceived
))
387 Status
= ReportDetectedPnpDevice(Buffer
, TotalBytesReceived
);
390 goto SerenumConnectIdle
;
392 if (!BufferContainsBeginId
) goto SerenumConnectIdle
;
393 if (!BufferContainsEndId
) goto SerenumConnectIdle
;
395 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_GET_MODEMSTATUS
,
396 NULL
, 0, &Msr
, &Size
);
397 if (!NT_SUCCESS(Status
)) goto ByeBye
;
398 if ((Msr
& SERIAL_DSR_STATE
) == 0) goto SerenumVerifyDisconnect
;
400 /* 7. Verify disconnect */
401 SerenumVerifyDisconnect
:
403 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
404 NULL
, 0, NULL
, NULL
);
405 if (!NT_SUCCESS(Status
)) goto ByeBye
;
406 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
407 NULL
, 0, NULL
, NULL
);
408 if (!NT_SUCCESS(Status
)) goto ByeBye
;
410 goto SerenumDisconnectIdle
;
412 /* 8. Connect idle */
415 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
416 NULL
, 0, NULL
, NULL
);
417 if (!NT_SUCCESS(Status
)) goto ByeBye
;
418 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
419 NULL
, 0, NULL
, NULL
);
420 if (!NT_SUCCESS(Status
)) goto ByeBye
;
422 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
423 &BaudRate
, sizeof(BaudRate
), NULL
, NULL
);
424 if (!NT_SUCCESS(Status
)) goto ByeBye
;
426 Lcr
.Parity
= NO_PARITY
;
427 Lcr
.StopBits
= STOP_BIT_1
;
428 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
429 &Lcr
, sizeof(Lcr
), NULL
, NULL
);
430 if (!NT_SUCCESS(Status
)) goto ByeBye
;
431 if (TotalBytesReceived
== 0)
432 Status
= STATUS_DEVICE_NOT_CONNECTED
;
434 Status
= STATUS_SUCCESS
;
437 /* 9. Disconnect idle */
438 SerenumDisconnectIdle
:
440 /* FIXME: report to OS device removal, if it was present */
441 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
442 NULL
, 0, NULL
, NULL
);
443 if (!NT_SUCCESS(Status
)) goto ByeBye
;
444 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
445 NULL
, 0, NULL
, NULL
);
446 if (!NT_SUCCESS(Status
)) goto ByeBye
;
448 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
449 &BaudRate
, sizeof(BaudRate
), NULL
, NULL
);
450 if (!NT_SUCCESS(Status
)) goto ByeBye
;
452 Lcr
.Parity
= NO_PARITY
;
453 Lcr
.StopBits
= STOP_BIT_1
;
454 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
455 &Lcr
, sizeof(Lcr
), NULL
, NULL
);
456 if (!NT_SUCCESS(Status
)) goto ByeBye
;
457 Status
= STATUS_DEVICE_NOT_CONNECTED
;
461 SerenumSendIrp(LowerDevice
, IRP_MJ_CLOSE
);
462 SerenumSendIrp(LowerDevice
, IRP_MJ_CLEANUP
);
467 SerenumDetectLegacyDevice(
468 IN PDEVICE_OBJECT DeviceObject
,
469 IN PDEVICE_OBJECT LowerDevice
)
474 SERIAL_TIMEOUTS Timeouts
;
475 SERIAL_LINE_CONTROL LCR
;
478 UNICODE_STRING DeviceDescription
;
479 UNICODE_STRING DeviceId
;
480 UNICODE_STRING InstanceId
;
481 UNICODE_STRING HardwareIds
;
482 UNICODE_STRING CompatibleIds
;
485 DPRINT("Serenum: SerenumDetectLegacyDevice(DeviceObject %p, LowerDevice %p)\n",
489 RtlZeroMemory(Buffer
, sizeof(Buffer
));
492 Status
= SerenumSendIrp(LowerDevice
, IRP_MJ_CREATE
);
493 if (!NT_SUCCESS(Status
)) return Status
;
497 Mcr
= 0; /* MCR: DTR/RTS/OUT2 off */
498 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_MODEM_CONTROL
,
499 &Mcr
, sizeof(Mcr
), NULL
, NULL
);
500 if (!NT_SUCCESS(Status
)) goto ByeBye
;
502 /* Set communications parameters */
506 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_FIFO_CONTROL
,
507 &Fcr
, sizeof(Fcr
), NULL
, NULL
);
508 if (!NT_SUCCESS(Status
)) goto ByeBye
;
509 /* Set serial port speed */
511 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
512 &BaudRate
, sizeof(BaudRate
), NULL
, NULL
);
513 if (!NT_SUCCESS(Status
)) goto ByeBye
;
516 LCR
.Parity
= NO_PARITY
;
517 LCR
.StopBits
= STOP_BITS_2
;
518 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
519 &LCR
, sizeof(LCR
), NULL
, NULL
);
520 if (!NT_SUCCESS(Status
)) goto ByeBye
;
522 /* Flush receive buffer */
524 Command
= SERIAL_PURGE_RXCLEAR
;
525 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_MODEM_CONTROL
,
526 &Command
, sizeof(Command
), NULL
, NULL
);
527 if (!NT_SUCCESS(Status
)) goto ByeBye
;
533 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
534 NULL
, 0, NULL
, NULL
);
535 if (!NT_SUCCESS(Status
)) goto ByeBye
;
536 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_RTS
,
537 NULL
, 0, NULL
, NULL
);
538 if (!NT_SUCCESS(Status
)) goto ByeBye
;
540 /* Set timeout to 500 microseconds */
542 Timeouts
.ReadIntervalTimeout
= 100;
543 Timeouts
.ReadTotalTimeoutMultiplier
= 0;
544 Timeouts
.ReadTotalTimeoutConstant
= 500;
545 Timeouts
.WriteTotalTimeoutMultiplier
= Timeouts
.WriteTotalTimeoutConstant
= 0;
546 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_TIMEOUTS
,
547 &Timeouts
, sizeof(Timeouts
), NULL
, NULL
);
548 if (!NT_SUCCESS(Status
)) goto ByeBye
;
550 /* Fill the read buffer */
552 Status
= ReadBytes(LowerDevice
, Buffer
, sizeof(Buffer
)/sizeof(Buffer
[0]), &Count
);
553 if (!NT_SUCCESS(Status
)) goto ByeBye
;
555 RtlInitUnicodeString(&DeviceId
, L
"Serenum\\Mouse");
556 RtlInitUnicodeString(&InstanceId
, L
"0000"); /* FIXME */
557 for (i
= 0; i
< Count
; i
++)
559 if (Buffer
[i
] == 'B')
561 /* Sign for Microsoft Ballpoint */
562 /* Hardware id: *PNP0F09
563 * Compatible id: *PNP0F0F, SERIAL_MOUSE
565 RtlInitUnicodeString(&DeviceDescription
, L
"Microsoft Ballpoint device");
566 SerenumInitMultiSzString(&HardwareIds
, "*PNP0F09", NULL
);
567 SerenumInitMultiSzString(&CompatibleIds
, "*PNP0F0F", "SERIAL_MOUSE", NULL
);
568 Status
= ReportDetectedDevice(DeviceObject
,
569 &DeviceDescription
, &DeviceId
, &InstanceId
, &HardwareIds
, &CompatibleIds
);
570 RtlFreeUnicodeString(&HardwareIds
);
571 RtlFreeUnicodeString(&CompatibleIds
);
574 else if (Buffer
[i
] == 'M')
576 /* Sign for Microsoft Mouse protocol followed by button specifier */
577 if (i
== sizeof(Buffer
) - 1)
580 Status
= STATUS_DEVICE_NOT_CONNECTED
;
583 switch (Buffer
[i
+ 1])
586 /* Hardware id: *PNP0F08
587 * Compatible id: SERIAL_MOUSE
589 RtlInitUnicodeString(&DeviceDescription
, L
"Microsoft Mouse with 3-buttons");
590 SerenumInitMultiSzString(&HardwareIds
, "*PNP0F08", NULL
);
591 SerenumInitMultiSzString(&CompatibleIds
, "SERIAL_MOUSE", NULL
);
593 /* Hardware id: *PNP0F01
594 * Compatible id: SERIAL_MOUSE
596 RtlInitUnicodeString(&DeviceDescription
, L
"Microsoft Mouse with 2-buttons or Microsoft Wheel Mouse");
597 SerenumInitMultiSzString(&HardwareIds
, "*PNP0F01", NULL
);
598 SerenumInitMultiSzString(&CompatibleIds
, "SERIAL_MOUSE", NULL
);
600 Status
= ReportDetectedDevice(DeviceObject
,
601 &DeviceDescription
, &DeviceId
, &InstanceId
, &HardwareIds
, &CompatibleIds
);
602 RtlFreeUnicodeString(&HardwareIds
);
603 RtlFreeUnicodeString(&CompatibleIds
);
608 Status
= STATUS_DEVICE_NOT_CONNECTED
;
612 SerenumSendIrp(LowerDevice
, IRP_MJ_CLOSE
);
613 SerenumSendIrp(LowerDevice
, IRP_MJ_CLEANUP
);