Merge from amd64 branch:
[reactos.git] / rosapps / drivers / green / pnp.c
1 /*
2 * PROJECT: ReactOS VT100 emulator
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/base/green/pnp.c
5 * PURPOSE: IRP_MJ_PNP operations
6 * PROGRAMMERS: Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
7 */
8
9 #include "green.h"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 static NTSTATUS
15 CreateGreenFdo(
16 IN PDRIVER_OBJECT DriverObject,
17 IN PDEVICE_OBJECT GreenPdo)
18 {
19 PGREEN_DRIVER_EXTENSION DriverExtension = NULL;
20 PGREEN_DEVICE_EXTENSION DeviceExtension = NULL;
21 OBJECT_ATTRIBUTES ObjectAttributes;
22 ULONG Fcr;
23 HANDLE LocalHandle = 0;
24 ACCESS_MASK DesiredAccess = FILE_ANY_ACCESS;
25 NTSTATUS Status;
26
27 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
28
29 Status = IoCreateDevice(
30 DriverObject,
31 sizeof(GREEN_DEVICE_EXTENSION),
32 NULL,
33 FILE_DEVICE_TERMSRV,
34 FILE_DEVICE_SECURE_OPEN,
35 FALSE,
36 &DriverExtension->GreenMainDO);
37 if (!NT_SUCCESS(Status))
38 {
39 DPRINT("IoCreateDevice() failed with status %08lx\n", Status);
40 goto cleanup;
41 }
42
43 DeviceExtension = (PGREEN_DEVICE_EXTENSION)DriverExtension->GreenMainDO->DeviceExtension;
44 RtlZeroMemory(DeviceExtension, sizeof(GREEN_DEVICE_EXTENSION));
45 DeviceExtension->Common.Type = GreenFDO;
46 DriverExtension->GreenMainDO->Flags |= DO_POWER_PAGABLE;
47 DriverExtension->LowerDevice = IoAttachDeviceToDeviceStack(DriverExtension->GreenMainDO, GreenPdo);
48
49 /* Initialize serial port */
50 InitializeObjectAttributes(&ObjectAttributes, &DriverExtension->AttachedDeviceName, OBJ_KERNEL_HANDLE, NULL, NULL);
51 Status = ObOpenObjectByName(
52 &ObjectAttributes,
53 IoFileObjectType,
54 KernelMode,
55 NULL,
56 DesiredAccess,
57 NULL,
58 &LocalHandle);
59 if (!NT_SUCCESS(Status))
60 {
61 DPRINT("ObOpenObjectByName() failed with status %08lx\n", Status);
62 goto cleanup;
63 }
64 Status = ObReferenceObjectByHandle(
65 LocalHandle,
66 DesiredAccess,
67 NULL,
68 KernelMode,
69 (PVOID*)&DeviceExtension->Serial,
70 NULL);
71 if (!NT_SUCCESS(Status))
72 {
73 DPRINT("ObReferenceObjectByHandle() failed with status %08lx\n", Status);
74 goto cleanup;
75 }
76 Fcr = 0;
77 Status = GreenDeviceIoControl(DeviceExtension->Serial, IOCTL_SERIAL_SET_FIFO_CONTROL,
78 &Fcr, sizeof(Fcr), NULL, NULL);
79 if (!NT_SUCCESS(Status))
80 {
81 DPRINT("GreenDeviceIoControl() failed with status %08lx\n", Status);
82 goto cleanup;
83 }
84 Status = GreenDeviceIoControl(DeviceExtension->Serial, IOCTL_SERIAL_SET_BAUD_RATE,
85 &DriverExtension->SampleRate, sizeof(DriverExtension->SampleRate), NULL, NULL);
86 if (!NT_SUCCESS(Status))
87 {
88 DPRINT("GreenDeviceIoControl() failed with status %08lx\n", Status);
89 goto cleanup;
90 }
91 DeviceExtension->LineControl.WordLength = 8;
92 DeviceExtension->LineControl.Parity = NO_PARITY;
93 DeviceExtension->LineControl.StopBits = STOP_BIT_1;
94 Status = GreenDeviceIoControl(DeviceExtension->Serial, IOCTL_SERIAL_SET_LINE_CONTROL,
95 &DeviceExtension->LineControl, sizeof(SERIAL_LINE_CONTROL), NULL, NULL);
96 if (!NT_SUCCESS(Status))
97 {
98 DPRINT("GreenDeviceIoControl() failed with status %08lx\n", Status);
99 goto cleanup;
100 }
101 RtlZeroMemory(&DeviceExtension->Timeouts, sizeof(SERIAL_TIMEOUTS));
102 DeviceExtension->Timeouts.ReadIntervalTimeout = 100;
103 Status = GreenDeviceIoControl(DeviceExtension->Serial, IOCTL_SERIAL_SET_TIMEOUTS,
104 &DeviceExtension->Timeouts, sizeof(SERIAL_TIMEOUTS), NULL, NULL);
105 if (!NT_SUCCESS(Status))
106 {
107 DPRINT("GreenDeviceIoControl() failed with status %08lx\n", Status);
108 goto cleanup;
109 }
110
111 DriverExtension->GreenMainDO->Flags |= DO_BUFFERED_IO;
112 DriverExtension->GreenMainDO->Flags &= ~DO_DEVICE_INITIALIZING;
113
114 Status = STATUS_SUCCESS;
115
116 cleanup:
117 if (LocalHandle != 0)
118 ZwClose(LocalHandle);
119 if (!NT_SUCCESS(Status))
120 {
121 if (DeviceExtension && DeviceExtension->Serial)
122 ObDereferenceObject(DeviceExtension->Serial);
123 if (DriverExtension)
124 {
125 if (DriverExtension->LowerDevice)
126 {
127 IoDetachDevice(DriverExtension->LowerDevice);
128 DriverExtension->LowerDevice = NULL;
129 }
130 if (DriverExtension->GreenMainDO)
131 {
132 IoDeleteDevice(DriverExtension->GreenMainDO);
133 DriverExtension->GreenMainDO = NULL;
134 }
135 }
136 }
137 return Status;
138 }
139
140 static NTSTATUS
141 ReportGreenPdo(
142 IN PDRIVER_OBJECT DriverObject,
143 IN PGREEN_DRIVER_EXTENSION DriverExtension)
144 {
145 PDEVICE_OBJECT GreenPdo = NULL;
146 NTSTATUS Status;
147
148 /* Create green PDO */
149 Status = IoReportDetectedDevice(
150 DriverObject,
151 InterfaceTypeUndefined, -1, -1,
152 NULL, NULL, TRUE,
153 &GreenPdo);
154 if (!NT_SUCCESS(Status))
155 {
156 DPRINT("IoReportDetectedDevice() failed with status 0x%lx\n", Status);
157 goto cleanup;
158 }
159
160 /* Create green FDO */
161 Status = CreateGreenFdo(DriverObject, GreenPdo);
162
163 IoInvalidateDeviceRelations(GreenPdo, BusRelations);
164
165 /* FIXME: Update registry, set "DeviceReported" to 1 */
166
167 Status = STATUS_SUCCESS;
168
169 cleanup:
170 if (!NT_SUCCESS(Status))
171 {
172 if (DriverExtension->GreenMainDO)
173 IoDeleteDevice(DriverExtension->GreenMainDO);
174 }
175 return Status;
176 }
177
178 NTSTATUS NTAPI
179 GreenAddDevice(
180 IN PDRIVER_OBJECT DriverObject,
181 IN PDEVICE_OBJECT Pdo)
182 {
183 PGREEN_DRIVER_EXTENSION DriverExtension;
184
185 DPRINT("AddDevice(DriverObject %p, Pdo %p)\n", DriverObject, Pdo);
186
187 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
188
189 if (Pdo == NULL)
190 {
191 if (DriverExtension->DeviceReported)
192 /* Green Pdo has already been reported during a previous boot.
193 * We will get another AddDevice call soon.
194 */
195 return STATUS_SUCCESS;
196 else
197 return ReportGreenPdo(DriverObject, DriverExtension);
198 }
199 else if (DriverExtension->GreenMainDO == NULL)
200 {
201 return CreateGreenFdo(DriverObject, Pdo);
202 }
203 else
204 {
205 PGREEN_DEVICE_EXTENSION GreenDeviceExtension;
206
207 GreenDeviceExtension = (PGREEN_DEVICE_EXTENSION)DriverExtension->GreenMainDO->DeviceExtension;
208 if (Pdo == GreenDeviceExtension->KeyboardPdo)
209 return KeyboardAddDevice(DriverObject, Pdo);
210 else if (Pdo == GreenDeviceExtension->ScreenPdo)
211 return ScreenAddDevice(DriverObject, Pdo);
212 else
213 /* Strange PDO. We don't know it */
214 ASSERT(FALSE);
215 return STATUS_UNSUCCESSFUL;
216 }
217 }
218
219 static NTSTATUS
220 GreenQueryBusRelations(
221 IN PDEVICE_OBJECT DeviceObject,
222 OUT PDEVICE_RELATIONS* pDeviceRelations)
223 {
224 PGREEN_DEVICE_EXTENSION DeviceExtension;
225 PDEVICE_RELATIONS DeviceRelations = NULL;
226 NTSTATUS Status;
227
228 DeviceExtension = (PGREEN_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
229
230 /* Create PDOs for keyboard and screen */
231 if (DeviceExtension->KeyboardPdo == NULL)
232 {
233 Status = IoCreateDevice(
234 DeviceObject->DriverObject,
235 sizeof(COMMON_DEVICE_EXTENSION),
236 NULL,
237 FILE_DEVICE_KEYBOARD,
238 FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN,
239 FALSE,
240 &DeviceExtension->KeyboardPdo);
241 if (!NT_SUCCESS(Status))
242 {
243 DPRINT("IoCreateDevice() failed with status 0x%lx\n", Status);
244 goto cleanup;
245 }
246 ((PCOMMON_DEVICE_EXTENSION)DeviceExtension->KeyboardPdo->DeviceExtension)->Type = KeyboardPDO;
247 DeviceExtension->KeyboardPdo->Flags |= DO_POWER_PAGABLE | DO_BUS_ENUMERATED_DEVICE;
248 DeviceExtension->KeyboardPdo->Flags &= ~DO_DEVICE_INITIALIZING;
249 }
250
251 if (DeviceExtension->ScreenPdo == NULL)
252 {
253 Status = IoCreateDevice(
254 DeviceObject->DriverObject,
255 sizeof(COMMON_DEVICE_EXTENSION),
256 NULL,
257 FILE_DEVICE_SCREEN,
258 FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN,
259 FALSE,
260 &DeviceExtension->ScreenPdo);
261 if (!NT_SUCCESS(Status))
262 {
263 DPRINT("IoCreateDevice() failed with status 0x%lx\n", Status);
264 goto cleanup;
265 }
266 ((PCOMMON_DEVICE_EXTENSION)DeviceExtension->ScreenPdo->DeviceExtension)->Type = ScreenPDO;
267 DeviceExtension->ScreenPdo->Flags |= DO_POWER_PAGABLE | DO_BUS_ENUMERATED_DEVICE;
268 DeviceExtension->ScreenPdo->Flags &= ~DO_DEVICE_INITIALIZING;
269 }
270
271 /* Allocate return structure */
272 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
273 PagedPool,
274 FIELD_OFFSET(DEVICE_RELATIONS, Objects) + 2 * sizeof(PDEVICE_OBJECT));
275 if (!DeviceRelations)
276 return STATUS_INSUFFICIENT_RESOURCES;
277
278 /* Fill return structure */
279 DeviceRelations->Count = 2;
280 ObReferenceObject(DeviceExtension->KeyboardPdo);
281 ObReferenceObject(DeviceExtension->ScreenPdo);
282 DeviceRelations->Objects[0] = DeviceExtension->KeyboardPdo;
283 DeviceRelations->Objects[1] = DeviceExtension->ScreenPdo;
284
285 *pDeviceRelations = DeviceRelations;
286 Status = STATUS_SUCCESS;
287
288 cleanup:
289 if (!NT_SUCCESS(Status))
290 {
291 if (DeviceRelations)
292 {
293 ULONG i;
294 for (i = 0; i < DeviceRelations->Count; i++)
295 ObDereferenceObject(DeviceRelations->Objects[i]);
296 ExFreePool(DeviceRelations);
297 }
298 if (DeviceExtension->KeyboardPdo)
299 {
300 IoDeleteDevice(DeviceExtension->KeyboardPdo);
301 DeviceExtension->KeyboardPdo = NULL;
302 }
303 if (DeviceExtension->ScreenPdo)
304 {
305 IoDeleteDevice(DeviceExtension->ScreenPdo);
306 DeviceExtension->ScreenPdo = NULL;
307 }
308 }
309 return Status;
310 }
311
312 static NTSTATUS
313 GreenQueryId(
314 IN PDEVICE_OBJECT DeviceObject,
315 IN PIRP Irp,
316 OUT ULONG_PTR* Information)
317 {
318 GREEN_DEVICE_TYPE Type;
319 ULONG IdType;
320 NTSTATUS Status = Irp->IoStatus.Status;
321
322 Type = ((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Type;
323 IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType;
324
325 switch (IdType)
326 {
327 case BusQueryDeviceID:
328 {
329 LPCWSTR Source = NULL;
330
331 if (Type == ScreenPDO)
332 Source = L"GREEN\\SCREEN";
333 else if (Type == KeyboardPDO)
334 Source = L"GREEN\\KEYBOARD";
335 else
336 {
337 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceId / Unknown type 0x%lx\n",
338 Type);
339 ASSERT(FALSE);
340 }
341
342 if (Source)
343 {
344 UNICODE_STRING SourceU, String;
345 RtlInitUnicodeString(&SourceU, Source);
346 Status = GreenDuplicateUnicodeString(
347 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
348 &SourceU,
349 &String);
350 *Information = (ULONG_PTR)String.Buffer;
351 }
352 break;
353 }
354 case BusQueryHardwareIDs:
355 {
356 UNICODE_STRING SourceU = { 0, };
357
358 if (Type == ScreenPDO)
359 {
360 RtlInitUnicodeString(&SourceU, L"GREEN\\SCREEN\0");
361 /* We can add the two \0 that are at the end of the string */
362 SourceU.Length = SourceU.MaximumLength = SourceU.Length + 2 * sizeof(WCHAR);
363 }
364 else if (Type == KeyboardPDO)
365 {
366 RtlInitUnicodeString(&SourceU, L"GREEN\\KEYBOARD\0");
367 /* We can add the two \0 that are at the end of the string */
368 SourceU.Length = SourceU.MaximumLength = SourceU.Length + 2 * sizeof(WCHAR);
369 }
370 else
371 {
372 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs / Unknown type 0x%lx\n",
373 Type);
374 ASSERT(FALSE);
375 }
376
377 if (SourceU.Length)
378 {
379 UNICODE_STRING String;
380 Status = GreenDuplicateUnicodeString(
381 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
382 &SourceU,
383 &String);
384 *Information = (ULONG_PTR)String.Buffer;
385 }
386 break;
387 }
388 case BusQueryCompatibleIDs:
389 {
390 /* We don't have any compatible ID */
391 break;
392 }
393 case BusQueryInstanceID:
394 {
395 /* We don't have any instance ID */
396 break;
397 }
398 default:
399 {
400 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
401 }
402 }
403
404 return Status;
405 }
406
407 NTSTATUS
408 GreenPnp(
409 IN PDEVICE_OBJECT DeviceObject,
410 IN PIRP Irp)
411 {
412 GREEN_DEVICE_TYPE Type;
413 PIO_STACK_LOCATION Stack;
414 ULONG_PTR Information = Irp->IoStatus.Information;
415 NTSTATUS Status = Irp->IoStatus.Status;
416
417 Type = ((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Type;
418 Stack = IoGetCurrentIrpStackLocation(Irp);
419
420 switch (Stack->MinorFunction)
421 {
422 case IRP_MN_START_DEVICE: /* 0x00 */
423 {
424 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
425 if (Type == GreenFDO || Type == KeyboardPDO || Type == ScreenPDO)
426 Status = STATUS_SUCCESS;
427 else
428 {
429 DPRINT1("IRP_MJ_PNP / IRP_MN_START_DEVICE / Unknown type 0x%lx\n",
430 Type);
431 ASSERT(FALSE);
432 }
433 break;
434 }
435 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
436 {
437 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS\n");
438 switch (Stack->Parameters.QueryDeviceRelations.Type)
439 {
440 case BusRelations:
441 {
442 if (Type == GreenFDO)
443 {
444 PDEVICE_RELATIONS DeviceRelations = NULL;
445 Status = GreenQueryBusRelations(DeviceObject, &DeviceRelations);
446 Information = (ULONG_PTR)DeviceRelations;
447 }
448 else if (Type == KeyboardPDO || Type == ScreenPDO)
449 {
450 PDEVICE_RELATIONS DeviceRelations = NULL;
451 DeviceRelations = ExAllocatePool(PagedPool, FIELD_OFFSET(DEVICE_RELATIONS, Objects));
452 if (!DeviceRelations)
453 Status = STATUS_INSUFFICIENT_RESOURCES;
454 else
455 {
456 DeviceRelations->Count = 0;
457 Status = STATUS_SUCCESS;
458 Information = (ULONG_PTR)DeviceRelations;
459 }
460 }
461 else
462 {
463 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations / Unknown type 0x%lx\n",
464 Type);
465 ASSERT(FALSE);
466 }
467 break;
468 }
469 default:
470 {
471 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
472 Stack->Parameters.QueryDeviceRelations.Type);
473 break;
474 }
475 }
476 break;
477 }
478 case IRP_MN_QUERY_RESOURCES: /* 0x0a */
479 {
480 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
481 /* We don't need resources */
482 break;
483 }
484 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */
485 {
486 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
487 /* We don't need resources */
488 break;
489 }
490 case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */
491 {
492 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT\n");
493 switch (Stack->Parameters.QueryDeviceText.DeviceTextType)
494 {
495 case DeviceTextDescription:
496 {
497 LPCWSTR Description = NULL;
498 if (Type == GreenFDO)
499 Description = L"Green device";
500 else if (Type == ScreenPDO)
501 Description = L"Green screen";
502 else if (Type == KeyboardPDO)
503 Description = L"Green keyboard";
504
505 if (Description != NULL)
506 {
507 LPWSTR Destination = ExAllocatePool(PagedPool, wcslen(Description) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
508 if (!Destination)
509 Status = STATUS_INSUFFICIENT_RESOURCES;
510 else
511 {
512 wcscpy(Destination, Description);
513 Information = (ULONG_PTR)Description;
514 Status = STATUS_SUCCESS;
515 }
516 }
517 else
518 {
519 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription / Unknown type 0x%lx\n",
520 Type);
521 ASSERT(FALSE);
522 }
523 break;
524 }
525 case DeviceTextLocationInformation:
526 {
527 /* We don't have any text location to report,
528 * and this query is optional, so ignore it.
529 */
530 break;
531 }
532 default:
533 {
534 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown type 0x%lx\n",
535 Stack->Parameters.QueryDeviceText.DeviceTextType);
536 ASSERT(FALSE);
537 break;
538 }
539 }
540 break;
541 }
542 case IRP_MN_QUERY_ID: /* 0x13 */
543 {
544 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID\n");
545 Status = GreenQueryId(DeviceObject, Irp, &Information);
546 break;
547 }
548 default:
549 {
550 DPRINT1("IRP_MJ_PNP / unknown minor function 0x%lx\n", Stack->MinorFunction);
551 break;
552 }
553 }
554
555 Irp->IoStatus.Status = Status;
556 Irp->IoStatus.Information = Information;
557 if (Status != STATUS_PENDING)
558 IoCompleteRequest(Irp, IO_NO_INCREMENT);
559
560 return Status;
561 }
562
563