Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3647 lines
114 KiB

// Test updates to colormap entries on IBM 561 via ioctl (used by overlays)
// cursor horizontal position is off on 640x480 (actually the screen is
// "shifted" 8 pixels to the left) -- pass 2 ASIC should fix this
/*++
Copyright (c) 1995 Digital Equipment Corporation
Module Name:
tga.c
Abstract:
TGA driver for NT
Author:
Ritu Bahl (ritub)
Creation Date:
22-Jul-1993
Environment:
Kernel mode only.
Revision History:
22-Jul-1993 (ritub) Created.
15-Nov-1993 (ritub) Ready for Comdex.
05-Jan-1994 (ritub) Hardware Cursor code tested.
07-Feb-1994 (ritub) Changed "stride" to 1284.
08-Feb-1994 (ritub) Host->Screen dma code tested.
15-Feb-1994 (ritub) Optimized host->screen code tested.
24-Feb-1994 (ritub) "Disable Pointer" bug fixed
28-Feb-1994 (ritub) Changed MB's to CYCLE_REGS.
10-Apr-1994 (ritub) Driver ported to Daytonna, dma ifdef'd out.
17-Apr-1994 (ritub) dma code compiled back in.
19-Apr-1994 (ritub) Initialized Pci latency timer and Command
Status Register.
01-Jun-1994 (ritub) Added a Slot-- to compensate for VideoPort
getAccessRanges returning one less than the
actual slot number.
04-Jun-1994 (ritub) IOCTL_VIDEO_MAP_MEMORY now returns two
pointers, start of tga space, and start
of Frame Buffer Space.
04-Jun-1994 (ritub) Changed Video Base Address Register
initialization from 1, i.e. 4k offset
to 0. This is needed for textmode setup
to work.
15-Jul-1994 (ritub) 24-plane support added. Hardware cursor
code not debugged yet.
02-Sep-1994 (ritub) shared interrupts fix.
20-Oct-1994 (macinnes) In IOCTL_VIDEO_MAP_VIDEO_MEMORY, if we have a
24-plane board, add 16KB to the FrameBufferBase
value returned. This is because the console
firmware has set VIDEO_BASE_ADDRESS to offset
the visible frame buffer by 16KB (it does not
do this for 8-plane).
****Note: if the console firmware does this differently in the future
****both the miniport and the display driver must be changed!!!!
Also, only return 32-bpp modes for a 24-plane
board and only 8-bpp modes for an 8-plane
board.
26-Oct-1994 (macinnes) Add support for 12-bit direct color. This
involved loading the window tag table and
a 16-entry color map. Enable latent support
for a 24-plane hardware cursor done by the display
driver.
28-Nov-1994 (macinnes) Remove outdated conditionals. Add more
comments.
02-Dec-1994 (macinnes) For the "AdapterString" written
to the Registry, be
more specific about the type of board found
(ZLXp-E1, -E2, -E3 and Step).
Add initial support for multi-head.
05-Dec-1994 (macinnes) In the find adapter routine, if the second
TGA is not the same type as the first, do
not accept it into the configuration.
08-Dec-1994 (macinnes) Add to the BT485 and BT463 initialization
routines so that we don't rely on any
previous RAMDAC init by the console firmware.
13-Dec-1994 (macinnes) Perform initialization of additional TGA
adapters in a multihead configuration. The
ARC firmware doesn't do this, so the miniport
driver must (set the DEEP register, etc.)
15-Dec-1994 (macinnes) Initial support for TGA2 8-plane added.
29-Dec-1994 (macinnes) Add TGA2 code for accessing RAMDAC and ICS
(Clock Generator, PLL data).
3-Jan-1995 (tannenbaum) Replaced "FrameBuffer Depth" with
"DefaultSettings.BitsPerPel"
11-Jan-1995 (macinnes) Rework RAMDAC function calling interfaces to use
an object oriented approach.
16-Jan-1995 (macinnes) The routines which perform DMA setup have been
taken out of tga.c and placed into tgadma.c
This was done because the dma code does not use
video port services, but instead uses kernel
services directly. This solves compilation
problems with conflicting .h files.
23-Jan-1995 (macinnes) Perform enable/disable cursor and set cursor
position synchronously, rather than in
interrupt service routine. It was causing a
crash during multihead operation.
25-Jan-1995 (macinnes) Remove restriction on number of adapters.
31-Jan-1995 (macinnes) Set PCI Latency Timer to 0xff (maximum value).
14-Feb-1995 (macinnes) Add RamdacBusy "lock" to prevent ISR from
accessing RAMDAC at the same time that the
startio code is. Add new clock generator
init code for TGA2.
15-Feb-1995 (macinnes) Add routine to reformat the cursor pattern data
for loading into the IBM561 RAMDAC.
21-Feb-1995 (macinnes) Add code to verify that color table writes to
the BT485 RAMDAC are done correctly.
23-Feb-1995 (macinnes) Remove unnecessary BT485 RAMDAC read operations.
(only the above color table verification
remains).
02-Mar-1995 (tannenbaum) Added IOCTLs to fetch registry info, PCRR
08-Mar-1995 (macinnes) More fine tuning of the clock init code for
TGA2.
13-Mar-1995 (macinnes) Up and running on TGA2 8-plane.
16-Mar-1995 (seitsinger) Added code to handle IOCTL_VIDEO_VIRT_TO_PHYS.
21-Mar-1995 (macinnes) Up and running on TGA2 24-plane, using
a software cursor.
28-Mar-1995 (macinnes) Hardware cursor support added for 24-plane TGA2.
28-Mar-1995 (langone/tannenbaum) Fixed new IOCTL's
11-Apr-1995 (macinnes) For TGA2 8-plane modes, access a table and not
hardcoded mode initialization.
17-Apr-1995 (macinnes) Extended the colormap ioctl support to
include the BT463 (for overlay planes).
24-Apr-1995 (macinnes) All of the TGA2 8-plane modes have been added.
05-May-1995 (macinnes) All functionality is present for TGA2 pass 1B
boards. Ready for first checkin into BGSDEV
CMS.
05-May-1995 (macinnes) Provided a table-lookup method of formatting
the IBM 561 cursor.
23-May-1995 (macinnes) Disable the BT485 cursor on powerup. Use
symbolic references for Interrupt Status
register.
26-May-1995 (macinnes) Add more comments to BT463 init code.
16-Jun-1995 (macinnes) Add initial support for DCI (map shared
view of frame buffer). This code has not
been debugged and is currently excluded from
the compilation.
19-Jun-1995 (macinnes) Change some include files related to the
IBM 561 common code.
28-Jul-1995 (page) Initialize Slot for each bus probed. This
fixed TGA's connected to the PCI Bridge.
08-Aug-1995 (seitsinger) Do NOT call VideoPortSetBusData for TGA2. No need
to, since we don't need to muck with the command bits,
and it's not important at this point to modify the
latency timer. Also, for some reason a fatal system error
(DATA_BUS_ERROR) occurs on the first VideoPortReadRegisterUlong
call that follows the VideoPortSetBusData call.
10-Aug-1995 (seitsinger) Modify adapter string for TGA2. Name is now ZLX2-E?.
Notes:
Data structures relating to DMA
AdapterObject -
A kernel-mode-only object type, defined by the I/O
Manager and supported by the HAL component. An
adapter object represents a hardware bus adapater
or DMA controller channel. Adapter objects "connect"
different kinds of devices on the bus or DMA
controller, with their corresponding software deiver.
AllocateAdapterChannelEvent -
The event that is waited on when we're allocating a DMA
adapter channel, and set by the DPC that is queued by
the I/O subsystem when the adapter channel is available.
MapRegisterBase -
The base address of the map registers. Whenever an
adapter channel is allocated, this value is passed to
our DPC, It's stored in the the device extension so it
can be used when we call IoMapTransfer() and
IoFlushAdapterBuffers().
Adapterobject -
An object obtained from HalGetAdapter() that must be
used when allocating a DMA adapter channel.
NumberOfMapRegisters -
The number of map registers available to this driver,
obtained from HalGetAdapter(), and possibly lowered to
the maximum number needed. Each register allows the driver
to map a single page (or more if the pages are contiguous,
but that's only counted on when the driver allocated the
contigous buffer itself). This value is used to determine
whether or not the driver needs to allocate a contiguous
buffer to accomodate a transfer the size of the largest
DMA buffer size, and is passed to IoAllocateAdapter-
Channel.
--*/
#include <wchar.h>
#include <dderror.h>
#include <devioctl.h>
#include <miniport.h>
#include <ntddvdeo.h>
#include <video.h>
//
// TGA specific:
//
#include "tga_reg.h"
#include "tga.h"
#include "tgadata.h"
#include "bt463.h"
#include "nt_defs.h"
void
TGA_INIT(
tga_info_t *
);
void
format_ibm561_cursor_data(PUCHAR bp_image, PUCHAR bp_mask, PUSHORT wp_pattern);
int
alloc_tga_info(
PHW_DEVICE_EXTENSION HwDeviceExtension);
void
load_common_data(
PHW_DEVICE_EXTENSION HwDeviceExtension);
ULONG
DriverEntry(
IN PVOID Context1,
IN PVOID Context2
);
extern VOID RtlMoveMemory();
extern ULONG TgaTestEv4 (PULONG Result);
BOOLEAN
virtual_to_physical(PUCHAR userBuffer,
PULONG busAddress);
VP_STATUS
TgaFindAdapter(
PVOID HwDeviceExtension,
PVOID HwContext,
PWSTR ArgumentString,
PVIDEO_PORT_CONFIG_INFO ConfigInfo,
PUCHAR Again
);
BOOLEAN
TgaInitialize(
PVOID HwDeviceExtension
);
BOOLEAN
TgaReset(
PVOID HwDeviceExtension,
ULONG columns,
ULONG rows
);
BOOLEAN
TgaStartIO(
PVOID HwDeviceExtension,
PVIDEO_REQUEST_PACKET RequestPacket
);
VP_STATUS
SetColorLookup(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CLUT ClutBuffer,
ULONG ClutBufferSize
);
BOOLEAN
TgaInterruptService(
PVOID hwDeviceExtension
);
VP_STATUS
TgaSetExtendedMode(
PHW_DEVICE_EXTENSION HwDeviceExtension,
ULONG Mode
);
VP_STATUS
Init_bt485(
PHW_DEVICE_EXTENSION HwDeviceExtension
);
VP_STATUS
Init_bt463(
PHW_DEVICE_EXTENSION HwDeviceExtension
);
VP_STATUS
bt463_load_wid(
ULONG index,
ULONG count,
Bt463_Wid_Cell *data,
PHW_DEVICE_EXTENSION HwDeviceExtension
);
VP_STATUS
bt463_init_color_map(
);
VP_STATUS
init_multihead_adapter(
PHW_DEVICE_EXTENSION HwDeviceExtension
);
void
tga2_ics_write(ULONG *base_address, ULONG data);
void
bt485_cursor_position (
PHW_DEVICE_EXTENSION HwDeviceExtension
);
void
bt485_cursor_pattern (
PHW_DEVICE_EXTENSION HwDeviceExtension
);
void
bt485_cursor_disable (
PHW_DEVICE_EXTENSION HwDeviceExtension
);
void
bt485_cursor_enable (
PHW_DEVICE_EXTENSION HwDeviceExtension
);
void
bt485_colormap_update (
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CLUT ClutBuffer
);
void
bt463_colormap_update (
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CLUT ClutBuffer
);
void
ibm561_colormap_update (
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CLUT ClutBuffer
);
void
ibm561_cursor_position (
PHW_DEVICE_EXTENSION HwDeviceExtension
);
void
ibm561_cursor_pattern (
PHW_DEVICE_EXTENSION HwDeviceExtension
);
void
ibm561_cursor_disable (
PHW_DEVICE_EXTENSION HwDeviceExtension
);
void
ibm561_cursor_enable (
PHW_DEVICE_EXTENSION HwDeviceExtension
);
void
Init_ibm561 (
PHW_DEVICE_EXTENSION HwDeviceExtension
);
BOOLEAN
dma_lock_pages (
PHW_DEVICE_EXTENSION HwDeviceExtension,
PUCHAR userBuffer,
ULONG userBufferSize,
PULONG busaddress
);
void
dma_unlock_pages (
PHW_DEVICE_EXTENSION HwDeviceExtension
);
BOOLEAN
dma_init (
PHW_DEVICE_EXTENSION HwDeviceExtension
);
ULONG Slot = 0; // When driver is loaded we will start with PCI slot 0
// (Note: this actually should be of type
// PCI_SLOT_NUMBER, but the function prototype
// for VideoPortGetBusData wants this
// to be ULONG)
PHW_DEVICE_EXTENSION first_extension = NULL;
// Pointer to device extension of 1st adapter
ULONG total_adapters = 0; // Running total of adapters found
ULONG
DriverEntry(
IN PVOID Context1,
IN PVOID Context2
)
/*++
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O Manager when
the driver is loaded (this video miniport driver has an entry
in the Registry with Start=1). The driver will need to determine
if there are any devices in the system that this driver supports.
Arguments:
Context1 - First context value passed by the operating system.
This is the value with which the miniport driver calls
VidePortInitialize(). It is the pointer to the driver
object created by the system for this driver. driver->
HardwareDatabase is a pointer to \Registry\Machine
\Description
\Resourcemap
\Devicemap.
Context2 - Second context value passed by the operating system.
This is the value with which the miniport driver calls
VideoPortInitialize(). It is the pointer to the
Unicode name of the registry path for this driver - \Registry\
System\CurrentControlSet\Services\tga.
Return Value:
Status from VideoPortInitialize().
--*/
{
VIDEO_HW_INITIALIZATION_DATA hwInitData;
ULONG InitializationStatus;
VideoDebugPrint(( 2, "\n Tga DriverEntry: enter\n" ));
#ifdef IBP
DbgBreakPoint();
#endif
//
// Zero out the driver initialization structure:
//
VideoPortZeroMemory(&hwInitData,
sizeof(VIDEO_HW_INITIALIZATION_DATA));
//
// Specify size of structure:
//
hwInitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
//
// Set the driver entry points
//
hwInitData.HwFindAdapter = TgaFindAdapter;
hwInitData.HwInitialize = TgaInitialize;
hwInitData.HwResetHw = TgaReset;
hwInitData.HwInterrupt = TgaInterruptService;
hwInitData.HwStartIO = TgaStartIO;
//
// Determine the size we require for the device extension.
// Is defined by this driver in tga.h
//
hwInitData.HwDeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
//
// Always start with parameters for device0 in this case.
//
hwInitData.StartingDeviceNumber = 0;
hwInitData.AdapterInterfaceType = PCIBus;
//
// This routine calls TgaFindAdapter() to find all tga and tga2 boards
// on the PCI bus.
//
InitializationStatus = VideoPortInitialize(Context1,
Context2,
&hwInitData,
Context1);
VideoDebugPrint( (2,"\nTga DriverEntry: exit\n" ));
return (InitializationStatus);
} // end DriverEntry()
VP_STATUS
TgaFindAdapter(
IN PVOID HwDeviceExtension,
IN PVOID HwContext,
IN PWSTR ArgumentString,
OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
OUT PUCHAR Again
)
/*++
Routine Description:
This routine is called by VideoPortInitialize() to determine
if another adapter for this driver is present in the system. If it
is present, the function fills out some information describing
the adapter. Stores whatever context the driver maintains about
the adapter in the device extension. This function fills the
configuration information structure. The video port will create
a device object for each adapter that is found.
This routine must not change the state of the adapter, as it is still
being used to output information about the startup of NT. Not until
TgaInitialize (the display driver is running) may the state of the
device be changed.
Arguments:
HwDeviceExtension - Supplies the miniport driver's adapter
storage. This storage is initialized to zero before
this call.
HwContext - Supplies a context value which was passed to
VidoPortInitialize(). This is driver-dependent.
ArgumentString - Supplies a NULL terminated ASCII string.
This string originates from the user.
ConfigInfo - Returns the configuration information structure
which is filled by the miniport driver. This structure is
initialized with any known configuration information (such
as SystemIoBusNumber) by the port driver. Where possible,
drivers should have one set of defaults which do not require
any supplied configuration information.
Again - Indicates if the miniport driver wants the port driver
to call its VIDEO_HW_FIND_ADAPTER function again with a new
device extension and the same config info. This is used by
the miniport drivers which can search for several adapters
on a bus.
Return Value:
This routine must return :
NO_ERROR - Indicates a host adapter was found and the confi-
guration information was successfully determined.
ERROR_INVALID_PARAMETER - Indicates an adapter was found but
there was an error obtaining the configuration information.
If possible, an error should be logged.
ERROR_DEV_NOT_EXIST - Indicates no host adapter was found for
the supplied configuration information.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
PVOID pDriverObject = HwContext;
ULONG i;
VP_STATUS status;
depth_reg Depth;
UCHAR mask;
ULONG Revision;
PCI_COMMON_CONFIG PCICommonConfig;
PHYSICAL_ADDRESS phys;
USHORT VendorId = 0x1011; // DIGITAL
USHORT DeviceId = 0x4; // TGA
USHORT DeviceId2 = 0xD; // TGA2
PWSTR pwszChip = L"Digital 21030";
ULONG cbChip = sizeof(L"Digital 21030");
PWSTR pwszAdapterString;
ULONG cbAdapterString;
PWSTR pwszDAC = L"Brooktree Bt463";
ULONG cbDAC = sizeof(L"Brooktree Bt463");
USHORT board_type;
//
// Array of access ranges this miniport wants to access.
// This is initialized by VideoPortGetAccessRanges which
// gets the information from the TGA PCI Config Space header.
// On X86, only the first is filled in. But on RISC, an entry for the
// ROM is also returned - so we must allocated the space for it.
VIDEO_ACCESS_RANGE accessRange[2];
//
// Make sure the size of the structure is at least as large
// as what we are expecting (check version of the config
// info structure.
//
if (ConfigInfo->Length < sizeof( VIDEO_PORT_CONFIG_INFO )) {
return (ERROR_INVALID_PARAMETER);
}
VideoDebugPrint(( 2,"\t Tga TgaFindAdapter : entry\n" ));
//
// Look for the next TGA or TGA2 device on the PCI bus. The device is
// identified by its Vendor ID and Device ID, which are in each board's
// PCI configuration space "Identification Register". This call
// will begin its search starting with the "Slot" value that is
// passed to it (eg. when looking for the first TGA/TGA2 device, "Slot"
// should be 0).
//
// For multihead, all the devices must be TGA or all must be TGA2.
// In addition they must all be 8-plane or all be 24-plane.
//
// First, look for a TGA device, if we have not *previously* found a TGA2.
//
if ((first_extension == NULL) || (first_extension->is_tga)) {
status = VideoPortGetAccessRanges(
hwDeviceExtension,
0,
(PIO_RESOURCE_DESCRIPTOR)NULL,
2,
&accessRange[0],
&VendorId,
&DeviceId,
&Slot
);
//
// If there are no more TGA adapters, but we found one previously,
// then return. We are done looking for adapters.
//
if (status != NO_ERROR) {
*Again = 0; // Don't call find adapter routine again
Slot = 0; // Initialize for next PCI bus probe.
return (ERROR_DEV_NOT_EXIST);
}
//
// If we found a TGA adapter, record its type. Also remember if
// this is the first one found.
//
if (status == NO_ERROR) {
hwDeviceExtension->is_tga = TRUE;
if (total_adapters == 0)
first_extension = hwDeviceExtension;
}
}
//
// Don't look for TGA2 anymore.
//
//
// We never get to this point if neither a TGA or TGA2 adapter were found.
// If we do get to this point, we have found the first such adapter, or
// an additional adapter of the same type (that is, TGA or TGA2) as the first.
//
hwDeviceExtension->adapter_number = total_adapters;
total_adapters++;
i = VideoPortGetBusData(hwDeviceExtension,
PCIConfiguration,
Slot,
&PCICommonConfig,
0,
PCI_COMMON_HEADER_LENGTH
);
ConfigInfo->BusInterruptLevel = PCICommonConfig.u.type0.InterruptLine;
ConfigInfo->InterruptMode = LevelSensitive;
// Modify the some PCI config values ONLY for TGA, not for TGA2.
#ifdef _MIPS_
((PULONG)&PCICommonConfig)[0x10] = 0x00000000;
#endif
if (hwDeviceExtension->is_tga)
{
// Note that the following is a field, and not the entire register.
PCICommonConfig.LatencyTimer = 0xFF; // Set the maximum value
PCICommonConfig.Command = 0x0006; // Can be PCI bus master,
// memory space enable
i = VideoPortSetBusData(hwDeviceExtension,
PCIConfiguration,
Slot,
&PCICommonConfig,
0,
PCI_COMMON_HEADER_LENGTH
);
}
hwDeviceExtension->pcrr = ((ULONG)PCICommonConfig.BaseClass << 24) | \
(PCICommonConfig.SubClass << 16) | \
(PCICommonConfig.ProgIf << 8) | \
(PCICommonConfig.RevisionID );
//
// Clear out the Emulator entries and the state size since
// this driver does not support them
//
ConfigInfo->NumEmulatorAccessEntries = 0;
ConfigInfo->EmulatorAccessEntries = NULL;
ConfigInfo->EmulatorAccessEntriesContext = 0;
ConfigInfo->HardwareStateSize = 0;
//
// Set cursor enable FALSE
//
hwDeviceExtension->CursorEnable = FALSE;
//
// No VDM (Virtual DOS Machine) support (Intel architecture only).
//
ConfigInfo->VdmPhysicalVideoMemoryAddress.LowPart = 0;
ConfigInfo->VdmPhysicalVideoMemoryAddress.HighPart = 0;
ConfigInfo->VdmPhysicalVideoMemoryLength = 0;
#ifdef _MIPS_
accessRange[0].RangeLength = 0x2000000;
#else
// Assume board is asking for enough space for 4 alias'.
// Guarantee we'll get at least 4Mbytes - the minimum
// required for 8plane.
if (0x400000 > accessRange[0].RangeLength)
accessRange[0].RangeLength = 0x400000;
else
accessRange[0].RangeLength = accessRange[0].RangeLength / 4;
#endif
hwDeviceExtension->PhysicalFrameAddress = accessRange[0].RangeStart;
hwDeviceExtension->FrameLength = accessRange[0].RangeLength;
hwDeviceExtension->InIoSpace = accessRange[0].RangeInIoSpace;
//
// Get the system virtual addresses for the Register Space.
//
phys = hwDeviceExtension->PhysicalFrameAddress;
phys.QuadPart += TGA_ASIC_OFFSET;
if ((hwDeviceExtension->RegisterSpace =
VideoPortGetDeviceBase(hwDeviceExtension,
phys,
TGA_ASIC_LENGTH,
hwDeviceExtension->InIoSpace)) == NULL ) {
return (ERROR_INVALID_PARAMETER);
}
//
// clean this up after cleanup of RAMDAC code
//
if ((hwDeviceExtension->memory_space_base =
VideoPortGetDeviceBase(
hwDeviceExtension,
hwDeviceExtension->PhysicalFrameAddress,
0x100000,
hwDeviceExtension->InIoSpace)) == NULL ) {
return (ERROR_INVALID_PARAMETER);
}
hwDeviceExtension->DriverObject = pDriverObject;
//
// If this is not the first adapter, then the ARC firmware has not done
// any initialization at all on it, so we must set the DEEP register, etc.
// For TGA2, the DEEP register is already set up.
//
// NOTE: we must always do this on X86 since there is no special support
// in firmware for the card
//
#ifndef _X86_
if ((total_adapters > 1) && (hwDeviceExtension->is_tga))
#endif
init_multihead_adapter(hwDeviceExtension);
//
// Get the particular frame buffer configuration we have.
//
Depth.deep_reg = VideoPortReadRegisterUlong ((PULONG)
(hwDeviceExtension->RegisterSpace + DEEP));
hwDeviceExtension->depth = Depth.deep;
if (hwDeviceExtension->is_tga) {
mask = hwDeviceExtension->depth.mask;
} else {
// For the TGA2, the Memory field of the Version register specifies
// the size of the frame buffer.
Revision = VideoPortReadRegisterUlong ((PULONG)
(hwDeviceExtension->RegisterSpace + START));
VideoDebugPrint(( 0, "Revision Register = %x\n", Revision ));
Revision >>= 21;
switch (Revision & 3) {
case 0x03:
mask = 0; // 2mb frame buffer
break;
case 0x02:
mask = 1; // 4mb frame buffer
break;
case 0x01:
mask = 3; // 8mb frame buffer
break;
case 0x00:
mask = 7; // 16mb frame buffer
break;
}
}
VideoDebugPrint(( 0, "Deep Register = %x , Mask Value = %x\n",
Depth.deep_reg, mask ));
if (hwDeviceExtension->depth.deep == 1) {
VideoDebugPrint(( 0, "deep = 1, 24 plane frame buffer\n" ));
hwDeviceExtension->bpp = 32;
if (hwDeviceExtension->is_tga) {
hwDeviceExtension->ramdac_type = BT463;
} else {
hwDeviceExtension->ramdac_type = IBM561;
pwszDAC = L"IBM RGB 561";
cbDAC = sizeof(L"IBM RGB 561");
}
}
else {
VideoDebugPrint(( 0, "\ndeep = 0, 8 plane frame buffer\n" ));
hwDeviceExtension->bpp = 8;
hwDeviceExtension->ramdac_type = BT485;
pwszDAC = L"Brooktree Bt485";
cbDAC = sizeof(L"Brooktree Bt485");
}
//
// If this is the second adapter, make sure it is the same type
// (number of planes) as the first. If not, release the resources of the
// second and don't accept it into the configuration.
//
if (total_adapters > 1) {
if ( hwDeviceExtension->bpp !=
((PHW_DEVICE_EXTENSION) first_extension)->bpp) {
VideoDebugPrint((0, "***Tga: Second adapter not same as first\n\n"));
VideoPortGetAccessRanges(
hwDeviceExtension,
0,
(PIO_RESOURCE_DESCRIPTOR)NULL,
0, // Free the access ranges
&accessRange[0],
NULL,
NULL,
&Slot
);
*Again = 0; // Don't call the find adapter routine again
status = ERROR_DEV_NOT_EXIST;
return (status);
} // if (hwDeviceExtension->bpp != first_extension->bpp)
} // if (total_adapters > 0)
//
// Save the frame buffer size, and offsets to the frame buffer
// and device registers.
//
switch (mask) {
case 0x00:
hwDeviceExtension->fb_offset = TGA_0_0_FB_OFFSET;
hwDeviceExtension->AdapterMemorySize = TGA_0_0_FB_SIZE;
break;
case 0x01:
hwDeviceExtension->fb_offset = TGA_0_1_FB_OFFSET;
hwDeviceExtension->AdapterMemorySize = TGA_0_1_FB_SIZE;
break;
case 0x03:
hwDeviceExtension->fb_offset = TGA_0_3_FB_OFFSET;
hwDeviceExtension->AdapterMemorySize = TGA_0_3_FB_SIZE;
break;
case 0x07:
hwDeviceExtension->fb_offset = TGA_0_7_FB_OFFSET;
hwDeviceExtension->AdapterMemorySize = TGA_0_7_FB_SIZE;
break;
default:
VideoDebugPrint((0, "Not enough VRAM"));
return (ERROR_INVALID_PARAMETER);
}
VideoDebugPrint((0, "\nhwDeviceExtension->fb_offset = %x\n \
\thwDeviceExtesnion->AdapterMemorySize = %x\n \
\thwDeviceExtension->bpp = %x\n",
hwDeviceExtension->fb_offset,
hwDeviceExtension->AdapterMemorySize,
hwDeviceExtension->bpp ));
//
// From the size of video memory calculate which modes are valid.
//
hwDeviceExtension->NumAvailModes = 0;
VideoDebugPrint(( 3,"\nNumAvailModes = %x \tNumTgaVideoModes = %x\n",
hwDeviceExtension->NumAvailModes,
NumTgaVideoModes ));
for (i=0; i < NumTgaVideoModes; i++) {
//
// Only set valid those modes for which the board has enough
// physical memory to support. For the 24 plane board, don't
// report 8-bit modes as valid. Don't report 32-bit modes for the
// 8 plane board.
if (TGAModes[i].RequiredVideoMemory <=
hwDeviceExtension->AdapterMemorySize) {
TGAModes[i].ModeValid = TRUE;
hwDeviceExtension->NumAvailModes++;
if ((hwDeviceExtension->bpp == 32) &&
(TGAModes[i].ModeInformation.BitsPerPlane != 32)) {
TGAModes[i].ModeValid = FALSE;
--hwDeviceExtension->NumAvailModes;
}
if ((hwDeviceExtension->bpp == 8) &&
(TGAModes[i].ModeInformation.BitsPerPlane != 8)) {
TGAModes[i].ModeValid = FALSE;
--hwDeviceExtension->NumAvailModes;
}
}
}
//
// Generate a string that specifies which kind of TGA board we have.
//
VideoDebugPrint((0, "PCI RevisionID = %x\n", PCICommonConfig.RevisionID ));
// Allocate some space for the resulting string, **modify this if the
// format is changed and the size of the resulting string is larger**
//
pwszAdapterString = L"Digital ZLXp-ENxx (Step xxx) ";
if (hwDeviceExtension->is_tga) {
if (8 == hwDeviceExtension->bpp)
board_type = 1; // 8BPP, 2 MB frame buffer
else
if (hwDeviceExtension->AdapterMemorySize >= TGA_0_7_FB_SIZE)
board_type = 3; // 24BPP, 16 MB frame buffer
else
board_type = 2; // 24BPP, 8 MB frame buffer
cbAdapterString = swprintf (pwszAdapterString,
L"Digital ZLXp-E%1d (Step %2d)",
board_type, PCICommonConfig.RevisionID);
} else { // is a TGA2
if (8 == hwDeviceExtension->bpp)
board_type = 1; // 8BPP, 2 MB frame buffer
else
if (hwDeviceExtension->AdapterMemorySize >= TGA_0_7_FB_SIZE)
board_type = 3; // 24BPP, 16 MB frame buffer
else
board_type = 2; // 24BPP, 8 MB frame buffer
cbAdapterString = swprintf (pwszAdapterString,
L"Digital ZLX2-E%-2d (Step %2d)",
board_type, PCICommonConfig.RevisionID & 0xF);
pwszChip = L"Digital";
cbChip = sizeof(L"Digital");
}
cbAdapterString = (cbAdapterString + 1) *2; // These are wide characters
//
// We now have a complete description of the hardware.
// Save the information to the registry so it can be used by
// configuration programs such as the display applet.
// (See registry key HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\tga)
//
VideoPortSetRegistryParameters( first_extension,
L"TotalAdapters",
&total_adapters,
sizeof(ULONG));
VideoPortSetRegistryParameters( hwDeviceExtension,
L"DefaultSettings.BitsPerPel",
&hwDeviceExtension->bpp,
sizeof(ULONG));
VideoPortSetRegistryParameters( hwDeviceExtension,
L"HardwareInformation.ChipType",
pwszChip,
cbChip);
VideoPortSetRegistryParameters( hwDeviceExtension,
L"HardwareInformation.DacType",
pwszDAC,
cbDAC);
VideoPortSetRegistryParameters( hwDeviceExtension,
L"HardwareInformation.MemorySize",
&hwDeviceExtension->AdapterMemorySize,
sizeof(ULONG));
VideoPortSetRegistryParameters( hwDeviceExtension,
L"HardwareInformation.AdapterString",
pwszAdapterString,
cbAdapterString);
//
// Indicate we *do* wish to be called over to try and find another
// TGA/TGA2. Continue searching the bus at next logical slot number.
//
*Again = 1;
Slot++;
//
// Indicate a successful completion status
//
VideoDebugPrint(( 2,"\nTgaFindAdapter: exit\n" ));
return (NO_ERROR);
} // end of TgaFindAdapter()
BOOLEAN
TgaInitialize(
PVOID HwDeviceExtension
)
/*++
Routine Description:
This routine does one time initialization of the device
(including the RAMDAC). It is called
when the corresponding display driver issues a CreateFile.
It does not change visible state of the device. Following
this routine, the display driver can issue DeviceIoControl requests.
For a TGA2, the device will be left in VGA mode until the first
IOCTL is received that sets a mode.
Arguments:
HwDeviceExtension - Pointer to the device extension.
Return Value:
Always returns TRUE since this routine can never fail.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
BOOLEAN status;
depth_reg deep;
ULONG video_base;
VideoDebugPrint(( 2,"\n Tga TgaInitialize: entry\n" ));
// The ARC firmware does not know about TGA2 specifically, so
// initialize some registers.
if (hwDeviceExtension->is_tga2) {
TGA_WRITE(DEEP, (0x10400) );
TGA_WRITE(PLANE_MASK, 0xFFFFFFFF);
TGA_WRITE(MODE, 0);
} // if tga2
//
// We will offset the framebuffer since this will help
// display driver performance - make sure this is reflected in the
// return information of MAP_VIDEO_MEMORY
//
deep.deep_reg = TGA_READ(DEEP);
if (deep.deep.col_size) {
VideoDebugPrint((0,"\n Tga TgaInitialize: colum Size = 1\n"));
video_base = 2;
} else {
VideoDebugPrint((0,"\n Tga TgaInitialize: colum Size = 0\n"));
video_base = 1;
}
TGA_WRITE (VIDEO_BASE_ADDR, video_base);
if ( hwDeviceExtension->depth.deep == 0) {
// Determine the type of RAMDAC. Initialize it and set the
// entry points for RAMDAC functions. For the 24-plane TGA, the
// hardware cursor functions are performed by the display driver.
Init_bt485(hwDeviceExtension);
hwDeviceExtension->set_cursor_position = bt485_cursor_position;
hwDeviceExtension->set_cursor_pattern = bt485_cursor_pattern;
hwDeviceExtension->set_cursor_enable = bt485_cursor_enable;
hwDeviceExtension->set_cursor_disable = bt485_cursor_disable;
hwDeviceExtension->set_color_entry = bt485_colormap_update;
} else {
if (hwDeviceExtension->is_tga) {
Init_bt463(hwDeviceExtension);
hwDeviceExtension->set_color_entry = bt463_colormap_update;
} else {
Init_ibm561(hwDeviceExtension);
hwDeviceExtension->set_cursor_position = ibm561_cursor_position;
hwDeviceExtension->set_cursor_pattern = ibm561_cursor_pattern;
hwDeviceExtension->set_cursor_enable = ibm561_cursor_enable;
hwDeviceExtension->set_cursor_disable = ibm561_cursor_disable;
hwDeviceExtension->set_color_entry = ibm561_colormap_update;
}
}
// Perform the one-time initialization of DMA resources.
status = dma_init(hwDeviceExtension);
VideoDebugPrint((2, "\t Tga DMA init %x\n", status));
VideoDebugPrint((2, "\t TgaInitialize : exit\n"));
return (TRUE);
} // end TgaInitialize()
BOOLEAN
TgaReset(
PVOID HwDeviceExtension,
ULONG column,
ULONG row
)
/*++
Routine Description:
This routine resets the device on a system crash or shutdown.
It re-enables the VGA mode for use by ARC firmware console output.
Arguments:
HwDeviceExtension - Pointer to the device extension.
Return Value:
Always returns TRUE since this routine can never fail.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
//
// If TGA2, then clear Video Valid to turn on VGA.
//
if (hwDeviceExtension->is_tga2)
TGA_WRITE (VIDEO_VALID, 0);
return (TRUE);
}
char *name_ioctl (int ioctl)
{
static char buf[64];
switch (ioctl)
{
case IOCTL_VIDEO_LOCK_PAGES:
return "LOCK_PAGES";
case IOCTL_VIDEO_UNLOCK_PAGES:
return "UNLOCK_PAGES";
case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
return "MAP_VIDEO_MEMORY";
case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
return "UNMAP_VIDEO_MEMORY";
case IOCTL_VIDEO_QUERY_AVAIL_MODES:
return "QUERY_AVAIL_MODES";
case IOCTL_VIDEO_QUERY_CURRENT_MODE:
return "QUERY_CURRENT_MODE";
case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
return "QUERY_NUM_AVAIL_MODES";
case IOCTL_VIDEO_SET_CURRENT_MODE:
return "SET_CURRENT_MODE";
case IOCTL_VIDEO_SET_COLOR_REGISTERS:
return "SET_COLOR_REGISTERS";
case IOCTL_VIDEO_RESET_DEVICE:
return "RESET_DEVICE";
case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
return "QUERY_POINTER_CAPABILITIES";
case IOCTL_VIDEO_ENABLE_POINTER:
return "ENABLE_POINTER";
case IOCTL_VIDEO_DISABLE_POINTER:
return "DISABLE_POINTER";
case IOCTL_VIDEO_SET_POINTER_POSITION:
return "SET_POINTER_POSITION";
case IOCTL_VIDEO_QUERY_POINTER_POSITION:
return "QUERY_POINTER_POSITION";
case IOCTL_VIDEO_SET_POINTER_ATTR:
return "SET_POINTER_ATTR";
case IOCTL_VIDEO_QUERY_POINTER_ATTR:
return "QUERY_POINTER_ATTR";
case IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES:
return "QUERY_COLOR_CAPABILITIES";
default:
return "Unknown IOCTL";
}
}
BOOLEAN
TgaStartIO(
PVOID HwDeviceExtension,
PVIDEO_REQUEST_PACKET RequestPacket
)
/*++
Routine Description:
This routine is the main execution routine for the miniport driver.
It accepts a Video Request Packet, performs the request, and then
returns with the appropriate status.
Arguments:
HwDeviceExtension - Pointer to the device extension.
RequestPacket - Pointer to the video request packet. This structure
contains all the parameters passed to the ioctl function.
Return Value:
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
VP_STATUS status;
ULONG InIoSpace;
PVIDEO_MODE_INFORMATION modeInformation;
PVIDEO_MEMORY_INFORMATION memoryInformation;
PVIDEO_CLUT clutBuffer;
ULONG CursorMaskSize;
ULONG modeNumber;
PVIDEO_POINTER_ATTRIBUTES pointerAttributes;
PVIDEO_POINTER_POSITION pointerPosition;
BOOLEAN writeOperation = TRUE;
ULONG i, index;
PUCHAR userBuffer;
ULONG userBufferSize;
PULONG busAddress;
PHYSICAL_ADDRESS phys;
ULONG offset;
VideoDebugPrint((2, "TgaStartIO card %d (0 based) - %s\n",
hwDeviceExtension->adapter_number,
name_ioctl (RequestPacket->IoControlCode)));
//
// Switch on the IoControlMode in the RequestPacket. It indicates which
// function must be performed by the driver.
//
switch (RequestPacket->IoControlCode) {
case IOCTL_VIDEO_TEST_EV4: // Test whether running on EV4 processor
{
if (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information = sizeof(ULONG)))
{
VideoDebugPrint ((2, "Output buffer too small!\n"));
RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
return ERROR_INSUFFICIENT_BUFFER;
}
RequestPacket->StatusBlock->Status = TgaTestEv4(RequestPacket->OutputBuffer);
return NO_ERROR;
}
case IOCTL_VIDEO_FETCH_PCRR: // Return PCI Class/Revision Register
{
ULONG *pPcrr = RequestPacket->OutputBuffer;
if (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information = sizeof(ULONG)))
{
VideoDebugPrint ((2, "Output buffer too small!\n"));
RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
return ERROR_INSUFFICIENT_BUFFER;
}
*pPcrr = hwDeviceExtension->pcrr;
RequestPacket->StatusBlock->Status = NO_ERROR;
return NO_ERROR;
}
//
//
// Return the bus-relative physical address of this buffer.
//
case IOCTL_VIDEO_VIRT_TO_PHYS:
VideoDebugPrint((2, "\n Pointer to the structure passed in = %x\n",
RequestPacket->InputBuffer ));
userBuffer = ((PTGA_DMA )RequestPacket->InputBuffer)->bitmap;
userBufferSize = ((PTGA_DMA )RequestPacket->InputBuffer)->size;
VideoDebugPrint(( 0,"\t User Space Virtual Address of bitmap = %x\n",
userBuffer));
VideoDebugPrint(( 0, "\n bitmap size = %x\n", userBufferSize ));
//
// Check to see if the size of the data in the input buffer is large
// enough.
//
if (RequestPacket->InputBufferLength < sizeof(TGA_DMA)) {
VideoDebugPrint(( 2,"\n Insufficient Buffer" ));
status = ERROR_INSUFFICIENT_BUFFER;
break;
}
if (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(ULONG) )) {
status = ERROR_INSUFFICIENT_BUFFER;
VideoDebugPrint((2, "Returning Insufficient Buffer Messge" ));
break;
}
busAddress = (PULONG)RequestPacket->OutputBuffer;
if (!virtual_to_physical(userBuffer, busAddress))
{
RequestPacket->StatusBlock->Information = 0;
status = ERROR_INSUFFICIENT_BUFFER;
VideoDebugPrint((0, "\nDMA Lock Return, busAddress [%d/%x]\n", *busAddress, *busAddress));
}
else
status = NO_ERROR;
VideoDebugPrint((0, "\nDMA Lock Returning back to the caller") );
break;
//
// Lock the specified user-space buffer into memory, return the
// PCI bus-relative physical address of this buffer.
//
case IOCTL_VIDEO_LOCK_PAGES:
//
// Check to see if the size of the data in the input buffer is large
// enough.
//
if (RequestPacket->InputBufferLength < sizeof(TGA_DMA)) {
VideoDebugPrint(( 2,"\n Insufficient Buffer" ));
status = ERROR_INSUFFICIENT_BUFFER;
break;
}
userBuffer = ((PTGA_DMA )RequestPacket->InputBuffer)->bitmap;
userBufferSize = ((PTGA_DMA )RequestPacket->InputBuffer)->size;
VideoDebugPrint(( 3,"\t User Space Virtual Address of bitmap = %x\n",
userBuffer));
VideoDebugPrint(( 3, "\n bitmap size = %x\n", userBufferSize ));
if (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(ULONG) )) {
status = ERROR_INSUFFICIENT_BUFFER;
break;
}
busAddress = (PULONG)RequestPacket->OutputBuffer;
if (!dma_lock_pages(hwDeviceExtension, userBuffer,
userBufferSize, busAddress))
{
RequestPacket->StatusBlock->Information = 0;
status = ERROR_INSUFFICIENT_BUFFER;
}
else
status = NO_ERROR;
VideoDebugPrint((0, "\nDMA Lock Return, busAddress [%d/%x]\n", *busAddress, *busAddress));
break;
//
// Unlock the user-space buffer that has just been used for DMA.
//
case IOCTL_VIDEO_UNLOCK_PAGES:
VideoPortReadRegisterUlong((PULONG)
(hwDeviceExtension->RegisterSpace + COMMAND_STATUS ));
dma_unlock_pages(hwDeviceExtension);
status = NO_ERROR;
VideoDebugPrint((0, "\nDMA Lock Returning back to the caller") );
break;
//
// Map the resources of the video card to the virtual address space of
// the display driver.
//
case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
// Make sure the input buffer and output buffer supplied by the display
// driver are large enough. The requesting process (display driver or
// NT Setup) wants to find out 1) the address and size of the video
// card's memory space and 2) the address and size of the frame buffer.
if ( (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(VIDEO_MEMORY_INFORMATION))) ||
(RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
status = ERROR_INSUFFICIENT_BUFFER;
}
// Set a pointer to the output buffer.
memoryInformation = RequestPacket->OutputBuffer;
// The input to this request is the "requested virtual address". This
// specifies the process virtual address into which the video board's
// memory is to be mapped. If it is 0 (in our implementation it is)
// then the video port produces a virtual address.
memoryInformation->VideoRamBase = ((PVIDEO_MEMORY)
(RequestPacket->InputBuffer))->RequestedVirtualAddress;
memoryInformation->VideoRamLength = hwDeviceExtension->AdapterMemorySize;
#ifdef _ALPHA_
InIoSpace = 4; // Dense space mapping
#else
InIoSpace = 0;
#endif
//
// Map the frame buffer.
//
phys = hwDeviceExtension->PhysicalFrameAddress;
phys.QuadPart += hwDeviceExtension->fb_offset;
status = VideoPortMapMemory(hwDeviceExtension,
phys,
&(memoryInformation->VideoRamLength),
&InIoSpace,
&(memoryInformation->VideoRamBase));
//
// Determine hardware frame buffer offset that was set using
// the VideoBase Register
//
if (hwDeviceExtension->bpp == 8) {
offset = FRAMEBUFFER_OFFSET_8;
} else {
offset = FRAMEBUFFER_OFFSET_24;
}
memoryInformation->FrameBufferBase =
((PUCHAR) memoryInformation->VideoRamBase) + offset;
memoryInformation->FrameBufferLength =
memoryInformation->VideoRamLength - offset;
break;
case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
// The input to this request is the process virtual address into
// which the video board's memory was mapped. The entire virtual
// address range will be unmapped.
if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) {
status = ERROR_INSUFFICIENT_BUFFER;
}
status = VideoPortUnmapMemory(hwDeviceExtension, ((PVIDEO_MEMORY)
(RequestPacket->InputBuffer))->RequestedVirtualAddress,
0);
break;
case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES:
{
PVIDEO_PUBLIC_ACCESS_RANGES portAccess;
PHYSICAL_ADDRESS physicalPortBase;
ULONG physicalPortLength;
if ( RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(VIDEO_PUBLIC_ACCESS_RANGES)) ) {
status = ERROR_INSUFFICIENT_BUFFER;
}
portAccess = RequestPacket->OutputBuffer;
portAccess->VirtualAddress = (PVOID) NULL; // Requested VA
#ifdef _ALPHA_
portAccess->InIoSpace = 4;
portAccess->MappedInIoSpace = 4;
#else
portAccess->InIoSpace = hwDeviceExtension->InIoSpace;
portAccess->MappedInIoSpace = hwDeviceExtension->InIoSpace;
#endif
physicalPortBase = hwDeviceExtension->PhysicalFrameAddress;
physicalPortBase.QuadPart += TGA_ASIC_OFFSET;
physicalPortLength = TGA_ASIC_LENGTH;
status = VideoPortMapMemory(hwDeviceExtension,
physicalPortBase,
&physicalPortLength,
&(portAccess->MappedInIoSpace),
&(portAccess->VirtualAddress));
}
break;
case IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES:
VideoDebugPrint((2, "QvStartIO - FreePublicAccessRanges\n"));
if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) {
status = ERROR_INSUFFICIENT_BUFFER;
}
status = VideoPortUnmapMemory(hwDeviceExtension,
((PVIDEO_MEMORY)
(RequestPacket->InputBuffer))->
RequestedVirtualAddress,
0); // VA to be freed is not in IO space
break;
//
// Return information on all of the available modes for this video card.
//
case IOCTL_VIDEO_QUERY_AVAIL_MODES:
if (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
hwDeviceExtension->NumAvailModes
* sizeof(VIDEO_MODE_INFORMATION) ) ) {
status = ERROR_INSUFFICIENT_BUFFER;
} else {
modeInformation = RequestPacket->OutputBuffer;
for ( i=0; i < NumTgaVideoModes; i++) {
if (TGAModes[i].ModeValid) {
*modeInformation = TGAModes[i].ModeInformation;
#if defined(_MIPS_)
//
// The NEC RA94 machines have a bug with 64 bit memory moves on the PCI
// bus.
//
modeInformation->AttributeFlags |=
VIDEO_MODE_NO_64_BIT_ACCESS;
#endif
modeInformation++;
}
}
status = NO_ERROR;
}
break;
//
// Return the mode information, for the current mode, for this video card.
//
case IOCTL_VIDEO_QUERY_CURRENT_MODE:
// Verify that the user output buffer is large enough, and then return
// the mode information for the specified mode number.
if (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(VIDEO_MODE_INFORMATION) )) {
status = ERROR_INSUFFICIENT_BUFFER;
} else {
*((PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer) =
TGAModes[hwDeviceExtension->CurrentModeNumber].ModeInformation;
status = NO_ERROR;
}
break;
//
// Return the number of available modes for this graphics card, and the
// size of a buffer needed to hold a single mode's description.
//
case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
// Find out the size of the data to be put in the buffer and
// return that in the status information (whether or not the
// information is there). If the buffer passed in is not large
// enough return the appropriate error code.
if (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(VIDEO_NUM_MODES) )) {
status = ERROR_INSUFFICIENT_BUFFER;
} else {
((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->NumModes =
hwDeviceExtension->NumAvailModes;
((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->ModeInformationLength
= sizeof(VIDEO_MODE_INFORMATION);
status = NO_ERROR;
}
break;
//
// Set a new monitor resolution and refresh rate.
//
case IOCTL_VIDEO_SET_CURRENT_MODE:
modeNumber = ((PVIDEO_MODE)RequestPacket->InputBuffer)->RequestedMode;
VideoDebugPrint((2,"\t Mode Number to set = %x\n", modeNumber));
//
// Check to see if the size of the data in the input buffer is large
// enough.
//
if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE)) {
VideoDebugPrint((2, "\nI am returning INSUFFICIENT BUFFER message"));
return (ERROR_INSUFFICIENT_BUFFER);
}
//
// Check to see if we are requesting a valid mode.
//
if ( (modeNumber >= NumTgaVideoModes) ||
(!TGAModes[modeNumber].ModeValid) ) {
VideoDebugPrint((2, "\t NumTgaVideoModes = %x \
\t TGAModes[modeNumber].ModeValid = %x",
NumTgaVideoModes,
TGAModes[modeNumber].ModeValid));
return (ERROR_INVALID_PARAMETER);
break;
}
//
// Save the mode number since we know the rest will work.
//
hwDeviceExtension->ModeNumber = modeNumber;
if (NO_ERROR != TgaSetExtendedMode(hwDeviceExtension,
TGAModes[modeNumber].ModeInformation.ModeIndex)) {
status = ERROR_INVALID_PARAMETER;
VideoDebugPrint((2,"\tSetTgaMode(%x, %.2x, %.2x ) failed\n",
hwDeviceExtension,
TGAModes[modeNumber].ModeInformation.ModeIndex));
} else
status = NO_ERROR;
break;
//
// Update one or more entries in the RAMDAC colormap.
//
case IOCTL_VIDEO_SET_COLOR_REGISTERS:
{
#define COLOR_MAP_MAX_RETRIES 5
ULONG limit = COLOR_MAP_MAX_RETRIES;
clutBuffer = RequestPacket->InputBuffer;
//
// Install the color entries into the RAMDAC. If this operation
// fails, retry it a few times (note: we don't have any actual
// evidence that the RAMDAC should have such "soft" failures).
//
do {
status = SetColorLookup(hwDeviceExtension,
(PVIDEO_CLUT)RequestPacket->InputBuffer,
RequestPacket->InputBufferLength);
} while ((status == ERROR_MORE_DATA) && (--limit > 0));
}
break;
case IOCTL_VIDEO_RESET_DEVICE:
status = NO_ERROR;
break;
case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
{
//
// return type of pointer supported: asynchronous monochrome
//
PVIDEO_POINTER_CAPABILITIES pointerCaps = RequestPacket->OutputBuffer;
if (RequestPacket->OutputBufferLength <
sizeof(PVIDEO_POINTER_CAPABILITIES)) {
RequestPacket->StatusBlock->Information = 0;
status = ERROR_INSUFFICIENT_BUFFER;
} else {
if (hwDeviceExtension->bpp == 8 ) {
pointerCaps->Flags = (VIDEO_MODE_ASYNC_POINTER |
VIDEO_MODE_MONO_POINTER);
pointerCaps->MaxWidth = BT485_CURSOR_WIDTH;
pointerCaps->MaxHeight = BT485_CURSOR_HEIGHT;
pointerCaps->HWPtrBitmapStart = (ULONG) -1;
pointerCaps->HWPtrBitmapEnd = (ULONG) -1;
} else {
pointerCaps->Flags = (VIDEO_MODE_ASYNC_POINTER |
VIDEO_MODE_MONO_POINTER);
pointerCaps->MaxWidth = IBM561_CURSOR_WIDTH;
pointerCaps->MaxHeight = IBM561_CURSOR_HEIGHT;
pointerCaps->HWPtrBitmapStart = (ULONG) -1;
pointerCaps->HWPtrBitmapEnd = (ULONG) -1;
}
//
// Number of bytes we are returning.
//
RequestPacket->StatusBlock->Information =
sizeof(VIDEO_POINTER_CAPABILITIES);
status = NO_ERROR;
}
break;
}
//
// Make the hardware cursor visible.
//
case IOCTL_VIDEO_ENABLE_POINTER:
//
// If the hardware cursor is currently disabled, then enable it.
//
if (hwDeviceExtension->CursorEnable == FALSE) {
(hwDeviceExtension->set_cursor_enable) (hwDeviceExtension);
hwDeviceExtension->CursorEnable = TRUE;
}
status = NO_ERROR;
break;
//
// Make the hardware cursor not visible.
//
case IOCTL_VIDEO_DISABLE_POINTER:
//
// If the hardware cursor is currently enabled, then disable it.
//
if (hwDeviceExtension->CursorEnable == TRUE) {
hwDeviceExtension->CursorEnable = FALSE;
(hwDeviceExtension->set_cursor_disable) (hwDeviceExtension);
}
status = NO_ERROR;
break;
//
// Move the hardware cursor to a different position on the screen.
//
case IOCTL_VIDEO_SET_POINTER_POSITION:
//
// Check if the size of the data in the input buffer is large enough.
//
if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_POSITION)) {
VideoDebugPrint((3,"The input buffer length is not large enough"));
status = ERROR_INSUFFICIENT_BUFFER;
} else {
pointerPosition = RequestPacket->InputBuffer;
hwDeviceExtension->CursorColumn = pointerPosition->Column;
hwDeviceExtension->CursorRow = pointerPosition->Row;
//
// Update the cursor location
//
(hwDeviceExtension->set_cursor_position) (hwDeviceExtension);
status = NO_ERROR;
}
break;
//
// Return the current position of the hardware cursor.
//
case IOCTL_VIDEO_QUERY_POINTER_POSITION:
//
// Find out the size of the data to be put in the buffer and
// return the status information. If the buffer passed in is
// not large enough return an appropriate error code.
//
if (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(VIDEO_POINTER_POSITION))) {
VideoDebugPrint((3, "ERROR:Output Buffer Length is not enough"));
status = ERROR_INSUFFICIENT_BUFFER;
} else {
//
// Return the current hardware cursor column and row values.
//
pointerPosition = RequestPacket->OutputBuffer;
pointerPosition->Column = hwDeviceExtension->CursorColumn;
pointerPosition->Row = hwDeviceExtension->CursorRow;
status = NO_ERROR;
}
break;
//
// Set the position and pattern of the hardware cursor.
//
case IOCTL_VIDEO_SET_POINTER_ATTR:
{
PVIDEO_POINTER_ATTRIBUTES pointerAttributes;
ULONG iCount = 512;
USHORT index;
ULONG attr_size;
pointerAttributes = RequestPacket->InputBuffer;
//
// Check if the size of the data in the input buffer is large enough
// (Each cursor pixel has 2 bits, compute the number of bytes for
// the pattern below)
//
if (hwDeviceExtension->bpp == 8)
attr_size = sizeof(VIDEO_POINTER_ATTRIBUTES) + BT485_CURSOR_WIDTH/8 *
BT485_CURSOR_HEIGHT * 2;
else
attr_size = sizeof(VIDEO_POINTER_ATTRIBUTES) + IBM561_CURSOR_WIDTH/8 *
IBM561_CURSOR_HEIGHT * 2;
if (RequestPacket->InputBufferLength < attr_size ) {
VideoDebugPrint((3,"\nInput buffer length is less than expected"));
status = ERROR_INSUFFICIENT_BUFFER;
break;
}
//
// If the specified cursor width or height is not valid, then
// return an invalid parameter error
//
VideoDebugPrint((3, "\npointerAttributes->Width = %d \
\npointerAttributes->Height = %d \
\npointerAttributes->WidthInBytes = %d \
\npointerAttributes->Enable = %d \
\npointerAttributes->Column= %d \
\npointerAttributes->Row = %d",
pointerAttributes->Width,
pointerAttributes->Height,
pointerAttributes->WidthInBytes,
pointerAttributes->Enable,
pointerAttributes->Column,
pointerAttributes->Row
));
if (hwDeviceExtension->bpp == 8 ) {
if ((pointerAttributes->Width > BT485_CURSOR_WIDTH) ||
(pointerAttributes->Height > BT485_CURSOR_HEIGHT)) {
VideoDebugPrint((3,"\n Width or Height is greater than expected"));
status = ERROR_INVALID_PARAMETER;
break;
}
}
if (hwDeviceExtension->bpp == 32 ) {
if ((pointerAttributes->Width > IBM561_CURSOR_WIDTH) ||
(pointerAttributes->Height > IBM561_CURSOR_HEIGHT)) {
VideoDebugPrint((3,"\n Width or Height is greater than expected"));
status = ERROR_INVALID_PARAMETER;
break;
}
}
//
// Capture the hardware cursor column, and row values.
//
hwDeviceExtension->CursorRow = pointerAttributes->Row;
hwDeviceExtension->CursorColumn = pointerAttributes->Column;
//
// The cursor shape is passed as a AND MASK and an XOR mask. These
// MASKS are 1bpp. First copy the XOR mask to the hwDeviceExtension
// structure then the AND mask since this is the order needed by
// the Bt485
// CursorMaskSize is in bytes - 128 bytes for a 32x32 cursor Width = 32
// CursorMaskSize is in bytes - 512 bytes for a 64x64 cursor Width = 64
//
CursorMaskSize = ((pointerAttributes->Width/8) *
pointerAttributes->Height);
VideoDebugPrint((3,"\n CursorMaskSize = %d", CursorMaskSize));
hwDeviceExtension->CursorMaskSize = CursorMaskSize;
//
// The first 128/512 pixels are the AND MASK,
// the next 128/512 pixels are the XOR MASK
//
if (hwDeviceExtension->bpp == 8 ) {
RtlMoveMemory( &hwDeviceExtension->CursorPixels[0],
&pointerAttributes->Pixels[CursorMaskSize],
CursorMaskSize);
RtlMoveMemory( &hwDeviceExtension->CursorPixels[CursorMaskSize],
&pointerAttributes->Pixels[0],
CursorMaskSize);
}
if (hwDeviceExtension->bpp == 32 ) {
//
// Put the AND and OR data into a format that can be directly
// loaded into the IBM 561 RAMDAC.
//
format_ibm561_cursor_data(
(PUCHAR) &pointerAttributes->Pixels[0], // AND mask
(PUCHAR) &pointerAttributes->Pixels[0 + CursorMaskSize], // OR
(PUSHORT) &hwDeviceExtension->CursorPixels[0]); // 561 result
}
//
// If the cursor is not enabled, then put the new pattern in now.
// Otherwise, request that it be done on the next VSYNC interrupt.
//
hwDeviceExtension->CursorEnable = (UCHAR) pointerAttributes->Enable;
if (hwDeviceExtension->CursorEnable) {
(hwDeviceExtension->set_cursor_position) (hwDeviceExtension);
(hwDeviceExtension->set_cursor_enable) (hwDeviceExtension);
hwDeviceExtension->UpdateCursorPixels = TRUE;
TGA_WRITE( INTR_STATUS, (TGA_INTR_VSYNC << TGA_INTR_ENABLE_SHIFT) );
} else {
(hwDeviceExtension->set_cursor_pattern) (hwDeviceExtension);
}
status = NO_ERROR;
break;
}
//
// Return all of the current attributes of the cursor. This includes
// its size, position, whether it is enabled, and the pattern itself.
//
case IOCTL_VIDEO_QUERY_POINTER_ATTR:
//
// Find out the size of the data to be put in the buffer and
// return that in the status information. If the buffer passed
// in is not large enough return an appropriate error code.
//
pointerAttributes = RequestPacket->OutputBuffer;
if (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(VIDEO_POINTER_ATTRIBUTES) + ((BT485_CURSOR_WIDTH * \
BT485_CURSOR_HEIGHT)/sizeof(UCHAR) * 2) )) {
status = ERROR_INSUFFICIENT_BUFFER;
break;
}
if (RequestPacket->OutputBufferLength <
(RequestPacket->StatusBlock->Information =
sizeof(VIDEO_POINTER_ATTRIBUTES) + ((IBM561_CURSOR_WIDTH * \
IBM561_CURSOR_HEIGHT)/sizeof(UCHAR) * 2) )) {
status = ERROR_INSUFFICIENT_BUFFER;
break;
}
//
// Return the current hardware cursor width, height column,
// row and enable values.
//
pointerAttributes->Column = hwDeviceExtension->CursorColumn;
pointerAttributes->Row = hwDeviceExtension->CursorRow;
pointerAttributes->Enable = hwDeviceExtension->CursorEnable;
if (hwDeviceExtension->bpp == 8 ) {
pointerAttributes->WidthInBytes = 4; // 32 pixels wide
pointerAttributes->Width = 32;
pointerAttributes->Height = 32;
} else {
pointerAttributes->WidthInBytes = 8; // 64 pixels wide
pointerAttributes->Width = 64;
pointerAttributes->Height = 64;
}
//
// Return the hardware cursor pixel values.
// Calculate the size in bytes of 1 mask.
//
CursorMaskSize = pointerAttributes->WidthInBytes * \
pointerAttributes->Height;
//
// Return the XOR mask ( first plane of BT485 cursor)
//
for (index=0; index < CursorMaskSize; index++ ) {
pointerAttributes->Pixels[index + CursorMaskSize] =
hwDeviceExtension->CursorPixels[index];
}
for ( index=0; index < CursorMaskSize; index++ ) {
pointerAttributes->Pixels[index] =
hwDeviceExtension->CursorPixels[index + CursorMaskSize];
}
status = NO_ERROR;
break;
case IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES:
//
// (Note: I couldn't find an example in any of the sample DDK drivers
// as to how this is handled. Intercept it but return an error.)
//
VideoDebugPrint((3,"\tQuery Color Capabilities - not supported\n"));
status = ERROR_INVALID_FUNCTION;
break;
//
// If we get here, an invalid IoControlCode was specified.
//
default:
VideoDebugPrint((0,"\tFell through StartIO routine - invalid command\n"));
VideoDebugPrint(( 0, "\nIoControlCode = %x\n",
RequestPacket->IoControlCode ));
} // end switch
RequestPacket->StatusBlock->Status = status;
VideoDebugPrint ((3, "Startio Issuing Return, status [%d]\n", status));
return (TRUE);
} // end TgaStartIO()
VP_STATUS
TgaSetExtendedMode(
PHW_DEVICE_EXTENSION HwDeviceExtension,
ULONG Mode
)
/*++
Routine Description:
This function sets the appropriate timing values
depending upon the mode number passed in.
Arguments:
HwDeviceExtension - Pointer to the device extension.
ModeNumber - Number of the mode to be set
Return Value:
NO_ERROR is the set mode was completed successfully
ERROR_INVALID_PARAMETER otherwise.
-*/
{
ULONG i, j, Temp, index;
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
VideoDebugPrint((0, "SetTGAExtMode ( %d) \n", Mode));
if (hwDeviceExtension->is_tga2) {
TGA_WRITE (VIDEO_VALID, 0);
}
TGA_WRITE( H_CONT, (TGAModes[Mode].h_cont.h_setup) );
TGA_WRITE( V_CONT, (TGAModes[Mode].v_cont.v_setup) );
VideoDebugPrint((0, "\tHORIZONTOL CONTROL REGISTER = %x\n, \
\tVERTICAL CONTROL REGISTER = %x\n",
TGAModes[Mode].h_cont.h_setup,
TGAModes[Mode].v_cont.v_setup));
//
// Write the PLL
//
if (hwDeviceExtension->is_tga) {
for (i=1; i<=7; i++) {
for (j = 0; j <= 7; j++) {
Temp = (TGAModes[Mode].PllData[i] >> (7-j)) & 1;
if (i == 7 && j == 7)
Temp |=2;
TGA_WRITE (CLOCK, (Temp) );
}
}
}
//
// For TGA2,
//
if (hwDeviceExtension->is_tga2) {
PUCHAR vaddr;
PHYSICAL_ADDRESS phys;
phys = hwDeviceExtension->PhysicalFrameAddress;
phys.QuadPart += 0x60000;
vaddr = VideoPortGetDeviceBase(hwDeviceExtension,
phys,
0x10000,
hwDeviceExtension->InIoSpace);
if (vaddr) {
VideoPortWriteRegisterUlong((PULONG) (vaddr + 0xF800), 0);
VideoPortWriteRegisterUlong((PULONG) (vaddr + 0xF000), 0);
VideoPortWriteRegisterUlong((PULONG)vaddr, TGAModes[Mode].PllData_tga2[0]);
VideoPortWriteRegisterUlong((PULONG)vaddr, TGAModes[Mode].PllData_tga2[1]);
VideoPortWriteRegisterUlong((PULONG)vaddr, TGAModes[Mode].PllData_tga2[2]);
VideoPortWriteRegisterUlong((PULONG)vaddr, TGAModes[Mode].PllData_tga2[3]);
VideoPortWriteRegisterUlong((PULONG)vaddr, TGAModes[Mode].PllData_tga2[4]);
VideoPortWriteRegisterUlong((PULONG)vaddr, TGAModes[Mode].PllData_tga2[5]);
VideoPortWriteRegisterUlong((PULONG) (vaddr + 0xF800), 0);
VideoPortFreeDeviceBase(hwDeviceExtension, vaddr);
}
}
#if 0
// This is for debug of the right and left part of the scanline problems.
// We are writing some pixels in the frame buffer and then setting a
// breakpoint so we can observe the result.
//
// Save some information in device extension
//
hwDeviceExtension->FrameAddress=
(PUCHAR) (hwDeviceExtension->memory_space_base +
hwDeviceExtension->fb_offset);
PULONG pFB;
pFB = (PULONG)hwDeviceExtension->FrameAddress + 4096;
for (i=0; i < 0x40000; i++) // on 8mb board
{
VideoPortWriteRegisterUlong(pFB, 0x800f0000);
pFB += 1;
VideoPortWriteRegisterUlong(pFB, 0x01010101);
pFB += 1;
VideoPortWriteRegisterUlong(pFB, 0x01010101);
pFB += 1;
VideoPortWriteRegisterUlong(pFB, 0x01010101);
pFB += 1;
VideoPortWriteRegisterUlong(pFB, 0x01010101);
pFB += 1;
VideoPortWriteRegisterUlong(pFB, 0xffFFffFF);
pFB += 1;
VideoPortWriteRegisterUlong(pFB, 0xffFFffFF);
pFB += 1;
VideoPortWriteRegisterUlong(pFB, 0xffFFffFF);
pFB += 1;
VideoPortWriteRegisterUlong(pFB, 0xffFFffFF);
pFB += 1;
}
for (i=0; i < 0x40000; i++) // on 8mb board
{
VideoPortWriteRegisterUlong(pFB, 0x80000000);
pFB += 1;
}
for (i=0; i < 0x40000; i++) // on 8mb board
{
VideoPortWriteRegisterUlong(pFB, 0x80030000);
pFB += 1;
}
// DbgBreakPoint(); // check out any right edge pattern
#endif
// For the 24-plane TGA2, program the RAMDAC with the clock
// values for this mode.
if (hwDeviceExtension->is_tga2 && hwDeviceExtension->bpp == 32) {
index = TGAModes[Mode].PllData_tga2[7];
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info,
TGA_RAMDAC_561_ADDR_LOW, TGA_RAMDAC_561_PLL_VCO_DIV_REG);
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info,
TGA_RAMDAC_561_ADDR_HIGH, (TGA_RAMDAC_561_PLL_VCO_DIV_REG >> 8));
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info,
TGA_RAMDAC_561_CMD_REGS, (pll[index].divVcoReg ));
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info,
TGA_RAMDAC_561_ADDR_LOW, TGA_RAMDAC_561_PLL_REF_REG);
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info,
TGA_RAMDAC_561_ADDR_HIGH, (TGA_RAMDAC_561_PLL_REF_REG >> 8));
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info,
TGA_RAMDAC_561_CMD_REGS, (pll[index].refReg ));
}
//
// If TGA2, then set Video Valid to turn off VGA.
//
if (hwDeviceExtension->is_tga2)
TGA_WRITE (VIDEO_VALID, 0x41);
// Enable video timing (turn off VGA),
// no blank, no cursor
return (NO_ERROR);
}
//
// Handle device interrupts (the only one we expect is VSYNC, which is
// enabled only to perform a specific cursor-related task).
//
BOOLEAN
TgaInterruptService(
PVOID HwDeviceExtension
)
/*++
Routine Description:
This routine is the interrupt service routine for the TGA/TGA2
Arguments:
HwDeviceExtension - Pointer to the miniport driver's adapter info
Return Value:
TRUE if the interrupt is serviced.
FALSE if not a TGA/TGA2 interrupt.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
ULONG InterruptEnable,InterruptSource;
//
// Read the interrupt source before disabling interrupts
// Should be 0x10001
//
InterruptSource = VideoPortReadRegisterUlong((PULONG)
(hwDeviceExtension->RegisterSpace + INTR_STATUS));
//
// New for TGA2: the DMA and parity error interrupts. We don't enable,
// these, and therefore don't handle these as a possibility.
// There is no Timer interrupt in TGA2.
// DMA interrupt enable is 0x40000 and DMA interrupt event is 0x4.
// Parity interrupt enable is 0x80000 and parity interrupt event is 0x8.
//
//
// Which TGA interrupts are actually enabled?
// (only one we ever enable is VSYNC)
//
InterruptEnable = InterruptSource & (TGA_INTR_ALL << TGA_INTR_ENABLE_SHIFT);
//
// Which TGA interrupts are pending?
//
InterruptSource &= TGA_INTR_ALL;
//
// Do we have a TGA interrupt?
//
if ( (InterruptSource == 0) || (InterruptEnable == 0) ) {
//
// Either TGA interrupts are enabled, but haven't happened yet, or
// TGA interrupts are disabled (in which case we ignore this).
//
VideoDebugPrint(( 0,
"Some other device besides TGA has interrupted!" ));
//
// Handle possible shared interrupt by indicating "Not My Interrupt"
//
return (FALSE);
}
//
// Disable all interrrupts and clear interrupt pending bits
//
if (hwDeviceExtension->is_tga) {
TGA_WRITE( INTR_STATUS, TGA_INTR_ALL_TGA);
} else {
TGA_WRITE( INTR_STATUS, TGA_INTR_ALL_TGA2);
}
//
// Do we have a VSYNC interrupt?
//
if (( InterruptSource & TGA_INTR_VSYNC) == TGA_INTR_VSYNC ) {
//
// If we have interrupted a thread that is accessing the RAMDAC,
// then just re-enable VSYNC interrupts and get out. Eventually we
// be able to go ahead and do our RAMDAC processing in the ISR.
//
if (hwDeviceExtension->RamdacBusy) {
if (hwDeviceExtension->RamdacBusyLogged == FALSE) {
VideoDebugPrint(( 0,
"Tga - interrupted lower level RAMDAC access" ));
hwDeviceExtension->RamdacBusyLogged = TRUE;
}
TGA_WRITE( INTR_STATUS, (TGA_INTR_VSYNC << TGA_INTR_ENABLE_SHIFT) );
return(TRUE);
}
//
// If the hardware cursor pixels should be updated, then load
// the cursor ram in the RAMDAC.
//
if (hwDeviceExtension->UpdateCursorPixels == TRUE) {
(hwDeviceExtension->set_cursor_pattern) (hwDeviceExtension);
hwDeviceExtension->UpdateCursorPixels = FALSE;
}
return (TRUE);
}
//
// We have TGA interrupt(s) other than VSYNC (shouldn't happen.)
//
VideoDebugPrint(( 0, "Some other TGA interrupt besides vsync posted" ));
return (TRUE);
} // end of TgaInterrupt
VP_STATUS
SetColorLookup(
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CLUT ClutBuffer,
ULONG ClutBufferSize
)
/*++
Routine Description:
This routine sets a specified portion of the color lookup table.
Arguments:
HwDeviceExtension - Ptr. to the miniport driver's device extension.
ClutBufferSize - Length of the input buffer supplied by the user.
ClutBuffer - Ptr. to the structure containing the color lookup table.
Return Value:
ERROR_INSUFFICIENT_BUFFER - Input buffer isn't large enough
ERROR_INVALID_PARAMETER - Bad color index specified
ERROR_MORE_DATA - Colors not physically stored in RAMDAC correctly
NO_ERROR - Success
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
VideoDebugPrint((2,"\tTga SetColorLookup: enter\n"));
//
// Check if the size if the data in the input buffer is large enough.
//
if ( (ClutBufferSize < sizeof(VIDEO_CLUT) - sizeof(ULONG) ) ||
(ClutBufferSize < sizeof(VIDEO_CLUT) +
(sizeof(ULONG) * (ClutBuffer->NumEntries -1)) ) ) {
return (ERROR_INSUFFICIENT_BUFFER);
}
//
// Check to see if the parameters are valid.
//
if ( (ClutBuffer->NumEntries == 0) ||
(ClutBuffer->FirstEntry > VIDEO_MAX_COLOR_REGISTER) ||
(ClutBuffer->FirstEntry + ClutBuffer->NumEntries >
VIDEO_MAX_COLOR_REGISTER + 1) ) {
return (ERROR_INVALID_PARAMETER);
}
(hwDeviceExtension->set_color_entry) (hwDeviceExtension, ClutBuffer);
//
// The following is a temporary diagnostic. Verify that the color entries
// were installed and stored correctly by the RAMDAC, by reading them
// out again.
//
#if 0
if ((hwDeviceExtension->bpp == 8) && (hwDeviceExtension->is_tga)) {
ULONG i, temp;
BOOLEAN retry_needed = FALSE;
//
// Read back the values to verify that the data made it to the RAMDAC
//
BT485_WRITE( BT485_ADDR_COLOR_PALETTE_READ, ClutBuffer->FirstEntry);
BT485_READ_SETUP( BT485_COLOR_PALETTE_DATA);
VideoDebugPrint((2,"\n\tChecking RAMDAC values \n\n"));
for (i=0; i < (ULONG)(ClutBuffer->NumEntries); i++) {
temp = VideoPortReadRegisterUlong ((PULONG)
(hwDeviceExtension->RegisterSpace + RAMDAC_INTERFACE));
temp = (temp >> 16) & 0xFF;
if (temp != (ULONG) (ClutBuffer->LookupTable[i].RgbArray.Red) ) {
VideoDebugPrint((0,"\t**** RAMDAC error Entry: %d (0x%02X) \
Red=%02X expected:%02X\n",
i+(ULONG)ClutBuffer->FirstEntry,
i+(ULONG)ClutBuffer->FirstEntry, (temp),
(ULONG) (ClutBuffer->LookupTable[i].RgbArray.Red)));
retry_needed = TRUE;
}
temp = VideoPortReadRegisterUlong ((PULONG)
(hwDeviceExtension->RegisterSpace + RAMDAC_INTERFACE));
temp = (temp >> 16) & 0xFF;
if (temp != (ULONG) (ClutBuffer->LookupTable[i].RgbArray.Green) ) {
VideoDebugPrint((0,"\t**** RAMDAC error Entry: %d (0x%02X) \
Green=%02X expected:%02X\n",
i+(ULONG)ClutBuffer->FirstEntry,
i+(ULONG)ClutBuffer->FirstEntry, (temp),
(ULONG) (ClutBuffer->LookupTable[i].RgbArray.Green)));
retry_needed = TRUE;
}
temp = VideoPortReadRegisterUlong ((PULONG)
(hwDeviceExtension->RegisterSpace + RAMDAC_INTERFACE));
temp = (temp >> 16) & 0xFF;
if (temp != (ULONG) (ClutBuffer->LookupTable[i].RgbArray.Blue) ) {
VideoDebugPrint((0,"\t**** RAMDAC error Entry: %d (0x%02X) \
Blue=%02X expected:%02X\n",
i+(ULONG)ClutBuffer->FirstEntry,
i+(ULONG)ClutBuffer->FirstEntry, (temp),
(ULONG) (ClutBuffer->LookupTable[i].RgbArray.Blue)));
retry_needed = TRUE;
}
} //for
if (retry_needed) {
VideoDebugPrint((0,"**** RAMDAC colormap entry requires reinstall\n"));
return (ERROR_MORE_DATA);
}
}
#endif
return (NO_ERROR);
} // end SetColorLookup()
VP_STATUS
Init_bt485(
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
USHORT index,i;
ULONG cmd_0, cmd_3, cmd_2;
// Set up some registers that we used to rely on the ARC firmware
// to initialize. Each register is 8-bits, please refer to the Brooktree
// spec for information on what each bit setting (0 or 1) represents.
// Enable 8-bit pixels
BT485_WRITE( BT485_CMD_REG_1, 0x40);
// Enable the PORTSEL input pin, clear two-color cursor
BT485_WRITE( BT485_CMD_REG_2, 0x20); // (is 0x26 in VMS/Unix TGA2)
BT485_WRITE( BT485_PIXEL_MASK_REGISTER, 0xFF);
// Set MSB of Command Register 0 to access Command Register 3 (via
// Status register), set 8-bit operation, set 7.5 IRE
BT485_WRITE( BT485_CMD_REG_0, 0xA2);
BT485_WRITE( BT485_PALETTE_CURSOR_WRITE_ADDR, 0x01);
if (hwDeviceExtension->is_tga2) {
BT485_WRITE( BT485_STATUS_REG,0x08); // Enable 2x clock multiplier
} else {
BT485_WRITE( BT485_STATUS_REG,0x10); // (This bit not documented
// in Brooktree spec.)
}
//
// Initialize cursor and overscan color
//
// Set address pointer base. Note that the BT485 uses autoincrement
// addressing.
//
BT485_WRITE( BT485_CURSOR_COLOR_WRITE_ADDR, 0);
//
// Zero cursor overscan color
//
for (i=0; i<3; i++) {
BT485_WRITE( BT485_DATA_CURSOR_COLOR, 0x00 );
}
//
// Set cursor color 1 to black
//
for (i=0; i<3; i++) {
BT485_WRITE( BT485_DATA_CURSOR_COLOR, 0x00 );
}
VideoDebugPrint((3,"\n Writing cursor color register 2 to white"));
for (i=0; i<3; i++) {
BT485_WRITE( BT485_DATA_CURSOR_COLOR, 0x0ff);
}
VideoDebugPrint((3,"\n Writing cursor color register 3 to white "));
for (i=0; i<3; i++) {
BT485_WRITE( BT485_DATA_CURSOR_COLOR, 0x0ff);
}
//
// Initialize the cursor RAM
//
// Set address pointer to base of ram.
//
BT485_WRITE( BT485_PALETTE_CURSOR_WRITE_ADDR, 0);
//
// Plane 0 = 0
//
for ( index=0; index < (BT485_CURSOR_NUMBER_OF_BYTES/2); index++) {
BT485_WRITE( BT485_CURSOR_RAM_ARRAY_DATA, 0L );
}
//
// Plane 1 = 1
//
for (index=0; index < (BT485_CURSOR_NUMBER_OF_BYTES /2); index++) {
BT485_WRITE( BT485_CURSOR_RAM_ARRAY_DATA, 1L);
}
//
// Initialize cursor positon register to 0, i.e. cursor off.
//
BT485_WRITE (BT485_CURSOR_X_LOW, 0);
BT485_WRITE (BT485_CURSOR_X_HIGH, 0);
BT485_WRITE (BT485_CURSOR_Y_LOW, 0);
BT485_WRITE (BT485_CURSOR_Y_HIGH, 0);
//
// Set the hardware cursor width, height, column, and row values.
//
hwDeviceExtension->CursorWidth = BT485_CURSOR_WIDTH;
hwDeviceExtension->CursorHeight = BT485_CURSOR_HEIGHT;
hwDeviceExtension->CursorColumn = 0;
hwDeviceExtension->CursorRow = 0;
//
// Set the cursor offsets
//
hwDeviceExtension->CursorXOrigin = 32;
hwDeviceExtension->CursorYOrigin = 32;
//
// Set the device extension copy of the hardware cursor ram memory.
//
for (index = 0; index < BT485_CURSOR_NUMBER_OF_BYTES; index++) {
hwDeviceExtension->CursorPixels[index] = 0x00ff;
}
return (NO_ERROR);
}
//
// Do a complete initialization of the Brooktree 463 RAMDAC. This
// includes initializing its registers, window tag table, cursor
// colors, and a color map for use by direct color.
//
VP_STATUS
Init_bt463(
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
ULONG i;
// The following table will be loaded into the RAMDAC. It will define
// the interpretation of a 32-bit pixel, based on a window id, which
// is stored in the high 4-bits of the pixel.
static Bt463_Wid_Cell wids[BT463_WINDOW_TAG_COUNT] = {
// Window id values to load
// Low Mid High
// 0-7 8-15 16-23
{ 0x00, 0xe1, 0x81, 0}, /* 0: 24-plane truecolor overlay */
{ 0x08, 0xe3, 0x01, 0}, /* 1: 8-plane cmap 0 buffer 1 overlay */
{ 0x00, 0xe3, 0x01, 0}, /* 2: 8-plane cmap 0 buffer 2 overlay */
{ 0x00, 0xe1, 0x01, 0}, /* 3: 24-plane cmap 0 overlay */
{ 0x10, 0xe3, 0x21, 0}, /* 4: 8-plane cmap 1 buffer 0 overlay */
{ 0x08, 0xe3, 0x21, 0}, /* 5: 8-plane cmap 1 buffer 1 overlay */
{ 0x00, 0xe3, 0x21, 0}, /* 6: 8-plane cmap 1 buffer 2 overlay */
{ 0x00, 0xe1, 0x21, 0}, /* 7: 24-plane cmap 1 overlay */
{ 0x84, 0xe0, 0x01, 0}, /* 8: 12-plane cmap 0 buffer 0 overlay */
{ 0x80, 0xe0, 0x01, 0}, /* 9: 12-plane cmap 0 buffer 1 overlay */
{ 0x84, 0xe0, 0x21, 0}, /* a: 12-plane cmap 1 buffer 0 overlay */
{ 0x80, 0xe0, 0x21, 0}, /* b: 12-plane cmap 1 buffer 1 overlay */
{ 0x00, 0xe1, 0x81, 0}, /* c: 24-plane truecolor overlay */
{ 0x00, 0x01, 0x80, 0}, /* d */
{ 0x00, 0x00, 0x00, 0}, /* e: cursor 0 color */
{ 0xff, 0xff, 0xff, 0}, /* f: cursor 1 color */
};
// "Blank" must be set while loading window tags.
TGA_WRITE (VIDEO_VALID, 0x03); // Enable video timing, no cursor, set blank
// Command Register values are from the pre-existing ARC firmware or Unix/VMS
// drivers. Each command register is 8-bits, please refer to the
// Brooktree spec for the definition of each bit (0 or 1).
BT463_LOAD_ADDRESS (BT463_COMMAND_REG_0); // Blink rate and multiplex select
BT463_WRITE (BT463_CONTROL_REGS, 0x48); // (note: firmware set 0x40)
BT463_LOAD_ADDRESS (BT463_COMMAND_REG_1); // 14 window tags (+2 for cursor colors)
BT463_WRITE (BT463_CONTROL_REGS, 0x48); // Overlays access colormap
// (note: firmware set 0x08)
BT463_LOAD_ADDRESS (BT463_COMMAND_REG_2);
BT463_WRITE (BT463_CONTROL_REGS, 0x40); // Sync enable
// All bit planes can access the RAMDAC colormap.
BT463_LOAD_ADDRESS (BT463_READ_MASK_P0_P7);
BT463_WRITE (BT463_CONTROL_REGS, 0xFF);
BT463_LOAD_ADDRESS (BT463_READ_MASK_P8_P15);
BT463_WRITE (BT463_CONTROL_REGS, 0xFF);
BT463_LOAD_ADDRESS (BT463_READ_MASK_P16_P23);
BT463_WRITE (BT463_CONTROL_REGS, 0xFF);
BT463_LOAD_ADDRESS (BT463_READ_MASK_P24_P27);
BT463_WRITE (BT463_CONTROL_REGS, 0x0F);
// Do not blink any of the bit planes.
BT463_LOAD_ADDRESS (BT463_BLINK_MASK_P0_P7);
BT463_WRITE (BT463_CONTROL_REGS, 0x00);
BT463_LOAD_ADDRESS (BT463_BLINK_MASK_P8_P15);
BT463_WRITE (BT463_CONTROL_REGS, 0x00);
BT463_LOAD_ADDRESS (BT463_BLINK_MASK_P16_P23);
BT463_WRITE (BT463_CONTROL_REGS, 0x00);
BT463_LOAD_ADDRESS (BT463_BLINK_MASK_P24_P27);
BT463_WRITE (BT463_CONTROL_REGS, 0x00 );
// Initialize cursor colors. Only the first two are used (set to black
// and white). The second two must be initialized but are not used.
// Each color has a red, green,
// blue component. The BT463 uses autoincrement addressing.
BT463_LOAD_ADDRESS (BT463_CURSOR_COLOR0);
for (i=0; i<3; i++) {
BT463_WRITE( BT463_CONTROL_REGS, 0x00 );
}
for (i=0; i<3; i++) {
BT463_WRITE( BT463_CONTROL_REGS, 0xff );
}
for (i=0; i<3; i++) {
BT463_WRITE( BT463_CONTROL_REGS, 0xff );
}
for (i=0; i<3; i++) {
BT463_WRITE( BT463_CONTROL_REGS, 0xff );
}
// Load window tag table entries, initialize a color map for use by
// direct color.
bt463_load_wid (0, BT463_WINDOW_TAG_COUNT, wids, hwDeviceExtension);
bt463_init_color_map (hwDeviceExtension);
TGA_WRITE (VIDEO_VALID, 0x01); // Enable video timing, no blank, no cursor
return (NO_ERROR);
}
//
// Write the window tag table into the RAMDAC. These define the various
// possibilities for window type, a "type" specifying the interpretation
// of a 32-bit pixel (true color, or direct color (buffer 0 or 1)).
//
VP_STATUS
bt463_load_wid(
ULONG index, // first location in wid to load
ULONG count, // number of entries in wid to load
Bt463_Wid_Cell *data, // data to load into wid
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
USHORT data_i;
BT463_LOAD_ADDRESS (BT463_WINDOW_TYPE_TABLE);
for ( data_i = 0; data_i < 16; data_i++) {
BT463_WRITE (BT463_CONTROL_REGS, data[data_i].low_byte);
BT463_WRITE (BT463_CONTROL_REGS, data[data_i].middle_byte);
BT463_WRITE (BT463_CONTROL_REGS, data[data_i].high_byte);
}
return (NO_ERROR);
}
//
// Initialize color map in Bt463 (for supporting direct color).
//
VP_STATUS
bt463_init_color_map(
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
ULONG value, i;
/*
* Make 16 entries in the color table. These will be used by
* the 12-bit direct color format (4 bits each for R G and B).
* The 4-bit index will fetch the appropriate R G or B 8-bit value
* out of this color table. A higher index fetches a brighter intensity.
*/
BT463_LOAD_ADDRESS( BT463_LUT_BASE); /* Specify color map entry 0 */
value = 0; /* Start with black */
for (i=0; i<16; i++) {
BT463_WRITE( BT463_COLOR_MAP, value); /* Red */
BT463_WRITE( BT463_COLOR_MAP, value); /* Green */
BT463_WRITE( BT463_COLOR_MAP, value); /* Blue */
value += 17; /* More intensity */
if (value > 255) value = 255; /* Only 8 bits */
}
return (NO_ERROR);
}
//
// The ARC console firmware does not perform any initialization on
// other than the first TGA. This routine will initialize the specified
// adapter just as the firmware would.
// (Note: this code was taken directly from the firmware source, the
// names of the functions called changed for the NT equivalents.)
//
VP_STATUS
init_multihead_adapter(
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
PVOID RomAddress;
ULONG Temp;
ULONG Config;
VP_STATUS status = ERROR_INVALID_PARAMETER;
RomAddress = VideoPortGetDeviceBase(hwDeviceExtension,
hwDeviceExtension->PhysicalFrameAddress,
4,
hwDeviceExtension->InIoSpace);
if (RomAddress != NULL) {
status = NO_ERROR;
//
// Get the configuration value from the first longword in Alternate
// ROM Space.
//
Temp = VideoPortReadRegisterUlong((PULONG) RomAddress);
VideoPortFreeDeviceBase(hwDeviceExtension, RomAddress);
VideoDebugPrint((0,"\n\t***tga: ALT ROM value is %x\n", Temp));
Config = (Temp >> 12) & 0x0F;
//
// Wait for not busy BEFORE writing Deep register
//
while ( (VideoPortReadRegisterUlong((PULONG)(
hwDeviceExtension->RegisterSpace +
COMMAND_STATUS)) & 1) == 1);
#define TGA_8PLANE 0
#define TGA_24PLANE 1
#define TGA_24PLANE_Z_BUF 3
switch (Config) {
case TGA_8PLANE:
TGA_WRITE (DEEP, 0x00014000);
// Wait for not busy AFTER writing Deep reg.
while ( (VideoPortReadRegisterUlong ((PULONG)(
hwDeviceExtension->RegisterSpace +
COMMAND_STATUS)) & 1) == 1);
TGA_WRITE (RASTER_OP, 0x0003); // Src->Dst, 8bpp
TGA_WRITE (MODE, 0x00002000); // Simple mode, 8bpp
break;
case TGA_24PLANE:
TGA_WRITE (DEEP, 0x0001440D);
// Wait for not busy AFTER writing Deep reg.
while ( (VideoPortReadRegisterUlong ((PULONG)(
hwDeviceExtension->RegisterSpace +
COMMAND_STATUS)) & 1) == 1);
TGA_WRITE (RASTER_OP, 0x0303); // Src->Dst, 32bpp
TGA_WRITE (MODE, 0x00002300); // Simple mode, 32bpp
break;
case TGA_24PLANE_Z_BUF:
TGA_WRITE (DEEP, 0x0001441D);
// Wait for not busy AFTER writing Deep reg.
while ( (VideoPortReadRegisterUlong ((PULONG)(
hwDeviceExtension->RegisterSpace +
COMMAND_STATUS)) & 1) == 1);
TGA_WRITE (RASTER_OP, 0x0303); // Src->Dst, 32bpp
TGA_WRITE (MODE, 0x00002300); // Simple mode, 32bpp
break;
default:
VideoDebugPrint((0,"\n\t***tga: additional adapter unrecognized type\n\n"));
return (ERROR_DEV_NOT_EXIST);
}
TGA_WRITE (PLANE_MASK, 0xFFFFFFFF);
TGA_WRITE (PERS_PIXEL_MASK, 0xFFFFFFFF);
TGA_WRITE (BLK_COLOR_R0, 0x12345678);
TGA_WRITE (BLK_COLOR_R1, 0x12345678);
#define TGA_HORZ_640_X_480_60HZ 0x018608A0
#define TGA_VERT_640_X_480_60HZ 0x084251E0
TGA_WRITE (H_CONT, TGA_HORZ_640_X_480_60HZ);
TGA_WRITE (V_CONT, TGA_VERT_640_X_480_60HZ);
TGA_WRITE (VIDEO_VALID, 0x01);
}
return (status);
}
//
// Set the position of the BT485 cursor.
//
void
bt485_cursor_position (
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
USHORT x,y;
x = hwDeviceExtension->CursorColumn +
hwDeviceExtension->CursorXOrigin;
y = hwDeviceExtension->CursorRow +
hwDeviceExtension->CursorYOrigin;
// Tell the interrupt service routine that it can't touch the RAMDAC
// right now.
hwDeviceExtension->RamdacBusy = TRUE;
BT485_WRITE(BT485_CURSOR_X_LOW, ( (x) & 0x00ff ) );
BT485_WRITE(BT485_CURSOR_X_HIGH, ( ( (x) & 0xff00 ) >> 8 ) );
BT485_WRITE(BT485_CURSOR_Y_LOW, ( (y) & 0x00ff ) );
BT485_WRITE(BT485_CURSOR_Y_HIGH, ( ( (y) & 0xff00 ) >> 8 ) );
hwDeviceExtension->RamdacBusy = FALSE;
hwDeviceExtension->RamdacBusyLogged = FALSE;
}
//
// Load a new cursor pattern into the BT485 RAMDAC
//
void
bt485_cursor_pattern (
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
USHORT index;
hwDeviceExtension->RamdacBusy = TRUE;
//
// Set the cursor ram address pointer to location 0
//
BT485_WRITE (BT485_PALETTE_CURSOR_WRITE_ADDR, 0);
//
// Update both cursor planes
//
for (index = 0; index < BT485_CURSOR_NUMBER_OF_BYTES; index++) {
BT485_WRITE( BT485_CURSOR_RAM_ARRAY_DATA,
(hwDeviceExtension->CursorPixels[index]));
hwDeviceExtension->RamdacBusy = FALSE;
hwDeviceExtension->RamdacBusyLogged = FALSE;
}
}
//
// Disable the BT485 cursor.
//
void
bt485_cursor_disable (
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
USHORT index;
hwDeviceExtension->RamdacBusy = TRUE;
// Enable the PORTSEL pin, set cursor disabled
BT485_WRITE(BT485_CMD_REG_2, 0x20);
hwDeviceExtension->RamdacBusy = FALSE;
hwDeviceExtension->RamdacBusyLogged = FALSE;
}
//
// Enable the BT485 cursor.
//
void
bt485_cursor_enable (
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
hwDeviceExtension->RamdacBusy = TRUE;
// Enable the PORTSEL pin, enable two-color cursor
BT485_WRITE(BT485_CMD_REG_2, 0x22);
hwDeviceExtension->RamdacBusy = FALSE;
hwDeviceExtension->RamdacBusyLogged = FALSE;
}
//
// Update some number of contiguous entries in the BT485 colormap.
//
void
bt485_colormap_update (
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CLUT ClutBuffer
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
USHORT i;
hwDeviceExtension->RamdacBusy = TRUE;
// Each entry is 8 bits each of Red, Green, and Blue.
BT485_WRITE( BT485_PALETTE_CURSOR_WRITE_ADDR, ClutBuffer->FirstEntry);
for (i=0; i < (ULONG)(ClutBuffer->NumEntries); i++) {
BT485_WRITE( BT485_COLOR_PALETTE_DATA,
(ULONG) (ClutBuffer->LookupTable[i].RgbArray.Red));
BT485_WRITE( BT485_COLOR_PALETTE_DATA,
(ULONG) (ClutBuffer->LookupTable[i].RgbArray.Green));
BT485_WRITE( BT485_COLOR_PALETTE_DATA,
(ULONG) (ClutBuffer->LookupTable[i].RgbArray.Blue));
}
hwDeviceExtension->RamdacBusy = FALSE;
hwDeviceExtension->RamdacBusyLogged = FALSE;
}
//
// Update some number of contiguous entries in the BT463 colormap.
//
void
bt463_colormap_update (
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CLUT ClutBuffer
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
USHORT i;
hwDeviceExtension->RamdacBusy = TRUE;
BT463_LOAD_ADDRESS( ClutBuffer->FirstEntry);
for (i=0; i < (ULONG)(ClutBuffer->NumEntries); i++) {
BT463_WRITE( BT463_COLOR_MAP,
(ULONG) (ClutBuffer->LookupTable[i].RgbArray.Red));
BT463_WRITE( BT463_COLOR_MAP,
(ULONG) (ClutBuffer->LookupTable[i].RgbArray.Green));
BT463_WRITE( BT463_COLOR_MAP,
(ULONG) (ClutBuffer->LookupTable[i].RgbArray.Blue));
}
hwDeviceExtension->RamdacBusy = FALSE;
hwDeviceExtension->RamdacBusyLogged = FALSE;
}
//
// Update some number of contiguous entries in the IBM 561 colormap.
//
void
ibm561_colormap_update (
PHW_DEVICE_EXTENSION HwDeviceExtension,
PVIDEO_CLUT ClutBuffer
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
USHORT i;
// This tells the interrupt service routine we are in the middle of
// accessing the RAMDAC.
hwDeviceExtension->RamdacBusy = TRUE;
// Set the address of the first color that will be updated. Use
// the same routine used by the "common code" for access
// to the IBM 561.
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info,
TGA_RAMDAC_561_ADDR_LOW,
(TGA_RAMDAC_561_COLOR_LOOKUP_TABLE | ClutBuffer->FirstEntry));
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info,
TGA_RAMDAC_561_ADDR_HIGH,
(TGA_RAMDAC_561_COLOR_LOOKUP_TABLE | ClutBuffer->FirstEntry) >> 8);
for (i=0; i < (ULONG)(ClutBuffer->NumEntries); i++) {
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info,
TGA_RAMDAC_561_CMD_CMAP,
(ULONG) (ClutBuffer->LookupTable[i].RgbArray.Red));
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info,
TGA_RAMDAC_561_CMD_CMAP,
(ULONG) (ClutBuffer->LookupTable[i].RgbArray.Green));
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info,
TGA_RAMDAC_561_CMD_CMAP,
(ULONG) (ClutBuffer->LookupTable[i].RgbArray.Blue));
}
hwDeviceExtension->RamdacBusy = FALSE;
hwDeviceExtension->RamdacBusyLogged = FALSE;
}
//
// Position the IBM 561 RAMDAC hardware cursor to the specified
// column/row position.
//
void
ibm561_cursor_position (
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_ADDR_LOW,
TGA_RAMDAC_561_CURSOR_X_LOW);
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_ADDR_HIGH,
(TGA_RAMDAC_561_CURSOR_X_LOW >> 8));
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_REGS,
hwDeviceExtension->CursorColumn );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_REGS,
hwDeviceExtension->CursorColumn >> 8 );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_REGS,
hwDeviceExtension->CursorRow );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_REGS,
hwDeviceExtension->CursorRow >> 8 );
}
//
// Load a previously generated cursor pattern into the IBM 561 RAMDAC.
// (1024 bytes). Disable the cursor while loading in the new pattern.
//
void
ibm561_cursor_pattern (
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
ULONG j;
PUCHAR cbp = hwDeviceExtension->CursorPixels;
UCHAR data;
hwDeviceExtension->RamdacBusy = TRUE;
ibm561_cursor_disable( hwDeviceExtension );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_ADDR_LOW,
TGA_RAMDAC_561_CURSOR_PIXMAP );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_ADDR_HIGH,
(TGA_RAMDAC_561_CURSOR_PIXMAP >> 8));
for ( j = 0; j < 1024; j++ ) {
data = *cbp++;
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_CURS_PIX, data );
}
ibm561_cursor_enable( hwDeviceExtension );
hwDeviceExtension->RamdacBusy = FALSE;
hwDeviceExtension->RamdacBusyLogged = FALSE;
}
//
// Enable the IBM 561 hardware cursor to appear on the screen.
//
void
ibm561_cursor_enable (
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_ADDR_LOW,
TGA_RAMDAC_561_CURSOR_CTRL_REG);
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_ADDR_HIGH,
(TGA_RAMDAC_561_CURSOR_CTRL_REG >> 8));
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_REGS, 1);
}
//
// Disable the IBM 561 hardware cursor from appearing on the screen.
//
void
ibm561_cursor_disable (
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_ADDR_LOW,
TGA_RAMDAC_561_CURSOR_CTRL_REG);
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_ADDR_HIGH,
(TGA_RAMDAC_561_CURSOR_CTRL_REG >> 8));
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_REGS, 0);
}
//
// Initialize the IBM 561 RAMDAC using the "common code" routines.
//
void
Init_ibm561 (
PHW_DEVICE_EXTENSION HwDeviceExtension
)
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
// Allocate and initialize the 2 data structures required by
// the common code. Store pointers to them in the hardware extension.
alloc_tga_info(hwDeviceExtension);
load_common_data(hwDeviceExtension);
// Do the basic init of the command registers.
// (Note that TGA_INIT is a routine, not a macro, in tga_common.c)
TGA_INIT(
hwDeviceExtension->a_tga_info
);
tga_ibm561_init(
hwDeviceExtension->a_tga_info,
hwDeviceExtension->a_ramdac_info
);
// Load the window ID definitions that will identify a pixel format.
tga_ibm561_clean_window_tag(
hwDeviceExtension->a_tga_info
);
// Load the colormap entries required by 12-bit direct color.
tga_ibm561_init_color_map(
hwDeviceExtension->a_tga_info,
hwDeviceExtension->a_ramdac_info
);
// Initialize the cursor colors (there are 3 cursor colors in the
// IBM 561, of which we will use only 2).
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_ADDR_LOW,
TGA_RAMDAC_561_CURSOR_LOOKUP_TABLE);
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_ADDR_HIGH,
(TGA_RAMDAC_561_CURSOR_LOOKUP_TABLE >> 8));
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_CURS_LUT, 0x0 );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_CURS_LUT, 0x0 );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_CURS_LUT, 0x0 );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_CURS_LUT, 0x0 );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_CURS_LUT, 0xFF );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_CURS_LUT, 0x0 );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_CURS_LUT, 0xFF );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_CURS_LUT, 0xFF );
TGA_IBM561_WRITE( hwDeviceExtension->a_tga_info, TGA_RAMDAC_561_CMD_CURS_LUT, 0xFF );
// The startup state is to have no cursor appear on the screen.
// The display driver will explicitly request a cursor pattern
// to be loaded.
ibm561_cursor_disable( hwDeviceExtension );
}
//#define COMPUTE_IBM_CURSOR 1
#ifdef COMPUTE_IBM_CURSOR
//
// Merge a cursor pattern that is represented by a buffer of 64x64 AND bits
// and a buffer of 64x64 OR bits. The result is a single buffer with
// alternating AND and OR bits. This is accomplished by taking a
// an 8-bit value and "widening" it to 16-bits, by inserting a 0 bit
// between each of the 8 bits. The "widened" image and mask words are then
// just "OR"ed together.
//
void
format_ibm561_cursor_data(bp_image, bp_mask, wp_pattern)
PUCHAR bp_image;
PUCHAR bp_mask;
PUSHORT wp_pattern;
{
UCHAR source;
USHORT target_image;
USHORT target_mask;
ULONG i,j;
USHORT temp;
// There are 512 AND bytes and 512 OR bytes to process
// The AND bits must be complemented. Colors 1 (black) and 3 (white)
// will be used.
for (j=0; j < 512; j++) {
target_image = 0; // Build a 16-bit value here
source = ~(*bp_image++); // Get the next 8-bits of AND
//#define EXPAND_BY_ASSEMBLER 1
#ifdef EXPAND_BY_ASSEMBLER
target_image = expand(source);
#else
for ( i=0; i<8; i++) {
if (source & 0x80) // Take next highest source bit
target_image |= 1; // Place in the 16-bit value
if (i<7)
target_image <<= 2; // Insert 0 and make room for next bit
source <<= 1; // Position the next source bit
}
#endif
target_mask = 0; // Do the same for the next OR byte
source = *bp_mask++;
#ifdef EXPAND_BY_ASSEMBLER
target_mask = expand(source);
#else
for ( i=0; i<8; i++) {
if (source & 0x80) // Take next highest source bit
target_mask |= 1;
if (i<7)
target_mask <<= 2;
source <<= 1;
}
#endif
// Combine the two 16-bit values into one, then swap the bytes
// since the upper byte currently has the lower order cursor pixels.
// The pattern will be loaded into the RAMDAC byte-by-byte in
// ascending pixel order.
temp = target_image | (target_mask << 1);
*wp_pattern++ = (temp >> 8) + (temp << 8);
} // End of For loop
}
#endif
//
// The following table represents load bytes for an IBM561 hardware cursor.
// Each byte represents 4 bits of AND and 4 bits of OR. This
// table was generated by gencursor.cpp.
//
#ifndef COMPUTE_IBM_CURSOR
UCHAR ibm561_cursor_lookup[256] =
{
0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15, 0x40, 0x41,
0x44, 0x45, 0x50, 0x51, 0x54, 0x55, 0x2, 0x3, 0x6, 0x7,
0x12, 0x13, 0x16, 0x17, 0x42, 0x43, 0x46, 0x47, 0x52, 0x53,
0x56, 0x57, 0x8, 0x9, 0xc, 0xd, 0x18, 0x19, 0x1c, 0x1d,
0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d, 0xa, 0xb,
0xe, 0xf, 0x1a, 0x1b, 0x1e, 0x1f, 0x4a, 0x4b, 0x4e, 0x4f,
0x5a, 0x5b, 0x5e, 0x5f, 0x20, 0x21, 0x24, 0x25, 0x30, 0x31,
0x34, 0x35, 0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75,
0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37, 0x62, 0x63,
0x66, 0x67, 0x72, 0x73, 0x76, 0x77, 0x28, 0x29, 0x2c, 0x2d,
0x38, 0x39, 0x3c, 0x3d, 0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79,
0x7c, 0x7d, 0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f,
0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f, 0x80, 0x81,
0x84, 0x85, 0x90, 0x91, 0x94, 0x95, 0xc0, 0xc1, 0xc4, 0xc5,
0xd0, 0xd1, 0xd4, 0xd5, 0x82, 0x83, 0x86, 0x87, 0x92, 0x93,
0x96, 0x97, 0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7,
0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d, 0xc8, 0xc9,
0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd, 0x8a, 0x8b, 0x8e, 0x8f,
0x9a, 0x9b, 0x9e, 0x9f, 0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb,
0xde, 0xdf, 0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5,
0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5, 0xa2, 0xa3,
0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7, 0xe2, 0xe3, 0xe6, 0xe7,
0xf2, 0xf3, 0xf6, 0xf7, 0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9,
0xbc, 0xbd, 0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd,
0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, 0xea, 0xeb,
0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff
};
//
// Merge a cursor pattern that is represented by a buffer of 64x64 AND bits
// and a buffer of 64x64 OR bits. The result is a single buffer with
// alternating AND and OR bits. This is accomplished by successively taking
// a 4-bit nibble from each buffer, forming an 8-bit index. This index is
// then used to retrieve an 8-bit byte which has the proper representation
// of those OR and AND bytes for loading into the RAMDAC.
//
void
format_ibm561_cursor_data(bp_image, bp_mask, wp_pattern)
PUCHAR bp_image;
PUCHAR bp_mask;
PUSHORT wp_pattern;
{
UCHAR and, or;
UCHAR and_nibble, or_nibble;
ULONG j, index;
PUCHAR target;
target = (PUCHAR) wp_pattern; // Compatibility with other implementation
// of this routine
// There are 512 AND bytes and 512 OR bytes to process
// The AND bits must be complemented. Colors 1 (black) and 3 (white)
// will be used.
for (j=0; j < 512; j++) {
and = ~(*bp_image++); // Get the next 8-bits of AND
or = *bp_mask++; // Get the next 8-bits of OR
and_nibble = (and >> 4) & 0xF; // Construct an index
or_nibble = or & 0xF0;
index = ((or_nibble | and_nibble) & 0xFF);
*target++ = ibm561_cursor_lookup[index];
and_nibble = (and & 0xF);
or_nibble = (or & 0xF);
index = (((or_nibble << 4) | and_nibble) & 0xFF);
*target++ = ibm561_cursor_lookup[index];
}
}
#endif
//
// This routine is called by the IBM 561 RAMDAC common code. It is also
// called by routines in tga.c which access this RAMDAC, so that there is a
// common routine for writing a byte to the RAMDAC.
//
void
TGA_IBM561_WRITE(tga_info_t *tgap, unsigned int control, unsigned int value) {
PHW_DEVICE_EXTENSION hwDeviceExtension;
hwDeviceExtension = (PHW_DEVICE_EXTENSION) tgap->auxstruc;
VideoPortWriteRegisterUlong((PULONG)((ULONG)hwDeviceExtension->memory_space_base +
0x80000 + 0xE000 + ((control >> 2) << 8)),
value & 0xFF);
}