xref: /reactos/modules/rosapps/drivers/green/screen.c (revision c2c66aff)
1 /*
2  * PROJECT:     ReactOS VT100 emulator
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        drivers/base/green/screen.c
5  * PURPOSE:     IRP_MJ_PNP operations
6  * PROGRAMMERS: Copyright 2005 Eric Kohl (ekohl@abo.rhein-zeitung.de)
7  *              Copyright 2005 Art Yerkes
8  *              Copyright 2005-2006 Herv� Poussineau (hpoussin@reactos.org)
9  */
10 
11 #include "green.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 #define ESC       ((UCHAR)0x1b)
17 
18 /* Force a move of the cursor on each printer char.
19  * Very useful for debug, but it is very slow...
20  */
21 //#define FORCE_POSITION
22 
23 /* UCHAR is promoted to int when passed through '...',
24  * so we get int with va_arg and cast them back to UCHAR.
25  */
26 static VOID
AddToSendBuffer(IN PSCREEN_DEVICE_EXTENSION DeviceExtension,IN ULONG NumberOfChars,...)27 AddToSendBuffer(
28 	IN PSCREEN_DEVICE_EXTENSION DeviceExtension,
29 	IN ULONG NumberOfChars,
30 	... /* IN int */)
31 {
32 	PIRP Irp;
33 	IO_STATUS_BLOCK ioStatus;
34 	va_list args;
35 	PDEVICE_OBJECT SerialDevice;
36 	ULONG SizeLeft;
37 	int CurrentInt;
38 	UCHAR CurrentChar;
39 	NTSTATUS Status;
40 	LARGE_INTEGER ZeroOffset;
41 
42 	ZeroOffset.QuadPart = 0;
43 
44 	SizeLeft = sizeof(DeviceExtension->SendBuffer) - DeviceExtension->SendBufferPosition;
45 	if (SizeLeft < NumberOfChars * 2 || NumberOfChars == 0)
46 	{
47 		SerialDevice = ((PGREEN_DEVICE_EXTENSION)DeviceExtension->Green->DeviceExtension)->Serial;
48 		Irp = IoBuildSynchronousFsdRequest(
49 			IRP_MJ_WRITE,
50 			SerialDevice,
51 			DeviceExtension->SendBuffer, DeviceExtension->SendBufferPosition,
52 			&ZeroOffset,
53 			NULL, /* Event */
54 			&ioStatus);
55 		if (!Irp)
56 		{
57 			DPRINT1("IoBuildSynchronousFsdRequest() failed. Unable to flush output buffer\n");
58 			return;
59 		}
60 
61 		Status = IoCallDriver(SerialDevice, Irp);
62 
63 		if (!NT_SUCCESS(Status) && Status != STATUS_PENDING)
64 		{
65 			DPRINT1("IoCallDriver() failed. Status = 0x%08lx\n", Status);
66 			return;
67 		}
68 		DeviceExtension->SendBufferPosition = 0;
69 		SizeLeft = sizeof(DeviceExtension->SendBuffer);
70 	}
71 
72 	va_start(args, NumberOfChars);
73 	while (NumberOfChars-- > 0)
74 	{
75 		CurrentInt = va_arg(args, int);
76 
77 		if (CurrentInt > 0)
78 		{
79 			CurrentChar = (UCHAR)CurrentInt;
80 
81 			/* Why 0xff chars are printed on a 'dir' ? */
82 			if (CurrentChar == 0xff) CurrentChar = ' ';
83 
84 			DeviceExtension->SendBuffer[DeviceExtension->SendBufferPosition++] = CurrentChar;
85 			SizeLeft--;
86 		}
87 		else if (CurrentInt == 0)
88 		{
89 			DeviceExtension->SendBuffer[DeviceExtension->SendBufferPosition++] = '0';
90 			SizeLeft--;
91 		}
92 		else
93 		{
94 			CurrentInt = -CurrentInt;
95 			ASSERT(CurrentInt < 100);
96 			if (CurrentInt >= 10)
97 			{
98 				DeviceExtension->SendBuffer[DeviceExtension->SendBufferPosition++] =
99 					(CurrentInt / 10) % 10 + '0';
100 				SizeLeft--;
101 			}
102 			DeviceExtension->SendBuffer[DeviceExtension->SendBufferPosition++] =
103 				CurrentInt % 10 + '0';
104 			SizeLeft--;
105 		}
106 	}
107 	va_end(args);
108 }
109 
110 NTSTATUS
ScreenAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT Pdo)111 ScreenAddDevice(
112 	IN PDRIVER_OBJECT DriverObject,
113 	IN PDEVICE_OBJECT Pdo)
114 {
115 	/* We want to be an upper filter of Blue, if it is existing.
116 	 * We also *have to* create a Fdo on top of the given Pdo.
117 	 * Hence, we have 2 cases:
118 	 * - Blue doesn't exist -> Create a unique Fdo (named Blue) at
119 	 *   the top of the given Pdo
120 	 * - Blue does exist -> Create a Fdo at the top of the existing
121 	 *   DO, and create a "pass to Green" FDO at the top of the Pdo
122 	 */
123 	PDEVICE_OBJECT Fdo = NULL;
124 	PDEVICE_OBJECT PassThroughFdo = NULL;
125 	PDEVICE_OBJECT LowerDevice = NULL;
126 	PDEVICE_OBJECT PreviousBlue = NULL;
127 	PSCREEN_DEVICE_EXTENSION DeviceExtension = NULL;
128 	UNICODE_STRING BlueScreenName = RTL_CONSTANT_STRING(L"\\Device\\BlueScreen");
129 	NTSTATUS Status;
130 
131 	DPRINT("ScreenInitialize() called\n");
132 
133 	/* Try to create a unique Fdo */
134 	Status = IoCreateDevice(
135 		DriverObject,
136 		sizeof(SCREEN_DEVICE_EXTENSION),
137 		&BlueScreenName,
138 		FILE_DEVICE_SCREEN,
139 		FILE_DEVICE_SECURE_OPEN,
140 		TRUE,
141 		&Fdo);
142 
143 	if (Status == STATUS_OBJECT_NAME_COLLISION)
144 	{
145 		DPRINT("Attaching to old blue\n");
146 
147 		/* Suggested by hpoussin .. Hide previous blue device
148 		 * This makes us able to coexist with blue, and install
149 		 * when loaded */
150 		Status = IoCreateDevice(
151 			DriverObject,
152 			sizeof(SCREEN_DEVICE_EXTENSION),
153 			NULL,
154 			FILE_DEVICE_SCREEN,
155 			FILE_DEVICE_SECURE_OPEN,
156 			TRUE,
157 			&Fdo);
158 		if (!NT_SUCCESS(Status))
159 		{
160 			DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
161 			goto cleanup;
162 		}
163 
164 		/* Initialize some fields, as IoAttachDevice will trigger the
165 		 * sending of IRP_MJ_CLEANUP/IRP_MJ_CLOSE. We have to know where to
166 		 * dispatch these IRPs... */
167 		((PSCREEN_DEVICE_EXTENSION)Fdo->DeviceExtension)->Common.Type = ScreenPDO;
168 		Status = IoAttachDevice(
169 			Fdo,
170 			&BlueScreenName,
171 			&LowerDevice);
172 		if (!NT_SUCCESS(Status))
173 		{
174 			DPRINT("IoAttachDevice() failed with status 0x%08lx\n", Status);
175 			goto cleanup;
176 		}
177 		PreviousBlue = LowerDevice;
178 
179 		/* Attach a faked FDO to PDO */
180 		Status = IoCreateDevice(
181 			DriverObject,
182 			sizeof(COMMON_FDO_DEVICE_EXTENSION),
183 			NULL,
184 			FILE_DEVICE_SCREEN,
185 			FILE_DEVICE_SECURE_OPEN,
186 			TRUE,
187 			&PassThroughFdo);
188 		if (!NT_SUCCESS(Status))
189 		{
190 			DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
191 			goto cleanup;
192 		}
193 		((PCOMMON_FDO_DEVICE_EXTENSION)PassThroughFdo->DeviceExtension)->Type = PassThroughFDO;
194 		((PCOMMON_FDO_DEVICE_EXTENSION)PassThroughFdo->DeviceExtension)->LowerDevice = Fdo;
195 		PassThroughFdo->StackSize = Fdo->StackSize + 1;
196 	}
197 	else if (NT_SUCCESS(Status))
198 	{
199 		/* Attach the named Fdo on top of Pdo */
200 		LowerDevice = IoAttachDeviceToDeviceStack(Fdo, Pdo);
201 	}
202 	else
203 	{
204 		DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
205 		return Status;
206 	}
207 
208 	/* We definately have a device object. PreviousBlue may or may
209 	 * not be null */
210 	DeviceExtension = (PSCREEN_DEVICE_EXTENSION)Fdo->DeviceExtension;
211 	RtlZeroMemory(DeviceExtension, sizeof(SCREEN_DEVICE_EXTENSION));
212 	DeviceExtension->Common.Type = ScreenFDO;
213 	DeviceExtension->Common.LowerDevice = LowerDevice;
214 	DeviceExtension->Green = ((PGREEN_DRIVER_EXTENSION)IoGetDriverObjectExtension(DriverObject, DriverObject))->GreenMainDO;
215 	((PGREEN_DEVICE_EXTENSION)DeviceExtension->Green->DeviceExtension)->ScreenFdo = Fdo;
216 	DeviceExtension->PreviousBlue = PreviousBlue;
217 	IoAttachDeviceToDeviceStack(PassThroughFdo ? PassThroughFdo : Fdo, Pdo);
218 
219 	/* initialize screen */
220 	DeviceExtension->Columns = 80;
221 	DeviceExtension->Rows = 25;
222 	DeviceExtension->ScanLines = 16;
223 	DeviceExtension->VideoMemory = (PUCHAR)ExAllocatePool(
224 		PagedPool,
225 		2 * DeviceExtension->Columns * DeviceExtension->Rows * sizeof(UCHAR));
226 	if (!DeviceExtension->VideoMemory)
227 	{
228 		DPRINT("ExAllocatePool() failed\n");
229 		Status = STATUS_INSUFFICIENT_RESOURCES;
230 		goto cleanup;
231 	}
232 	DeviceExtension->TabWidth = 8;
233 
234 	/* more initialization */
235 	DeviceExtension->Mode = ENABLE_PROCESSED_OUTPUT |
236 		ENABLE_WRAP_AT_EOL_OUTPUT;
237 
238 	/* initialize screen at next write */
239 	AddToSendBuffer(DeviceExtension, 2, ESC, 'c'); /* reset device */
240 	AddToSendBuffer(DeviceExtension, 4, ESC, '[', '7', 'l'); /* disable line wrap */
241 	AddToSendBuffer(DeviceExtension, 4, ESC, '[', '3', 'g'); /* clear all tabs */
242 
243 	Fdo->Flags |= DO_POWER_PAGABLE;
244 	Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
245 
246 	Status = STATUS_SUCCESS;
247 
248 cleanup:
249 	if (!NT_SUCCESS(Status))
250 	{
251 		if (DeviceExtension)
252 			ExFreePool(DeviceExtension->VideoMemory);
253 		if (LowerDevice)
254 			IoDetachDevice(LowerDevice);
255 		if (Fdo)
256 			IoDeleteDevice(Fdo);
257 		if (PassThroughFdo)
258 			IoDeleteDevice(PassThroughFdo);
259 	}
260 
261 	return Status;
262 }
263 
264 NTSTATUS
ScreenWrite(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)265 ScreenWrite(
266 	IN PDEVICE_OBJECT DeviceObject,
267 	IN PIRP Irp)
268 {
269 	PIO_STACK_LOCATION Stack;
270 	PUCHAR Buffer;
271 	PSCREEN_DEVICE_EXTENSION DeviceExtension;
272 	PDEVICE_OBJECT SerialDevice;
273 	PUCHAR VideoMemory; /* FIXME: is it useful? */
274 	ULONG VideoMemorySize; /* FIXME: is it useful? */
275 
276 	ULONG Columns, Rows;
277 	ULONG CursorX, CursorY;
278 	ULONG i, j;
279 	DBG_UNREFERENCED_LOCAL_VARIABLE(VideoMemory);
280 	DBG_UNREFERENCED_LOCAL_VARIABLE(VideoMemorySize);
281 
282 	DPRINT("ScreenWrite() called\n");
283 
284 	Stack = IoGetCurrentIrpStackLocation (Irp);
285 	Buffer = Irp->UserBuffer;
286 	DeviceExtension = (PSCREEN_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
287 	VideoMemory = DeviceExtension->VideoMemory;
288 
289 	SerialDevice = ((PGREEN_DEVICE_EXTENSION)DeviceExtension->Green->DeviceExtension)->Serial;
290 	if (!SerialDevice)
291 	{
292 		DPRINT1("Calling blue\n");
293 		IoSkipCurrentIrpStackLocation(Irp);
294 		return IoCallDriver(DeviceExtension->PreviousBlue, Irp);
295 	}
296 
297 	Columns = DeviceExtension->Columns;
298 	Rows = DeviceExtension->Rows;
299 	CursorX = (DeviceExtension->LogicalOffset / 2) % Columns + 1;
300 	CursorY = (DeviceExtension->LogicalOffset / 2) / Columns + 1;
301 	VideoMemorySize = Columns * Rows * 2 * sizeof(UCHAR);
302 
303 	if (!(DeviceExtension->Mode & ENABLE_PROCESSED_OUTPUT))
304 	{
305 		/* raw output mode */
306 		Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
307 		IoCompleteRequest (Irp, IO_NO_INCREMENT);
308 
309 		return STATUS_NOT_SUPPORTED;
310 	}
311 	else
312 	{
313 		for (i = 0; i < Stack->Parameters.Write.Length; i++, Buffer++)
314 		{
315 			switch (*Buffer)
316 			{
317 				case '\b':
318 				{
319 					if (CursorX > 1)
320 					{
321 						CursorX--;
322 						AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', -(int)CursorX, 'H');
323 						AddToSendBuffer(DeviceExtension, 1, ' ');
324 						AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', -(int)CursorX, 'H');
325 					}
326 					else if (CursorY > 1)
327 					{
328 						CursorX = Columns;
329 						CursorY--;
330 						AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', -(int)CursorX, 'H');
331 					}
332 					break;
333 				}
334 				case '\n':
335 				{
336 					CursorY++;
337 					CursorX = 1;
338 					AddToSendBuffer(DeviceExtension, 1, '\n');
339 					AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', '1', 'H');
340 					break;
341 				}
342 				case '\r':
343 				{
344 					if (CursorX > 1)
345 					{
346 						AddToSendBuffer(DeviceExtension, 4, ESC, '[', -(int)(CursorX-1), 'D');
347 						CursorX = 1;
348 					}
349 					break;
350 				}
351 				case '\t':
352 				{
353 					ULONG Offset = DeviceExtension->TabWidth - (CursorX % DeviceExtension->TabWidth);
354 					for (j = 0; j < Offset; j++)
355 					{
356 #ifdef FORCE_POSITION
357 						AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', -(int)CursorX, 'H');
358 #endif
359 						AddToSendBuffer(DeviceExtension, 1, ' ');
360 						CursorX++;
361 						if (CursorX > Columns)
362 						{
363 							CursorX = 1;
364 							CursorY++;
365 						}
366 					}
367 					break;
368 				}
369 				default:
370 				{
371 #ifdef FORCE_POSITION
372 					AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', -(int)CursorX, 'H');
373 #endif
374 					AddToSendBuffer(DeviceExtension, 1, *Buffer);
375 					CursorX++;
376 					if (CursorX > Columns)
377 					{
378 						CursorX = 1;
379 						DPRINT("Y: %lu -> %lu\n", CursorY, CursorY + 1);
380 						CursorY++;
381 						AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', '1', 'H');
382 
383 					}
384 				}
385 			}
386 			if (CursorY >= Rows)
387 			{
388 				DPRINT("Y: %lu -> %lu\n", CursorY, CursorY - 1);
389 				CursorY--;
390 				AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)1, ';', -(int)(Rows), 'r');
391 				AddToSendBuffer(DeviceExtension, 2, ESC, 'D');
392 				AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', -(int)CursorX, 'H');
393 			}
394 		}
395 	}
396 
397 	DeviceExtension->LogicalOffset = ((CursorX-1) + (CursorY-1) * Columns) * 2;
398 
399 	/* flush output buffer */
400 	AddToSendBuffer(DeviceExtension, 0);
401 
402 	/* Call lower driver */
403 	IoSkipCurrentIrpStackLocation(Irp);
404 	return IoCallDriver(DeviceExtension->Common.LowerDevice, Irp);
405 }
406 
407 NTSTATUS
ScreenDeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)408 ScreenDeviceControl(
409 	IN PDEVICE_OBJECT DeviceObject,
410 	IN PIRP Irp)
411 {
412 	PIO_STACK_LOCATION Stack;
413 	PSCREEN_DEVICE_EXTENSION DeviceExtension;
414 	PDEVICE_OBJECT SerialDevice;
415 	NTSTATUS Status;
416 
417 	Stack = IoGetCurrentIrpStackLocation(Irp);
418 	DeviceExtension = (PSCREEN_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
419 	SerialDevice = ((PGREEN_DEVICE_EXTENSION)DeviceExtension->Green->DeviceExtension)->Serial;
420 	if (!SerialDevice)
421 	{
422 		DPRINT1("Calling blue\n");
423 		IoSkipCurrentIrpStackLocation(Irp);
424 		return IoCallDriver(DeviceExtension->PreviousBlue, Irp);
425 	}
426 
427 	switch (Stack->Parameters.DeviceIoControl.IoControlCode)
428 	{
429 #if 0
430 		case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO:
431 		{
432 			PCONSOLE_SCREEN_BUFFER_INFO pcsbi;
433 			DPRINT("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO\n");
434 
435 			pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
436 
437 			pcsbi->dwSize.X = DeviceExtension->Columns;
438 			pcsbi->dwSize.Y = DeviceExtension->Rows;
439 
440 			pcsbi->dwCursorPosition.X = (SHORT)(DeviceExtension->LogicalOffset % DeviceExtension->Columns);
441 			pcsbi->dwCursorPosition.Y = (SHORT)(DeviceExtension->LogicalOffset / DeviceExtension->Columns);
442 
443 			pcsbi->wAttributes = DeviceExtension->CharAttribute;
444 
445 			pcsbi->srWindow.Left   = 1;
446 			pcsbi->srWindow.Right  = DeviceExtension->Columns;
447 			pcsbi->srWindow.Top    = 1;
448 			pcsbi->srWindow.Bottom = DeviceExtension->Rows;
449 
450 			pcsbi->dwMaximumWindowSize.X = DeviceExtension->Columns;
451 			pcsbi->dwMaximumWindowSize.Y = DeviceExtension->Rows;
452 
453 			Irp->IoStatus.Information = sizeof(CONSOLE_SCREEN_BUFFER_INFO);
454 			Status = STATUS_SUCCESS;
455 			break;
456 		}
457 		case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO:
458 		{
459 			PCONSOLE_SCREEN_BUFFER_INFO pcsbi;
460 			DPRINT("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO\n");
461 
462 			pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
463 			/* FIXME: remove */ { pcsbi->dwCursorPosition.X++; }
464 			/* FIXME: remove */ { pcsbi->dwCursorPosition.Y++; }
465 			ASSERT(pcsbi->dwCursorPosition.X >= 1);
466 			ASSERT(pcsbi->dwCursorPosition.Y >= 1);
467 			ASSERT(pcsbi->dwCursorPosition.X <= DeviceExtension->Columns);
468 			ASSERT(pcsbi->dwCursorPosition.Y <= DeviceExtension->Rows);
469 
470 			DeviceExtension->LogicalOffset = (
471 				(pcsbi->dwCursorPosition.Y-1) * DeviceExtension->Columns +
472 				(pcsbi->dwCursorPosition.X-1)) * 2;
473 			AddToSendBuffer(DeviceExtension, 6, ESC, '[',
474 				-(int)pcsbi->dwCursorPosition.Y, ';',
475 				-(int)pcsbi->dwCursorPosition.X, 'H');
476 
477 			/* flush buffer */
478 			AddToSendBuffer(DeviceExtension, 0);
479 
480 			DeviceExtension->CharAttribute = pcsbi->wAttributes;
481 
482 			Irp->IoStatus.Information = 0;
483 			Status = STATUS_SUCCESS;
484 			break;
485 		}
486 		case IOCTL_CONSOLE_GET_CURSOR_INFO:
487 		{
488 			PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
489 			DPRINT("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_GET_CURSOR_INFO\n");
490 
491 			pcci->dwSize = 1;
492 			pcci->bVisible = TRUE;
493 
494 			Irp->IoStatus.Information = sizeof (CONSOLE_CURSOR_INFO);
495 			Status = STATUS_SUCCESS;
496 			break;
497 		}
498 		case IOCTL_CONSOLE_GET_MODE:
499 		{
500 			PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
501 			DPRINT("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_GET_MODE\n");
502 
503 			pcm->dwMode = DeviceExtension->Mode;
504 
505 			Irp->IoStatus.Information = sizeof(CONSOLE_MODE);
506 			Status = STATUS_SUCCESS;
507 			break;
508 		}
509 		case IOCTL_CONSOLE_SET_MODE:
510 		{
511 			PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
512 			DPRINT("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_SET_MODE\n");
513 
514 			DeviceExtension->Mode = pcm->dwMode;
515 
516 			Irp->IoStatus.Information = 0;
517 			Status = STATUS_SUCCESS;
518 			break;
519 		}
520 		case IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE:
521 		{
522 			DPRINT1("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE\n");
523 			Status = STATUS_NOT_IMPLEMENTED; /* FIXME: IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE */
524 			break;
525 		}
526 		case IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE:
527 		{
528 			DPRINT1("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE\n");
529 			Status = STATUS_NOT_IMPLEMENTED; /* FIXME: IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE */
530 			break;
531 		}
532 		case IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE:
533 		{
534 			DPRINT1("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE\n");
535 			Status = STATUS_NOT_IMPLEMENTED; /* FIXME: IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE */
536 			break;
537 		}
538 		case IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE:
539 		{
540 			DPRINT("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE\n");
541 
542 			DeviceExtension->CharAttribute = (WORD)*(PWORD)Irp->AssociatedIrp.SystemBuffer;
543 			Irp->IoStatus.Information = 0;
544 			Status = STATUS_SUCCESS;
545 			break;
546 		}
547 		case IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER:
548 		{
549 			DPRINT1("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER\n");
550 			Status = STATUS_NOT_IMPLEMENTED; /* FIXME:IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER */
551 			break;
552 		}
553 		case IOCTL_CONSOLE_READ_OUTPUT_CHARACTER:
554 		{
555 			DPRINT1("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_READ_OUTPUT_CHARACTER\n");
556 			Status = STATUS_NOT_IMPLEMENTED; /* FIXME: IOCTL_CONSOLE_READ_OUTPUT_CHARACTER */
557 			break;
558 		}
559 		case IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER:
560 		{
561 			DPRINT1("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER\n");
562 			Status = STATUS_NOT_IMPLEMENTED; /* FIXME: IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER */
563 			break;
564 		}
565 		case IOCTL_CONSOLE_DRAW:
566 		{
567 			PCONSOLE_DRAW ConsoleDraw;
568 			PUCHAR Video;
569 			ULONG x, y;
570 			BOOLEAN DoOptimization = FALSE;
571 			DPRINT("IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_DRAW\n");
572 
573 			ConsoleDraw = (PCONSOLE_DRAW)MmGetSystemAddressForMdl(Irp->MdlAddress);
574 			/* FIXME: remove */ { ConsoleDraw->X++; ConsoleDraw->CursorX++; }
575 			/* FIXME: remove */ { ConsoleDraw->Y++; ConsoleDraw->CursorY++; }
576 			DPRINT1("%lu %lu %lu %lu\n",
577 				ConsoleDraw->X, ConsoleDraw->Y,
578 				ConsoleDraw->SizeX, ConsoleDraw->SizeY);
579 			ASSERT(ConsoleDraw->X >= 1);
580 			ASSERT(ConsoleDraw->Y >= 1);
581 			ASSERT(ConsoleDraw->X <= DeviceExtension->Columns);
582 			ASSERT(ConsoleDraw->Y <= DeviceExtension->Rows);
583 			ASSERT(ConsoleDraw->X + ConsoleDraw->SizeX >= 1);
584 			ASSERT(ConsoleDraw->Y + ConsoleDraw->SizeY >= 1);
585 			ASSERT(ConsoleDraw->X + ConsoleDraw->SizeX - 1 <= DeviceExtension->Columns);
586 			ASSERT(ConsoleDraw->Y + ConsoleDraw->SizeY - 1 <= DeviceExtension->Rows);
587 			ASSERT(ConsoleDraw->CursorX >= 1);
588 			ASSERT(ConsoleDraw->CursorY >= 1);
589 			ASSERT(ConsoleDraw->CursorX <= DeviceExtension->Columns);
590 			ASSERT(ConsoleDraw->CursorY <= DeviceExtension->Rows);
591 
592 #if 0
593 			if (ConsoleDraw->X == 1
594 				&& ConsoleDraw->Y == 1
595 				&& ConsoleDraw->SizeX == DeviceExtension->Columns
596 				&& ConsoleDraw->SizeY == DeviceExtension->Rows)
597 			{
598 				/* search if we need to clear all screen */
599 				DoOptimization = TRUE;
600 				Video = (PUCHAR)(ConsoleDraw + 1);
601 				x = 0;
602 				while (DoOptimization && x < DeviceExtension->Columns * DeviceExtension->Rows)
603 				{
604 					if (Video[x++] != ' ')
605 					{
606 						DoOptimization = FALSE;
607 					}
608 					/*if (Video[x++] != DeviceExtension->CharAttribute) DoOptimization = FALSE; */
609 				}
610 				if (DoOptimization)
611 				{
612 					AddToSendBuffer(DeviceExtension, 4, ESC, '[', '2', 'J');
613 				}
614 			}
615 #endif
616 			/* add here more optimizations if needed */
617 
618 			if (!DoOptimization)
619 			{
620 				for (y = 0; y < ConsoleDraw->SizeY; y++)
621 				{
622 					AddToSendBuffer(DeviceExtension, 6, ESC, '[',
623 						-(int)(ConsoleDraw->Y + y), ';',
624 						-(int)(ConsoleDraw->X), 'H');
625 					Video = (PUCHAR)(ConsoleDraw + 1);
626 					Video = &Video[((ConsoleDraw->Y + y) * /*DeviceExtension->Columns +*/ ConsoleDraw->X) * 2];
627 					for (x = 0; x < ConsoleDraw->SizeX; x++)
628 					{
629 						AddToSendBuffer(DeviceExtension, 1, Video[x * 2]);
630 					}
631 				}
632 			}
633 
634 			DeviceExtension->LogicalOffset = (
635 				(ConsoleDraw->CursorY-1) * DeviceExtension->Columns +
636 				(ConsoleDraw->CursorX-1)) * 2;
637 			AddToSendBuffer(DeviceExtension, 6, ESC, '[',
638 				-(int)(ConsoleDraw->CursorY), ';',
639 				-(int)(ConsoleDraw->CursorX), 'H');
640 
641 			/* flush buffer */
642 			AddToSendBuffer(DeviceExtension, 0);
643 
644 			Irp->IoStatus.Information = 0;
645 			Status = STATUS_SUCCESS;
646 			break;
647 		}
648 #endif
649 		default:
650 		{
651 			DPRINT1("IRP_MJ_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
652 				Stack->Parameters.DeviceIoControl.IoControlCode);
653 			/* Call lower driver */
654 			IoSkipCurrentIrpStackLocation(Irp);
655 			return IoCallDriver(DeviceExtension->Common.LowerDevice, Irp);
656 		}
657 	}
658 
659 	if (!NT_SUCCESS(Status))
660 	{
661 		/* Don't call blue (if any), as we encountered an error */
662 		Irp->IoStatus.Status = Status;
663 		IoCompleteRequest(Irp, IO_NO_INCREMENT);
664 		return Status;
665 	}
666 	else
667 	{
668 		/* Call lower driver */
669 		IoSkipCurrentIrpStackLocation(Irp);
670 		return IoCallDriver(DeviceExtension->Common.LowerDevice, Irp);
671 	}
672 }
673