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