xref: /reactos/drivers/setup/blue/blue.c (revision cc439606)
1 /*
2  * COPYRIGHT:            See COPYING in the top level directory
3  * PROJECT:              ReactOS kernel
4  * FILE:                 services/dd/blue/blue.c
5  * PURPOSE:              Console (blue screen) device driver
6  * PROGRAMMER:           Eric Kohl
7  * UPDATE HISTORY:
8  *                       ??? Created
9  */
10 
11 /* INCLUDES ******************************************************************/
12 
13 #include "blue.h"
14 
15 #define NDEBUG
16 #include <debug.h>
17 
18 // ROS Internal. Please deprecate.
19 NTHALAPI
20 BOOLEAN
21 NTAPI
22 HalQueryDisplayOwnership(
23     VOID
24 );
25 
26 /* NOTES ******************************************************************/
27 /*
28  *  [[character][attribute]][[character][attribute]]....
29  */
30 
31 
32 /* TYPEDEFS ***************************************************************/
33 
34 typedef struct _DEVICE_EXTENSION
35 {
36     PUCHAR VideoMemory;    /* Pointer to video memory */
37     ULONG CursorSize;
38     INT  CursorVisible;
39     USHORT  CharAttribute;
40     ULONG Mode;
41     UCHAR  ScanLines;      /* Height of a text line */
42     USHORT  Rows;           /* Number of rows        */
43     USHORT  Columns;        /* Number of columns     */
44 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
45 
46 typedef struct _VGA_REGISTERS
47 {
48    UCHAR CRT[24];
49    UCHAR Attribute[21];
50    UCHAR Graphics[9];
51    UCHAR Sequencer[5];
52    UCHAR Misc;
53 } VGA_REGISTERS, *PVGA_REGISTERS;
54 
55 static const VGA_REGISTERS VidpMode3Regs =
56 {
57    /* CRT Controller Registers */
58    {0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F, 0x00, 0x47, 0x1E, 0x00,
59     0x00, 0x00, 0x05, 0xF0, 0x9C, 0x8E, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3},
60    /* Attribute Controller Registers */
61    {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B,
62     0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x08, 0x00},
63    /* Graphics Controller Registers */
64    {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00, 0xFF},
65    /* Sequencer Registers */
66    {0x03, 0x00, 0x03, 0x00, 0x02},
67    /* Misc Output Register */
68    0x67
69 };
70 
71 static const UCHAR DefaultPalette[] =
72 {
73    0, 0, 0,
74    0, 0, 0xC0,
75    0, 0xC0, 0,
76    0, 0xC0, 0xC0,
77    0xC0, 0, 0,
78    0xC0, 0, 0xC0,
79    0xC0, 0xC0, 0,
80    0xC0, 0xC0, 0xC0,
81    0x80, 0x80, 0x80,
82    0, 0, 0xFF,
83    0, 0xFF, 0,
84    0, 0xFF, 0xFF,
85    0xFF, 0, 0,
86    0xFF, 0, 0xFF,
87    0xFF, 0xFF, 0,
88    0xFF, 0xFF, 0xFF
89 };
90 
91 /* FUNCTIONS **************************************************************/
92 
93 static VOID FASTCALL
94 ScrSetRegisters(const VGA_REGISTERS *Registers)
95 {
96     UINT32 i;
97 
98     /* Update misc output register */
99     WRITE_PORT_UCHAR(MISC, Registers->Misc);
100 
101     /* Synchronous reset on */
102     WRITE_PORT_UCHAR(SEQ, 0x00);
103     WRITE_PORT_UCHAR(SEQDATA, 0x01);
104 
105     /* Write sequencer registers */
106     for (i = 1; i < sizeof(Registers->Sequencer); i++)
107 {
108         WRITE_PORT_UCHAR(SEQ, i);
109         WRITE_PORT_UCHAR(SEQDATA, Registers->Sequencer[i]);
110     }
111 
112     /* Synchronous reset off */
113     WRITE_PORT_UCHAR(SEQ, 0x00);
114     WRITE_PORT_UCHAR(SEQDATA, 0x03);
115 
116     /* Deprotect CRT registers 0-7 */
117     WRITE_PORT_UCHAR(CRTC, 0x11);
118     WRITE_PORT_UCHAR(CRTCDATA, Registers->CRT[0x11] & 0x7f);
119 
120     /* Write CRT registers */
121     for (i = 0; i < sizeof(Registers->CRT); i++)
122     {
123         WRITE_PORT_UCHAR(CRTC, i);
124         WRITE_PORT_UCHAR(CRTCDATA, Registers->CRT[i]);
125     }
126 
127     /* Write graphics controller registers */
128     for (i = 0; i < sizeof(Registers->Graphics); i++)
129     {
130         WRITE_PORT_UCHAR(GRAPHICS, i);
131         WRITE_PORT_UCHAR(GRAPHICSDATA, Registers->Graphics[i]);
132     }
133 
134     /* Write attribute controller registers */
135     for (i = 0; i < sizeof(Registers->Attribute); i++)
136     {
137         READ_PORT_UCHAR(STATUS);
138         WRITE_PORT_UCHAR(ATTRIB, i);
139         WRITE_PORT_UCHAR(ATTRIB, Registers->Attribute[i]);
140     }
141 
142     /* Set the PEL mask. */
143     WRITE_PORT_UCHAR(PELMASK, 0xff);
144 }
145 
146 static VOID FASTCALL
147 ScrAcquireOwnership(PDEVICE_EXTENSION DeviceExtension)
148 {
149     unsigned int offset;
150     UCHAR data, value;
151     ULONG Index;
152 
153     ScrSetRegisters(&VidpMode3Regs);
154 
155     /* Disable screen and enable palette access. */
156     READ_PORT_UCHAR(STATUS);
157     WRITE_PORT_UCHAR(ATTRIB, 0x00);
158 
159     for (Index = 0; Index < sizeof(DefaultPalette) / 3; Index++)
160     {
161        WRITE_PORT_UCHAR(PELINDEX, Index);
162        WRITE_PORT_UCHAR(PELDATA, DefaultPalette[Index * 3] >> 2);
163        WRITE_PORT_UCHAR(PELDATA, DefaultPalette[Index * 3 + 1] >> 2);
164        WRITE_PORT_UCHAR(PELDATA, DefaultPalette[Index * 3 + 2] >> 2);
165     }
166 
167     /* Enable screen and disable palette access. */
168     READ_PORT_UCHAR(STATUS);
169     WRITE_PORT_UCHAR(ATTRIB, 0x20);
170 
171     /* get current output position */
172     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
173     offset = READ_PORT_UCHAR (CRTC_DATA);
174     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
175     offset += (READ_PORT_UCHAR (CRTC_DATA) << 8);
176 
177     /* switch blinking characters off */
178     READ_PORT_UCHAR (ATTRC_INPST1);
179     value = READ_PORT_UCHAR (ATTRC_WRITEREG);
180     WRITE_PORT_UCHAR (ATTRC_WRITEREG, 0x10);
181     data  = READ_PORT_UCHAR (ATTRC_READREG);
182     data  = data & ~0x08;
183     WRITE_PORT_UCHAR (ATTRC_WRITEREG, data);
184     WRITE_PORT_UCHAR (ATTRC_WRITEREG, value);
185     READ_PORT_UCHAR (ATTRC_INPST1);
186 
187     /* read screen information from crt controller */
188     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_COLUMNS);
189     DeviceExtension->Columns = READ_PORT_UCHAR (CRTC_DATA) + 1;
190     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_ROWS);
191     DeviceExtension->Rows = READ_PORT_UCHAR (CRTC_DATA);
192     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_OVERFLOW);
193     data = READ_PORT_UCHAR (CRTC_DATA);
194     DeviceExtension->Rows |= (((data & 0x02) << 7) | ((data & 0x40) << 3));
195     DeviceExtension->Rows++;
196     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_SCANLINES);
197     DeviceExtension->ScanLines = (READ_PORT_UCHAR (CRTC_DATA) & 0x1F) + 1;
198 
199     /* show blinking cursor */
200     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORSTART);
201     WRITE_PORT_UCHAR (CRTC_DATA, (DeviceExtension->ScanLines - 1) & 0x1F);
202     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSOREND);
203     data = READ_PORT_UCHAR (CRTC_DATA) & 0xE0;
204     WRITE_PORT_UCHAR (CRTC_DATA,
205                       data | ((DeviceExtension->ScanLines - 1) & 0x1F));
206 
207     /* calculate number of text rows */
208     DeviceExtension->Rows =
209         DeviceExtension->Rows / DeviceExtension->ScanLines;
210 #ifdef BOCHS_30ROWS
211     DeviceExtension->Rows = 30;
212 #endif
213 
214     DPRINT ("%d Columns  %d Rows %d Scanlines\n",
215             DeviceExtension->Columns,
216             DeviceExtension->Rows,
217             DeviceExtension->ScanLines);
218 }
219 
220 NTSTATUS NTAPI
221 DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
222 
223 static DRIVER_DISPATCH ScrCreate;
224 static NTSTATUS NTAPI
225 ScrCreate(PDEVICE_OBJECT DeviceObject,
226       PIRP Irp)
227 {
228     PDEVICE_EXTENSION DeviceExtension;
229     PHYSICAL_ADDRESS BaseAddress;
230     NTSTATUS Status;
231 
232     DeviceExtension = DeviceObject->DeviceExtension;
233 
234     if (!InbvCheckDisplayOwnership())
235     {
236         ScrAcquireOwnership(DeviceExtension);
237 
238         /* get pointer to video memory */
239         BaseAddress.QuadPart = VIDMEM_BASE;
240         DeviceExtension->VideoMemory =
241             (PUCHAR)MmMapIoSpace (BaseAddress, DeviceExtension->Rows * DeviceExtension->Columns * 2, MmNonCached);
242     }
243     else
244     {
245         /* store dummy values here */
246         DeviceExtension->Columns = 1;
247         DeviceExtension->Rows = 1;
248         DeviceExtension->ScanLines = 1;
249     }
250 
251     DeviceExtension->CursorSize    = 5; /* FIXME: value correct?? */
252     DeviceExtension->CursorVisible = TRUE;
253 
254     /* more initialization */
255     DeviceExtension->CharAttribute = 0x17;  /* light grey on blue */
256     DeviceExtension->Mode = ENABLE_PROCESSED_OUTPUT |
257                             ENABLE_WRAP_AT_EOL_OUTPUT;
258 
259     Status = STATUS_SUCCESS;
260 
261     Irp->IoStatus.Status = Status;
262     IoCompleteRequest (Irp, IO_NO_INCREMENT);
263 
264     return (Status);
265 }
266 
267 static DRIVER_DISPATCH ScrWrite;
268 static NTSTATUS NTAPI
269 ScrWrite(PDEVICE_OBJECT DeviceObject,
270      PIRP Irp)
271 {
272     PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation (Irp);
273     PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
274     NTSTATUS Status;
275     char *pch = Irp->UserBuffer;
276     PUCHAR vidmem;
277     unsigned int i;
278     int j, offset;
279     int cursorx, cursory;
280     int rows, columns;
281     int processed = DeviceExtension->Mode & ENABLE_PROCESSED_OUTPUT;
282 
283     if (InbvCheckDisplayOwnership())
284     {
285         /* Display is in graphics mode, we're not allowed to touch it */
286         Status = STATUS_SUCCESS;
287 
288         Irp->IoStatus.Status = Status;
289         IoCompleteRequest (Irp, IO_NO_INCREMENT);
290 
291         return Status;
292     }
293 
294     vidmem  = DeviceExtension->VideoMemory;
295     rows = DeviceExtension->Rows;
296     columns = DeviceExtension->Columns;
297 
298     _disable();
299     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
300     offset = READ_PORT_UCHAR (CRTC_DATA)<<8;
301     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
302     offset += READ_PORT_UCHAR (CRTC_DATA);
303     _enable();
304 
305     cursory = offset / columns;
306     cursorx = offset % columns;
307     if( processed == 0 )
308        {
309       /* raw output mode */
310       // FIXME: Does the buffer only contains chars? or chars + attributes?
311       // FIXME2: Fix buffer overflow.
312       memcpy( &vidmem[(cursorx * 2) + (cursory * columns * 2)], pch, stk->Parameters.Write.Length );
313       offset += (stk->Parameters.Write.Length / 2);
314        }
315     else {
316       for (i = 0; i < stk->Parameters.Write.Length; i++, pch++)
317       {
318         switch (*pch)
319         {
320         case '\b':
321            if (cursorx > 0)
322               {
323              cursorx--;
324               }
325            else if (cursory > 0)
326               {
327              cursorx = columns - 1;
328              cursory--;
329               }
330            vidmem[(cursorx * 2) + (cursory * columns * 2)] = ' ';
331            vidmem[(cursorx * 2) + (cursory * columns * 2) + 1] = (char) DeviceExtension->CharAttribute;
332            break;
333 
334         case '\n':
335            cursory++;
336            cursorx = 0;
337            break;
338 
339         case '\r':
340            cursorx = 0;
341            break;
342 
343         case '\t':
344            offset = TAB_WIDTH - (cursorx % TAB_WIDTH);
345            for (j = 0; j < offset; j++)
346               {
347              vidmem[(cursorx * 2) + (cursory * columns * 2)] = ' ';
348              cursorx++;
349 
350              if (cursorx >= columns)
351                 {
352                    cursory++;
353                    cursorx = 0;
354                 }
355               }
356            break;
357 
358         default:
359            vidmem[(cursorx * 2) + (cursory * columns * 2)] = *pch;
360            vidmem[(cursorx * 2) + (cursory * columns * 2) + 1] = (char) DeviceExtension->CharAttribute;
361            cursorx++;
362            if (cursorx >= columns)
363               {
364              cursory++;
365              cursorx = 0;
366               }
367            break;
368         }
369 
370         /* Scroll up the contents of the screen if we are at the end */
371         if (cursory >= rows)
372         {
373            unsigned short *LinePtr;
374 
375            memcpy (vidmem,
376                &vidmem[columns * 2],
377                columns * (rows - 1) * 2);
378 
379            LinePtr = (unsigned short *) &vidmem[columns * (rows - 1) * 2];
380 
381            for (j = 0; j < columns; j++)
382               {
383              LinePtr[j] = DeviceExtension->CharAttribute << 8;
384               }
385            cursory = rows - 1;
386            for (j = 0; j < columns; j++)
387               {
388              vidmem[(j * 2) + (cursory * columns * 2)] = ' ';
389              vidmem[(j * 2) + (cursory * columns * 2) + 1] = (char)DeviceExtension->CharAttribute;
390               }
391         }
392       }
393 
394        /* Set the cursor position */
395        offset = (cursory * columns) + cursorx;
396     }
397     _disable();
398     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
399     WRITE_PORT_UCHAR (CRTC_DATA, offset);
400     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
401     offset >>= 8;
402     WRITE_PORT_UCHAR (CRTC_DATA, offset);
403     _enable();
404 
405     Status = STATUS_SUCCESS;
406 
407     Irp->IoStatus.Status = Status;
408     IoCompleteRequest (Irp, IO_NO_INCREMENT);
409 
410     return Status;
411 }
412 
413 static DRIVER_DISPATCH ScrIoControl;
414 static NTSTATUS NTAPI
415 ScrIoControl(PDEVICE_OBJECT DeviceObject,
416          PIRP Irp)
417 {
418   PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation (Irp);
419   PDEVICE_EXTENSION DeviceExtension;
420   NTSTATUS Status;
421 
422   DeviceExtension = DeviceObject->DeviceExtension;
423   switch (stk->Parameters.DeviceIoControl.IoControlCode)
424     {
425       case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO:
426         {
427           PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
428           int rows = DeviceExtension->Rows;
429           int columns = DeviceExtension->Columns;
430           unsigned int offset;
431 
432           if (!InbvCheckDisplayOwnership())
433           {
434             /* read cursor position from crtc */
435             _disable();
436             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
437             offset = READ_PORT_UCHAR (CRTC_DATA);
438             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
439             offset += (READ_PORT_UCHAR (CRTC_DATA) << 8);
440             _enable();
441           }
442           else
443           {
444             offset = 0;
445           }
446 
447           pcsbi->dwSize.X = columns;
448           pcsbi->dwSize.Y = rows;
449 
450           pcsbi->dwCursorPosition.X = (SHORT)(offset % columns);
451           pcsbi->dwCursorPosition.Y = (SHORT)(offset / columns);
452 
453           pcsbi->wAttributes = DeviceExtension->CharAttribute;
454 
455           pcsbi->srWindow.Left   = 0;
456           pcsbi->srWindow.Right  = columns - 1;
457           pcsbi->srWindow.Top    = 0;
458           pcsbi->srWindow.Bottom = rows - 1;
459 
460           pcsbi->dwMaximumWindowSize.X = columns;
461           pcsbi->dwMaximumWindowSize.Y = rows;
462 
463           Irp->IoStatus.Information = sizeof (CONSOLE_SCREEN_BUFFER_INFO);
464           Status = STATUS_SUCCESS;
465         }
466         break;
467 
468       case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO:
469         {
470           PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
471           unsigned int offset;
472 
473           if ( pcsbi->dwCursorPosition.X < 0 || pcsbi->dwCursorPosition.X >= DeviceExtension->Columns ||
474                pcsbi->dwCursorPosition.Y < 0 || pcsbi->dwCursorPosition.Y >= DeviceExtension->Rows )
475           {
476               Irp->IoStatus.Information = 0;
477               Status = STATUS_INVALID_PARAMETER;
478               break;
479           }
480 
481           DeviceExtension->CharAttribute = pcsbi->wAttributes;
482           offset = (pcsbi->dwCursorPosition.Y * DeviceExtension->Columns) +
483                     pcsbi->dwCursorPosition.X;
484 
485           if (!InbvCheckDisplayOwnership())
486           {
487             _disable();
488             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
489             WRITE_PORT_UCHAR (CRTC_DATA, offset);
490             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
491             WRITE_PORT_UCHAR (CRTC_DATA, offset>>8);
492             _enable();
493           }
494 
495           Irp->IoStatus.Information = 0;
496           Status = STATUS_SUCCESS;
497         }
498         break;
499 
500       case IOCTL_CONSOLE_GET_CURSOR_INFO:
501         {
502           PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
503 
504           pcci->dwSize = DeviceExtension->CursorSize;
505           pcci->bVisible = DeviceExtension->CursorVisible;
506 
507           Irp->IoStatus.Information = sizeof (CONSOLE_CURSOR_INFO);
508           Status = STATUS_SUCCESS;
509         }
510         break;
511 
512       case IOCTL_CONSOLE_SET_CURSOR_INFO:
513         {
514           PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
515           UCHAR data, value;
516           ULONG size, height;
517 
518           DeviceExtension->CursorSize = pcci->dwSize;
519           DeviceExtension->CursorVisible = pcci->bVisible;
520 
521           if (!InbvCheckDisplayOwnership())
522           {
523             height = DeviceExtension->ScanLines;
524             data = (pcci->bVisible) ? 0x00 : 0x20;
525 
526             size = (pcci->dwSize * height) / 100;
527             if (size < 1)
528             {
529               size = 1;
530             }
531 
532             data |= (UCHAR)(height - size);
533 
534             _disable();
535             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORSTART);
536             WRITE_PORT_UCHAR (CRTC_DATA, data);
537             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSOREND);
538             value = READ_PORT_UCHAR (CRTC_DATA) & 0xE0;
539             WRITE_PORT_UCHAR (CRTC_DATA, value | (height - 1));
540 
541             _enable();
542           }
543 
544           Irp->IoStatus.Information = 0;
545           Status = STATUS_SUCCESS;
546         }
547         break;
548 
549       case IOCTL_CONSOLE_GET_MODE:
550         {
551           PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
552 
553           pcm->dwMode = DeviceExtension->Mode;
554 
555           Irp->IoStatus.Information = sizeof(CONSOLE_MODE);
556           Status = STATUS_SUCCESS;
557         }
558         break;
559 
560       case IOCTL_CONSOLE_SET_MODE:
561         {
562           PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
563 
564           DeviceExtension->Mode = pcm->dwMode;
565 
566           Irp->IoStatus.Information = 0;
567           Status = STATUS_SUCCESS;
568         }
569         break;
570 
571       case IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE:
572         {
573           POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
574           PUCHAR vidmem;
575           int offset;
576           ULONG dwCount;
577           ULONG nMaxLength = Buf->nLength;
578 
579           if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
580                Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
581           {
582               Buf->dwTransfered = 0;
583               Irp->IoStatus.Information = 0;
584               Status = STATUS_SUCCESS;
585               break;
586           }
587 
588           if (!InbvCheckDisplayOwnership())
589           {
590             vidmem = DeviceExtension->VideoMemory;
591             offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
592                      (Buf->dwCoord.X * 2) + 1;
593 
594             nMaxLength = min(nMaxLength,
595                              (DeviceExtension->Rows - Buf->dwCoord.Y)
596                                 * DeviceExtension->Columns - Buf->dwCoord.X);
597 
598             for (dwCount = 0; dwCount < nMaxLength; dwCount++)
599             {
600               vidmem[offset + (dwCount * 2)] = (char) Buf->wAttribute;
601             }
602           }
603 
604           Buf->dwTransfered = nMaxLength;
605 
606           Irp->IoStatus.Information = 0;
607           Status = STATUS_SUCCESS;
608         }
609         break;
610 
611       case IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE:
612         {
613           POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
614           PUSHORT pAttr = (PUSHORT)MmGetSystemAddressForMdl(Irp->MdlAddress);
615           PUCHAR vidmem;
616           int offset;
617           ULONG dwCount;
618           ULONG nMaxLength;
619 
620           if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
621                Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
622           {
623               Buf->dwTransfered = 0;
624               Irp->IoStatus.Information = 0;
625               Status = STATUS_SUCCESS;
626               break;
627           }
628 
629           if (!InbvCheckDisplayOwnership())
630           {
631             vidmem = DeviceExtension->VideoMemory;
632             offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
633                      (Buf->dwCoord.X * 2) + 1;
634 
635             nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength,
636                              (DeviceExtension->Rows - Buf->dwCoord.Y)
637                                 * DeviceExtension->Columns - Buf->dwCoord.X);
638 
639             for (dwCount = 0; dwCount < nMaxLength; dwCount++, pAttr++)
640             {
641               *((char *)pAttr) = vidmem[offset + (dwCount * 2)];
642             }
643 
644             Buf->dwTransfered = dwCount;
645           }
646           else
647           {
648             Buf->dwTransfered = 0;
649           }
650 
651           Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
652           Status = STATUS_SUCCESS;
653         }
654         break;
655 
656       case IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE:
657         {
658           COORD *pCoord = (COORD *)MmGetSystemAddressForMdl(Irp->MdlAddress);
659           CHAR *pAttr = (CHAR *)(pCoord + 1);
660           PUCHAR vidmem;
661           int offset;
662           ULONG dwCount;
663           ULONG nMaxLength;
664 
665           if ( pCoord->X < 0 || pCoord->X >= DeviceExtension->Columns ||
666                pCoord->Y < 0 || pCoord->Y >= DeviceExtension->Rows )
667           {
668               Irp->IoStatus.Information = 0;
669               Status = STATUS_SUCCESS;
670               break;
671           }
672 
673           if (!InbvCheckDisplayOwnership())
674           {
675             vidmem = DeviceExtension->VideoMemory;
676             offset = (pCoord->Y * DeviceExtension->Columns * 2) +
677                      (pCoord->X * 2) + 1;
678 
679             nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD),
680                              (DeviceExtension->Rows - pCoord->Y)
681                                 * DeviceExtension->Columns - pCoord->X);
682 
683             for (dwCount = 0; dwCount < nMaxLength; dwCount++, pAttr++)
684             {
685               vidmem[offset + (dwCount * 2)] = *pAttr;
686             }
687           }
688 
689           Irp->IoStatus.Information = 0;
690           Status = STATUS_SUCCESS;
691         }
692         break;
693 
694       case IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE:
695         DeviceExtension->CharAttribute = (USHORT)*(PUSHORT)Irp->AssociatedIrp.SystemBuffer;
696         Irp->IoStatus.Information = 0;
697         Status = STATUS_SUCCESS;
698         break;
699 
700       case IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER:
701         {
702           POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
703           PUCHAR vidmem;
704           int offset;
705           ULONG dwCount;
706           ULONG nMaxLength = Buf->nLength;
707 
708           if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
709                Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
710           {
711               Buf->dwTransfered = 0;
712               Irp->IoStatus.Information = 0;
713               Status = STATUS_SUCCESS;
714               break;
715           }
716 
717           if (!InbvCheckDisplayOwnership())
718           {
719             vidmem = DeviceExtension->VideoMemory;
720             offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
721                      (Buf->dwCoord.X * 2);
722 
723             nMaxLength = min(nMaxLength,
724                              (DeviceExtension->Rows - Buf->dwCoord.Y)
725                                 * DeviceExtension->Columns - Buf->dwCoord.X);
726 
727             for (dwCount = 0; dwCount < nMaxLength; dwCount++)
728             {
729               vidmem[offset + (dwCount * 2)] = (char) Buf->cCharacter;
730             }
731           }
732 
733           Buf->dwTransfered = nMaxLength;
734 
735           Irp->IoStatus.Information = 0;
736           Status = STATUS_SUCCESS;
737         }
738         break;
739 
740       case IOCTL_CONSOLE_READ_OUTPUT_CHARACTER:
741         {
742           POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
743           LPSTR pChar = (LPSTR)MmGetSystemAddressForMdl(Irp->MdlAddress);
744           PUCHAR vidmem;
745           int offset;
746           ULONG dwCount;
747           ULONG nMaxLength;
748 
749           if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
750                Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
751           {
752               Buf->dwTransfered = 0;
753               Irp->IoStatus.Information = 0;
754               Status = STATUS_SUCCESS;
755               break;
756           }
757 
758           if (!InbvCheckDisplayOwnership())
759           {
760             vidmem = DeviceExtension->VideoMemory;
761             offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
762                      (Buf->dwCoord.X * 2);
763 
764             nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength,
765                              (DeviceExtension->Rows - Buf->dwCoord.Y)
766                                 * DeviceExtension->Columns - Buf->dwCoord.X);
767 
768             for (dwCount = 0; dwCount < nMaxLength; dwCount++, pChar++)
769             {
770               *pChar = vidmem[offset + (dwCount * 2)];
771             }
772 
773             Buf->dwTransfered = dwCount;
774           }
775           else
776           {
777             Buf->dwTransfered = 0;
778           }
779 
780           Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
781           Status = STATUS_SUCCESS;
782         }
783         break;
784 
785       case IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER:
786         {
787           COORD *pCoord = (COORD *)MmGetSystemAddressForMdl(Irp->MdlAddress);
788           LPSTR pChar = (CHAR *)(pCoord + 1);
789           PUCHAR vidmem;
790           int offset;
791           ULONG dwCount;
792           ULONG nMaxLength;
793 
794           if ( pCoord->X < 0 || pCoord->X >= DeviceExtension->Columns ||
795                pCoord->Y < 0 || pCoord->Y >= DeviceExtension->Rows )
796           {
797               Irp->IoStatus.Information = 0;
798               Status = STATUS_SUCCESS;
799               break;
800           }
801 
802           if (!InbvCheckDisplayOwnership())
803           {
804             vidmem = DeviceExtension->VideoMemory;
805             offset = (pCoord->Y * DeviceExtension->Columns * 2) +
806                      (pCoord->X * 2);
807 
808             nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD),
809                              (DeviceExtension->Rows - pCoord->Y)
810                                 * DeviceExtension->Columns - pCoord->X);
811 
812             for (dwCount = 0; dwCount < nMaxLength; dwCount++, pChar++)
813             {
814               vidmem[offset + (dwCount * 2)] = *pChar;
815             }
816           }
817 
818           Irp->IoStatus.Information = 0;
819           Status = STATUS_SUCCESS;
820         }
821         break;
822 
823       case IOCTL_CONSOLE_DRAW:
824         {
825           PCONSOLE_DRAW ConsoleDraw;
826           PUCHAR Src, Dest;
827           UINT32 SrcDelta, DestDelta, i, Offset;
828 
829           if (!InbvCheckDisplayOwnership())
830           {
831             ConsoleDraw = (PCONSOLE_DRAW) MmGetSystemAddressForMdl(Irp->MdlAddress);
832             Src = (PUCHAR) (ConsoleDraw + 1);
833             SrcDelta = ConsoleDraw->SizeX * 2;
834             Dest = DeviceExtension->VideoMemory +
835                     (ConsoleDraw->Y * DeviceExtension->Columns + ConsoleDraw->X) * 2;
836             DestDelta = DeviceExtension->Columns * 2;
837 
838             for (i = 0; i < ConsoleDraw->SizeY; i++)
839             {
840               RtlCopyMemory(Dest, Src, SrcDelta);
841               Src += SrcDelta;
842               Dest += DestDelta;
843             }
844 
845             Offset = (ConsoleDraw->CursorY * DeviceExtension->Columns) +
846                       ConsoleDraw->CursorX;
847 
848             _disable();
849             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
850             WRITE_PORT_UCHAR (CRTC_DATA, Offset);
851             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
852             WRITE_PORT_UCHAR (CRTC_DATA, Offset >> 8);
853             _enable();
854           }
855 
856           Irp->IoStatus.Information = 0;
857           Status = STATUS_SUCCESS;
858         }
859         break;
860 
861       case IOCTL_CONSOLE_LOADFONT:
862           {
863               UINT32 CodePage = (UINT32)*(PULONG)Irp->AssociatedIrp.SystemBuffer;
864 
865               if (!InbvCheckDisplayOwnership())
866               {
867                 // Upload a font for the codepage if needed
868                 ScrLoadFontTable(CodePage);
869               }
870 
871               Irp->IoStatus.Information = 0;
872               Status = STATUS_SUCCESS;
873           }
874           break;
875 
876       default:
877         Status = STATUS_NOT_IMPLEMENTED;
878     }
879 
880   Irp->IoStatus.Status = Status;
881   IoCompleteRequest (Irp, IO_NO_INCREMENT);
882 
883   return Status;
884 }
885 
886 static DRIVER_DISPATCH ScrDispatch;
887 static NTSTATUS NTAPI
888 ScrDispatch(PDEVICE_OBJECT DeviceObject,
889         PIRP Irp)
890 {
891     PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
892     NTSTATUS Status;
893 
894     switch (stk->MajorFunction)
895     {
896         case IRP_MJ_CLOSE:
897             Status = STATUS_SUCCESS;
898             break;
899 
900         default:
901             Status = STATUS_NOT_IMPLEMENTED;
902             break;
903     }
904 
905 
906     Irp->IoStatus.Status = Status;
907     IoCompleteRequest (Irp, IO_NO_INCREMENT);
908 
909     return Status;
910 }
911 
912 
913 /*
914  * Module entry point
915  */
916 NTSTATUS NTAPI
917 DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
918 {
919     PDEVICE_OBJECT DeviceObject;
920     NTSTATUS Status;
921     UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\BlueScreen");
922     UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\BlueScreen");
923 
924     DPRINT ("Screen Driver 0.0.6\n");
925 
926     DriverObject->MajorFunction[IRP_MJ_CREATE] = ScrCreate;
927     DriverObject->MajorFunction[IRP_MJ_CLOSE]  = ScrDispatch;
928     DriverObject->MajorFunction[IRP_MJ_READ]   = ScrDispatch;
929     DriverObject->MajorFunction[IRP_MJ_WRITE]  = ScrWrite;
930     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL ] = ScrIoControl;
931 
932     Status = IoCreateDevice (DriverObject,
933                              sizeof(DEVICE_EXTENSION),
934                              &DeviceName,
935                              FILE_DEVICE_SCREEN,
936                              FILE_DEVICE_SECURE_OPEN,
937                              TRUE,
938                              &DeviceObject);
939 
940     if (!NT_SUCCESS(Status))
941     {
942         return Status;
943     }
944 
945     Status = IoCreateSymbolicLink (&SymlinkName, &DeviceName);
946     if (NT_SUCCESS(Status))
947         DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
948     else
949         IoDeleteDevice (DeviceObject);
950     return Status;
951 }
952 
953 /* EOF */
954