xref: /reactos/drivers/setup/blue/blue.c (revision 84ccccab)
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       memcpy( &vidmem[(cursorx * 2) + (cursory * columns * 2)], pch, stk->Parameters.Write.Length );
311       offset += (stk->Parameters.Write.Length / 2);
312        }
313     else {
314        for (i = 0; i < stk->Parameters.Write.Length; i++, pch++)
315       {
316          switch (*pch)
317         {
318         case '\b':
319            if (cursorx > 0)
320               {
321              cursorx--;
322               }
323            else if (cursory > 0)
324               {
325              cursorx = columns - 1;
326              cursory--;
327               }
328            vidmem[(cursorx * 2) + (cursory * columns * 2)] = ' ';
329            vidmem[(cursorx * 2) + (cursory * columns * 2) + 1] = (char) DeviceExtension->CharAttribute;
330            break;
331 
332         case '\n':
333            cursory++;
334            cursorx = 0;
335            break;
336 
337         case '\r':
338            cursorx = 0;
339            break;
340 
341         case '\t':
342            offset = TAB_WIDTH - (cursorx % TAB_WIDTH);
343            for (j = 0; j < offset; j++)
344               {
345              vidmem[(cursorx * 2) + (cursory * columns * 2)] = ' ';
346              cursorx++;
347 
348              if (cursorx >= columns)
349                 {
350                    cursory++;
351                    cursorx = 0;
352                 }
353               }
354            break;
355 
356         default:
357            vidmem[(cursorx * 2) + (cursory * columns * 2)] = *pch;
358            vidmem[(cursorx * 2) + (cursory * columns * 2) + 1] = (char) DeviceExtension->CharAttribute;
359            cursorx++;
360            if (cursorx >= columns)
361               {
362              cursory++;
363              cursorx = 0;
364               }
365            break;
366         }
367          if (cursory >= rows)
368         {
369            unsigned short *LinePtr;
370 
371            memcpy (vidmem,
372                &vidmem[columns * 2],
373                columns * (rows - 1) * 2);
374 
375            LinePtr = (unsigned short *) &vidmem[columns * (rows - 1) * 2];
376 
377            for (j = 0; j < columns; j++)
378               {
379              LinePtr[j] = DeviceExtension->CharAttribute << 8;
380               }
381            cursory = rows - 1;
382            for (j = 0; j < columns; j++)
383               {
384              vidmem[(j * 2) + (cursory * columns * 2)] = ' ';
385              vidmem[(j * 2) + (cursory * columns * 2) + 1] = (char)DeviceExtension->CharAttribute;
386               }
387         }
388       }
389 
390        /* Set the cursor position */
391        offset = (cursory * columns) + cursorx;
392     }
393     _disable();
394     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
395     WRITE_PORT_UCHAR (CRTC_DATA, offset);
396     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
397     offset >>= 8;
398     WRITE_PORT_UCHAR (CRTC_DATA, offset);
399     _enable();
400 
401     Status = STATUS_SUCCESS;
402 
403     Irp->IoStatus.Status = Status;
404     IoCompleteRequest (Irp, IO_NO_INCREMENT);
405 
406     return (Status);
407 }
408 
409 static DRIVER_DISPATCH ScrIoControl;
410 static NTSTATUS NTAPI
411 ScrIoControl(PDEVICE_OBJECT DeviceObject,
412          PIRP Irp)
413 {
414   PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation (Irp);
415   PDEVICE_EXTENSION DeviceExtension;
416   NTSTATUS Status;
417 
418   DeviceExtension = DeviceObject->DeviceExtension;
419   switch (stk->Parameters.DeviceIoControl.IoControlCode)
420     {
421       case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO:
422         {
423           PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
424           int rows = DeviceExtension->Rows;
425           int columns = DeviceExtension->Columns;
426           unsigned int offset;
427 
428           if (!InbvCheckDisplayOwnership())
429           {
430             /* read cursor position from crtc */
431             _disable();
432             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
433             offset = READ_PORT_UCHAR (CRTC_DATA);
434             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
435             offset += (READ_PORT_UCHAR (CRTC_DATA) << 8);
436             _enable();
437           }
438           else
439           {
440             offset = 0;
441           }
442 
443           pcsbi->dwSize.X = columns;
444           pcsbi->dwSize.Y = rows;
445 
446           pcsbi->dwCursorPosition.X = (SHORT)(offset % columns);
447           pcsbi->dwCursorPosition.Y = (SHORT)(offset / columns);
448 
449           pcsbi->wAttributes = DeviceExtension->CharAttribute;
450 
451           pcsbi->srWindow.Left   = 0;
452           pcsbi->srWindow.Right  = columns - 1;
453           pcsbi->srWindow.Top    = 0;
454           pcsbi->srWindow.Bottom = rows - 1;
455 
456           pcsbi->dwMaximumWindowSize.X = columns;
457           pcsbi->dwMaximumWindowSize.Y = rows;
458 
459           Irp->IoStatus.Information = sizeof (CONSOLE_SCREEN_BUFFER_INFO);
460           Status = STATUS_SUCCESS;
461         }
462         break;
463 
464       case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO:
465         {
466           PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
467           unsigned int offset;
468 
469           DeviceExtension->CharAttribute = pcsbi->wAttributes;
470           offset = (pcsbi->dwCursorPosition.Y * DeviceExtension->Columns) +
471                     pcsbi->dwCursorPosition.X;
472 
473           if (!InbvCheckDisplayOwnership())
474           {
475             _disable();
476             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
477             WRITE_PORT_UCHAR (CRTC_DATA, offset);
478             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
479             WRITE_PORT_UCHAR (CRTC_DATA, offset>>8);
480             _enable();
481           }
482 
483           Irp->IoStatus.Information = 0;
484           Status = STATUS_SUCCESS;
485         }
486         break;
487 
488       case IOCTL_CONSOLE_GET_CURSOR_INFO:
489         {
490           PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
491 
492           pcci->dwSize = DeviceExtension->CursorSize;
493           pcci->bVisible = DeviceExtension->CursorVisible;
494 
495           Irp->IoStatus.Information = sizeof (CONSOLE_CURSOR_INFO);
496           Status = STATUS_SUCCESS;
497         }
498         break;
499 
500       case IOCTL_CONSOLE_SET_CURSOR_INFO:
501         {
502           PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
503           UCHAR data, value;
504           ULONG size, height;
505 
506           DeviceExtension->CursorSize = pcci->dwSize;
507           DeviceExtension->CursorVisible = pcci->bVisible;
508 
509           if (!InbvCheckDisplayOwnership())
510           {
511             height = DeviceExtension->ScanLines;
512             data = (pcci->bVisible) ? 0x00 : 0x20;
513 
514             size = (pcci->dwSize * height) / 100;
515             if (size < 1)
516             {
517               size = 1;
518             }
519 
520             data |= (UCHAR)(height - size);
521 
522             _disable();
523             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORSTART);
524             WRITE_PORT_UCHAR (CRTC_DATA, data);
525             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSOREND);
526             value = READ_PORT_UCHAR (CRTC_DATA) & 0xE0;
527             WRITE_PORT_UCHAR (CRTC_DATA, value | (height - 1));
528 
529             _enable();
530           }
531 
532           Irp->IoStatus.Information = 0;
533           Status = STATUS_SUCCESS;
534         }
535         break;
536 
537       case IOCTL_CONSOLE_GET_MODE:
538         {
539           PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
540 
541           pcm->dwMode = DeviceExtension->Mode;
542 
543           Irp->IoStatus.Information = sizeof(CONSOLE_MODE);
544           Status = STATUS_SUCCESS;
545         }
546         break;
547 
548       case IOCTL_CONSOLE_SET_MODE:
549         {
550           PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
551 
552           DeviceExtension->Mode = pcm->dwMode;
553 
554           Irp->IoStatus.Information = 0;
555           Status = STATUS_SUCCESS;
556         }
557         break;
558 
559       case IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE:
560         {
561           POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
562           PUCHAR vidmem;
563           int offset;
564           ULONG dwCount;
565 
566           if (!InbvCheckDisplayOwnership())
567           {
568             vidmem = DeviceExtension->VideoMemory;
569             offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
570                         (Buf->dwCoord.X * 2) + 1;
571 
572             for (dwCount = 0; dwCount < Buf->nLength; dwCount++)
573             {
574               vidmem[offset + (dwCount * 2)] = (char) Buf->wAttribute;
575             }
576           }
577 
578           Buf->dwTransfered = Buf->nLength;
579 
580           Irp->IoStatus.Information = 0;
581           Status = STATUS_SUCCESS;
582         }
583         break;
584 
585       case IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE:
586         {
587           POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
588           PUSHORT pAttr = (PUSHORT)MmGetSystemAddressForMdl(Irp->MdlAddress);
589           PUCHAR vidmem;
590           int offset;
591           ULONG dwCount;
592 
593           if (!InbvCheckDisplayOwnership())
594           {
595             vidmem = DeviceExtension->VideoMemory;
596             offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
597                      (Buf->dwCoord.X * 2) + 1;
598 
599             for (dwCount = 0; dwCount < stk->Parameters.DeviceIoControl.OutputBufferLength; dwCount++, pAttr++)
600             {
601               *((char *) pAttr) = vidmem[offset + (dwCount * 2)];
602             }
603 
604             Buf->dwTransfered = dwCount;
605           }
606           else
607           {
608             Buf->dwTransfered = 0;
609           }
610 
611           Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
612           Status = STATUS_SUCCESS;
613         }
614         break;
615 
616       case IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE:
617         {
618           COORD *pCoord = (COORD *)MmGetSystemAddressForMdl(Irp->MdlAddress);
619           CHAR *pAttr = (CHAR *)(pCoord + 1);
620           PUCHAR vidmem;
621           int offset;
622           ULONG dwCount;
623 
624           if (!InbvCheckDisplayOwnership())
625           {
626             vidmem = DeviceExtension->VideoMemory;
627             offset = (pCoord->Y * DeviceExtension->Columns * 2) +
628                     (pCoord->X * 2) + 1;
629 
630             for (dwCount = 0; dwCount < (stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof( COORD )); dwCount++, pAttr++)
631             {
632               vidmem[offset + (dwCount * 2)] = *pAttr;
633             }
634           }
635 
636           Irp->IoStatus.Information = 0;
637           Status = STATUS_SUCCESS;
638         }
639         break;
640 
641       case IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE:
642         DeviceExtension->CharAttribute = (USHORT)*(PUSHORT)Irp->AssociatedIrp.SystemBuffer;
643         Irp->IoStatus.Information = 0;
644         Status = STATUS_SUCCESS;
645         break;
646 
647       case IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER:
648         {
649           POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
650           PUCHAR vidmem;
651           int offset;
652           ULONG dwCount;
653 
654           if (!InbvCheckDisplayOwnership())
655           {
656             vidmem = DeviceExtension->VideoMemory;
657             offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
658                     (Buf->dwCoord.X * 2);
659 
660 
661             for (dwCount = 0; dwCount < Buf->nLength; dwCount++)
662             {
663               vidmem[offset + (dwCount * 2)] = (char) Buf->cCharacter;
664             }
665           }
666 
667           Buf->dwTransfered = Buf->nLength;
668 
669           Irp->IoStatus.Information = 0;
670           Status = STATUS_SUCCESS;
671         }
672         break;
673 
674       case IOCTL_CONSOLE_READ_OUTPUT_CHARACTER:
675         {
676           POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
677           LPSTR pChar = (LPSTR)MmGetSystemAddressForMdl(Irp->MdlAddress);
678           PUCHAR vidmem;
679           int offset;
680           ULONG dwCount;
681 
682           if (!InbvCheckDisplayOwnership())
683           {
684             vidmem = DeviceExtension->VideoMemory;
685             offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
686                     (Buf->dwCoord.X * 2);
687 
688             for (dwCount = 0; dwCount < stk->Parameters.DeviceIoControl.OutputBufferLength; dwCount++, pChar++)
689             {
690               *pChar = vidmem[offset + (dwCount * 2)];
691             }
692 
693             Buf->dwTransfered = dwCount;
694           }
695           else
696           {
697             Buf->dwTransfered = 0;
698           }
699 
700           Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
701           Status = STATUS_SUCCESS;
702         }
703         break;
704 
705       case IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER:
706         {
707           COORD *pCoord;
708           LPSTR pChar;
709           PUCHAR vidmem;
710           int offset;
711           ULONG dwCount;
712 
713           if (!InbvCheckDisplayOwnership())
714           {
715             pCoord = (COORD *)MmGetSystemAddressForMdl(Irp->MdlAddress);
716             pChar = (CHAR *)(pCoord + 1);
717             vidmem = DeviceExtension->VideoMemory;
718             offset = (pCoord->Y * DeviceExtension->Columns * 2) +
719                     (pCoord->X * 2);
720 
721             for (dwCount = 0; dwCount < (stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof( COORD )); dwCount++, pChar++)
722             {
723               vidmem[offset + (dwCount * 2)] = *pChar;
724             }
725           }
726 
727           Irp->IoStatus.Information = 0;
728           Status = STATUS_SUCCESS;
729         }
730         break;
731 
732       case IOCTL_CONSOLE_DRAW:
733         {
734           PCONSOLE_DRAW ConsoleDraw;
735           PUCHAR Src, Dest;
736           UINT32 SrcDelta, DestDelta, i, Offset;
737 
738           if (!InbvCheckDisplayOwnership())
739           {
740             ConsoleDraw = (PCONSOLE_DRAW) MmGetSystemAddressForMdl(Irp->MdlAddress);
741             Src = (PUCHAR) (ConsoleDraw + 1);
742             SrcDelta = ConsoleDraw->SizeX * 2;
743             Dest = DeviceExtension->VideoMemory +
744                     (ConsoleDraw->Y * DeviceExtension->Columns + ConsoleDraw->X) * 2;
745             DestDelta = DeviceExtension->Columns * 2;
746 
747             for (i = 0; i < ConsoleDraw->SizeY; i++)
748             {
749               RtlCopyMemory(Dest, Src, SrcDelta);
750               Src += SrcDelta;
751               Dest += DestDelta;
752             }
753 
754             Offset = (ConsoleDraw->CursorY * DeviceExtension->Columns) +
755                     ConsoleDraw->CursorX;
756 
757             _disable();
758             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
759             WRITE_PORT_UCHAR (CRTC_DATA, Offset);
760             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
761             WRITE_PORT_UCHAR (CRTC_DATA, Offset >> 8);
762             _enable();
763           }
764 
765           Irp->IoStatus.Information = 0;
766           Status = STATUS_SUCCESS;
767         }
768         break;
769 
770       case IOCTL_CONSOLE_LOADFONT:
771           {
772               UINT32 CodePage = (UINT32)*(PULONG)Irp->AssociatedIrp.SystemBuffer;
773 
774               if (!InbvCheckDisplayOwnership())
775               {
776                 // Upload a font for the codepage if needed
777                 ScrLoadFontTable(CodePage);
778               }
779 
780               Irp->IoStatus.Information = 0;
781               Status = STATUS_SUCCESS;
782           }
783           break;
784 
785       default:
786         Status = STATUS_NOT_IMPLEMENTED;
787     }
788 
789   Irp->IoStatus.Status = Status;
790   IoCompleteRequest (Irp, IO_NO_INCREMENT);
791 
792   return Status;
793 }
794 
795 static DRIVER_DISPATCH ScrDispatch;
796 static NTSTATUS NTAPI
797 ScrDispatch(PDEVICE_OBJECT DeviceObject,
798         PIRP Irp)
799 {
800     PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
801     NTSTATUS Status;
802 
803     switch (stk->MajorFunction)
804     {
805         case IRP_MJ_CLOSE:
806             Status = STATUS_SUCCESS;
807             break;
808 
809         default:
810             Status = STATUS_NOT_IMPLEMENTED;
811             break;
812     }
813 
814 
815     Irp->IoStatus.Status = Status;
816     IoCompleteRequest (Irp, IO_NO_INCREMENT);
817 
818     return (Status);
819 }
820 
821 
822 /*
823  * Module entry point
824  */
825 NTSTATUS NTAPI
826 DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
827 {
828     PDEVICE_OBJECT DeviceObject;
829     NTSTATUS Status;
830     UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\BlueScreen");
831     UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\BlueScreen");
832 
833     DPRINT ("Screen Driver 0.0.6\n");
834 
835     DriverObject->MajorFunction[IRP_MJ_CREATE] = ScrCreate;
836     DriverObject->MajorFunction[IRP_MJ_CLOSE]  = ScrDispatch;
837     DriverObject->MajorFunction[IRP_MJ_READ]   = ScrDispatch;
838     DriverObject->MajorFunction[IRP_MJ_WRITE]  = ScrWrite;
839     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL ] = ScrIoControl;
840 
841     Status = IoCreateDevice (DriverObject,
842                              sizeof(DEVICE_EXTENSION),
843                              &DeviceName,
844                              FILE_DEVICE_SCREEN,
845                              FILE_DEVICE_SECURE_OPEN,
846                              TRUE,
847                              &DeviceObject);
848 
849     if (!NT_SUCCESS(Status))
850     {
851         return Status;
852     }
853 
854     Status = IoCreateSymbolicLink (&SymlinkName, &DeviceName);
855     if (NT_SUCCESS(Status))
856         DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
857     else
858         IoDeleteDevice (DeviceObject);
859     return Status;
860 }
861 
862 /* EOF */
863