update for HEAD-2003091401
[reactos.git] / drivers / dd / blue / blue.c
1 /* $Id$
2  *
3  * COPYRIGHT:            See COPYING in the top level directory
4  * PROJECT:              ReactOS kernel
5  * FILE:                 services/dd/blue/blue.c
6  * PURPOSE:              Console (blue screen) device driver
7  * PROGRAMMER:           Eric Kohl (ekohl@abo.rhein-zeitung.de)
8  * UPDATE HISTORY:
9  *                       ??? Created
10  */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <roskrnl.h>
15 #include <ddk/ntddblue.h>
16 #include <string.h>
17 #include <defines.h>
18
19 #define NDEBUG
20 #include <debug.h>
21
22
23 /* DEFINITIONS ***************************************************************/
24
25 #define VIDMEM_BASE        0xb8000
26
27 #define CRTC_COMMAND       ((PUCHAR)0x3d4)
28 #define CRTC_DATA          ((PUCHAR)0x3d5)
29
30 #define CRTC_COLUMNS       0x01
31 #define CRTC_OVERFLOW      0x07
32 #define CRTC_ROWS          0x12
33 #define CRTC_SCANLINES     0x09
34 #define CRTC_CURSORSTART   0x0a
35 #define CRTC_CURSOREND     0x0b
36 #define CRTC_CURSORPOSHI   0x0e
37 #define CRTC_CURSORPOSLO   0x0f
38
39 #define ATTRC_WRITEREG     ((PUCHAR)0x3c0)
40 #define ATTRC_READREG      ((PUCHAR)0x3c1)
41 #define ATTRC_INPST1       ((PUCHAR)0x3da)
42
43 #define TAB_WIDTH          8
44
45
46 /* NOTES ******************************************************************/
47 /*
48  *  [[character][attribute]][[character][attribute]]....
49  */
50
51
52 /* TYPEDEFS ***************************************************************/
53
54 typedef struct _DEVICE_EXTENSION
55 {
56     PBYTE VideoMemory;    /* Pointer to video memory */
57     DWORD CursorSize;
58     BOOL  CursorVisible;
59     WORD  CharAttribute;
60     DWORD Mode;
61     BYTE  ScanLines;      /* Height of a text line */
62     WORD  Rows;           /* Number of rows        */
63     WORD  Columns;        /* Number of columns     */
64 } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
65
66
67 /* FUNCTIONS **************************************************************/
68
69 NTSTATUS STDCALL
70 ScrCreate(PDEVICE_OBJECT DeviceObject,
71           PIRP Irp)
72 {
73     PDEVICE_EXTENSION DeviceExtension;
74     PHYSICAL_ADDRESS BaseAddress;
75     NTSTATUS Status;
76     unsigned int offset;
77     BYTE data, value;
78
79     DeviceExtension = DeviceObject->DeviceExtension;
80
81     /* disable interrupts */
82     __asm__("cli\n\t");
83
84     /* get current output position */
85     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
86     offset = READ_PORT_UCHAR (CRTC_DATA);
87     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
88     offset += (READ_PORT_UCHAR (CRTC_DATA) << 8);
89
90     /* switch blinking characters off */
91     READ_PORT_UCHAR (ATTRC_INPST1);
92     value = READ_PORT_UCHAR (ATTRC_WRITEREG);
93     WRITE_PORT_UCHAR (ATTRC_WRITEREG, 0x10);
94     data  = READ_PORT_UCHAR (ATTRC_READREG);
95     data  = data & ~0x08;
96     WRITE_PORT_UCHAR (ATTRC_WRITEREG, data);
97     WRITE_PORT_UCHAR (ATTRC_WRITEREG, value);
98     READ_PORT_UCHAR (ATTRC_INPST1);
99
100     /* read screen information from crt controller */
101     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_COLUMNS);
102     DeviceExtension->Columns = READ_PORT_UCHAR (CRTC_DATA) + 1;
103     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_ROWS);
104     DeviceExtension->Rows = READ_PORT_UCHAR (CRTC_DATA);
105     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_OVERFLOW);
106     data = READ_PORT_UCHAR (CRTC_DATA);
107     DeviceExtension->Rows |= (((data & 0x02) << 7) | ((data & 0x40) << 3));
108     DeviceExtension->Rows++;
109     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_SCANLINES);
110     DeviceExtension->ScanLines = (READ_PORT_UCHAR (CRTC_DATA) & 0x1F) + 1;
111
112     /* enable interrupts */
113     __asm__("sti\n\t");
114
115     /* calculate number of text rows */
116     DeviceExtension->Rows =
117         DeviceExtension->Rows / DeviceExtension->ScanLines;
118 #ifdef BOCHS_30ROWS
119     DeviceExtension->Rows = 30;
120 #endif
121
122     DPRINT ("%d Columns  %d Rows %d Scanlines\n",
123             DeviceExtension->Columns,
124             DeviceExtension->Rows,
125             DeviceExtension->ScanLines);
126
127     /* get pointer to video memory */
128     BaseAddress.QuadPart = VIDMEM_BASE;
129     DeviceExtension->VideoMemory =
130         (PBYTE)MmMapIoSpace (BaseAddress, DeviceExtension->Rows * DeviceExtension->Columns * 2, FALSE);
131
132     DeviceExtension->CursorSize    = 5; /* FIXME: value correct?? */
133     DeviceExtension->CursorVisible = TRUE;
134
135     /* more initialization */
136     DeviceExtension->CharAttribute = 0x17;  /* light grey on blue */
137     DeviceExtension->Mode = ENABLE_PROCESSED_OUTPUT |
138                             ENABLE_WRAP_AT_EOL_OUTPUT;
139
140     /* show blinking cursor */
141     __asm__("cli\n\t");
142     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORSTART);
143     WRITE_PORT_UCHAR (CRTC_DATA, (DeviceExtension->ScanLines - 1) & 0x1F);
144     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSOREND);
145     data = READ_PORT_UCHAR (CRTC_DATA) & 0xE0;
146     WRITE_PORT_UCHAR (CRTC_DATA,
147                       data | ((DeviceExtension->ScanLines - 1) & 0x1F));
148     __asm__("sti\n\t");
149
150     Status = STATUS_SUCCESS;
151
152     Irp->IoStatus.Status = Status;
153     IoCompleteRequest (Irp, IO_NO_INCREMENT);
154
155     return (Status);
156 }
157
158
159 NTSTATUS STDCALL
160 ScrWrite(PDEVICE_OBJECT DeviceObject,
161          PIRP Irp)
162 {
163     PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation (Irp);
164     PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
165     NTSTATUS Status;
166     char *pch = Irp->UserBuffer;
167     char *vidmem;
168     int i, j, offset;
169     int cursorx, cursory;
170     int rows, columns;
171     int processed = DeviceExtension->Mode & ENABLE_PROCESSED_OUTPUT;
172
173     if (HalQueryDisplayOwnership())
174        {
175           /* Display is in graphics mode, we're not allowed to touch it */
176           Status = STATUS_SUCCESS;
177
178           Irp->IoStatus.Status = Status;
179           IoCompleteRequest (Irp, IO_NO_INCREMENT);
180
181           return Status;
182        }
183
184     vidmem  = DeviceExtension->VideoMemory;
185     rows = DeviceExtension->Rows;
186     columns = DeviceExtension->Columns;
187
188     __asm__ ("cli\n\t");
189     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
190     offset = READ_PORT_UCHAR (CRTC_DATA)<<8;
191     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
192     offset += READ_PORT_UCHAR (CRTC_DATA);
193     __asm__ ("sti\n\t");
194
195     cursory = offset / columns;
196     cursorx = offset % columns;
197     if( processed == 0 )
198        {
199           /* raw output mode */
200           memcpy( &vidmem[(cursorx * 2) + (cursory * columns * 2)], pch, stk->Parameters.Write.Length );
201           offset += (stk->Parameters.Write.Length / 2);
202        }
203     else {
204        for (i = 0; i < stk->Parameters.Write.Length; i++, pch++)
205           {
206              switch (*pch)
207                 {
208                 case '\b':
209                    if (cursorx > 0)
210                       {
211                          cursorx--;
212                       }
213                    else if (cursory > 0)
214                       {
215                          cursorx = columns - 1;
216                          cursory--;
217                       }
218                    vidmem[(cursorx * 2) + (cursory * columns * 2)] = ' ';
219                    vidmem[(cursorx * 2) + (cursory * columns * 2) + 1] = (char) DeviceExtension->CharAttribute;
220                    break;
221                    
222                 case '\n':
223                    cursory++;
224                    cursorx = 0;
225                    break;
226                    
227                 case '\r':
228                    cursorx = 0;
229                    break;
230                    
231                 case '\t':
232                    offset = TAB_WIDTH - (cursorx % TAB_WIDTH);
233                    for (j = 0; j < offset; j++)
234                       {
235                          vidmem[(cursorx * 2) + (cursory * columns * 2)] = ' ';
236                          cursorx++;
237                          
238                          if (cursorx >= columns)
239                             {
240                                cursory++;
241                                cursorx = 0;
242                             }
243                       }
244                    break;
245                    
246                 default:
247                    vidmem[(cursorx * 2) + (cursory * columns * 2)] = *pch;
248                    vidmem[(cursorx * 2) + (cursory * columns * 2) + 1] = (char) DeviceExtension->CharAttribute;
249                    cursorx++;
250                    if (cursorx >= columns)
251                       {
252                          cursory++;
253                          cursorx = 0;
254                       }
255                    break;
256                 }
257              if (cursory >= rows)
258                 {
259                    unsigned short *LinePtr;
260
261                    memcpy (vidmem,
262                            &vidmem[columns * 2],
263                            columns * (rows - 1) * 2);
264
265                    LinePtr = (unsigned short *) &vidmem[columns * (rows - 1) * 2];
266
267                    for (j = 0; j < columns; j++)
268                       {
269                          LinePtr[j] = DeviceExtension->CharAttribute << 8;
270                       }
271                    cursory = rows - 1;
272                    for (j = 0; j < columns; j++)
273                       {
274                          vidmem[(j * 2) + (cursory * columns * 2)] = ' ';
275                          vidmem[(j * 2) + (cursory * columns * 2) + 1] = (char)DeviceExtension->CharAttribute;
276                       }
277                 }
278           }
279        
280        /* Set the cursor position */
281        offset = (cursory * columns) + cursorx;
282     }
283     __asm__ ("cli\n\t");
284     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
285     WRITE_PORT_UCHAR (CRTC_DATA, offset);
286     WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
287     offset >>= 8;
288     WRITE_PORT_UCHAR (CRTC_DATA, offset);
289     __asm__ ("sti\n\t");
290
291     Status = STATUS_SUCCESS;
292
293     Irp->IoStatus.Status = Status;
294     IoCompleteRequest (Irp, IO_NO_INCREMENT);
295
296     return (Status);
297 }
298
299
300 NTSTATUS STDCALL
301 ScrIoControl(PDEVICE_OBJECT DeviceObject,
302              PIRP Irp)
303 {
304     PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation (Irp);
305     PDEVICE_EXTENSION DeviceExtension;
306     NTSTATUS Status;
307     DeviceExtension = DeviceObject->DeviceExtension;
308     switch (stk->Parameters.DeviceIoControl.IoControlCode)
309     {
310         case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO:
311             {
312                 PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
313                 int rows = DeviceExtension->Rows;
314                 int columns = DeviceExtension->Columns;
315                 unsigned int offset;
316
317                 /* read cursor position from crtc */
318                 __asm__("cli\n\t");
319                 WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
320                 offset = READ_PORT_UCHAR (CRTC_DATA);
321                 WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
322                 offset += (READ_PORT_UCHAR (CRTC_DATA) << 8);
323                 __asm__("sti\n\t");
324
325                 pcsbi->dwSize.X = columns;
326                 pcsbi->dwSize.Y = rows;
327
328                 pcsbi->dwCursorPosition.X = (SHORT)(offset % columns);
329                 pcsbi->dwCursorPosition.Y = (SHORT)(offset / columns);
330
331                 pcsbi->wAttributes = DeviceExtension->CharAttribute;
332
333                 pcsbi->srWindow.Left   = 0;
334                 pcsbi->srWindow.Right  = columns - 1;
335                 pcsbi->srWindow.Top    = 0;
336                 pcsbi->srWindow.Bottom = rows - 1;
337
338                 pcsbi->dwMaximumWindowSize.X = columns;
339                 pcsbi->dwMaximumWindowSize.Y = rows;
340
341                 Irp->IoStatus.Information = sizeof (CONSOLE_SCREEN_BUFFER_INFO);
342                 Status = STATUS_SUCCESS;
343             }
344             break;
345
346         case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO:
347             {
348                 PCONSOLE_SCREEN_BUFFER_INFO pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
349                 unsigned int offset;
350
351                 DeviceExtension->CharAttribute = pcsbi->wAttributes;
352                 offset = (pcsbi->dwCursorPosition.Y * DeviceExtension->Columns) +
353                           pcsbi->dwCursorPosition.X;
354
355                 __asm__("cli\n\t");
356                 WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSLO);
357                 WRITE_PORT_UCHAR (CRTC_DATA, offset);
358                 WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORPOSHI);
359                 WRITE_PORT_UCHAR (CRTC_DATA, offset>>8);
360                 __asm__("sti\n\t");
361
362                 Irp->IoStatus.Information = 0;
363                 Status = STATUS_SUCCESS;
364             }
365             break;
366
367         case IOCTL_CONSOLE_GET_CURSOR_INFO:
368             {
369                 PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
370
371                 pcci->dwSize = DeviceExtension->CursorSize;
372                 pcci->bVisible = DeviceExtension->CursorVisible;
373
374                 Irp->IoStatus.Information = sizeof (CONSOLE_CURSOR_INFO);
375                 Status = STATUS_SUCCESS;
376             }
377             break;
378
379         case IOCTL_CONSOLE_SET_CURSOR_INFO:
380             {
381                 PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
382                 BYTE data, value;
383                 DWORD size, height;
384
385                 DeviceExtension->CursorSize = pcci->dwSize;
386                 DeviceExtension->CursorVisible = pcci->bVisible;
387                 height = DeviceExtension->ScanLines;
388                 data = (pcci->bVisible) ? 0x40 : 0x20;
389
390                 size = (pcci->dwSize * height) / 100;
391                 if (size < 1)
392                     size = 1;
393
394                 data |= (BYTE)(height - size);
395
396                 __asm__("cli\n\t");
397                 WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSORSTART);
398                 WRITE_PORT_UCHAR (CRTC_DATA, data);
399                 WRITE_PORT_UCHAR (CRTC_COMMAND, CRTC_CURSOREND);
400                 value = READ_PORT_UCHAR (CRTC_DATA) & 0xE0;
401                 WRITE_PORT_UCHAR (CRTC_DATA, value | (height - 1));
402
403                 __asm__("sti\n\t");
404
405                 Irp->IoStatus.Information = 0;
406                 Status = STATUS_SUCCESS;
407             }
408             break;
409
410         case IOCTL_CONSOLE_GET_MODE:
411             {
412                 PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
413
414                 pcm->dwMode = DeviceExtension->Mode;
415
416                 Irp->IoStatus.Information = sizeof(CONSOLE_MODE);
417                 Status = STATUS_SUCCESS;
418             }
419             break;
420
421         case IOCTL_CONSOLE_SET_MODE:
422             {
423                 PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
424
425                 DeviceExtension->Mode = pcm->dwMode;
426
427                 Irp->IoStatus.Information = 0;
428                 Status = STATUS_SUCCESS;
429             }
430             break;
431
432         case IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE:
433             {
434                 POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
435                 char *vidmem;
436                 int offset;
437                 DWORD dwCount;
438
439                 vidmem = DeviceExtension->VideoMemory;
440                 offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
441                          (Buf->dwCoord.X * 2) + 1;
442
443                 for (dwCount = 0; dwCount < Buf->nLength; dwCount++)
444                 {
445                     vidmem[offset + (dwCount * 2)] = (char) Buf->wAttribute;
446                 }
447
448                 Buf->dwTransfered = Buf->nLength;
449                 
450                 Irp->IoStatus.Information = 0;
451                 Status = STATUS_SUCCESS;
452             }
453             break;
454
455         case IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE:
456             {
457                 POUTPUT_ATTRIBUTE Buf = (POUTPUT_ATTRIBUTE)Irp->AssociatedIrp.SystemBuffer;
458                 PWORD pAttr = (PWORD)MmGetSystemAddressForMdl(Irp->MdlAddress);
459                 char *vidmem;
460                 int offset;
461                 DWORD dwCount;
462
463                 vidmem = DeviceExtension->VideoMemory;
464                 offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
465                          (Buf->dwCoord.X * 2) + 1;
466
467                 for (dwCount = 0; dwCount < stk->Parameters.DeviceIoControl.OutputBufferLength; dwCount++, pAttr++)
468                 {
469                     (char) *pAttr = vidmem[offset + (dwCount * 2)];
470                 }
471
472                 Buf->dwTransfered = dwCount;
473
474                 Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
475                 Status = STATUS_SUCCESS;
476             }
477             break;
478
479         case IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE:
480             {
481                 COORD *pCoord = (COORD *)MmGetSystemAddressForMdl(Irp->MdlAddress);
482                 CHAR *pAttr = (CHAR *)(pCoord + 1);
483                 char *vidmem;
484                 int offset;
485                 DWORD dwCount;
486
487                 vidmem = DeviceExtension->VideoMemory;
488                 offset = (pCoord->Y * DeviceExtension->Columns * 2) +
489                          (pCoord->X * 2) + 1;
490
491                 for (dwCount = 0; dwCount < (stk->Parameters.DeviceIoControl.InputBufferLength - sizeof( COORD )); dwCount++, pAttr++)
492                 {
493                     vidmem[offset + (dwCount * 2)] = *pAttr;
494                 }
495                 Irp->IoStatus.Information = 0;
496                 Status = STATUS_SUCCESS;
497             }
498             break;
499
500         case IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE:
501             DeviceExtension->CharAttribute = (WORD)*(PWORD)Irp->AssociatedIrp.SystemBuffer;
502             Irp->IoStatus.Information = 0;
503             Status = STATUS_SUCCESS;
504             break;
505
506
507         case IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER:
508             {
509                 POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
510                 char *vidmem;
511                 int offset;
512                 DWORD dwCount;
513
514                 vidmem = DeviceExtension->VideoMemory;
515                 offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
516                          (Buf->dwCoord.X * 2);
517
518                 CHECKPOINT
519
520                 for (dwCount = 0; dwCount < Buf->nLength; dwCount++)
521                 {
522                     vidmem[offset + (dwCount * 2)] = (char) Buf->cCharacter;
523                 }
524
525                 Buf->dwTransfered = Buf->nLength;
526
527                 Irp->IoStatus.Information = 0;
528                 Status = STATUS_SUCCESS;
529             }
530             break;
531
532         case IOCTL_CONSOLE_READ_OUTPUT_CHARACTER:
533             {
534                 POUTPUT_CHARACTER Buf = (POUTPUT_CHARACTER)Irp->AssociatedIrp.SystemBuffer;
535                 LPSTR pChar = (LPSTR)MmGetSystemAddressForMdl(Irp->MdlAddress);
536                 char *vidmem;
537                 int offset;
538                 DWORD dwCount;
539
540                 vidmem = DeviceExtension->VideoMemory;
541                 offset = (Buf->dwCoord.Y * DeviceExtension->Columns * 2) +
542                          (Buf->dwCoord.X * 2);
543
544                 for (dwCount = 0; dwCount < stk->Parameters.DeviceIoControl.OutputBufferLength; dwCount++, pChar++)
545                 {
546                     *pChar = vidmem[offset + (dwCount * 2)];
547                 }
548
549                 Buf->dwTransfered = dwCount;
550
551                 Irp->IoStatus.Information = sizeof(OUTPUT_ATTRIBUTE);
552                 Status = STATUS_SUCCESS;
553             }
554             break;
555
556         case IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER:
557             {
558                 COORD *pCoord;
559                 LPSTR pChar;
560                 char *vidmem;
561                 int offset;
562                 DWORD dwCount;
563                 pCoord = (COORD *)MmGetSystemAddressForMdl(Irp->MdlAddress);
564                 pChar = (CHAR *)(pCoord + 1);
565                 vidmem = DeviceExtension->VideoMemory;
566                 offset = (pCoord->Y * DeviceExtension->Columns * 2) +
567                          (pCoord->X * 2);
568
569                 for (dwCount = 0; dwCount < (stk->Parameters.DeviceIoControl.InputBufferLength - sizeof( COORD )); dwCount++, pChar++)
570                 {
571                     vidmem[offset + (dwCount * 2)] = *pChar;
572                 }
573
574                 Irp->IoStatus.Information = 0;
575                 Status = STATUS_SUCCESS;
576             }
577             break;
578
579
580         default:
581             Status = STATUS_NOT_IMPLEMENTED;
582     }
583
584     Irp->IoStatus.Status = Status;
585     IoCompleteRequest (Irp, IO_NO_INCREMENT);
586
587     return (Status);
588 }
589
590
591 NTSTATUS STDCALL
592 ScrDispatch(PDEVICE_OBJECT DeviceObject,
593             PIRP Irp)
594 {
595     PIO_STACK_LOCATION stk = IoGetCurrentIrpStackLocation(Irp);
596     NTSTATUS Status;
597
598     switch (stk->MajorFunction)
599     {
600         case IRP_MJ_CLOSE:
601             Status = STATUS_SUCCESS;
602             break;
603
604         default:
605             Status = STATUS_NOT_IMPLEMENTED;
606             break;
607     }
608
609
610     Irp->IoStatus.Status = Status;
611     IoCompleteRequest (Irp, IO_NO_INCREMENT);
612
613     return (Status);
614 }
615
616
617 /*
618  * Module entry point
619  */
620 NTSTATUS STDCALL
621 DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
622 {
623     PDEVICE_OBJECT DeviceObject;
624     UNICODE_STRING DeviceName = UNICODE_STRING_INITIALIZER(L"\\Device\\BlueScreen");
625     UNICODE_STRING SymlinkName = UNICODE_STRING_INITIALIZER(L"\\??\\BlueScreen");
626
627     DPRINT ("Screen Driver 0.0.6\n");
628
629     DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH) ScrCreate;
630     DriverObject->MajorFunction[IRP_MJ_CLOSE]  = (PDRIVER_DISPATCH) ScrDispatch;
631     DriverObject->MajorFunction[IRP_MJ_READ]   = (PDRIVER_DISPATCH) ScrDispatch;
632     DriverObject->MajorFunction[IRP_MJ_WRITE]  = (PDRIVER_DISPATCH) ScrWrite;
633     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL ] = (PDRIVER_DISPATCH) ScrIoControl;
634
635     IoCreateDevice (DriverObject,
636                     sizeof(DEVICE_EXTENSION),
637                     &DeviceName,
638                     FILE_DEVICE_SCREEN,
639                     0,
640                     TRUE,
641                     &DeviceObject);
642
643     IoCreateSymbolicLink (&SymlinkName, &DeviceName);
644
645     return (STATUS_SUCCESS);
646 }
647
648 /* EOF */