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