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)
12 /* INCLUDES ******************************************************************/
14 #include <ddk/ntddk.h>
16 #include <blue/ntddblue.h>
17 #include <ndk/halfuncs.h>
23 /* DEFINITIONS ***************************************************************/
25 #define VIDMEM_BASE 0xb8000
27 #define CRTC_COMMAND ((PUCHAR)0x3d4)
28 #define CRTC_DATA ((PUCHAR)0x3d5)
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
39 #define ATTRC_WRITEREG ((PUCHAR)0x3c0)
40 #define ATTRC_READREG ((PUCHAR)0x3c1)
41 #define ATTRC_INPST1 ((PUCHAR)0x3da)
46 /* NOTES ******************************************************************/
48 * [[character][attribute]][[character][attribute]]....
52 /* TYPEDEFS ***************************************************************/
54 typedef struct _DEVICE_EXTENSION
56 PBYTE VideoMemory
; /* Pointer to video memory */
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
;
67 /* FUNCTIONS **************************************************************/
70 DriverEntry (PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
);
72 static NTSTATUS STDCALL
73 ScrCreate(PDEVICE_OBJECT DeviceObject
,
76 PDEVICE_EXTENSION DeviceExtension
;
77 PHYSICAL_ADDRESS BaseAddress
;
82 DeviceExtension
= DeviceObject
->DeviceExtension
;
84 /* disable interrupts */
87 /* get current output position */
88 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORPOSLO
);
89 offset
= READ_PORT_UCHAR (CRTC_DATA
);
90 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORPOSHI
);
91 offset
+= (READ_PORT_UCHAR (CRTC_DATA
) << 8);
93 /* switch blinking characters off */
94 READ_PORT_UCHAR (ATTRC_INPST1
);
95 value
= READ_PORT_UCHAR (ATTRC_WRITEREG
);
96 WRITE_PORT_UCHAR (ATTRC_WRITEREG
, 0x10);
97 data
= READ_PORT_UCHAR (ATTRC_READREG
);
99 WRITE_PORT_UCHAR (ATTRC_WRITEREG
, data
);
100 WRITE_PORT_UCHAR (ATTRC_WRITEREG
, value
);
101 READ_PORT_UCHAR (ATTRC_INPST1
);
103 /* read screen information from crt controller */
104 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_COLUMNS
);
105 DeviceExtension
->Columns
= READ_PORT_UCHAR (CRTC_DATA
) + 1;
106 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_ROWS
);
107 DeviceExtension
->Rows
= READ_PORT_UCHAR (CRTC_DATA
);
108 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_OVERFLOW
);
109 data
= READ_PORT_UCHAR (CRTC_DATA
);
110 DeviceExtension
->Rows
|= (((data
& 0x02) << 7) | ((data
& 0x40) << 3));
111 DeviceExtension
->Rows
++;
112 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_SCANLINES
);
113 DeviceExtension
->ScanLines
= (READ_PORT_UCHAR (CRTC_DATA
) & 0x1F) + 1;
115 /* enable interrupts */
118 /* calculate number of text rows */
119 DeviceExtension
->Rows
=
120 DeviceExtension
->Rows
/ DeviceExtension
->ScanLines
;
122 DeviceExtension
->Rows
= 30;
125 DPRINT ("%d Columns %d Rows %d Scanlines\n",
126 DeviceExtension
->Columns
,
127 DeviceExtension
->Rows
,
128 DeviceExtension
->ScanLines
);
130 /* get pointer to video memory */
131 BaseAddress
.QuadPart
= VIDMEM_BASE
;
132 DeviceExtension
->VideoMemory
=
133 (PBYTE
)MmMapIoSpace (BaseAddress
, DeviceExtension
->Rows
* DeviceExtension
->Columns
* 2, MmNonCached
);
135 DeviceExtension
->CursorSize
= 5; /* FIXME: value correct?? */
136 DeviceExtension
->CursorVisible
= TRUE
;
138 /* more initialization */
139 DeviceExtension
->CharAttribute
= 0x17; /* light grey on blue */
140 DeviceExtension
->Mode
= ENABLE_PROCESSED_OUTPUT
|
141 ENABLE_WRAP_AT_EOL_OUTPUT
;
143 /* show blinking cursor */
145 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORSTART
);
146 WRITE_PORT_UCHAR (CRTC_DATA
, (DeviceExtension
->ScanLines
- 1) & 0x1F);
147 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSOREND
);
148 data
= READ_PORT_UCHAR (CRTC_DATA
) & 0xE0;
149 WRITE_PORT_UCHAR (CRTC_DATA
,
150 data
| ((DeviceExtension
->ScanLines
- 1) & 0x1F));
153 Status
= STATUS_SUCCESS
;
155 Irp
->IoStatus
.Status
= Status
;
156 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
162 static NTSTATUS STDCALL
163 ScrWrite(PDEVICE_OBJECT DeviceObject
,
166 PIO_STACK_LOCATION stk
= IoGetCurrentIrpStackLocation (Irp
);
167 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
169 char *pch
= Irp
->UserBuffer
;
173 int cursorx
, cursory
;
175 int processed
= DeviceExtension
->Mode
& ENABLE_PROCESSED_OUTPUT
;
177 if (HalQueryDisplayOwnership())
179 /* Display is in graphics mode, we're not allowed to touch it */
180 Status
= STATUS_SUCCESS
;
182 Irp
->IoStatus
.Status
= Status
;
183 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
188 vidmem
= DeviceExtension
->VideoMemory
;
189 rows
= DeviceExtension
->Rows
;
190 columns
= DeviceExtension
->Columns
;
193 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORPOSHI
);
194 offset
= READ_PORT_UCHAR (CRTC_DATA
)<<8;
195 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORPOSLO
);
196 offset
+= READ_PORT_UCHAR (CRTC_DATA
);
199 cursory
= offset
/ columns
;
200 cursorx
= offset
% columns
;
203 /* raw output mode */
204 memcpy( &vidmem
[(cursorx
* 2) + (cursory
* columns
* 2)], pch
, stk
->Parameters
.Write
.Length
);
205 offset
+= (stk
->Parameters
.Write
.Length
/ 2);
208 for (i
= 0; i
< stk
->Parameters
.Write
.Length
; i
++, pch
++)
217 else if (cursory
> 0)
219 cursorx
= columns
- 1;
222 vidmem
[(cursorx
* 2) + (cursory
* columns
* 2)] = ' ';
223 vidmem
[(cursorx
* 2) + (cursory
* columns
* 2) + 1] = (char) DeviceExtension
->CharAttribute
;
236 offset
= TAB_WIDTH
- (cursorx
% TAB_WIDTH
);
237 for (j
= 0; j
< offset
; j
++)
239 vidmem
[(cursorx
* 2) + (cursory
* columns
* 2)] = ' ';
242 if (cursorx
>= columns
)
251 vidmem
[(cursorx
* 2) + (cursory
* columns
* 2)] = *pch
;
252 vidmem
[(cursorx
* 2) + (cursory
* columns
* 2) + 1] = (char) DeviceExtension
->CharAttribute
;
254 if (cursorx
>= columns
)
263 unsigned short *LinePtr
;
266 &vidmem
[columns
* 2],
267 columns
* (rows
- 1) * 2);
269 LinePtr
= (unsigned short *) &vidmem
[columns
* (rows
- 1) * 2];
271 for (j
= 0; j
< columns
; j
++)
273 LinePtr
[j
] = DeviceExtension
->CharAttribute
<< 8;
276 for (j
= 0; j
< columns
; j
++)
278 vidmem
[(j
* 2) + (cursory
* columns
* 2)] = ' ';
279 vidmem
[(j
* 2) + (cursory
* columns
* 2) + 1] = (char)DeviceExtension
->CharAttribute
;
284 /* Set the cursor position */
285 offset
= (cursory
* columns
) + cursorx
;
288 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORPOSLO
);
289 WRITE_PORT_UCHAR (CRTC_DATA
, offset
);
290 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORPOSHI
);
292 WRITE_PORT_UCHAR (CRTC_DATA
, offset
);
295 Status
= STATUS_SUCCESS
;
297 Irp
->IoStatus
.Status
= Status
;
298 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
304 static NTSTATUS STDCALL
305 ScrIoControl(PDEVICE_OBJECT DeviceObject
,
308 PIO_STACK_LOCATION stk
= IoGetCurrentIrpStackLocation (Irp
);
309 PDEVICE_EXTENSION DeviceExtension
;
312 DeviceExtension
= DeviceObject
->DeviceExtension
;
313 switch (stk
->Parameters
.DeviceIoControl
.IoControlCode
)
315 case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
:
317 PCONSOLE_SCREEN_BUFFER_INFO pcsbi
= (PCONSOLE_SCREEN_BUFFER_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
318 int rows
= DeviceExtension
->Rows
;
319 int columns
= DeviceExtension
->Columns
;
322 /* read cursor position from crtc */
324 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORPOSLO
);
325 offset
= READ_PORT_UCHAR (CRTC_DATA
);
326 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORPOSHI
);
327 offset
+= (READ_PORT_UCHAR (CRTC_DATA
) << 8);
330 pcsbi
->dwSize
.X
= columns
;
331 pcsbi
->dwSize
.Y
= rows
;
333 pcsbi
->dwCursorPosition
.X
= (SHORT
)(offset
% columns
);
334 pcsbi
->dwCursorPosition
.Y
= (SHORT
)(offset
/ columns
);
336 pcsbi
->wAttributes
= DeviceExtension
->CharAttribute
;
338 pcsbi
->srWindow
.Left
= 0;
339 pcsbi
->srWindow
.Right
= columns
- 1;
340 pcsbi
->srWindow
.Top
= 0;
341 pcsbi
->srWindow
.Bottom
= rows
- 1;
343 pcsbi
->dwMaximumWindowSize
.X
= columns
;
344 pcsbi
->dwMaximumWindowSize
.Y
= rows
;
346 Irp
->IoStatus
.Information
= sizeof (CONSOLE_SCREEN_BUFFER_INFO
);
347 Status
= STATUS_SUCCESS
;
351 case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
:
353 PCONSOLE_SCREEN_BUFFER_INFO pcsbi
= (PCONSOLE_SCREEN_BUFFER_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
356 DeviceExtension
->CharAttribute
= pcsbi
->wAttributes
;
357 offset
= (pcsbi
->dwCursorPosition
.Y
* DeviceExtension
->Columns
) +
358 pcsbi
->dwCursorPosition
.X
;
361 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORPOSLO
);
362 WRITE_PORT_UCHAR (CRTC_DATA
, offset
);
363 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORPOSHI
);
364 WRITE_PORT_UCHAR (CRTC_DATA
, offset
>>8);
367 Irp
->IoStatus
.Information
= 0;
368 Status
= STATUS_SUCCESS
;
372 case IOCTL_CONSOLE_GET_CURSOR_INFO
:
374 PCONSOLE_CURSOR_INFO pcci
= (PCONSOLE_CURSOR_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
376 pcci
->dwSize
= DeviceExtension
->CursorSize
;
377 pcci
->bVisible
= DeviceExtension
->CursorVisible
;
379 Irp
->IoStatus
.Information
= sizeof (CONSOLE_CURSOR_INFO
);
380 Status
= STATUS_SUCCESS
;
384 case IOCTL_CONSOLE_SET_CURSOR_INFO
:
386 PCONSOLE_CURSOR_INFO pcci
= (PCONSOLE_CURSOR_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
390 DeviceExtension
->CursorSize
= pcci
->dwSize
;
391 DeviceExtension
->CursorVisible
= pcci
->bVisible
;
392 height
= DeviceExtension
->ScanLines
;
393 data
= (pcci
->bVisible
) ? 0x00 : 0x20;
395 size
= (pcci
->dwSize
* height
) / 100;
401 data
|= (BYTE
)(height
- size
);
404 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORSTART
);
405 WRITE_PORT_UCHAR (CRTC_DATA
, data
);
406 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSOREND
);
407 value
= READ_PORT_UCHAR (CRTC_DATA
) & 0xE0;
408 WRITE_PORT_UCHAR (CRTC_DATA
, value
| (height
- 1));
412 Irp
->IoStatus
.Information
= 0;
413 Status
= STATUS_SUCCESS
;
417 case IOCTL_CONSOLE_GET_MODE
:
419 PCONSOLE_MODE pcm
= (PCONSOLE_MODE
)Irp
->AssociatedIrp
.SystemBuffer
;
421 pcm
->dwMode
= DeviceExtension
->Mode
;
423 Irp
->IoStatus
.Information
= sizeof(CONSOLE_MODE
);
424 Status
= STATUS_SUCCESS
;
428 case IOCTL_CONSOLE_SET_MODE
:
430 PCONSOLE_MODE pcm
= (PCONSOLE_MODE
)Irp
->AssociatedIrp
.SystemBuffer
;
432 DeviceExtension
->Mode
= pcm
->dwMode
;
434 Irp
->IoStatus
.Information
= 0;
435 Status
= STATUS_SUCCESS
;
439 case IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE
:
441 POUTPUT_ATTRIBUTE Buf
= (POUTPUT_ATTRIBUTE
)Irp
->AssociatedIrp
.SystemBuffer
;
446 vidmem
= DeviceExtension
->VideoMemory
;
447 offset
= (Buf
->dwCoord
.Y
* DeviceExtension
->Columns
* 2) +
448 (Buf
->dwCoord
.X
* 2) + 1;
450 for (dwCount
= 0; dwCount
< Buf
->nLength
; dwCount
++)
452 vidmem
[offset
+ (dwCount
* 2)] = (char) Buf
->wAttribute
;
455 Buf
->dwTransfered
= Buf
->nLength
;
457 Irp
->IoStatus
.Information
= 0;
458 Status
= STATUS_SUCCESS
;
462 case IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE
:
464 POUTPUT_ATTRIBUTE Buf
= (POUTPUT_ATTRIBUTE
)Irp
->AssociatedIrp
.SystemBuffer
;
465 PWORD pAttr
= (PWORD
)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
470 vidmem
= DeviceExtension
->VideoMemory
;
471 offset
= (Buf
->dwCoord
.Y
* DeviceExtension
->Columns
* 2) +
472 (Buf
->dwCoord
.X
* 2) + 1;
474 for (dwCount
= 0; dwCount
< stk
->Parameters
.DeviceIoControl
.OutputBufferLength
; dwCount
++, pAttr
++)
476 *((char *) pAttr
) = vidmem
[offset
+ (dwCount
* 2)];
479 Buf
->dwTransfered
= dwCount
;
481 Irp
->IoStatus
.Information
= sizeof(OUTPUT_ATTRIBUTE
);
482 Status
= STATUS_SUCCESS
;
486 case IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE
:
488 COORD
*pCoord
= (COORD
*)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
489 CHAR
*pAttr
= (CHAR
*)(pCoord
+ 1);
494 vidmem
= DeviceExtension
->VideoMemory
;
495 offset
= (pCoord
->Y
* DeviceExtension
->Columns
* 2) +
498 for (dwCount
= 0; dwCount
< (stk
->Parameters
.DeviceIoControl
.OutputBufferLength
- sizeof( COORD
)); dwCount
++, pAttr
++)
500 vidmem
[offset
+ (dwCount
* 2)] = *pAttr
;
502 Irp
->IoStatus
.Information
= 0;
503 Status
= STATUS_SUCCESS
;
507 case IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE
:
508 DeviceExtension
->CharAttribute
= (WORD
)*(PWORD
)Irp
->AssociatedIrp
.SystemBuffer
;
509 Irp
->IoStatus
.Information
= 0;
510 Status
= STATUS_SUCCESS
;
513 case IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER
:
515 POUTPUT_CHARACTER Buf
= (POUTPUT_CHARACTER
)Irp
->AssociatedIrp
.SystemBuffer
;
520 vidmem
= DeviceExtension
->VideoMemory
;
521 offset
= (Buf
->dwCoord
.Y
* DeviceExtension
->Columns
* 2) +
522 (Buf
->dwCoord
.X
* 2);
526 for (dwCount
= 0; dwCount
< Buf
->nLength
; dwCount
++)
528 vidmem
[offset
+ (dwCount
* 2)] = (char) Buf
->cCharacter
;
531 Buf
->dwTransfered
= Buf
->nLength
;
533 Irp
->IoStatus
.Information
= 0;
534 Status
= STATUS_SUCCESS
;
538 case IOCTL_CONSOLE_READ_OUTPUT_CHARACTER
:
540 POUTPUT_CHARACTER Buf
= (POUTPUT_CHARACTER
)Irp
->AssociatedIrp
.SystemBuffer
;
541 LPSTR pChar
= (LPSTR
)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
546 vidmem
= DeviceExtension
->VideoMemory
;
547 offset
= (Buf
->dwCoord
.Y
* DeviceExtension
->Columns
* 2) +
548 (Buf
->dwCoord
.X
* 2);
550 for (dwCount
= 0; dwCount
< stk
->Parameters
.DeviceIoControl
.OutputBufferLength
; dwCount
++, pChar
++)
552 *pChar
= vidmem
[offset
+ (dwCount
* 2)];
555 Buf
->dwTransfered
= dwCount
;
557 Irp
->IoStatus
.Information
= sizeof(OUTPUT_ATTRIBUTE
);
558 Status
= STATUS_SUCCESS
;
562 case IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
:
570 pCoord
= (COORD
*)MmGetSystemAddressForMdl(Irp
->MdlAddress
);
571 pChar
= (CHAR
*)(pCoord
+ 1);
572 vidmem
= DeviceExtension
->VideoMemory
;
573 offset
= (pCoord
->Y
* DeviceExtension
->Columns
* 2) +
576 for (dwCount
= 0; dwCount
< (stk
->Parameters
.DeviceIoControl
.OutputBufferLength
- sizeof( COORD
)); dwCount
++, pChar
++)
578 vidmem
[offset
+ (dwCount
* 2)] = *pChar
;
581 Irp
->IoStatus
.Information
= 0;
582 Status
= STATUS_SUCCESS
;
586 case IOCTL_CONSOLE_DRAW
:
588 PCONSOLE_DRAW ConsoleDraw
;
590 UINT SrcDelta
, DestDelta
, i
, Offset
;
592 ConsoleDraw
= (PCONSOLE_DRAW
) MmGetSystemAddressForMdl(Irp
->MdlAddress
);
593 Src
= (PBYTE
) (ConsoleDraw
+ 1);
594 SrcDelta
= ConsoleDraw
->SizeX
* 2;
595 Dest
= DeviceExtension
->VideoMemory
+
596 (ConsoleDraw
->Y
* DeviceExtension
->Columns
+ ConsoleDraw
->X
) * 2;
597 DestDelta
= DeviceExtension
->Columns
* 2;
599 for (i
= 0; i
< ConsoleDraw
->SizeY
; i
++)
601 RtlCopyMemory(Dest
, Src
, SrcDelta
);
606 Offset
= (ConsoleDraw
->CursorY
* DeviceExtension
->Columns
) +
607 ConsoleDraw
->CursorX
;
610 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORPOSLO
);
611 WRITE_PORT_UCHAR (CRTC_DATA
, Offset
);
612 WRITE_PORT_UCHAR (CRTC_COMMAND
, CRTC_CURSORPOSHI
);
613 WRITE_PORT_UCHAR (CRTC_DATA
, Offset
>> 8);
616 Irp
->IoStatus
.Information
= 0;
617 Status
= STATUS_SUCCESS
;
622 Status
= STATUS_NOT_IMPLEMENTED
;
625 Irp
->IoStatus
.Status
= Status
;
626 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
632 static NTSTATUS STDCALL
633 ScrDispatch(PDEVICE_OBJECT DeviceObject
,
636 PIO_STACK_LOCATION stk
= IoGetCurrentIrpStackLocation(Irp
);
639 switch (stk
->MajorFunction
)
642 Status
= STATUS_SUCCESS
;
646 Status
= STATUS_NOT_IMPLEMENTED
;
651 Irp
->IoStatus
.Status
= Status
;
652 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
662 DriverEntry (PDRIVER_OBJECT DriverObject
, PUNICODE_STRING RegistryPath
)
664 PDEVICE_OBJECT DeviceObject
;
665 UNICODE_STRING DeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\BlueScreen");
666 UNICODE_STRING SymlinkName
= RTL_CONSTANT_STRING(L
"\\??\\BlueScreen");
668 DPRINT ("Screen Driver 0.0.6\n");
670 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScrCreate
;
671 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScrDispatch
;
672 DriverObject
->MajorFunction
[IRP_MJ_READ
] = ScrDispatch
;
673 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = ScrWrite
;
674 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScrIoControl
;
676 IoCreateDevice (DriverObject
,
677 sizeof(DEVICE_EXTENSION
),
684 IoCreateSymbolicLink (&SymlinkName
, &DeviceName
);
686 return (STATUS_SUCCESS
);