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