remove whitespace from end of lines
[reactos.git] / reactos / drivers / bus / serenum / detect.c
1 /* $Id:
2 *
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
7 *
8 * PROGRAMMERS: Jason Filby (jasonfilby@yahoo.com)
9 * Filip Navara (xnavara@volny.cz)
10 * Hervé Poussineau (hpoussin@reactos.com)
11 */
12
13 #define NDEBUG
14 #include "serenum.h"
15
16 static NTSTATUS
17 SerenumDeviceIoControl(
18 IN PDEVICE_OBJECT DeviceObject,
19 IN ULONG CtlCode,
20 IN PVOID InputBuffer OPTIONAL,
21 IN ULONG InputBufferSize,
22 IN OUT PVOID OutputBuffer OPTIONAL,
23 IN OUT PULONG OutputBufferSize)
24 {
25 KEVENT Event;
26 PIRP Irp;
27 IO_STATUS_BLOCK IoStatus;
28 NTSTATUS Status;
29
30 KeInitializeEvent (&Event, NotificationEvent, FALSE);
31
32 Irp = IoBuildDeviceIoControlRequest(CtlCode,
33 DeviceObject,
34 InputBuffer,
35 InputBufferSize,
36 OutputBuffer,
37 (OutputBufferSize) ? *OutputBufferSize : 0,
38 FALSE,
39 &Event,
40 &IoStatus);
41 if (Irp == NULL)
42 {
43 DPRINT("Serenum: IoBuildDeviceIoControlRequest() failed\n");
44 return STATUS_INSUFFICIENT_RESOURCES;
45 }
46
47 Status = IoCallDriver(DeviceObject, Irp);
48
49 if (Status == STATUS_PENDING)
50 {
51 DPRINT("Serenum: Operation pending\n");
52 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
53 Status = IoStatus.Status;
54 }
55
56 if (OutputBufferSize)
57 {
58 *OutputBufferSize = IoStatus.Information;
59 }
60
61 return Status;
62 }
63
64 static NTSTATUS
65 ReadBytes(
66 IN PDEVICE_OBJECT LowerDevice,
67 OUT PUCHAR Buffer,
68 IN ULONG BufferSize,
69 OUT PULONG FilledBytes)
70 {
71 PIRP Irp;
72 IO_STATUS_BLOCK ioStatus;
73 KEVENT event;
74 LARGE_INTEGER zero;
75 NTSTATUS Status;
76
77 KeInitializeEvent(&event, NotificationEvent, FALSE);
78 zero.QuadPart = 0;
79 Irp = IoBuildSynchronousFsdRequest(
80 IRP_MJ_READ,
81 LowerDevice,
82 Buffer, BufferSize,
83 &zero,
84 &event,
85 &ioStatus);
86 if (!Irp)
87 return FALSE;
88
89 Status = IoCallDriver(LowerDevice, Irp);
90 if (Status == STATUS_PENDING)
91 {
92 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
93 Status = ioStatus.Status;
94 }
95 DPRINT("Serenum: bytes received: %lu/%lu\n",
96 ioStatus.Information, BufferSize);
97 *FilledBytes = ioStatus.Information;
98 return Status;
99 }
100
101 static NTSTATUS
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)
108 {
109 PDEVICE_OBJECT Pdo = NULL;
110 PPDO_DEVICE_EXTENSION PdoDeviceExtension = NULL;
111 PFDO_DEVICE_EXTENSION FdoDeviceExtension;
112 NTSTATUS Status;
113
114 DPRINT("Serenum: SerenumReportDetectedDevice() called with %wZ (%wZ) detected\n", DeviceId, DeviceDescription);
115
116 Status = IoCreateDevice(
117 DeviceObject->DriverObject,
118 sizeof(PDO_DEVICE_EXTENSION),
119 NULL,
120 FILE_DEVICE_CONTROLLER,
121 FILE_AUTOGENERATED_DEVICE_NAME,
122 FALSE,
123 &Pdo);
124 if (!NT_SUCCESS(Status)) goto ByeBye;
125
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;
140
141 /* Device attached to serial port (Pdo) may delegate work to
142 * serial port stack (Fdo = DeviceObject variable) */
143 Pdo->StackSize = DeviceObject->StackSize + 1;
144
145 FdoDeviceExtension->AttachedPdo = Pdo;
146 PdoDeviceExtension->AttachedFdo = DeviceObject;
147
148 Pdo->Flags |= DO_BUFFERED_IO;
149 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
150
151 return STATUS_SUCCESS;
152
153 ByeBye:
154 if (Pdo)
155 {
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);
164 IoDeleteDevice(Pdo);
165 }
166 return Status;
167 }
168
169 static BOOLEAN
170 SerenumIsValidPnpIdString(
171 IN PUCHAR Buffer,
172 IN ULONG BufferLength)
173 {
174 /* FIXME: SerenumIsValidPnpIdString not implemented */
175 DPRINT1("Serenum: SerenumIsValidPnpIdString() unimplemented\n");
176 return STATUS_SUCCESS;
177 }
178
179 static NTSTATUS
180 ReportDetectedPnpDevice(
181 IN PUCHAR Buffer,
182 IN ULONG BufferLength)
183 {
184 ULONG i;
185 /* FIXME: ReportDetectedPnpDevice not implemented */
186 DPRINT1("Serenum: ReportDetectedPnpDevice() unimplemented\n");
187 DPRINT1("");
188 for (i = 0; i < BufferLength; i++)
189 DbgPrint("%c", Buffer[i]);
190 DbgPrint("\n");
191 /* Call ReportDetectedDevice */
192 return STATUS_SUCCESS;
193 }
194
195 #define BEGIN_ID '('
196 #define END_ID ')'
197
198 static NTSTATUS
199 SerenumWait(ULONG milliseconds)
200 {
201 KTIMER Timer;
202 LARGE_INTEGER DueTime;
203
204 DueTime.QuadPart = milliseconds * -10;
205 KeInitializeTimer(&Timer);
206 KeSetTimer(&Timer, DueTime, NULL);
207 return KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, NULL);
208 }
209
210 NTSTATUS
211 SerenumDetectPnpDevice(
212 IN PDEVICE_OBJECT DeviceObject,
213 IN PDEVICE_OBJECT LowerDevice)
214 {
215 UCHAR Buffer[256];
216 ULONG BaudRate;
217 ULONG TotalBytesReceived = 0;
218 ULONG Size;
219 ULONG Msr, Purge;
220 ULONG i;
221 BOOLEAN BufferContainsBeginId = FALSE;
222 BOOLEAN BufferContainsEndId = FALSE;
223 SERIAL_LINE_CONTROL Lcr;
224 SERIAL_TIMEOUTS Timeouts;
225 SERIALPERF_STATS PerfStats;
226 NTSTATUS Status;
227
228 /* 1. COM port initialization, check for device enumerate */
229 CHECKPOINT;
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;
236 SerenumWait(200);
237 Size = sizeof(Msr);
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;
242
243 /* 2. COM port setup, 1st phase */
244 CHECKPOINT;
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;
249 Lcr.WordLength = 7;
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;
261 SerenumWait(200);
262 Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
263 NULL, 0, NULL, NULL);
264 if (!NT_SUCCESS(Status)) return Status;
265 SerenumWait(200);
266
267 /* 3. Wait for response, 1st phase */
268 CHECKPOINT;
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;
282
283 /* 4. COM port setup, 2nd phase */
284 CHECKPOINT;
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;
295 SerenumWait(200);
296
297 /* 5. Wait for response, 2nd phase */
298 CHECKPOINT;
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;
308 Size = sizeof(Msr);
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;
313
314 /* 6. Collect PnP COM device ID */
315 SerenumCollectPnpComDeviceId:
316 CHECKPOINT;
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++)
332 {
333 if (Buffer[i] == BEGIN_ID) BufferContainsBeginId = TRUE;
334 if (Buffer[i] == END_ID) BufferContainsEndId = TRUE;
335 }
336 if (TotalBytesReceived == 1 || BufferContainsEndId)
337 {
338 if (SerenumIsValidPnpIdString(Buffer, TotalBytesReceived))
339 return ReportDetectedPnpDevice(Buffer, TotalBytesReceived);
340 goto SerenumConnectIdle;
341 }
342 if (!BufferContainsBeginId) goto SerenumConnectIdle;
343 if (!BufferContainsEndId) goto SerenumConnectIdle;
344 Size = sizeof(Msr);
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;
349
350 /* 7. Verify disconnect */
351 SerenumVerifyDisconnect:
352 CHECKPOINT;
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;
359 SerenumWait(5000);
360 goto SerenumDisconnectIdle;
361
362 /* 8. Connect idle */
363 SerenumConnectIdle:
364 CHECKPOINT;
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;
375 Lcr.WordLength = 7;
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;
383 else
384 return STATUS_SUCCESS;
385
386 /* 9. Disconnect idle */
387 SerenumDisconnectIdle:
388 CHECKPOINT;
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;
400 Lcr.WordLength = 7;
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;
407 }
408
409 NTSTATUS
410 SerenumDetectLegacyDevice(
411 IN PDEVICE_OBJECT DeviceObject,
412 IN PDEVICE_OBJECT LowerDevice)
413 {
414 ULONG Fcr, Mcr;
415 ULONG BaudRate;
416 ULONG Command;
417 SERIAL_TIMEOUTS Timeouts;
418 SERIAL_LINE_CONTROL LCR;
419 ULONG i, Count;
420 UCHAR Buffer[16];
421 UNICODE_STRING DeviceDescription;
422 UNICODE_STRING DeviceId;
423 UNICODE_STRING HardwareIds;
424 UNICODE_STRING CompatibleIds;
425 NTSTATUS Status;
426
427 DPRINT("Serenum: SerenumDetectLegacyDevice(DeviceObject %p, LowerDevice %p)\n",
428 DeviceObject,
429 LowerDevice);
430
431 RtlZeroMemory(Buffer, sizeof(Buffer));
432
433 /* Reset UART */
434 CHECKPOINT;
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;
439
440 /* Set communications parameters */
441 CHECKPOINT;
442 /* DLAB off */
443 Fcr = 0;
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;
452 /* Set LCR */
453 LCR.WordLength = 7;
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;
459
460 /* Flush receive buffer */
461 CHECKPOINT;
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;
466 /* Wait 100 ms */
467 SerenumWait(100);
468
469 /* Enable DTR/RTS */
470 CHECKPOINT;
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;
477
478 /* Set timeout to 500 microseconds */
479 CHECKPOINT;
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;
487
488 /* Fill the read buffer */
489 CHECKPOINT;
490 Status = ReadBytes(LowerDevice, Buffer, sizeof(Buffer)/sizeof(Buffer[0]), &Count);
491 if (!NT_SUCCESS(Status)) return Status;
492
493 for (i = 0; i < Count; i++)
494 {
495 if (Buffer[i] == 'B')
496 {
497 /* Sign for Microsoft Ballpoint */
498 /* Hardware id: *PNP0F09
499 * Compatible id: *PNP0F0F, SERIAL_MOUSE
500 */
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);
509 return Status;
510 }
511 else if (Buffer[i] == 'M')
512 {
513 /* Sign for Microsoft Mouse protocol followed by button specifier */
514 if (i == sizeof(Buffer) - 1)
515 {
516 /* Overflow Error */
517 return STATUS_DEVICE_NOT_CONNECTED;
518 }
519 switch (Buffer[i + 1])
520 {
521 case '3':
522 /* Hardware id: *PNP0F08
523 * Compatible id: SERIAL_MOUSE
524 */
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);
529 default:
530 /* Hardware id: *PNP0F01
531 * Compatible id: SERIAL_MOUSE
532 */
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);
537 }
538 Status = ReportDetectedDevice(DeviceObject,
539 &DeviceDescription, &DeviceId, &HardwareIds, &CompatibleIds);
540 RtlFreeUnicodeString(&HardwareIds);
541 RtlFreeUnicodeString(&CompatibleIds);
542 return Status;
543 }
544 }
545
546 return STATUS_DEVICE_NOT_CONNECTED;
547 }