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