3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS Serial enumerator driver
5 * FILE: drivers/bus/serenum/detect.c
6 * PURPOSE: Detection of serial devices
8 * PROGRAMMERS: Jason Filby (jasonfilby@yahoo.com)
9 * Filip Navara (xnavara@volny.cz)
10 * Hervé Poussineau (hpoussin@reactos.com)
17 SerenumDeviceIoControl(
18 IN PDEVICE_OBJECT DeviceObject
,
20 IN PVOID InputBuffer OPTIONAL
,
21 IN ULONG InputBufferSize
,
22 IN OUT PVOID OutputBuffer OPTIONAL
,
23 IN OUT PULONG OutputBufferSize
)
27 IO_STATUS_BLOCK IoStatus
;
30 KeInitializeEvent (&Event
, NotificationEvent
, FALSE
);
32 Irp
= IoBuildDeviceIoControlRequest(CtlCode
,
37 (OutputBufferSize
) ? *OutputBufferSize
: 0,
43 DPRINT("Serenum: IoBuildDeviceIoControlRequest() failed\n");
44 return STATUS_INSUFFICIENT_RESOURCES
;
47 Status
= IoCallDriver(DeviceObject
, Irp
);
49 if (Status
== STATUS_PENDING
)
51 DPRINT("Serenum: Operation pending\n");
52 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
53 Status
= IoStatus
.Status
;
58 *OutputBufferSize
= IoStatus
.Information
;
66 IN PDEVICE_OBJECT LowerDevice
,
69 OUT PULONG FilledBytes
)
72 IO_STATUS_BLOCK ioStatus
;
77 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
79 Irp
= IoBuildSynchronousFsdRequest(
89 Status
= IoCallDriver(LowerDevice
, Irp
);
90 if (Status
== STATUS_PENDING
)
92 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
93 Status
= ioStatus
.Status
;
95 DPRINT("Serenum: bytes received: %lu/%lu\n",
96 ioStatus
.Information
, BufferSize
);
97 *FilledBytes
= ioStatus
.Information
;
102 ReportDetectedDevice(
103 IN PDEVICE_OBJECT DeviceObject
,
104 IN PUNICODE_STRING DeviceDescription
,
105 IN PUNICODE_STRING DeviceId
,
106 IN PUNICODE_STRING HardwareIds
,
107 IN PUNICODE_STRING CompatibleIds
)
109 PDEVICE_OBJECT Pdo
= NULL
;
110 PPDO_DEVICE_EXTENSION PdoDeviceExtension
= NULL
;
111 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
114 DPRINT("Serenum: SerenumReportDetectedDevice() called with %wZ (%wZ) detected\n", DeviceId
, DeviceDescription
);
116 Status
= IoCreateDevice(
117 DeviceObject
->DriverObject
,
118 sizeof(PDO_DEVICE_EXTENSION
),
120 FILE_DEVICE_CONTROLLER
,
121 FILE_AUTOGENERATED_DEVICE_NAME
,
124 if (!NT_SUCCESS(Status
)) goto ByeBye
;
126 Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
127 Pdo
->Flags
|= DO_POWER_PAGABLE
;
128 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Pdo
->DeviceExtension
;
129 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
130 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
131 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
132 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->DeviceDescription
, DeviceDescription
, PagedPool
);
133 if (!NT_SUCCESS(Status
)) goto ByeBye
;
134 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->DeviceId
, DeviceId
, PagedPool
);
135 if (!NT_SUCCESS(Status
)) goto ByeBye
;
136 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->HardwareIds
, HardwareIds
, PagedPool
);
137 if (!NT_SUCCESS(Status
)) goto ByeBye
;
138 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->CompatibleIds
, CompatibleIds
, PagedPool
);
139 if (!NT_SUCCESS(Status
)) goto ByeBye
;
141 /* Device attached to serial port (Pdo) may delegate work to
142 * serial port stack (Fdo = DeviceObject variable) */
143 Pdo
->StackSize
= DeviceObject
->StackSize
+ 1;
145 FdoDeviceExtension
->AttachedPdo
= Pdo
;
146 PdoDeviceExtension
->AttachedFdo
= DeviceObject
;
148 Pdo
->Flags
|= DO_BUFFERED_IO
;
149 Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
151 return STATUS_SUCCESS
;
156 if (PdoDeviceExtension
->DeviceDescription
.Buffer
)
157 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceDescription
);
158 if (PdoDeviceExtension
->DeviceId
.Buffer
)
159 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceId
);
160 if (PdoDeviceExtension
->HardwareIds
.Buffer
)
161 RtlFreeUnicodeString(&PdoDeviceExtension
->HardwareIds
);
162 if (PdoDeviceExtension
->CompatibleIds
.Buffer
)
163 RtlFreeUnicodeString(&PdoDeviceExtension
->CompatibleIds
);
170 SerenumIsValidPnpIdString(
172 IN ULONG BufferLength
)
174 /* FIXME: SerenumIsValidPnpIdString not implemented */
175 DPRINT1("Serenum: SerenumIsValidPnpIdString() unimplemented\n");
176 return STATUS_SUCCESS
;
180 ReportDetectedPnpDevice(
182 IN ULONG BufferLength
)
185 /* FIXME: ReportDetectedPnpDevice not implemented */
186 DPRINT1("Serenum: ReportDetectedPnpDevice() unimplemented\n");
188 for (i
= 0; i
< BufferLength
; i
++)
189 DbgPrint("%c", Buffer
[i
]);
191 /* Call ReportDetectedDevice */
192 return STATUS_SUCCESS
;
199 SerenumWait(ULONG milliseconds
)
202 LARGE_INTEGER DueTime
;
204 DueTime
.QuadPart
= milliseconds
* -10;
205 KeInitializeTimer(&Timer
);
206 KeSetTimer(&Timer
, DueTime
, NULL
);
207 return KeWaitForSingleObject(&Timer
, Executive
, KernelMode
, FALSE
, NULL
);
211 SerenumDetectPnpDevice(
212 IN PDEVICE_OBJECT DeviceObject
,
213 IN PDEVICE_OBJECT LowerDevice
)
217 ULONG TotalBytesReceived
= 0;
221 BOOLEAN BufferContainsBeginId
= FALSE
;
222 BOOLEAN BufferContainsEndId
= FALSE
;
223 SERIAL_LINE_CONTROL Lcr
;
224 SERIAL_TIMEOUTS Timeouts
;
225 SERIALPERF_STATS PerfStats
;
228 /* 1. COM port initialization, check for device enumerate */
230 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_DTR
,
231 NULL
, 0, NULL
, NULL
);
232 if (!NT_SUCCESS(Status
)) return Status
;
233 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
234 NULL
, 0, NULL
, NULL
);
235 if (!NT_SUCCESS(Status
)) return Status
;
238 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_GET_MODEMSTATUS
,
239 NULL
, 0, &Msr
, &Size
);
240 if (!NT_SUCCESS(Status
)) return Status
;
241 if ((Msr
& SR_MSR_DSR
) == 0) goto SerenumDisconnectIdle
;
243 /* 2. COM port setup, 1st phase */
245 BaudRate
= SERIAL_BAUD_1200
;
246 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
247 &BaudRate
, sizeof(BaudRate
), NULL
, 0);
248 if (!NT_SUCCESS(Status
)) return Status
;
250 Lcr
.Parity
= NO_PARITY
;
251 Lcr
.StopBits
= STOP_BIT_1
;
252 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
253 &Lcr
, sizeof(Lcr
), NULL
, NULL
);
254 if (!NT_SUCCESS(Status
)) return Status
;
255 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_DTR
,
256 NULL
, 0, NULL
, NULL
);
257 if (!NT_SUCCESS(Status
)) return Status
;
258 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
259 NULL
, 0, NULL
, NULL
);
260 if (!NT_SUCCESS(Status
)) return Status
;
262 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
263 NULL
, 0, NULL
, NULL
);
264 if (!NT_SUCCESS(Status
)) return Status
;
267 /* 3. Wait for response, 1st phase */
269 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_RTS
,
270 NULL
, 0, NULL
, NULL
);
271 if (!NT_SUCCESS(Status
)) return Status
;
272 Timeouts
.ReadIntervalTimeout
= 0;
273 Timeouts
.ReadTotalTimeoutMultiplier
= 0;
274 Timeouts
.ReadTotalTimeoutConstant
= 200;
275 Timeouts
.WriteTotalTimeoutMultiplier
= Timeouts
.WriteTotalTimeoutConstant
= 0;
276 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_TIMEOUTS
,
277 &Timeouts
, sizeof(Timeouts
), NULL
, NULL
);
278 if (!NT_SUCCESS(Status
)) return Status
;
279 Status
= ReadBytes(LowerDevice
, Buffer
, sizeof(Buffer
), &Size
);
280 if (!NT_SUCCESS(Status
)) return Status
;
281 if (Size
!= 0) goto SerenumCollectPnpComDeviceId
;
283 /* 4. COM port setup, 2nd phase */
285 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_DTR
,
286 NULL
, 0, NULL
, NULL
);
287 if (!NT_SUCCESS(Status
)) return Status
;
288 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
289 NULL
, 0, NULL
, NULL
);
290 if (!NT_SUCCESS(Status
)) return Status
;
291 Purge
= SERIAL_PURGE_RXABORT
| SERIAL_PURGE_RXCLEAR
;
292 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_PURGE
,
293 &Purge
, 0, NULL
, NULL
);
294 if (!NT_SUCCESS(Status
)) return Status
;
297 /* 5. Wait for response, 2nd phase */
299 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
300 NULL
, 0, NULL
, NULL
);
301 if (!NT_SUCCESS(Status
)) return Status
;
302 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_RTS
,
303 NULL
, 0, NULL
, NULL
);
304 if (!NT_SUCCESS(Status
)) return Status
;
305 Status
= ReadBytes(LowerDevice
, Buffer
, 1, &TotalBytesReceived
);
306 if (!NT_SUCCESS(Status
)) return Status
;
307 if (TotalBytesReceived
!= 0) goto SerenumCollectPnpComDeviceId
;
309 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_GET_MODEMSTATUS
,
310 NULL
, 0, &Msr
, &Size
);
311 if (!NT_SUCCESS(Status
)) return Status
;
312 if ((Msr
& SR_MSR_DSR
) == 0) goto SerenumVerifyDisconnect
; else goto SerenumConnectIdle
;
314 /* 6. Collect PnP COM device ID */
315 SerenumCollectPnpComDeviceId
:
317 Timeouts
.ReadIntervalTimeout
= 200;
318 Timeouts
.ReadTotalTimeoutMultiplier
= 0;
319 Timeouts
.ReadTotalTimeoutConstant
= 2200;
320 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_TIMEOUTS
,
321 &Timeouts
, sizeof(Timeouts
), NULL
, NULL
);
322 if (!NT_SUCCESS(Status
)) return Status
;
323 Status
= ReadBytes(LowerDevice
, &Buffer
[TotalBytesReceived
], sizeof(Buffer
) - TotalBytesReceived
, &Size
);
324 if (!NT_SUCCESS(Status
)) return Status
;
325 TotalBytesReceived
+= Size
;
326 Size
= sizeof(PerfStats
);
327 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_GET_STATS
,
328 NULL
, 0, &PerfStats
, &Size
);
329 if (!NT_SUCCESS(Status
)) return Status
;
330 if (PerfStats
.FrameErrorCount
+ PerfStats
.ParityErrorCount
!= 0) goto SerenumConnectIdle
;
331 for (i
= 0; i
< TotalBytesReceived
; i
++)
333 if (Buffer
[i
] == BEGIN_ID
) BufferContainsBeginId
= TRUE
;
334 if (Buffer
[i
] == END_ID
) BufferContainsEndId
= TRUE
;
336 if (TotalBytesReceived
== 1 || BufferContainsEndId
)
338 if (SerenumIsValidPnpIdString(Buffer
, TotalBytesReceived
))
339 return ReportDetectedPnpDevice(Buffer
, TotalBytesReceived
);
340 goto SerenumConnectIdle
;
342 if (!BufferContainsBeginId
) goto SerenumConnectIdle
;
343 if (!BufferContainsEndId
) goto SerenumConnectIdle
;
345 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_GET_MODEMSTATUS
,
346 NULL
, 0, &Msr
, &Size
);
347 if (!NT_SUCCESS(Status
)) return Status
;
348 if ((Msr
& SR_MSR_DSR
) == 0) goto SerenumVerifyDisconnect
;
350 /* 7. Verify disconnect */
351 SerenumVerifyDisconnect
:
353 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
354 NULL
, 0, NULL
, NULL
);
355 if (!NT_SUCCESS(Status
)) return Status
;
356 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
357 NULL
, 0, NULL
, NULL
);
358 if (!NT_SUCCESS(Status
)) return Status
;
360 goto SerenumDisconnectIdle
;
362 /* 8. Connect idle */
365 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
366 NULL
, 0, NULL
, NULL
);
367 if (!NT_SUCCESS(Status
)) return Status
;
368 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
369 NULL
, 0, NULL
, NULL
);
370 if (!NT_SUCCESS(Status
)) return Status
;
371 BaudRate
= SERIAL_BAUD_300
;
372 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
373 &BaudRate
, sizeof(BaudRate
), NULL
, NULL
);
374 if (!NT_SUCCESS(Status
)) return Status
;
376 Lcr
.Parity
= NO_PARITY
;
377 Lcr
.StopBits
= STOP_BIT_1
;
378 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
379 &Lcr
, sizeof(Lcr
), NULL
, NULL
);
380 if (!NT_SUCCESS(Status
)) return Status
;
381 if (TotalBytesReceived
== 0)
382 return STATUS_DEVICE_NOT_CONNECTED
;
384 return STATUS_SUCCESS
;
386 /* 9. Disconnect idle */
387 SerenumDisconnectIdle
:
389 /* FIXME: report to OS device removal, if it was present */
390 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
391 NULL
, 0, NULL
, NULL
);
392 if (!NT_SUCCESS(Status
)) return Status
;
393 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
394 NULL
, 0, NULL
, NULL
);
395 if (!NT_SUCCESS(Status
)) return Status
;
396 BaudRate
= SERIAL_BAUD_300
;
397 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
398 &BaudRate
, sizeof(BaudRate
), NULL
, NULL
);
399 if (!NT_SUCCESS(Status
)) return Status
;
401 Lcr
.Parity
= NO_PARITY
;
402 Lcr
.StopBits
= STOP_BIT_1
;
403 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
404 &Lcr
, sizeof(Lcr
), NULL
, NULL
);
405 if (!NT_SUCCESS(Status
)) return Status
;
406 return STATUS_DEVICE_NOT_CONNECTED
;
410 SerenumDetectLegacyDevice(
411 IN PDEVICE_OBJECT DeviceObject
,
412 IN PDEVICE_OBJECT LowerDevice
)
417 SERIAL_TIMEOUTS Timeouts
;
418 SERIAL_LINE_CONTROL LCR
;
421 UNICODE_STRING DeviceDescription
;
422 UNICODE_STRING DeviceId
;
423 UNICODE_STRING HardwareIds
;
424 UNICODE_STRING CompatibleIds
;
427 DPRINT("Serenum: SerenumDetectLegacyDevice(DeviceObject %p, LowerDevice %p)\n",
431 RtlZeroMemory(Buffer
, sizeof(Buffer
));
435 Mcr
= 0; /* MCR: DTR/RTS/OUT2 off */
436 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_MODEM_CONTROL
,
437 &Mcr
, sizeof(Mcr
), NULL
, NULL
);
438 if (!NT_SUCCESS(Status
)) return Status
;
440 /* Set communications parameters */
444 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_FIFO_CONTROL
,
445 &Fcr
, sizeof(Fcr
), NULL
, NULL
);
446 if (!NT_SUCCESS(Status
)) return Status
;
447 /* Set serial port speed */
448 BaudRate
= SERIAL_BAUD_1200
;
449 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
450 &BaudRate
, sizeof(BaudRate
), NULL
, NULL
);
451 if (!NT_SUCCESS(Status
)) return Status
;
454 LCR
.Parity
= NO_PARITY
;
455 LCR
.StopBits
= STOP_BITS_2
;
456 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
457 &LCR
, sizeof(LCR
), NULL
, NULL
);
458 if (!NT_SUCCESS(Status
)) return Status
;
460 /* Flush receive buffer */
462 Command
= SERIAL_PURGE_RXCLEAR
;
463 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_MODEM_CONTROL
,
464 &Command
, sizeof(Command
), NULL
, NULL
);
465 if (!NT_SUCCESS(Status
)) return Status
;
471 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
472 NULL
, 0, NULL
, NULL
);
473 if (!NT_SUCCESS(Status
)) return Status
;
474 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_RTS
,
475 NULL
, 0, NULL
, NULL
);
476 if (!NT_SUCCESS(Status
)) return Status
;
478 /* Set timeout to 500 microseconds */
480 Timeouts
.ReadIntervalTimeout
= 100;
481 Timeouts
.ReadTotalTimeoutMultiplier
= 0;
482 Timeouts
.ReadTotalTimeoutConstant
= 500;
483 Timeouts
.WriteTotalTimeoutMultiplier
= Timeouts
.WriteTotalTimeoutConstant
= 0;
484 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_TIMEOUTS
,
485 &Timeouts
, sizeof(Timeouts
), NULL
, NULL
);
486 if (!NT_SUCCESS(Status
)) return Status
;
488 /* Fill the read buffer */
490 Status
= ReadBytes(LowerDevice
, Buffer
, sizeof(Buffer
)/sizeof(Buffer
[0]), &Count
);
491 if (!NT_SUCCESS(Status
)) return Status
;
493 for (i
= 0; i
< Count
; i
++)
495 if (Buffer
[i
] == 'B')
497 /* Sign for Microsoft Ballpoint */
498 /* Hardware id: *PNP0F09
499 * Compatible id: *PNP0F0F, SERIAL_MOUSE
501 RtlInitUnicodeString(&DeviceDescription
, L
"Microsoft Ballpoint device");
502 RtlInitUnicodeString(&DeviceId
, L
"*PNP0F09");
503 SerenumInitMultiSzString(&HardwareIds
, "*PNP0F09", NULL
);
504 SerenumInitMultiSzString(&CompatibleIds
, "*PNP0F0F", "SERIAL_MOUSE", NULL
);
505 Status
= ReportDetectedDevice(DeviceObject
,
506 &DeviceDescription
, &DeviceId
, &HardwareIds
, &CompatibleIds
);
507 RtlFreeUnicodeString(&HardwareIds
);
508 RtlFreeUnicodeString(&CompatibleIds
);
511 else if (Buffer
[i
] == 'M')
513 /* Sign for Microsoft Mouse protocol followed by button specifier */
514 if (i
== sizeof(Buffer
) - 1)
517 return STATUS_DEVICE_NOT_CONNECTED
;
519 switch (Buffer
[i
+ 1])
522 /* Hardware id: *PNP0F08
523 * Compatible id: SERIAL_MOUSE
525 RtlInitUnicodeString(&DeviceDescription
, L
"Microsoft Mouse with 3-buttons");
526 RtlInitUnicodeString(&DeviceId
, L
"*PNP0F08");
527 SerenumInitMultiSzString(&HardwareIds
, "*PNP0F08", NULL
);
528 SerenumInitMultiSzString(&CompatibleIds
, "SERIAL_MOUSE", NULL
);
530 /* Hardware id: *PNP0F01
531 * Compatible id: SERIAL_MOUSE
533 RtlInitUnicodeString(&DeviceDescription
, L
"Microsoft Mouse with 2-buttons or Microsoft Wheel Mouse");
534 RtlInitUnicodeString(&DeviceId
, L
"*PNP0F01");
535 SerenumInitMultiSzString(&HardwareIds
, "*PNP0F01", NULL
);
536 SerenumInitMultiSzString(&CompatibleIds
, "SERIAL_MOUSE", NULL
);
538 Status
= ReportDetectedDevice(DeviceObject
,
539 &DeviceDescription
, &DeviceId
, &HardwareIds
, &CompatibleIds
);
540 RtlFreeUnicodeString(&HardwareIds
);
541 RtlFreeUnicodeString(&CompatibleIds
);
546 return STATUS_DEVICE_NOT_CONNECTED
;