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