[ROSAPPS]
[reactos.git] / rosapps / drivers / green / screen.c
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
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
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
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
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 }