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
;
76 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
77 Irp
= IoBuildSynchronousFsdRequest(
87 Status
= IoCallDriver(LowerDevice
, Irp
);
88 if (Status
== STATUS_PENDING
)
90 KeWaitForSingleObject(&event
, Suspended
, KernelMode
, FALSE
, NULL
);
91 Status
= ioStatus
.Status
;
93 DPRINT("Serenum: bytes received: %lu/%lu\n",
94 ioStatus
.Information
, BufferSize
);
95 *FilledBytes
= ioStatus
.Information
;
100 ReportDetectedDevice(
101 IN PDEVICE_OBJECT DeviceObject
,
102 IN PUNICODE_STRING DeviceDescription
,
103 IN PUNICODE_STRING DeviceId
,
104 IN PUNICODE_STRING HardwareIds
,
105 IN PUNICODE_STRING CompatibleIds
)
107 PDEVICE_OBJECT Pdo
= NULL
;
108 PPDO_DEVICE_EXTENSION PdoDeviceExtension
;
109 PFDO_DEVICE_EXTENSION FdoDeviceExtension
;
112 DPRINT("Serenum: SerenumReportDetectedDevice() called with %wZ (%wZ) detected\n", DeviceId
, DeviceDescription
);
114 Status
= IoCreateDevice(
115 DeviceObject
->DriverObject
,
116 sizeof(PDO_DEVICE_EXTENSION
),
118 FILE_DEVICE_CONTROLLER
,
119 FILE_AUTOGENERATED_DEVICE_NAME
,
122 if (!NT_SUCCESS(Status
)) goto ByeBye
;
124 Pdo
->Flags
|= DO_BUS_ENUMERATED_DEVICE
;
125 Pdo
->Flags
|= DO_POWER_PAGABLE
;
126 PdoDeviceExtension
= (PPDO_DEVICE_EXTENSION
)Pdo
->DeviceExtension
;
127 FdoDeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
128 RtlZeroMemory(PdoDeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
129 PdoDeviceExtension
->Common
.IsFDO
= FALSE
;
130 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->DeviceDescription
, DeviceDescription
, PagedPool
);
131 if (!NT_SUCCESS(Status
)) goto ByeBye
;
132 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->DeviceId
, DeviceId
, PagedPool
);
133 if (!NT_SUCCESS(Status
)) goto ByeBye
;
134 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->HardwareIds
, HardwareIds
, PagedPool
);
135 if (!NT_SUCCESS(Status
)) goto ByeBye
;
136 Status
= SerenumDuplicateUnicodeString(&PdoDeviceExtension
->CompatibleIds
, CompatibleIds
, PagedPool
);
137 if (!NT_SUCCESS(Status
)) goto ByeBye
;
139 /* Device attached to serial port (Pdo) may delegate work to
140 * serial port stack (Fdo = DeviceObject variable) */
141 Pdo
->StackSize
= DeviceObject
->StackSize
+ 1;
143 FdoDeviceExtension
->AttachedPdo
= Pdo
;
144 PdoDeviceExtension
->AttachedFdo
= DeviceObject
;
146 Pdo
->Flags
|= DO_BUFFERED_IO
;
147 Pdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
149 return STATUS_SUCCESS
;
154 if (PdoDeviceExtension
->DeviceDescription
.Buffer
)
155 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceDescription
);
156 if (PdoDeviceExtension
->DeviceId
.Buffer
)
157 RtlFreeUnicodeString(&PdoDeviceExtension
->DeviceId
);
158 if (PdoDeviceExtension
->HardwareIds
.Buffer
)
159 RtlFreeUnicodeString(&PdoDeviceExtension
->HardwareIds
);
160 if (PdoDeviceExtension
->CompatibleIds
.Buffer
)
161 RtlFreeUnicodeString(&PdoDeviceExtension
->CompatibleIds
);
168 SerenumIsValidPnpIdString(
170 IN ULONG BufferLength
)
172 /* FIXME: SerenumIsValidPnpIdString not implemented */
173 DPRINT1("Serenum: SerenumIsValidPnpIdString() unimplemented\n");
174 return STATUS_SUCCESS
;
178 ReportDetectedPnpDevice(
180 IN ULONG BufferLength
)
183 /* FIXME: ReportDetectedPnpDevice not implemented */
184 DPRINT1("Serenum: ReportDetectedPnpDevice() unimplemented\n");
186 for (i
= 0; i
< BufferLength
; i
++)
187 DbgPrint("%c", Buffer
[i
]);
189 /* Call ReportDetectedDevice */
190 return STATUS_SUCCESS
;
197 SerenumWait(ULONG milliseconds
)
200 LARGE_INTEGER DueTime
;
202 DueTime
.QuadPart
= -milliseconds
* 10;
203 KeInitializeTimer(&Timer
);
204 KeSetTimer(&Timer
, DueTime
, NULL
);
205 return KeWaitForSingleObject(&Timer
, Executive
, KernelMode
, FALSE
, NULL
);
209 SerenumDetectPnpDevice(
210 IN PDEVICE_OBJECT DeviceObject
,
211 IN PDEVICE_OBJECT LowerDevice
)
215 ULONG TotalBytesReceived
= 0;
219 BOOLEAN BufferContainsBeginId
, BufferContainsEndId
;
220 SERIAL_LINE_CONTROL Lcr
;
221 SERIAL_TIMEOUTS Timeouts
;
222 SERIALPERF_STATS PerfStats
;
225 /* 1. COM port initialization, check for device enumerate */
227 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_DTR
,
228 NULL
, 0, NULL
, NULL
);
229 if (!NT_SUCCESS(Status
)) return Status
;
230 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
231 NULL
, 0, NULL
, NULL
);
232 if (!NT_SUCCESS(Status
)) return Status
;
235 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_GET_MODEMSTATUS
,
236 NULL
, 0, &Msr
, &Size
);
237 if (!NT_SUCCESS(Status
)) return Status
;
238 if ((Msr
& SR_MSR_DSR
) == 0) goto SerenumDisconnectIdle
;
240 /* 2. COM port setup, 1st phase */
242 BaudRate
= SERIAL_BAUD_1200
;
243 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
244 &BaudRate
, sizeof(BaudRate
), NULL
, 0);
245 if (!NT_SUCCESS(Status
)) return Status
;
247 Lcr
.Parity
= NO_PARITY
;
248 Lcr
.StopBits
= STOP_BIT_1
;
249 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
250 &Lcr
, sizeof(Lcr
), NULL
, NULL
);
251 if (!NT_SUCCESS(Status
)) return Status
;
252 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_DTR
,
253 NULL
, 0, NULL
, NULL
);
254 if (!NT_SUCCESS(Status
)) return Status
;
255 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
256 NULL
, 0, NULL
, NULL
);
257 if (!NT_SUCCESS(Status
)) return Status
;
259 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
260 NULL
, 0, NULL
, NULL
);
261 if (!NT_SUCCESS(Status
)) return Status
;
264 /* 3. Wait for response, 1st phase */
266 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_RTS
,
267 NULL
, 0, NULL
, NULL
);
268 if (!NT_SUCCESS(Status
)) return Status
;
269 Timeouts
.ReadIntervalTimeout
= 0;
270 Timeouts
.ReadTotalTimeoutMultiplier
= 0;
271 Timeouts
.ReadTotalTimeoutConstant
= 200;
272 Timeouts
.WriteTotalTimeoutMultiplier
= Timeouts
.WriteTotalTimeoutConstant
= 0;
273 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_TIMEOUTS
,
274 &Timeouts
, sizeof(Timeouts
), NULL
, NULL
);
275 if (!NT_SUCCESS(Status
)) return Status
;
276 Status
= ReadBytes(LowerDevice
, Buffer
, sizeof(Buffer
), &Size
);
277 if (!NT_SUCCESS(Status
)) return Status
;
278 if (Size
!= 0) goto SerenumCollectPnpComDeviceId
;
280 /* 4. COM port setup, 2nd phase */
282 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_DTR
,
283 NULL
, 0, NULL
, NULL
);
284 if (!NT_SUCCESS(Status
)) return Status
;
285 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
286 NULL
, 0, NULL
, NULL
);
287 if (!NT_SUCCESS(Status
)) return Status
;
288 Purge
= SERIAL_PURGE_RXABORT
| SERIAL_PURGE_RXCLEAR
;
289 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_PURGE
,
290 &Purge
, 0, NULL
, NULL
);
291 if (!NT_SUCCESS(Status
)) return Status
;
294 /* 5. Wait for response, 2nd phase */
296 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
297 NULL
, 0, NULL
, NULL
);
298 if (!NT_SUCCESS(Status
)) return Status
;
299 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_RTS
,
300 NULL
, 0, NULL
, NULL
);
301 if (!NT_SUCCESS(Status
)) return Status
;
302 Status
= ReadBytes(LowerDevice
, Buffer
, 1, &TotalBytesReceived
);
303 if (!NT_SUCCESS(Status
)) return Status
;
304 if (TotalBytesReceived
!= 0) goto SerenumCollectPnpComDeviceId
;
306 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_GET_MODEMSTATUS
,
307 NULL
, 0, &Msr
, &Size
);
308 if (!NT_SUCCESS(Status
)) return Status
;
309 if ((Msr
& SR_MSR_DSR
) == 0) goto SerenumVerifyDisconnect
; else goto SerenumConnectIdle
;
311 /* 6. Collect PnP COM device ID */
312 SerenumCollectPnpComDeviceId
:
314 Timeouts
.ReadIntervalTimeout
= 200;
315 Timeouts
.ReadTotalTimeoutMultiplier
= 0;
316 Timeouts
.ReadTotalTimeoutConstant
= 2200;
317 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_TIMEOUTS
,
318 &Timeouts
, sizeof(Timeouts
), NULL
, NULL
);
319 if (!NT_SUCCESS(Status
)) return Status
;
320 Status
= ReadBytes(LowerDevice
, &Buffer
[TotalBytesReceived
], sizeof(Buffer
) - TotalBytesReceived
, &Size
);
321 if (!NT_SUCCESS(Status
)) return Status
;
322 TotalBytesReceived
+= Size
;
323 Size
= sizeof(PerfStats
);
324 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_GET_STATS
,
325 NULL
, 0, &PerfStats
, &Size
);
326 if (!NT_SUCCESS(Status
)) return Status
;
327 if (PerfStats
.FrameErrorCount
+ PerfStats
.ParityErrorCount
!= 0) goto SerenumConnectIdle
;
328 BufferContainsBeginId
= BufferContainsEndId
= FALSE
;
329 for (i
= 0; i
< TotalBytesReceived
; i
++)
331 if (Buffer
[i
] == BEGIN_ID
) BufferContainsBeginId
= TRUE
;
332 if (Buffer
[i
] == END_ID
) BufferContainsEndId
= TRUE
;
334 if (TotalBytesReceived
== 1 || BufferContainsEndId
)
336 if (SerenumIsValidPnpIdString(Buffer
, TotalBytesReceived
))
337 return ReportDetectedPnpDevice(Buffer
, TotalBytesReceived
);
338 goto SerenumConnectIdle
;
340 if (!BufferContainsBeginId
) goto SerenumConnectIdle
;
341 if (!BufferContainsEndId
) goto SerenumConnectIdle
;
343 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_GET_MODEMSTATUS
,
344 NULL
, 0, &Msr
, &Size
);
345 if (!NT_SUCCESS(Status
)) return Status
;
346 if ((Msr
& SR_MSR_DSR
) == 0) goto SerenumVerifyDisconnect
;
348 /* 7. Verify disconnect */
349 SerenumVerifyDisconnect
:
351 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
352 NULL
, 0, NULL
, NULL
);
353 if (!NT_SUCCESS(Status
)) return Status
;
354 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
355 NULL
, 0, NULL
, NULL
);
356 if (!NT_SUCCESS(Status
)) return Status
;
358 goto SerenumDisconnectIdle
;
360 /* 8. Connect idle */
363 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
364 NULL
, 0, NULL
, NULL
);
365 if (!NT_SUCCESS(Status
)) return Status
;
366 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
367 NULL
, 0, NULL
, NULL
);
368 if (!NT_SUCCESS(Status
)) return Status
;
369 BaudRate
= SERIAL_BAUD_300
;
370 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
371 &BaudRate
, sizeof(BaudRate
), NULL
, NULL
);
372 if (!NT_SUCCESS(Status
)) return Status
;
374 Lcr
.Parity
= NO_PARITY
;
375 Lcr
.StopBits
= STOP_BIT_1
;
376 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
377 &Lcr
, sizeof(Lcr
), NULL
, NULL
);
378 if (!NT_SUCCESS(Status
)) return Status
;
379 if (TotalBytesReceived
== 0)
380 return STATUS_DEVICE_NOT_CONNECTED
;
382 return STATUS_SUCCESS
;
384 /* 9. Disconnect idle */
385 SerenumDisconnectIdle
:
387 /* FIXME: report to OS device removal, if it was present */
388 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
389 NULL
, 0, NULL
, NULL
);
390 if (!NT_SUCCESS(Status
)) return Status
;
391 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_CLR_RTS
,
392 NULL
, 0, NULL
, NULL
);
393 if (!NT_SUCCESS(Status
)) return Status
;
394 BaudRate
= SERIAL_BAUD_300
;
395 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
396 &BaudRate
, sizeof(BaudRate
), NULL
, NULL
);
397 if (!NT_SUCCESS(Status
)) return Status
;
399 Lcr
.Parity
= NO_PARITY
;
400 Lcr
.StopBits
= STOP_BIT_1
;
401 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
402 &Lcr
, sizeof(Lcr
), NULL
, NULL
);
403 if (!NT_SUCCESS(Status
)) return Status
;
404 return STATUS_DEVICE_NOT_CONNECTED
;
408 SerenumDetectLegacyDevice(
409 IN PDEVICE_OBJECT DeviceObject
,
410 IN PDEVICE_OBJECT LowerDevice
)
415 SERIAL_TIMEOUTS Timeouts
;
416 SERIAL_LINE_CONTROL LCR
;
419 UNICODE_STRING DeviceDescription
;
420 UNICODE_STRING DeviceId
;
421 UNICODE_STRING HardwareIds
;
422 UNICODE_STRING CompatibleIds
;
425 RtlZeroMemory(Buffer
, sizeof(Buffer
));
429 Mcr
= 0; /* MCR: DTR/RTS/OUT2 off */
430 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_MODEM_CONTROL
,
431 &Mcr
, sizeof(Mcr
), NULL
, NULL
);
432 if (!NT_SUCCESS(Status
)) return Status
;
434 /* Set communications parameters */
438 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_FIFO_CONTROL
,
439 &Fcr
, sizeof(Fcr
), NULL
, NULL
);
440 if (!NT_SUCCESS(Status
)) return Status
;
441 /* Set serial port speed */
442 BaudRate
= SERIAL_BAUD_1200
;
443 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_BAUD_RATE
,
444 &BaudRate
, sizeof(BaudRate
), NULL
, NULL
);
445 if (!NT_SUCCESS(Status
)) return Status
;
448 LCR
.Parity
= NO_PARITY
;
449 LCR
.StopBits
= STOP_BITS_2
;
450 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_LINE_CONTROL
,
451 &LCR
, sizeof(LCR
), NULL
, NULL
);
452 if (!NT_SUCCESS(Status
)) return Status
;
454 /* Flush receive buffer */
456 Command
= SERIAL_PURGE_RXCLEAR
;
457 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_MODEM_CONTROL
,
458 &Command
, sizeof(Command
), NULL
, NULL
);
459 if (!NT_SUCCESS(Status
)) return Status
;
465 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_DTR
,
466 NULL
, 0, NULL
, NULL
);
467 if (!NT_SUCCESS(Status
)) return Status
;
468 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_RTS
,
469 NULL
, 0, NULL
, NULL
);
470 if (!NT_SUCCESS(Status
)) return Status
;
472 /* Set timeout to 500 microseconds */
474 Timeouts
.ReadIntervalTimeout
= 100;
475 Timeouts
.ReadTotalTimeoutMultiplier
= 0;
476 Timeouts
.ReadTotalTimeoutConstant
= 500;
477 Timeouts
.WriteTotalTimeoutMultiplier
= Timeouts
.WriteTotalTimeoutConstant
= 0;
478 Status
= SerenumDeviceIoControl(LowerDevice
, IOCTL_SERIAL_SET_TIMEOUTS
,
479 &Timeouts
, sizeof(Timeouts
), NULL
, NULL
);
480 if (!NT_SUCCESS(Status
)) return Status
;
482 /* Fill the read buffer */
484 Status
= ReadBytes(LowerDevice
, Buffer
, sizeof(Buffer
)/sizeof(Buffer
[0]), &Count
);
485 if (!NT_SUCCESS(Status
)) return Status
;
487 for (i
= 0; i
< Count
; i
++)
489 if (Buffer
[i
] == 'B')
491 /* Sign for Microsoft Ballpoint */
492 /* Hardware id: *PNP0F09
493 * Compatible id: *PNP0F0F, SERIAL_MOUSE
495 RtlInitUnicodeString(&DeviceDescription
, L
"Microsoft Ballpoint device");
496 RtlInitUnicodeString(&DeviceId
, L
"*PNP0F09");
497 SerenumInitMultiSzString(&HardwareIds
, "*PNP0F09", NULL
);
498 SerenumInitMultiSzString(&CompatibleIds
, "*PNP0F0F", "SERIAL_MOUSE", NULL
);
499 Status
= ReportDetectedDevice(DeviceObject
,
500 &DeviceDescription
, &DeviceId
, &HardwareIds
, &CompatibleIds
);
501 RtlFreeUnicodeString(&HardwareIds
);
502 RtlFreeUnicodeString(&CompatibleIds
);
505 else if (Buffer
[i
] == 'M')
507 /* Sign for Microsoft Mouse protocol followed by button specifier */
508 if (i
== sizeof(Buffer
) - 1)
511 return STATUS_DEVICE_NOT_CONNECTED
;
513 switch (Buffer
[i
+ 1])
516 /* Hardware id: *PNP0F08
517 * Compatible id: SERIAL_MOUSE
519 RtlInitUnicodeString(&DeviceDescription
, L
"Microsoft Mouse with 3-buttons");
520 RtlInitUnicodeString(&DeviceId
, L
"*PNP0F08");
521 SerenumInitMultiSzString(&HardwareIds
, "*PNP0F08", NULL
);
522 SerenumInitMultiSzString(&CompatibleIds
, "SERIAL_MOUSE", NULL
);
524 /* Hardware id: *PNP0F01
525 * Compatible id: SERIAL_MOUSE
527 RtlInitUnicodeString(&DeviceDescription
, L
"Microsoft Mouse with 2-buttons or Microsoft Wheel Mouse");
528 RtlInitUnicodeString(&DeviceId
, L
"*PNP0F01");
529 SerenumInitMultiSzString(&HardwareIds
, "*PNP0F01", NULL
);
530 SerenumInitMultiSzString(&CompatibleIds
, "SERIAL_MOUSE", NULL
);
532 Status
= ReportDetectedDevice(DeviceObject
,
533 &DeviceDescription
, &DeviceId
, &HardwareIds
, &CompatibleIds
);
534 RtlFreeUnicodeString(&HardwareIds
);
535 RtlFreeUnicodeString(&CompatibleIds
);
540 return STATUS_DEVICE_NOT_CONNECTED
;