xref: /reactos/modules/rosapps/drivers/green/pnp.c (revision c2c66aff)
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
CreateGreenFdo(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT GreenPdo)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
ReportGreenPdo(IN PDRIVER_OBJECT DriverObject,IN PGREEN_DRIVER_EXTENSION DriverExtension)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
GreenAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT Pdo)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
GreenQueryBusRelations(IN PDEVICE_OBJECT DeviceObject,OUT PDEVICE_RELATIONS * pDeviceRelations)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
GreenQueryId(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,OUT ULONG_PTR * Information)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
GreenPnp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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 
564