merge ROS Shell without integrated explorer part into trunk
[reactos.git] / reactos / drivers / dd / green / screen.c
1 /* $Id:
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS VT100 emulator
5 * FILE: drivers/dd/green/screen.c
6 * PURPOSE: Screen part of green management
7 *
8 * PROGRAMMERS: Eric Kohl (ekohl@abo.rhein-zeitung.de)
9 * Art Yerkes
10 * Hervé Poussineau (hpoussin@reactos.com)
11 */
12
13 #define NDEBUG
14 #include "green.h"
15 #include <stdarg.h>
16
17 #define ESC ((UCHAR)0x1b)
18
19 /* Force a move of the cursor on each printer char.
20 * Very useful for debug, but it is very slow...
21 */
22 //#define FORCE_POSITION
23
24 /* UCHAR is promoted to int when passed through '...',
25 * so we get int with va_arg and cast them back to UCHAR.
26 */
27 static VOID
28 AddToSendBuffer(
29 IN PSCREEN_DEVICE_EXTENSION DeviceExtension,
30 IN ULONG NumberOfChars,
31 ... /* IN int */)
32 {
33 PIRP Irp;
34 IO_STATUS_BLOCK ioStatus;
35 va_list args;
36 PDEVICE_OBJECT SerialDevice;
37 ULONG SizeLeft;
38 int CurrentInt;
39 UCHAR CurrentChar;
40 NTSTATUS Status;
41
42 SizeLeft = sizeof(DeviceExtension->SendBuffer) - DeviceExtension->SendBufferPosition;
43 if (SizeLeft < NumberOfChars * 2 || NumberOfChars == 0)
44 {
45 SerialDevice = ((PGREEN_DEVICE_EXTENSION)DeviceExtension->Green->DeviceExtension)->Serial;
46 Irp = IoBuildSynchronousFsdRequest(
47 IRP_MJ_WRITE,
48 SerialDevice,
49 DeviceExtension->SendBuffer, DeviceExtension->SendBufferPosition,
50 NULL, /* StartingOffset */
51 NULL, /* Event */
52 &ioStatus);
53 if (!Irp)
54 {
55 DPRINT1("Green: IoBuildSynchronousFsdRequest() failed. Unable to flush output buffer\n");
56 return;
57 }
58 Status = IoCallDriver(SerialDevice, Irp);
59 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING)
60 {
61 DPRINT1("Green: IoCallDriver() failed. Status = 0x%08lx\n", Status);
62 return;
63 }
64 DeviceExtension->SendBufferPosition = 0;
65 SizeLeft = sizeof(DeviceExtension->SendBuffer);
66 }
67
68 va_start(args, NumberOfChars);
69 while (NumberOfChars-- > 0)
70 {
71 CurrentInt = va_arg(args, int);
72 if (CurrentInt > 0)
73 {
74 CurrentChar = (UCHAR)CurrentInt;
75
76 /* Why 0xff chars are printed on a 'dir' ? */
77 if (CurrentChar == 0xff) CurrentChar = ' ';
78
79 DeviceExtension->SendBuffer[DeviceExtension->SendBufferPosition++] = CurrentChar;
80 SizeLeft--;
81 }
82 else if (CurrentInt == 0)
83 {
84 DeviceExtension->SendBuffer[DeviceExtension->SendBufferPosition++] = '0';
85 SizeLeft--;
86 }
87 else
88 {
89 CurrentInt = -CurrentInt;
90 ASSERT(CurrentInt < 100);
91 if (CurrentInt >= 10)
92 {
93 DeviceExtension->SendBuffer[DeviceExtension->SendBufferPosition++] =
94 (CurrentInt / 10) % 10 + '0';
95 SizeLeft--;
96 }
97 DeviceExtension->SendBuffer[DeviceExtension->SendBufferPosition++] =
98 CurrentInt % 10 + '0';
99 SizeLeft--;
100 }
101 }
102 va_end(args);
103 }
104
105 NTSTATUS
106 ScreenInitialize(
107 IN PDRIVER_OBJECT DriverObject,
108 OUT PDEVICE_OBJECT* ScreenFdo)
109 {
110 PDEVICE_OBJECT Fdo;
111 PSCREEN_DEVICE_EXTENSION DeviceExtension;
112 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\BlueScreen");
113 NTSTATUS Status;
114
115 DPRINT("Green: ScreenInitialize() called\n");
116
117 Status = IoCreateDevice(DriverObject,
118 sizeof(SCREEN_DEVICE_EXTENSION),
119 &DeviceName, /* FIXME: don't hardcode string */
120 FILE_DEVICE_SCREEN,
121 FILE_DEVICE_SECURE_OPEN,
122 TRUE,
123 &Fdo);
124 if (!NT_SUCCESS(Status))
125 return Status;
126
127 DeviceExtension = (PSCREEN_DEVICE_EXTENSION)Fdo->DeviceExtension;
128 RtlZeroMemory(DeviceExtension, sizeof(SCREEN_DEVICE_EXTENSION));
129 DeviceExtension->Common.Type = Screen;
130 /* initialize screen */
131 DeviceExtension->Columns = 80;
132 DeviceExtension->Rows = 25;
133 DeviceExtension->ScanLines = 16;
134 DeviceExtension->VideoMemory = (PUCHAR)ExAllocatePool(
135 PagedPool,
136 2 * DeviceExtension->Columns * DeviceExtension->Rows * sizeof(UCHAR));
137 if (!DeviceExtension->VideoMemory)
138 {
139 IoDeleteDevice(Fdo);
140 return STATUS_INSUFFICIENT_RESOURCES;
141 }
142 DeviceExtension->TabWidth = 8;
143
144 /* more initialization */
145 DeviceExtension->Mode = ENABLE_PROCESSED_OUTPUT |
146 ENABLE_WRAP_AT_EOL_OUTPUT;
147
148 /* initialize screen at next write */
149 AddToSendBuffer(DeviceExtension, 2, ESC, 'c'); /* reset device */
150 AddToSendBuffer(DeviceExtension, 4, ESC, '[', '7', 'l'); /* disable line wrap */
151 AddToSendBuffer(DeviceExtension, 4, ESC, '[', '3', 'g'); /* clear all tabs */
152
153 Fdo->Flags |= DO_POWER_PAGABLE | DO_BUFFERED_IO;
154 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
155
156 *ScreenFdo = Fdo;
157
158 return STATUS_SUCCESS;
159 }
160
161 NTSTATUS
162 ScreenWrite(
163 IN PDEVICE_OBJECT DeviceObject,
164 IN PIRP Irp)
165 {
166 PIO_STACK_LOCATION Stack;
167 PUCHAR Buffer;
168 PSCREEN_DEVICE_EXTENSION DeviceExtension;
169 PUCHAR VideoMemory; /* FIXME: is it useful? */
170 ULONG VideoMemorySize; /* FIXME: is it useful? */
171
172 ULONG Columns, Rows;
173 ULONG CursorX, CursorY;
174 ULONG i, j;
175 NTSTATUS Status;
176
177 DPRINT("Green: IRP_MJ_WRITE\n");
178
179 Stack = IoGetCurrentIrpStackLocation (Irp);
180 Buffer = Irp->UserBuffer;
181 DeviceExtension = (PSCREEN_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
182 VideoMemory = DeviceExtension->VideoMemory;
183
184 Columns = DeviceExtension->Columns;
185 Rows = DeviceExtension->Rows;
186 CursorX = (DeviceExtension->LogicalOffset / 2) % Columns + 1;
187 CursorY = (DeviceExtension->LogicalOffset / 2) / Columns + 1;
188 VideoMemorySize = Columns * Rows * 2 * sizeof(UCHAR);
189 DPRINT1("Y: %lu\n", CursorY);
190 DPRINT1("Buffer =");
191 for (i = 0; i < Stack->Parameters.Write.Length; i++)
192 DbgPrint(" 0x%02x", Buffer[i]);
193 DbgPrint("\n");
194
195 if (!(DeviceExtension->Mode & ENABLE_PROCESSED_OUTPUT))
196 {
197 /* raw output mode */
198 CHECKPOINT;
199 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
200 IoCompleteRequest (Irp, IO_NO_INCREMENT);
201
202 return STATUS_NOT_SUPPORTED;
203 }
204 else
205 {
206 for (i = 0; i < Stack->Parameters.Write.Length; i++, Buffer++)
207 {
208 switch (*Buffer)
209 {
210 case '\b':
211 {
212 if (CursorX > 1)
213 {
214 CursorX--;
215 AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', -(int)CursorX, 'H');
216 AddToSendBuffer(DeviceExtension, 1, ' ');
217 AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', -(int)CursorX, 'H');
218 }
219 else if (CursorY > 1)
220 {
221 CursorX = Columns;
222 CursorY--;
223 AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', -(int)CursorX, 'H');
224 }
225 break;
226 }
227 case '\n':
228 {
229 CursorY++;
230 CursorX = 1;
231 AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', '1', 'H');
232 break;
233 }
234 case '\r':
235 {
236 if (CursorX > 1)
237 {
238 AddToSendBuffer(DeviceExtension, 4, ESC, '[', -(int)(CursorX-1), 'D');
239 CursorX = 1;
240 }
241 break;
242 }
243 case '\t':
244 {
245 ULONG Offset = DeviceExtension->TabWidth - (CursorX % DeviceExtension->TabWidth);
246 for (j = 0; j < Offset; j++)
247 {
248 #ifdef FORCE_POSITION
249 AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', -(int)CursorX, 'H');
250 #endif
251 AddToSendBuffer(DeviceExtension, 1, ' ');
252 CursorX++;
253 if (CursorX > Columns)
254 {
255 CursorX = 1;
256 CursorY++;
257 }
258 }
259 break;
260 }
261 default:
262 {
263 #ifdef FORCE_POSITION
264 AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', -(int)CursorX, 'H');
265 #endif
266 AddToSendBuffer(DeviceExtension, 1, *Buffer);
267 CursorX++;
268 if (CursorX > Columns)
269 {
270 CursorX = 1;
271 DPRINT1("Y: %lu -> %lu\n", CursorY, CursorY + 1);
272 CursorY++;
273 AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', '1', 'H');
274
275 }
276 }
277 }
278 if (CursorY > Rows)
279 {
280 DPRINT1("Y: %lu -> %lu\n", CursorY, CursorY - 1);
281 CursorY--;
282 AddToSendBuffer(DeviceExtension, 2, ESC, 'D');
283 AddToSendBuffer(DeviceExtension, 6, ESC, '[', -(int)CursorY, ';', -(int)CursorX, 'H');
284 }
285 }
286 }
287
288 DeviceExtension->LogicalOffset = ((CursorX-1) + (CursorY-1) * Columns) * 2;
289
290 /* flush output buffer */
291 AddToSendBuffer(DeviceExtension, 0);
292
293 Status = STATUS_SUCCESS;
294 Irp->IoStatus.Status = Status;
295 IoCompleteRequest (Irp, IO_NO_INCREMENT);
296
297 return Status;
298 }
299
300 NTSTATUS
301 ScreenDeviceControl(
302 IN PDEVICE_OBJECT DeviceObject,
303 IN PIRP Irp)
304 {
305 PIO_STACK_LOCATION Stack;
306 PSCREEN_DEVICE_EXTENSION DeviceExtension;
307 NTSTATUS Status;
308
309 Stack = IoGetCurrentIrpStackLocation(Irp);
310 DeviceExtension = (PSCREEN_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
311
312 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
313 {
314 case IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO:
315 {
316 PCONSOLE_SCREEN_BUFFER_INFO pcsbi;
317 DPRINT("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO\n");
318
319 pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
320
321 pcsbi->dwSize.X = DeviceExtension->Columns;
322 pcsbi->dwSize.Y = DeviceExtension->Rows;
323
324 pcsbi->dwCursorPosition.X = (SHORT)(DeviceExtension->LogicalOffset % DeviceExtension->Columns);
325 pcsbi->dwCursorPosition.Y = (SHORT)(DeviceExtension->LogicalOffset / DeviceExtension->Columns);
326
327 pcsbi->wAttributes = DeviceExtension->CharAttribute;
328
329 pcsbi->srWindow.Left = 1;
330 pcsbi->srWindow.Right = DeviceExtension->Columns;
331 pcsbi->srWindow.Top = 1;
332 pcsbi->srWindow.Bottom = DeviceExtension->Rows;
333
334 pcsbi->dwMaximumWindowSize.X = DeviceExtension->Columns;
335 pcsbi->dwMaximumWindowSize.Y = DeviceExtension->Rows;
336
337 Irp->IoStatus.Information = sizeof(CONSOLE_SCREEN_BUFFER_INFO);
338 Status = STATUS_SUCCESS;
339 break;
340 }
341 case IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO:
342 {
343 PCONSOLE_SCREEN_BUFFER_INFO pcsbi;
344 DPRINT("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO\n");
345
346 pcsbi = (PCONSOLE_SCREEN_BUFFER_INFO)Irp->AssociatedIrp.SystemBuffer;
347 /* FIXME: remove */ { pcsbi->dwCursorPosition.X++; }
348 /* FIXME: remove */ { pcsbi->dwCursorPosition.Y++; }
349 ASSERT(pcsbi->dwCursorPosition.X >= 1);
350 ASSERT(pcsbi->dwCursorPosition.Y >= 1);
351 ASSERT(pcsbi->dwCursorPosition.X <= DeviceExtension->Columns);
352 ASSERT(pcsbi->dwCursorPosition.Y <= DeviceExtension->Rows);
353
354 DeviceExtension->LogicalOffset = (
355 (pcsbi->dwCursorPosition.Y-1) * DeviceExtension->Columns +
356 (pcsbi->dwCursorPosition.X-1)) * 2;
357 AddToSendBuffer(DeviceExtension, 6, ESC, '[',
358 -(int)pcsbi->dwCursorPosition.Y, ';',
359 -(int)pcsbi->dwCursorPosition.X, 'H');
360
361 /* flush buffer */
362 AddToSendBuffer(DeviceExtension, 0);
363
364 DeviceExtension->CharAttribute = pcsbi->wAttributes;
365
366 Irp->IoStatus.Information = 0;
367 Status = STATUS_SUCCESS;
368 break;
369 }
370 case IOCTL_CONSOLE_GET_CURSOR_INFO:
371 {
372 PCONSOLE_CURSOR_INFO pcci = (PCONSOLE_CURSOR_INFO)Irp->AssociatedIrp.SystemBuffer;
373 DPRINT("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_GET_CURSOR_INFO\n");
374
375 pcci->dwSize = 1;
376 pcci->bVisible = TRUE;
377
378 Irp->IoStatus.Information = sizeof (CONSOLE_CURSOR_INFO);
379 Status = STATUS_SUCCESS;
380 break;
381 }
382 case IOCTL_CONSOLE_GET_MODE:
383 {
384 PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
385 DPRINT("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_GET_MODE\n");
386
387 pcm->dwMode = DeviceExtension->Mode;
388
389 Irp->IoStatus.Information = sizeof(CONSOLE_MODE);
390 Status = STATUS_SUCCESS;
391 break;
392 }
393 case IOCTL_CONSOLE_SET_MODE:
394 {
395 PCONSOLE_MODE pcm = (PCONSOLE_MODE)Irp->AssociatedIrp.SystemBuffer;
396 DPRINT("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_SET_MODE\n");
397
398 DeviceExtension->Mode = pcm->dwMode;
399
400 Irp->IoStatus.Information = 0;
401 Status = STATUS_SUCCESS;
402 break;
403 }
404 case IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE:
405 {
406 DPRINT1("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE\n");
407 Status = STATUS_NOT_IMPLEMENTED; /* FIXME: IOCTL_CONSOLE_FILL_OUTPUT_ATTRIBUTE */
408 break;
409 }
410 case IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE:
411 {
412 DPRINT1("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE\n");
413 Status = STATUS_NOT_IMPLEMENTED; /* FIXME: IOCTL_CONSOLE_READ_OUTPUT_ATTRIBUTE */
414 break;
415 }
416 case IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE:
417 {
418 DPRINT1("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE\n");
419 Status = STATUS_NOT_IMPLEMENTED; /* FIXME: IOCTL_CONSOLE_WRITE_OUTPUT_ATTRIBUTE */
420 break;
421 }
422 case IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE:
423 {
424 DPRINT("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE\n");
425
426 DeviceExtension->CharAttribute = (WORD)*(PWORD)Irp->AssociatedIrp.SystemBuffer;
427 Irp->IoStatus.Information = 0;
428 Status = STATUS_SUCCESS;
429 break;
430 }
431 case IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER:
432 {
433 DPRINT1("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER\n");
434 Status = STATUS_NOT_IMPLEMENTED; /* FIXME:IOCTL_CONSOLE_FILL_OUTPUT_CHARACTER */
435 break;
436 }
437 case IOCTL_CONSOLE_READ_OUTPUT_CHARACTER:
438 {
439 DPRINT1("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_READ_OUTPUT_CHARACTER\n");
440 Status = STATUS_NOT_IMPLEMENTED; /* FIXME: IOCTL_CONSOLE_READ_OUTPUT_CHARACTER */
441 break;
442 }
443 case IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER:
444 {
445 DPRINT1("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER\n");
446 Status = STATUS_NOT_IMPLEMENTED; /* FIXME: IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER */
447 break;
448 }
449 case IOCTL_CONSOLE_DRAW:
450 {
451 PCONSOLE_DRAW ConsoleDraw;
452 PUCHAR Video;
453 ULONG x, y;
454 BOOLEAN DoOptimization = FALSE;
455 DPRINT("Green: IRP_MJ_DEVICE_CONTROL / IOCTL_CONSOLE_DRAW\n");
456
457 ConsoleDraw = (PCONSOLE_DRAW)MmGetSystemAddressForMdl(Irp->MdlAddress);
458 /* FIXME: remove */ { ConsoleDraw->X++; ConsoleDraw->CursorX++; }
459 /* FIXME: remove */ { ConsoleDraw->Y++; ConsoleDraw->CursorY++; }
460 DPRINT1("%lu %lu %lu %lu\n",
461 ConsoleDraw->X, ConsoleDraw->Y,
462 ConsoleDraw->SizeX, ConsoleDraw->SizeY);
463 ASSERT(ConsoleDraw->X >= 1);
464 ASSERT(ConsoleDraw->Y >= 1);
465 ASSERT(ConsoleDraw->X <= DeviceExtension->Columns);
466 ASSERT(ConsoleDraw->Y <= DeviceExtension->Rows);
467 ASSERT(ConsoleDraw->X + ConsoleDraw->SizeX >= 1);
468 ASSERT(ConsoleDraw->Y + ConsoleDraw->SizeY >= 1);
469 ASSERT(ConsoleDraw->X + ConsoleDraw->SizeX - 1 <= DeviceExtension->Columns);
470 ASSERT(ConsoleDraw->Y + ConsoleDraw->SizeY - 1 <= DeviceExtension->Rows);
471 ASSERT(ConsoleDraw->CursorX >= 1);
472 ASSERT(ConsoleDraw->CursorY >= 1);
473 ASSERT(ConsoleDraw->CursorX <= DeviceExtension->Columns);
474 ASSERT(ConsoleDraw->CursorY <= DeviceExtension->Rows);
475
476 #if 0
477 if (ConsoleDraw->X == 1
478 && ConsoleDraw->Y == 1
479 && ConsoleDraw->SizeX == DeviceExtension->Columns
480 && ConsoleDraw->SizeY == DeviceExtension->Rows)
481 {
482 CHECKPOINT1;
483 /* search if we need to clear all screen */
484 DoOptimization = TRUE;
485 Video = (PUCHAR)(ConsoleDraw + 1);
486 x = 0;
487 while (DoOptimization && x < DeviceExtension->Columns * DeviceExtension->Rows)
488 {
489 if (Video[x++] != ' ')
490 {
491 CHECKPOINT1;
492 DoOptimization = FALSE;
493 }
494 /*if (Video[x++] != DeviceExtension->CharAttribute) DoOptimization = FALSE; */
495 }
496 if (DoOptimization)
497 {
498 CHECKPOINT1;
499 AddToSendBuffer(DeviceExtension, 4, ESC, '[', '2', 'J');
500 }
501 }
502 #endif
503 /* add here more optimizations if needed */
504
505 if (!DoOptimization)
506 {
507 for (y = 0; y < ConsoleDraw->SizeY; y++)
508 {
509 AddToSendBuffer(DeviceExtension, 6, ESC, '[',
510 -(int)(ConsoleDraw->Y + y), ';',
511 -(int)(ConsoleDraw->X), 'H');
512 Video = (PUCHAR)(ConsoleDraw + 1);
513 Video = &Video[((ConsoleDraw->Y + y) * DeviceExtension->Columns + ConsoleDraw->X) * 2];
514 for (x = 0; x < ConsoleDraw->SizeX; x++)
515 {
516 AddToSendBuffer(DeviceExtension, 1, Video[x * 2]);
517 }
518 }
519 }
520
521 DeviceExtension->LogicalOffset = (
522 (ConsoleDraw->CursorY-1) * DeviceExtension->Columns +
523 (ConsoleDraw->CursorX-1)) * 2;
524 AddToSendBuffer(DeviceExtension, 6, ESC, '[',
525 -(int)(ConsoleDraw->CursorY), ';',
526 -(int)(ConsoleDraw->CursorX), 'H');
527
528 /* flush buffer */
529 AddToSendBuffer(DeviceExtension, 0);
530
531 Irp->IoStatus.Information = 0;
532 Status = STATUS_SUCCESS;
533 break;
534 }
535 default:
536 DPRINT1("Green: IRP_MJ_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
537 Stack->Parameters.DeviceIoControl.IoControlCode);
538 Status = STATUS_NOT_IMPLEMENTED;
539 }
540
541 Irp->IoStatus.Status = Status;
542 IoCompleteRequest (Irp, IO_NO_INCREMENT);
543 return Status;
544 }