- Add new unified VGA/VBE miniport driver. Based on NT4 DDK Cirrus Miniport Driver...
[reactos.git] / reactos / drivers / video / miniport / vga_new / modeset.c
1 /*
2 * PROJECT: ReactOS VGA Miniport Driver
3 * LICENSE: Microsoft NT4 DDK Sample Code License
4 * FILE: boot/drivers/video/miniport/vga/modeset.c
5 * PURPOSE: Handles switching to Standard VGA Modes for compatible cards
6 * PROGRAMMERS: Copyright (c) 1992 Microsoft Corporation
7 * ReactOS Portable Systems Group
8 */
9
10 #include "vga.h"
11
12 VP_STATUS
13 VgaInterpretCmdStream(
14 PHW_DEVICE_EXTENSION HwDeviceExtension,
15 PUSHORT pusCmdStream
16 );
17
18 VP_STATUS
19 VgaSetMode(
20 PHW_DEVICE_EXTENSION HwDeviceExtension,
21 PVIDEO_MODE Mode,
22 ULONG ModeSize,
23 // eVb: 2.1 [SET MODE] - Add new output parameter for framebuffer update functionality
24 PULONG PhysPtrChange
25 // eVb: 2.1 [END]
26 );
27
28 VP_STATUS
29 VgaQueryAvailableModes(
30 PHW_DEVICE_EXTENSION HwDeviceExtension,
31 PVIDEO_MODE_INFORMATION ModeInformation,
32 ULONG ModeInformationSize,
33 PULONG OutputSize
34 );
35
36 VP_STATUS
37 VgaQueryNumberOfAvailableModes(
38 PHW_DEVICE_EXTENSION HwDeviceExtension,
39 PVIDEO_NUM_MODES NumModes,
40 ULONG NumModesSize,
41 PULONG OutputSize
42 );
43
44 VOID
45 VgaZeroVideoMemory(
46 PHW_DEVICE_EXTENSION HwDeviceExtension
47 );
48
49 #if defined(ALLOC_PRAGMA)
50 #pragma alloc_text(PAGE,VgaInterpretCmdStream)
51 #pragma alloc_text(PAGE,VgaSetMode)
52 #pragma alloc_text(PAGE,VgaQueryAvailableModes)
53 #pragma alloc_text(PAGE,VgaQueryNumberOfAvailableModes)
54 #pragma alloc_text(PAGE,VgaZeroVideoMemory)
55 #endif
56
57 //---------------------------------------------------------------------------
58 VP_STATUS
59 VgaInterpretCmdStream(
60 PHW_DEVICE_EXTENSION HwDeviceExtension,
61 PUSHORT pusCmdStream
62 )
63
64 /*++
65
66 Routine Description:
67
68 Interprets the appropriate command array to set up VGA registers for the
69 requested mode. Typically used to set the VGA into a particular mode by
70 programming all of the registers
71
72 Arguments:
73
74 HwDeviceExtension - Pointer to the miniport driver's device extension.
75
76 pusCmdStream - array of commands to be interpreted.
77
78 Return Value:
79
80 The status of the operation (can only fail on a bad command); TRUE for
81 success, FALSE for failure.
82
83 --*/
84
85 {
86 ULONG ulCmd;
87 ULONG ulPort;
88 UCHAR jValue;
89 USHORT usValue;
90 ULONG culCount;
91 ULONG ulIndex;
92 ULONG ulBase;
93
94 if (pusCmdStream == NULL) {
95
96 VideoDebugPrint((1, "VgaInterpretCmdStream - Invalid pusCmdStream\n"));
97 return TRUE;
98 }
99
100 ulBase = (ULONG)HwDeviceExtension->IOAddress;
101
102 //
103 // Now set the adapter to the desired mode.
104 //
105
106 while ((ulCmd = *pusCmdStream++) != EOD) {
107
108 //
109 // Determine major command type
110 //
111
112 switch (ulCmd & 0xF0) {
113
114 //
115 // Basic input/output command
116 //
117
118 case INOUT:
119
120 //
121 // Determine type of inout instruction
122 //
123
124 if (!(ulCmd & IO)) {
125
126 //
127 // Out instruction. Single or multiple outs?
128 //
129
130 if (!(ulCmd & MULTI)) {
131
132 //
133 // Single out. Byte or word out?
134 //
135
136 if (!(ulCmd & BW)) {
137
138 //
139 // Single byte out
140 //
141
142 ulPort = *pusCmdStream++;
143 jValue = (UCHAR) *pusCmdStream++;
144 VideoPortWritePortUchar((PUCHAR)(ulBase+ulPort),
145 jValue);
146
147 } else {
148
149 //
150 // Single word out
151 //
152
153 ulPort = *pusCmdStream++;
154 usValue = *pusCmdStream++;
155 VideoPortWritePortUshort((PUSHORT)(ulBase+ulPort),
156 usValue);
157
158 }
159
160 } else {
161
162 //
163 // Output a string of values
164 // Byte or word outs?
165 //
166
167 if (!(ulCmd & BW)) {
168
169 //
170 // String byte outs. Do in a loop; can't use
171 // VideoPortWritePortBufferUchar because the data
172 // is in USHORT form
173 //
174
175 ulPort = ulBase + *pusCmdStream++;
176 culCount = *pusCmdStream++;
177
178 while (culCount--) {
179 jValue = (UCHAR) *pusCmdStream++;
180 VideoPortWritePortUchar((PUCHAR)ulPort,
181 jValue);
182
183 }
184
185 } else {
186
187 //
188 // String word outs
189 //
190
191 ulPort = *pusCmdStream++;
192 culCount = *pusCmdStream++;
193 VideoPortWritePortBufferUshort((PUSHORT)
194 (ulBase + ulPort), pusCmdStream, culCount);
195 pusCmdStream += culCount;
196
197 }
198 }
199
200 } else {
201
202 // In instruction
203 //
204 // Currently, string in instructions aren't supported; all
205 // in instructions are handled as single-byte ins
206 //
207 // Byte or word in?
208 //
209
210 if (!(ulCmd & BW)) {
211 //
212 // Single byte in
213 //
214
215 ulPort = *pusCmdStream++;
216 jValue = VideoPortReadPortUchar((PUCHAR)ulBase+ulPort);
217
218 } else {
219
220 //
221 // Single word in
222 //
223
224 ulPort = *pusCmdStream++;
225 usValue = VideoPortReadPortUshort((PUSHORT)
226 (ulBase+ulPort));
227
228 }
229
230 }
231
232 break;
233
234 //
235 // Higher-level input/output commands
236 //
237
238 case METAOUT:
239
240 //
241 // Determine type of metaout command, based on minor
242 // command field
243 //
244 switch (ulCmd & 0x0F) {
245
246 //
247 // Indexed outs
248 //
249
250 case INDXOUT:
251
252 ulPort = ulBase + *pusCmdStream++;
253 culCount = *pusCmdStream++;
254 ulIndex = *pusCmdStream++;
255
256 while (culCount--) {
257
258 usValue = (USHORT) (ulIndex +
259 (((ULONG)(*pusCmdStream++)) << 8));
260 VideoPortWritePortUshort((PUSHORT)ulPort, usValue);
261
262 ulIndex++;
263
264 }
265
266 break;
267
268 //
269 // Masked out (read, AND, XOR, write)
270 //
271
272 case MASKOUT:
273
274 ulPort = *pusCmdStream++;
275 jValue = VideoPortReadPortUchar((PUCHAR)ulBase+ulPort);
276 jValue &= *pusCmdStream++;
277 jValue ^= *pusCmdStream++;
278 VideoPortWritePortUchar((PUCHAR)ulBase + ulPort,
279 jValue);
280 break;
281
282 //
283 // Attribute Controller out
284 //
285
286 case ATCOUT:
287
288 ulPort = ulBase + *pusCmdStream++;
289 culCount = *pusCmdStream++;
290 ulIndex = *pusCmdStream++;
291
292 while (culCount--) {
293
294 // Write Attribute Controller index
295 VideoPortWritePortUchar((PUCHAR)ulPort,
296 (UCHAR)ulIndex);
297
298 // Write Attribute Controller data
299 jValue = (UCHAR) *pusCmdStream++;
300 VideoPortWritePortUchar((PUCHAR)ulPort, jValue);
301
302 ulIndex++;
303
304 }
305
306 break;
307
308 //
309 // None of the above; error
310 //
311 default:
312
313 return FALSE;
314
315 }
316
317
318 break;
319
320 //
321 // NOP
322 //
323
324 case NCMD:
325
326 break;
327
328 //
329 // Unknown command; error
330 //
331
332 default:
333
334 return FALSE;
335
336 }
337
338 }
339
340 return TRUE;
341
342 } // end VgaInterpretCmdStream()
343
344 \f
345 VP_STATUS
346 VgaSetMode(
347 PHW_DEVICE_EXTENSION HwDeviceExtension,
348 PVIDEO_MODE Mode,
349 ULONG ModeSize,
350 // eVb: 2.2 [SET MODE] - Add new output parameter for framebuffer update functionality
351 PULONG PhysPtrChange
352 // eVb: 2.2 [END]
353 )
354
355 /*++
356
357 Routine Description:
358
359 This routine sets the vga into the requested mode.
360
361 Arguments:
362
363 HwDeviceExtension - Pointer to the miniport driver's device extension.
364
365 Mode - Pointer to the structure containing the information about the
366 font to be set.
367
368 ModeSize - Length of the input buffer supplied by the user.
369
370 Return Value:
371
372 ERROR_INSUFFICIENT_BUFFER if the input buffer was not large enough
373 for the input data.
374
375 ERROR_INVALID_PARAMETER if the mode number is invalid.
376
377 NO_ERROR if the operation completed successfully.
378
379 --*/
380
381 {
382 PVIDEOMODE pRequestedMode;
383 VP_STATUS status;
384 ULONG RequestedModeNum;
385 // eVb: 2.3 [SET MODE] - Add new output parameter for framebuffer update functionality
386 *PhysPtrChange = FALSE;
387 // eVb: 2.3 [END]
388 //
389 // Check if the size of the data in the input buffer is large enough.
390 //
391
392 if (ModeSize < sizeof(VIDEO_MODE))
393 {
394 return ERROR_INSUFFICIENT_BUFFER;
395 }
396
397 //
398 // Extract the clear memory, and map linear bits.
399 //
400
401 RequestedModeNum = Mode->RequestedMode &
402 ~(VIDEO_MODE_NO_ZERO_MEMORY | VIDEO_MODE_MAP_MEM_LINEAR);
403
404
405 if (!(Mode->RequestedMode & VIDEO_MODE_NO_ZERO_MEMORY))
406 {
407 #if defined(_X86_)
408 VgaZeroVideoMemory(HwDeviceExtension);
409 #endif
410 }
411
412 //
413 // Check to see if we are requesting a valid mode
414 //
415 // eVb: 2.4 [CIRRUS] - Remove Cirrus-specific check for valid mode
416 if ( (RequestedModeNum >= NumVideoModes) )
417 // eVb: 2.4 [END]
418 {
419 VideoDebugPrint((0, "Invalide Mode Number = %d!\n", RequestedModeNum));
420
421 return ERROR_INVALID_PARAMETER;
422 }
423
424 VideoDebugPrint((2, "Attempting to set mode %d\n",
425 RequestedModeNum));
426 // eVb: 2.5 [VBE] - Use dynamic VBE mode list instead of hard-coded VGA list
427 pRequestedMode = &VgaModeList[RequestedModeNum];
428 // eVb: 2.5 [END]
429 VideoDebugPrint((2, "Info on Requested Mode:\n"
430 "\tResolution: %dx%d\n",
431 pRequestedMode->hres,
432 pRequestedMode->vres ));
433
434 //
435 // VESA BIOS mode switch
436 //
437 // eVb: 2.6 [VBE] - VBE Mode Switch Support
438 status = VbeSetMode(HwDeviceExtension, pRequestedMode, PhysPtrChange);
439 if (status == ERROR_INVALID_FUNCTION)
440 {
441 //
442 // VGA mode switch
443 //
444
445 if (!pRequestedMode->CmdStream) return ERROR_INVALID_FUNCTION;
446 if (!VgaInterpretCmdStream(HwDeviceExtension, pRequestedMode->CmdStream)) return ERROR_INVALID_FUNCTION;
447 goto Cleanup;
448 }
449 else if (status != NO_ERROR) return status;
450 // eVb: 2.6 [END]
451 // eVb: 2.7 [MODE-X] - Windows VGA Miniport Supports Mode-X, we should too
452 //
453 // ModeX check
454 //
455
456 if (pRequestedMode->hres == 320)
457 {
458 VideoPortDebugPrint(0, "ModeX not support!!!\n");
459 return ERROR_INVALID_PARAMETER;
460 }
461 // eVb: 2.7 [END]
462 //
463 // Text mode check
464 //
465
466 if (!(pRequestedMode->fbType & VIDEO_MODE_GRAPHICS))
467 {
468 // eVb: 2.8 [TODO] - This code path is not implemented yet
469 VideoPortDebugPrint(0, "Text-mode not support!!!\n");
470 return ERROR_INVALID_PARAMETER;
471 // eVb: 2.8 [END]
472 }
473
474 Cleanup:
475 //
476 // Update the location of the physical frame buffer within video memory.
477 //
478 // eVb: 2.9 [VBE] - Linear and banked support is unified in VGA, unlike Cirrus
479 HwDeviceExtension->PhysicalVideoMemoryBase.LowPart = pRequestedMode->PhysBase;
480 HwDeviceExtension->PhysicalVideoMemoryLength = pRequestedMode->PhysSize;
481
482 HwDeviceExtension->PhysicalFrameLength =
483 pRequestedMode->FrameBufferSize;
484
485 HwDeviceExtension->PhysicalFrameOffset.LowPart =
486 pRequestedMode->FrameBufferBase;
487 // eVb: 2.9 [END]
488
489 //
490 // Store the new mode value.
491 //
492
493 HwDeviceExtension->CurrentMode = pRequestedMode;
494 HwDeviceExtension->ModeIndex = Mode->RequestedMode;
495
496 return NO_ERROR;
497
498 } //end VgaSetMode()
499 \f
500 VP_STATUS
501 VgaQueryAvailableModes(
502 PHW_DEVICE_EXTENSION HwDeviceExtension,
503 PVIDEO_MODE_INFORMATION ModeInformation,
504 ULONG ModeInformationSize,
505 PULONG OutputSize
506 )
507
508 /*++
509
510 Routine Description:
511
512 This routine returns the list of all available available modes on the
513 card.
514
515 Arguments:
516
517 HwDeviceExtension - Pointer to the miniport driver's device extension.
518
519 ModeInformation - Pointer to the output buffer supplied by the user.
520 This is where the list of all valid modes is stored.
521
522 ModeInformationSize - Length of the output buffer supplied by the user.
523
524 OutputSize - Pointer to a buffer in which to return the actual size of
525 the data in the buffer. If the buffer was not large enough, this
526 contains the minimum required buffer size.
527
528 Return Value:
529
530 ERROR_INSUFFICIENT_BUFFER if the output buffer was not large enough
531 for the data being returned.
532
533 NO_ERROR if the operation completed successfully.
534
535 --*/
536
537 {
538 PVIDEO_MODE_INFORMATION videoModes = ModeInformation;
539 ULONG i;
540
541 //
542 // Find out the size of the data to be put in the buffer and return
543 // that in the status information (whether or not the information is
544 // there). If the buffer passed in is not large enough return an
545 // appropriate error code.
546 //
547
548 if (ModeInformationSize < (*OutputSize =
549 // eVb: 2.10 [VBE] - We store VBE/VGA mode count in this global, not in DevExt like Cirrus
550 NumVideoModes *
551 // eVb: 2.10 [END]
552 sizeof(VIDEO_MODE_INFORMATION)) ) {
553
554 return ERROR_INSUFFICIENT_BUFFER;
555
556 }
557
558 //
559 // For each mode supported by the card, store the mode characteristics
560 // in the output buffer.
561 //
562
563 for (i = 0; i < NumVideoModes; i++)
564 {
565 videoModes->Length = sizeof(VIDEO_MODE_INFORMATION);
566 videoModes->ModeIndex = i;
567 // eVb: 2.11 [VBE] - Use dynamic VBE mode list instead of hard-coded VGA list
568 videoModes->VisScreenWidth = VgaModeList[i].hres;
569 videoModes->ScreenStride = VgaModeList[i].wbytes;
570 videoModes->VisScreenHeight = VgaModeList[i].vres;
571 videoModes->NumberOfPlanes = VgaModeList[i].numPlanes;
572 videoModes->BitsPerPlane = VgaModeList[i].bitsPerPlane;
573 videoModes->Frequency = VgaModeList[i].Frequency;
574 videoModes->XMillimeter = 320; // temporary hardcoded constant
575 videoModes->YMillimeter = 240; // temporary hardcoded constant
576 videoModes->AttributeFlags = VgaModeList[i].fbType;
577 // eVb: 2.11 [END]
578
579 if ((VgaModeList[i].bitsPerPlane == 32) ||
580 (VgaModeList[i].bitsPerPlane == 24))
581 {
582
583 videoModes->NumberRedBits = 8;
584 videoModes->NumberGreenBits = 8;
585 videoModes->NumberBlueBits = 8;
586 videoModes->RedMask = 0xff0000;
587 videoModes->GreenMask = 0x00ff00;
588 videoModes->BlueMask = 0x0000ff;
589
590 }
591 else if (VgaModeList[i].bitsPerPlane == 16)
592 {
593
594 videoModes->NumberRedBits = 6;
595 videoModes->NumberGreenBits = 6;
596 videoModes->NumberBlueBits = 6;
597 videoModes->RedMask = 0x1F << 11;
598 videoModes->GreenMask = 0x3F << 5;
599 videoModes->BlueMask = 0x1F;
600
601 }
602 // eVb: 2.12 [VGA] - Add support for 15bpp modes, which Cirrus doesn't support
603 else if (VgaModeList[i].bitsPerPlane == 15)
604 {
605
606 videoModes->NumberRedBits = 6;
607 videoModes->NumberGreenBits = 6;
608 videoModes->NumberBlueBits = 6;
609 videoModes->RedMask = 0x3E << 9;
610 videoModes->GreenMask = 0x1F << 5;
611 videoModes->BlueMask = 0x1F;
612 }
613 // eVb: 2.12 [END]
614 else
615 {
616
617 videoModes->NumberRedBits = 6;
618 videoModes->NumberGreenBits = 6;
619 videoModes->NumberBlueBits = 6;
620 videoModes->RedMask = 0;
621 videoModes->GreenMask = 0;
622 videoModes->BlueMask = 0;
623 }
624
625 // eVb: 2.13 [VGA] - All modes are palette managed/driven, unlike Cirrus
626 videoModes->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN |
627 VIDEO_MODE_MANAGED_PALETTE;
628 // eVb: 2.13 [END]
629 videoModes++;
630
631 }
632
633 return NO_ERROR;
634
635 } // end VgaGetAvailableModes()
636 \f
637 VP_STATUS
638 VgaQueryNumberOfAvailableModes(
639 PHW_DEVICE_EXTENSION HwDeviceExtension,
640 PVIDEO_NUM_MODES NumModes,
641 ULONG NumModesSize,
642 PULONG OutputSize
643 )
644
645 /*++
646
647 Routine Description:
648
649 This routine returns the number of available modes for this particular
650 video card.
651
652 Arguments:
653
654 HwDeviceExtension - Pointer to the miniport driver's device extension.
655
656 NumModes - Pointer to the output buffer supplied by the user. This is
657 where the number of modes is stored.
658
659 NumModesSize - Length of the output buffer supplied by the user.
660
661 OutputSize - Pointer to a buffer in which to return the actual size of
662 the data in the buffer.
663
664 Return Value:
665
666 ERROR_INSUFFICIENT_BUFFER if the output buffer was not large enough
667 for the data being returned.
668
669 NO_ERROR if the operation completed successfully.
670
671 --*/
672
673 {
674 //
675 // Find out the size of the data to be put in the the buffer and return
676 // that in the status information (whether or not the information is
677 // there). If the buffer passed in is not large enough return an
678 // appropriate error code.
679 //
680
681 if (NumModesSize < (*OutputSize = sizeof(VIDEO_NUM_MODES)) ) {
682
683 return ERROR_INSUFFICIENT_BUFFER;
684
685 }
686
687 //
688 // Store the number of modes into the buffer.
689 //
690
691 // eVb: 2.14 [VBE] - We store VBE/VGA mode count in this global, not in DevExt like Cirrus
692 NumModes->NumModes = NumVideoModes;
693 // eVb: 2.14 [END]
694 NumModes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
695
696 return NO_ERROR;
697
698 } // end VgaGetNumberOfAvailableModes()
699 \f
700 VOID
701 VgaZeroVideoMemory(
702 PHW_DEVICE_EXTENSION HwDeviceExtension
703 )
704
705 /*++
706
707 Routine Description:
708
709 This routine zeros the first 256K on the VGA.
710
711 Arguments:
712
713 HwDeviceExtension - Pointer to the miniport driver's device extension.
714
715
716 Return Value:
717
718 None.
719
720 --*/
721 {
722 UCHAR temp;
723
724 //
725 // Map font buffer at A0000
726 //
727
728 VgaInterpretCmdStream(HwDeviceExtension, EnableA000Data);
729
730 //
731 // Enable all planes.
732 //
733
734 VideoPortWritePortUchar(HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
735 IND_MAP_MASK);
736
737 temp = VideoPortReadPortUchar(HwDeviceExtension->IOAddress +
738 SEQ_DATA_PORT) | (UCHAR)0x0F;
739
740 VideoPortWritePortUchar(HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
741 temp);
742
743 VideoPortZeroDeviceMemory(HwDeviceExtension->VideoMemoryAddress, 0xFFFF);
744
745 VgaInterpretCmdStream(HwDeviceExtension, DisableA000Color);
746
747 }