xref: /reactos/drivers/setup/blue/blue.c (revision 62919904)
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     /* Upload a default font for the default codepage 437 */
215     ScrLoadFontTable(437);
216 
217     DPRINT ("%d Columns  %d Rows %d Scanlines\n",
218             DeviceExtension->Columns,
219             DeviceExtension->Rows,
220             DeviceExtension->ScanLines);
221 }
222 
223 NTSTATUS NTAPI
224 DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
225 
226 static DRIVER_DISPATCH ScrCreate;
227 static NTSTATUS NTAPI
228 ScrCreate(PDEVICE_OBJECT DeviceObject,
229       PIRP Irp)
230 {
231     PDEVICE_EXTENSION DeviceExtension;
232     PHYSICAL_ADDRESS BaseAddress;
233     NTSTATUS Status;
234 
235     DeviceExtension = DeviceObject->DeviceExtension;
236 
237     if (!InbvCheckDisplayOwnership())
238     {
239         ScrAcquireOwnership(DeviceExtension);
240 
241         /* get pointer to video memory */
242         BaseAddress.QuadPart = VIDMEM_BASE;
243         DeviceExtension->VideoMemory =
244             (PUCHAR)MmMapIoSpace (BaseAddress, DeviceExtension->Rows * DeviceExtension->Columns * 2, MmNonCached);
245     }
246     else
247     {
248         /* store dummy values here */
249         DeviceExtension->Columns = 1;
250         DeviceExtension->Rows = 1;
251         DeviceExtension->ScanLines = 1;
252     }
253 
254     DeviceExtension->CursorSize    = 5; /* FIXME: value correct?? */
255     DeviceExtension->CursorVisible = TRUE;
256 
257     /* more initialization */
258     DeviceExtension->CharAttribute = 0x17;  /* light grey on blue */
259     DeviceExtension->Mode = ENABLE_PROCESSED_OUTPUT |
260                             ENABLE_WRAP_AT_EOL_OUTPUT;
261 
262     Status = STATUS_SUCCESS;
263 
264     Irp->IoStatus.Status = Status;
265     IoCompleteRequest (Irp, IO_NO_INCREMENT);
266 
267     return (Status);
268 }
269 
270 static DRIVER_DISPATCH ScrWrite;
271 static NTSTATUS NTAPI
272 ScrWrite(PDEVICE_OBJECT DeviceObject,
273      PIRP Irp)
274 {
275     PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation (Irp);
276     PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
277     NTSTATUS Status;
278     char *pch = Irp->UserBuffer;
279     PUCHAR vidmem;
280     unsigned int i;
281     int j, offset;
282     int cursorx, cursory;
283     int rows, columns;
284     int processed = DeviceExtension->Mode & ENABLE_PROCESSED_OUTPUT;
285 
286     if (InbvCheckDisplayOwnership())
287     {
288         /* Display is in graphics mode, we're not allowed to touch it */
289         Status = STATUS_SUCCESS;
290 
291         Irp->IoStatus.Status = Status;
292         IoCompleteRequest (Irp, IO_NO_INCREMENT);
293 
294         return Status;
295     }
296 
297     vidmem  = DeviceExtension->VideoMemory;
298     rows = DeviceExtension->Rows;
299     columns = DeviceExtension->Columns;
300 
301     _disable();
302     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
303     offset = READ_PORT_UCHAR (CRTC_DATA)<<8;
304     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
305     offset += READ_PORT_UCHAR (CRTC_DATA);
306     _enable();
307 
308     cursory = offset / columns;
309     cursorx = offset % columns;
310     if( processed == 0 )
311        {
312       /* raw output mode */
313       // FIXME: Does the buffer only contains chars? or chars + attributes?
314       // FIXME2: Fix buffer overflow.
315       memcpy( &vidmem[(cursorx * 2) + (cursory * columns * 2)], pch, stk->Parameters.Write.Length );
316       offset += (stk->Parameters.Write.Length / 2);
317        }
318     else {
319       for (i = 0; i < stk->Parameters.Write.Length; i++, pch++)
320       {
321         switch (*pch)
322         {
323         case '\b':
324            if (cursorx > 0)
325               {
326              cursorx--;
327               }
328            else if (cursory > 0)
329               {
330              cursorx = columns - 1;
331              cursory--;
332               }
333            vidmem[(cursorx * 2) + (cursory * columns * 2)] = ' ';
334            vidmem[(cursorx * 2) + (cursory * columns * 2) + 1] = (char) DeviceExtension->CharAttribute;
335            break;
336 
337         case '\n':
338            cursory++;
339            cursorx = 0;
340            break;
341 
342         case '\r':
343            cursorx = 0;
344            break;
345 
346         case '\t':
347            offset = TAB_WIDTH - (cursorx % TAB_WIDTH);
348            for (j = 0; j < offset; j++)
349               {
350              vidmem[(cursorx * 2) + (cursory * columns * 2)] = ' ';
351              cursorx++;
352 
353              if (cursorx >= columns)
354                 {
355                    cursory++;
356                    cursorx = 0;
357                 }
358               }
359            break;
360 
361         default:
362            vidmem[(cursorx * 2) + (cursory * columns * 2)] = *pch;
363            vidmem[(cursorx * 2) + (cursory * columns * 2) + 1] = (char) DeviceExtension->CharAttribute;
364            cursorx++;
365            if (cursorx >= columns)
366               {
367              cursory++;
368              cursorx = 0;
369               }
370            break;
371         }
372 
373         /* Scroll up the contents of the screen if we are at the end */
374         if (cursory >= rows)
375         {
376            unsigned short *LinePtr;
377 
378            memcpy (vidmem,
379                &vidmem[columns * 2],
380                columns * (rows - 1) * 2);
381 
382            LinePtr = (unsigned short *) &vidmem[columns * (rows - 1) * 2];
383 
384            for (j = 0; j < columns; j++)
385               {
386              LinePtr[j] = DeviceExtension->CharAttribute << 8;
387               }
388            cursory = rows - 1;
389            for (j = 0; j < columns; j++)
390               {
391              vidmem[(j * 2) + (cursory * columns * 2)] = ' ';
392              vidmem[(j * 2) + (cursory * columns * 2) + 1] = (char)DeviceExtension->CharAttribute;
393               }
394         }
395       }
396 
397        /* Set the cursor position */
398        offset = (cursory * columns) + cursorx;
399     }
400     _disable();
401     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
402     WRITE_PORT_UCHAR (CRTC_DATA, offset);
403     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
404     offset >>= 8;
405     WRITE_PORT_UCHAR (CRTC_DATA, offset);
406     _enable();
407 
408     Status = STATUS_SUCCESS;
409 
410     Irp->IoStatus.Status = Status;
411     IoCompleteRequest (Irp, IO_NO_INCREMENT);
412 
413     return Status;
414 }
415 
416 static DRIVER_DISPATCH ScrIoControl;
417 static NTSTATUS NTAPI
418 ScrIoControl(PDEVICE_OBJECT DeviceObject,
419          PIRP Irp)
420 {
421   PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation (Irp);
422   PDEVICE_EXTENSION DeviceExtension;
423   NTSTATUS Status;
424 
425   DeviceExtension = DeviceObject->DeviceExtension;
426   switch (stk->Parameters.DeviceIoControl.IoControlCode)
427     {
428       case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO:
429         {
430           PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
431           int rows = DeviceExtension->Rows;
432           int columns = DeviceExtension->Columns;
433           unsigned int offset;
434 
435           if (!InbvCheckDisplayOwnership())
436           {
437             /* read cursor position from crtc */
438             _disable();
439             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
440             offset = READ_PORT_UCHAR (CRTC_DATA);
441             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
442             offset += (READ_PORT_UCHAR (CRTC_DATA) << 8);
443             _enable();
444           }
445           else
446           {
447             offset = 0;
448           }
449 
450           pcsbi->dwSize.X = columns;
451           pcsbi->dwSize.Y = rows;
452 
453           pcsbi->dwCursorPosition.X = (SHORT)(offset % columns);
454           pcsbi->dwCursorPosition.Y = (SHORT)(offset / columns);
455 
456           pcsbi->wAttributes = DeviceExtension->CharAttribute;
457 
458           pcsbi->srWindow.Left   = 0;
459           pcsbi->srWindow.Right  = columns - 1;
460           pcsbi->srWindow.Top    = 0;
461           pcsbi->srWindow.Bottom = rows - 1;
462 
463           pcsbi->dwMaximumWindowSize.X = columns;
464           pcsbi->dwMaximumWindowSize.Y = rows;
465 
466           Irp->IoStatus.Information = sizeof (CONSOLE_SCREEN_BUFFER_INFO);
467           Status = STATUS_SUCCESS;
468         }
469         break;
470 
471       case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO:
472         {
473           PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
474           unsigned int offset;
475 
476           if ( pcsbi->dwCursorPosition.X < 0 || pcsbi->dwCursorPosition.X >= DeviceExtension->Columns ||
477                pcsbi->dwCursorPosition.Y < 0 || pcsbi->dwCursorPosition.Y >= DeviceExtension->Rows )
478           {
479               Irp->IoStatus.Information = 0;
480               Status = STATUS_INVALID_PARAMETER;
481               break;
482           }
483 
484           DeviceExtension->CharAttribute = pcsbi->wAttributes;
485           offset = (pcsbi->dwCursorPosition.Y * DeviceExtension->Columns) +
486                     pcsbi->dwCursorPosition.X;
487 
488           if (!InbvCheckDisplayOwnership())
489           {
490             _disable();
491             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
492             WRITE_PORT_UCHAR (CRTC_DATA, offset);
493             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
494             WRITE_PORT_UCHAR (CRTC_DATA, offset>>8);
495             _enable();
496           }
497 
498           Irp->IoStatus.Information = 0;
499           Status = STATUS_SUCCESS;
500         }
501         break;
502 
503       case IOCTL_CONSOLE_GET_CURSOR_INFO:
504         {
505           PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
506 
507           pcci->dwSize = DeviceExtension->CursorSize;
508           pcci->bVisible = DeviceExtension->CursorVisible;
509 
510           Irp->IoStatus.Information = sizeof (CONSOLE_CURSOR_INFO);
511           Status = STATUS_SUCCESS;
512         }
513         break;
514 
515       case IOCTL_CONSOLE_SET_CURSOR_INFO:
516         {
517           PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
518           UCHAR data, value;
519           ULONG size, height;
520 
521           DeviceExtension->CursorSize = pcci->dwSize;
522           DeviceExtension->CursorVisible = pcci->bVisible;
523 
524           if (!InbvCheckDisplayOwnership())
525           {
526             height = DeviceExtension->ScanLines;
527             data = (pcci->bVisible) ? 0x00 : 0x20;
528 
529             size = (pcci->dwSize * height) / 100;
530             if (size < 1)
531             {
532               size = 1;
533             }
534 
535             data |= (UCHAR)(height - size);
536 
537             _disable();
538             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORSTART);
539             WRITE_PORT_UCHAR (CRTC_DATA, data);
540             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSOREND);
541             value = READ_PORT_UCHAR (CRTC_DATA) & 0xE0;
542             WRITE_PORT_UCHAR (CRTC_DATA, value | (height - 1));
543 
544             _enable();
545           }
546 
547           Irp->IoStatus.Information = 0;
548           Status = STATUS_SUCCESS;
549         }
550         break;
551 
552       case IOCTL_CONSOLE_GET_MODE:
553         {
554           PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
555 
556           pcm->dwMode = DeviceExtension->Mode;
557 
558           Irp->IoStatus.Information = sizeof(CONSOLE_MODE);
559           Status = STATUS_SUCCESS;
560         }
561         break;
562 
563       case IOCTL_CONSOLE_SET_MODE:
564         {
565           PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
566 
567           DeviceExtension->Mode = pcm->dwMode;
568 
569           Irp->IoStatus.Information = 0;
570           Status = STATUS_SUCCESS;
571         }
572         break;
573 
574       case IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE:
575         {
576           POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
577           PUCHAR vidmem;
578           int offset;
579           ULONG dwCount;
580           ULONG nMaxLength = Buf->nLength;
581 
582           if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
583                Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
584           {
585               Buf->dwTransfered = 0;
586               Irp->IoStatus.Information = 0;
587               Status = STATUS_SUCCESS;
588               break;
589           }
590 
591           if (!InbvCheckDisplayOwnership())
592           {
593             vidmem = DeviceExtension->VideoMemory;
594             offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
595                      (Buf->dwCoord.X * 2) + 1;
596 
597             nMaxLength = min(nMaxLength,
598                              (DeviceExtension->Rows - Buf->dwCoord.Y)
599                                 * DeviceExtension->Columns - Buf->dwCoord.X);
600 
601             for (dwCount = 0; dwCount < nMaxLength; dwCount++)
602             {
603               vidmem[offset + (dwCount * 2)] = (char) Buf->wAttribute;
604             }
605           }
606 
607           Buf->dwTransfered = nMaxLength;
608 
609           Irp->IoStatus.Information = 0;
610           Status = STATUS_SUCCESS;
611         }
612         break;
613 
614       case IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE:
615         {
616           POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
617           PUSHORT pAttr = (PUSHORT)MmGetSystemAddressForMdl(Irp->MdlAddress);
618           PUCHAR vidmem;
619           int offset;
620           ULONG dwCount;
621           ULONG nMaxLength;
622 
623           if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
624                Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
625           {
626               Buf->dwTransfered = 0;
627               Irp->IoStatus.Information = 0;
628               Status = STATUS_SUCCESS;
629               break;
630           }
631 
632           if (!InbvCheckDisplayOwnership())
633           {
634             vidmem = DeviceExtension->VideoMemory;
635             offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
636                      (Buf->dwCoord.X * 2) + 1;
637 
638             nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength,
639                              (DeviceExtension->Rows - Buf->dwCoord.Y)
640                                 * DeviceExtension->Columns - Buf->dwCoord.X);
641 
642             for (dwCount = 0; dwCount < nMaxLength; dwCount++, pAttr++)
643             {
644               *((char *)pAttr) = vidmem[offset + (dwCount * 2)];
645             }
646 
647             Buf->dwTransfered = dwCount;
648           }
649           else
650           {
651             Buf->dwTransfered = 0;
652           }
653 
654           Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
655           Status = STATUS_SUCCESS;
656         }
657         break;
658 
659       case IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE:
660         {
661           COORD *pCoord = (COORD *)MmGetSystemAddressForMdl(Irp->MdlAddress);
662           CHAR *pAttr = (CHAR *)(pCoord + 1);
663           PUCHAR vidmem;
664           int offset;
665           ULONG dwCount;
666           ULONG nMaxLength;
667 
668           if ( pCoord->X < 0 || pCoord->X >= DeviceExtension->Columns ||
669                pCoord->Y < 0 || pCoord->Y >= DeviceExtension->Rows )
670           {
671               Irp->IoStatus.Information = 0;
672               Status = STATUS_SUCCESS;
673               break;
674           }
675 
676           if (!InbvCheckDisplayOwnership())
677           {
678             vidmem = DeviceExtension->VideoMemory;
679             offset = (pCoord->Y * DeviceExtension->Columns * 2) +
680                      (pCoord->X * 2) + 1;
681 
682             nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD),
683                              (DeviceExtension->Rows - pCoord->Y)
684                                 * DeviceExtension->Columns - pCoord->X);
685 
686             for (dwCount = 0; dwCount < nMaxLength; dwCount++, pAttr++)
687             {
688               vidmem[offset + (dwCount * 2)] = *pAttr;
689             }
690           }
691 
692           Irp->IoStatus.Information = 0;
693           Status = STATUS_SUCCESS;
694         }
695         break;
696 
697       case IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE:
698         DeviceExtension->CharAttribute = (USHORT)*(PUSHORT)Irp->AssociatedIrp.SystemBuffer;
699         Irp->IoStatus.Information = 0;
700         Status = STATUS_SUCCESS;
701         break;
702 
703       case IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER:
704         {
705           POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
706           PUCHAR vidmem;
707           int offset;
708           ULONG dwCount;
709           ULONG nMaxLength = Buf->nLength;
710 
711           if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
712                Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
713           {
714               Buf->dwTransfered = 0;
715               Irp->IoStatus.Information = 0;
716               Status = STATUS_SUCCESS;
717               break;
718           }
719 
720           if (!InbvCheckDisplayOwnership())
721           {
722             vidmem = DeviceExtension->VideoMemory;
723             offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
724                      (Buf->dwCoord.X * 2);
725 
726             nMaxLength = min(nMaxLength,
727                              (DeviceExtension->Rows - Buf->dwCoord.Y)
728                                 * DeviceExtension->Columns - Buf->dwCoord.X);
729 
730             for (dwCount = 0; dwCount < nMaxLength; dwCount++)
731             {
732               vidmem[offset + (dwCount * 2)] = (char) Buf->cCharacter;
733             }
734           }
735 
736           Buf->dwTransfered = nMaxLength;
737 
738           Irp->IoStatus.Information = 0;
739           Status = STATUS_SUCCESS;
740         }
741         break;
742 
743       case IOCTL_CONSOLE_READ_OUTPUT_CHARACTER:
744         {
745           POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
746           LPSTR pChar = (LPSTR)MmGetSystemAddressForMdl(Irp->MdlAddress);
747           PUCHAR vidmem;
748           int offset;
749           ULONG dwCount;
750           ULONG nMaxLength;
751 
752           if ( Buf->dwCoord.X < 0 || Buf->dwCoord.X >= DeviceExtension->Columns ||
753                Buf->dwCoord.Y < 0 || Buf->dwCoord.Y >= DeviceExtension->Rows )
754           {
755               Buf->dwTransfered = 0;
756               Irp->IoStatus.Information = 0;
757               Status = STATUS_SUCCESS;
758               break;
759           }
760 
761           if (!InbvCheckDisplayOwnership())
762           {
763             vidmem = DeviceExtension->VideoMemory;
764             offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
765                      (Buf->dwCoord.X * 2);
766 
767             nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength,
768                              (DeviceExtension->Rows - Buf->dwCoord.Y)
769                                 * DeviceExtension->Columns - Buf->dwCoord.X);
770 
771             for (dwCount = 0; dwCount < nMaxLength; dwCount++, pChar++)
772             {
773               *pChar = vidmem[offset + (dwCount * 2)];
774             }
775 
776             Buf->dwTransfered = dwCount;
777           }
778           else
779           {
780             Buf->dwTransfered = 0;
781           }
782 
783           Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
784           Status = STATUS_SUCCESS;
785         }
786         break;
787 
788       case IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER:
789         {
790           COORD *pCoord = (COORD *)MmGetSystemAddressForMdl(Irp->MdlAddress);
791           LPSTR pChar = (CHAR *)(pCoord + 1);
792           PUCHAR vidmem;
793           int offset;
794           ULONG dwCount;
795           ULONG nMaxLength;
796 
797           if ( pCoord->X < 0 || pCoord->X >= DeviceExtension->Columns ||
798                pCoord->Y < 0 || pCoord->Y >= DeviceExtension->Rows )
799           {
800               Irp->IoStatus.Information = 0;
801               Status = STATUS_SUCCESS;
802               break;
803           }
804 
805           if (!InbvCheckDisplayOwnership())
806           {
807             vidmem = DeviceExtension->VideoMemory;
808             offset = (pCoord->Y * DeviceExtension->Columns * 2) +
809                      (pCoord->X * 2);
810 
811             nMaxLength = min(stk->Parameters.DeviceIoControl.OutputBufferLength - sizeof(COORD),
812                              (DeviceExtension->Rows - pCoord->Y)
813                                 * DeviceExtension->Columns - pCoord->X);
814 
815             for (dwCount = 0; dwCount < nMaxLength; dwCount++, pChar++)
816             {
817               vidmem[offset + (dwCount * 2)] = *pChar;
818             }
819           }
820 
821           Irp->IoStatus.Information = 0;
822           Status = STATUS_SUCCESS;
823         }
824         break;
825 
826       case IOCTL_CONSOLE_DRAW:
827         {
828           PCONSOLE_DRAW ConsoleDraw;
829           PUCHAR Src, Dest;
830           UINT32 SrcDelta, DestDelta, i, Offset;
831 
832           if (!InbvCheckDisplayOwnership())
833           {
834             ConsoleDraw = (PCONSOLE_DRAW) MmGetSystemAddressForMdl(Irp->MdlAddress);
835             Src = (PUCHAR) (ConsoleDraw + 1);
836             SrcDelta = ConsoleDraw->SizeX * 2;
837             Dest = DeviceExtension->VideoMemory +
838                     (ConsoleDraw->Y * DeviceExtension->Columns + ConsoleDraw->X) * 2;
839             DestDelta = DeviceExtension->Columns * 2;
840 
841             for (i = 0; i < ConsoleDraw->SizeY; i++)
842             {
843               RtlCopyMemory(Dest, Src, SrcDelta);
844               Src += SrcDelta;
845               Dest += DestDelta;
846             }
847 
848             Offset = (ConsoleDraw->CursorY * DeviceExtension->Columns) +
849                       ConsoleDraw->CursorX;
850 
851             _disable();
852             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
853             WRITE_PORT_UCHAR (CRTC_DATA, Offset);
854             WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
855             WRITE_PORT_UCHAR (CRTC_DATA, Offset >> 8);
856             _enable();
857           }
858 
859           Irp->IoStatus.Information = 0;
860           Status = STATUS_SUCCESS;
861         }
862         break;
863 
864       case IOCTL_CONSOLE_LOADFONT:
865           {
866               UINT32 CodePage = (UINT32)*(PULONG)Irp->AssociatedIrp.SystemBuffer;
867 
868               if (!InbvCheckDisplayOwnership())
869               {
870                 /* Upload a font for the codepage if needed */
871                 ScrLoadFontTable(CodePage);
872               }
873 
874               Irp->IoStatus.Information = 0;
875               Status = STATUS_SUCCESS;
876           }
877           break;
878 
879       default:
880         Status = STATUS_NOT_IMPLEMENTED;
881     }
882 
883   Irp->IoStatus.Status = Status;
884   IoCompleteRequest (Irp, IO_NO_INCREMENT);
885 
886   return Status;
887 }
888 
889 static DRIVER_DISPATCH ScrDispatch;
890 static NTSTATUS NTAPI
891 ScrDispatch(PDEVICE_OBJECT DeviceObject,
892         PIRP Irp)
893 {
894     PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
895     NTSTATUS Status;
896 
897     switch (stk->MajorFunction)
898     {
899         case IRP_MJ_CLOSE:
900             Status = STATUS_SUCCESS;
901             break;
902 
903         default:
904             Status = STATUS_NOT_IMPLEMENTED;
905             break;
906     }
907 
908 
909     Irp->IoStatus.Status = Status;
910     IoCompleteRequest (Irp, IO_NO_INCREMENT);
911 
912     return Status;
913 }
914 
915 
916 /*
917  * Module entry point
918  */
919 NTSTATUS NTAPI
920 DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
921 {
922     PDEVICE_OBJECT DeviceObject;
923     NTSTATUS Status;
924     UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\BlueScreen");
925     UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\BlueScreen");
926 
927     DPRINT ("Screen Driver 0.0.6\n");
928 
929     DriverObject->MajorFunction[IRP_MJ_CREATE] = ScrCreate;
930     DriverObject->MajorFunction[IRP_MJ_CLOSE]  = ScrDispatch;
931     DriverObject->MajorFunction[IRP_MJ_READ]   = ScrDispatch;
932     DriverObject->MajorFunction[IRP_MJ_WRITE]  = ScrWrite;
933     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL ] = ScrIoControl;
934 
935     Status = IoCreateDevice (DriverObject,
936                              sizeof(DEVICE_EXTENSION),
937                              &DeviceName,
938                              FILE_DEVICE_SCREEN,
939                              FILE_DEVICE_SECURE_OPEN,
940                              TRUE,
941                              &DeviceObject);
942 
943     if (!NT_SUCCESS(Status))
944     {
945         return Status;
946     }
947 
948     Status = IoCreateSymbolicLink (&SymlinkName, &DeviceName);
949     if (NT_SUCCESS(Status))
950         DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
951     else
952         IoDeleteDevice (DeviceObject);
953     return Status;
954 }
955 
956 /* EOF */
957