Copyright ©1995 by NeXT Computer, Inc.  All Rights Reserved.

IOSVGADisplay



Inherits From: IODisplay : IODirectDevice : IODevice : Object
Conforms To: IOScreenEvents
Declared In: driverkit/IOSVGADisplay.h



Class Description

IOSVGADisplay is an abstract class for managing Super VGA (SVGA) video displays. It provides most of the functionality needed by SVGA drivers. Functionality that varies from card to card must be provided by subclasses of IOSVGADisplay. In particular, different SVGA cards have different ways of setting the current plane and segment and of entering and exiting SVGA modes.

IOSVGADisplay supports 2-bit grayscale modes; it doesn't currently support 8-bit gray or color modes. To provide 2-bit grayscale support, IOSVGADisplay uses 2 of the 8 planes associated with screen pixels. The IOSVGADisplay subclass maps the values in the two planes into four entries in the hardware color palette, as described in enterSVGAMode.

Because the VGA specification allows only 64KB of screen memory to be mapped (from 0xa0000 to 0xbffff), the screen is split up into segments of 64KB or less. The display system tells the driver which segment and plane to map into the 64KB of available space. For a screen that's 768 pixels high by 1024 wide, the first 64KB segment (segment 0) consists of the top 512 rows of pixels. The next segment consists of the bottom 256 rows.

To write an SVGA display driver, you need to write two software modules:

A subclass of IOSVGADisplay
Five functions to be loaded into a user-level PostScript driver

How to write these modules is described below. See the IODisplay class description for additional notes on implementing a display driver.



Implementing a Subclass

In your subclass of IOSVGADisplay, you must implement the following methods:

initFromDeviceDescription:
enterSVGAMode
revertToVGAMode
savePlaneAndSegmentSettings
restorePlaneAndSegmentSettings
setReadPlane:
setReadSegment:
setWritePlane:
setWriteSegment:

If the hardware supports setting brightness, you should also implement setBrightness:token:.



Writing Functions for the PostScript Driver

Besides implementing a subclass of IOSVGADisplay, you also need to write five C functions. One, named IOSetSVGAFunctions(), should fill in the structure it's passed with pointers to the other four functions. It should return zero on success. The other four functions correspond exactly to four methods that you must also implement; each function should have exactly the same code as its corresponding method.

Function Prototype Corresponding Method
void setReadPlane(unsigned char num) setReadPlane:
void setReadSegment(unsigned char num) setReadSegment:
void setWritePlane(unsigned char num) setWritePlane:
void setWriteSegment(unsigned char num) setWriteSegment:

Here's an example of how to implement IOSetSVGAFunctions().

void SetReadPlane(unsigned char num) . . .
void SetReadSegment(unsigned char num) . . .
void SetWriteSegment(unsigned char num) . . .
void SetWritePlane(unsigned char num) . . .

int IOSetSVGAFunctions(IOSVGAFunctions *funcs)
{
funcs->setReadSegment = SetReadSegment;
funcs->setWriteSegment = SetWriteSegment;
funcs->setReadPlane = SetReadPlane;
funcs->setWritePlane = SetWritePlane;

return 0;
}

Note:  The functions must contain only C code; Objective C code won't work.

The five functions should be defined in a user-level executable, to be loaded into the SVGA PostScript driver at run time. You need to inform the PostScript driver of the executable's location using the configuration key "SVGA PostScript Driver Extension". You also need to specify the SVGA PostScript driver (/usr/lib/NextStep/Displays/SVGA_psdrvr) with the "PostScript Driver" key. For example, the lines below specify that the SVGA PostScript driver should load the executable named TsengLabsET4000_psdrvr from the driver's configuration bundle.

"SVGA PostScript Driver Extension" = "TsengLabsET4000_psdrvr";
"PostScript Driver" = "/usr/lib/NextStep/Displays/SVGA_psdrvr";

Note:  See the IODisplay class description for other configuration keys that must be specified.



Instance Variables

None declared in this class.



Method Types

Creating and initializing IOSVGADisplays
+ probe:
initFromDeviceDescription:
Getting and setting parameters getIntValues:forParameter:count:
setIntValues:forParameter:count:
Handling the cursor hideCursor:
moveCursor:frame:token:
showCursor:frame:token:
Setting screen brightness setBrightness:token:
Mapping memory mapFrameBufferAtPhysicalAddress:length:
Choosing video modes enterSVGAMode
revertToVGAMode
selectMode:count:
selectMode:count:valid:
Setting planes and segments savePlaneAndSegmentSettings
restorePlaneAndSegmentSettings
setReadPlane:
setReadSegment:
setWritePlane:
setWriteSegment:



Class Methods

probe:
+ (BOOL)probe:deviceDescription

Without checking for the presence of hardware, allocates and initializes an IOSVGADisplay. You shouldn't reimplement this method.

If initialization (done with initFromDeviceDescription:) is unsuccessful, this method returns NO. Otherwise, this method sets the device kind to "frame buffer", invokes registerDevice, and returns YES.



Instance Methods

enterSVGAMode
(void)enterSVGAMode

Implemented by subclasses to put the display into SVGA mode. This method is invoked by the system when appropriate, such as when the window server starts running. This method should set up all the registers necessary for the selected mode, set the color palette, and clear the screen.

You should set the color palette to contain values for the four supported shades of gray in the first four entries; the rest of the entries should be zeroed out. NeXT drivers currently use the palette values shown in the following table.

Color Palette Index Value
Black 0 0
Dark gray 1 0x26
Light gray 2 0x34
White 3 0x3F


See also:  revertToVGAMode



getIntValues:forParameter:count:
(IOReturn)getIntValues:(unsigned int *)parameterArray
forParameter:(IOParameterName)parameterName
count:(unsigned int *)count

Handles NeXT-internal parameters specific to IOSVGADisplays; forwards the handling of all other parameters to super.



hideCursor:
hideCursor:(int)token

Implements this method, as described in the IOScreenEvents protocol specification. You should never need to invoke or implement this method.



initFromDeviceDescription:
initFromDeviceDescription:deviceDescription

Invokes initFromDeviceDescription: on super. If successful, sets the unit number and the name (to "SVGADisplay" followed by the unit number). Frees itself if initialization was unsuccessful.

Subclasses must implement this method so that it performs all initialization necessary to set up the device and the driver. After invoking initFromDeviceDescription: on super, this method should determine its mode (invoking selectMode:count: or selectMode:count:valid:, if necessary) and set [self displayMode] to the IODisplayInfo appropriate for the mode. The driver should finish by invoking mapFrameBufferAtPhysicalAddress:length: and setting the IODisplayInfo's frameBuffer field to the value returned.

If possible, this method should check the hardware to see if it matches the IOConfigTable. If the hardware doesn't match, the driver should do what it can to ensure that the display is still usable.

See also:  IODisplay class description ("IODisplayInfo")



mapFrameBufferAtPhysicalAddress:length:
(vm_address_t)mapFrameBufferAtPhysicalAddress:(unsigned int)address length:(int)numBytes

Maps the physical memory for this instance into virtual memory for use by the device driver. If address is 0, this method maps the physical memory corresponding to local memory range 0, and numBytes is ignored. If address is not 0, the reserved resources are overridden--address is used as the physical memory address and numBytes is used as the length. The mapped memory range is cached as IO_WriteThrough.

Note:  When overriding reserved resources, you can't map memory outside of the memory range reserved for the device. However, you can map a subset of the memory range.

You should invoke this method during initialization.

Returns the virtual address that corresponds to address. If the memory mapping failed, this method logs an error message and returns NULL.



moveCursor:frame:token:
moveCursor:(Point *)cursorLoc
frame:(int)frame
token:(int)token

Implements this method, as described by the IOScreenEvents protocol. You should never need to invoke or implement this method.



restorePlaneAndSegmentSettings
(void)restorePlaneAndSegmentSettings

Implemented by subclasses to restore the plane and segment settings to the saved values. This method is invoked by IOSVGADisplay's cursor handling methods. The cursor handling methods invoke savePlaneAndSegmentSettings, do whatever is necessary to update the cursor, and then invoke restorePlaneAndSegmentSettings to restore the display's state.

Here's an example of implementing this method by saving the current settings into subclass-defined instance variables.

- (void)restorePlaneAndSegmentSettings
{
IOWriteRegister(EIDR_SEQ_ADDR, SEQ_AT_MPK, writePlane);
IOWriteRegister(EIDR_GCR_ADDR, GCR_AT_READ_MAPS, readPlane);
outb(EIDR_GCR_SEGS, readSegment);
outb(EIDR_GCR_SEGS, writeSegment);
}


revertToVGAMode
(void)revertToVGAMode

Implemented by subclasses to remove the display from whatever advanced mode it's in and enter a mode in which it can be used as a standard VGA device. Implementing this method usually consists of setting registers that aren't used by VGA.



savePlaneAndSegmentSettings
(void)savePlaneAndSegmentSettings

Implemented by subclasses to save the current plane and segment settings. This method is invoked by IOSVGADisplay's cursor handling methods. The cursor handling methods invoke savePlaneAndSegmentSettings, do whatever is necessary to update the cursor, and then invoke restorePlaneAndSegmentSettings to restore the display's state.

Each invocation of savePlaneAndSegmentSettings is followed by exactly one invocation of restorePlaneAndSegmentSettings, with no intervening invocations of savePlaneAndSegmentSettings. In other words, the driver only has to remember one group of settings at a time.

Here's an example of implementing this method by saving the current settings into subclass-defined instance variables.

- (void)savePlaneAndSegmentSettings
{
writePlane = IOReadRegister(EIDR_SEQ_ADDR, SEQ_AT_MPK);
readPlane = IOReadRegister(EIDR_GCR_ADDR, GCR_AT_READ_MAPS);
readSegment = inb(EIDR_GCR_SEGS);
writeSegment = inb(EIDR_GCR_SEGS);
}


selectMode:count:
(int)selectMode:(const IODisplayInfo *)modeList count:(int)count

Invokes selectMode:count:valid:, specifying 0 for the last argument.



selectMode:count:valid:
(int)selectMode:(const IODisplayInfo *)modeList
count:(int)count
valid:(const BOOL *)isValid

Determines which IODisplayInfo in the driver-supplied modeList matches the value of the "Display Mode" key in the device's IOConfigTable. Drivers that support multiple advanced modes should invoke this method during initialization. When the driver receives a enterSVGAMode message, it should enter the mode selected by this method. If this method doesn't find a valid mode, the driver should determine a mode that will work.

The "Display Mode" key is a configuration key that can be used by drivers to support multiple modes--for example, 66 Hz and 72 Hz. IODisplayInfo is defined in the header file driverkit/displayDefs.h.

The modeList argument should contain an IODisplayInfo for each advanced mode the driver supports. The count argument should specify the number of IODisplayInfos in modeList. isValid should either be 0 (in which case it's ignored) or an array that corresponds to the modeList. If isValid[1] is NO, for example, then this method ignores the IODisplayInfo pointed to by modeList[1].

If this method finds a match, it returns the index of the matching IODisplayInfo in modeList. If the "Display Mode" key is missing or its value is improperly formatted, or if a corresponding IODisplayInfo isn't found, this method returns -1.

See the IODisplay class description for information on display modes and the IODisplayInfo type.



setBrightness:token:
setBrightness:(int)level token:(int)token

Checks whether level is between EV_SCREEN_MIN_BRIGHTNESS and EV_SCREEN_MAX_BRIGHTNESS (inclusive). If not, logs an error message. Subclasses that support brightness changes should override this method. A typical implementation has code like this:

/*  Color palette constants (gamma 2.2, for typical CRT displays) */
#define WHITE_PALETTE_VALUE 0x3F
#define LIGHT_GRAY_PALETTE_VALUE 0x34
#define DARK_GRAY_PALETTE_VALUE 0x26
#define BLACK_PALETTE_VALUE 0
.
.
.
unsigned char val;

val = EV_SCALE_BRIGHTNESS(level, WHITE_PALETTE_VALUE);
/* Write val to the hardware's color palette entry for white */

val = EV_SCALE_BRIGHTNESS(level, LIGHT_GRAY_PALETTE_VALUE);
/* Write val to the entry for light gray */

val = EV_SCALE_BRIGHTNESS(level, DARK_GRAY_PALETTE_VALUE);
/* Write val to the entry for dark gray */

val = EV_SCALE_BRIGHTNESS(level, BLACK_PALETTE_VALUE);
/* Write val to the entry for black */

Returns self.



setIntValues:forParameter:count:
(IOReturn)setIntValues:(unsigned int *)parameterArray
forParameter:(IOParameterName)parameterName
count:(unsigned int)count

Handles NeXT-internal parameters specific to IOSVGADisplays; forwards the handling of all other parameters to super.

See also:  setIntValues:forParameter:count: (IODevice)



setReadPlane:
(void)setReadPlane:(unsigned char)planeNum

Implemented by subclasses to set which of two planes the display subsystem will read from. Only one plane can be active at a time. Here's an example of implementing this method.

#define GRAPHICS_CONTROLLER_REGISTER_ADDRESS 0x03CE
#define SEGMENT_REGISTER_INDEX               0x09

- (void)setReadSegment: (unsigned char)segmentNum
{
IOWriteRegister(GRAPHICS_CONTROLLER_REGISTER_ADDRESS,
SEGMENT_REGISTER_INDEX,
(segmentNum << 4));
}

See also:  setWritePlane:



setReadSegment:
(void)setReadSegment:(unsigned char)segmentNum

Implemented by the subclass to set the 64KB segment the display subsystem will read from.

#define GRAPHICS_CONTROLLER_REGISTER_ADDRESS   0x03CE
#define PLANE_REGISTER_INDEX                   0x04
#define PROTECT_HIGH_REGISTER_BITS             0xFC

- (void)setReadPlane: (unsigned char)planeNum
{
IOReadModifyWriteRegister(GRAPHICS_CONTROLLER_REGISTER_ADDRESS,
PLANE_REGISTER_INDEX,
PROTECT_HIGH_REGISTER_BITS,
planeNum);
}

See also:  setWriteSegment:



setWritePlane:
(void)setWritePlane:(unsigned char)planeNum

Implemented by subclasses to set which of two planes the display subsystem will write to. Only one plane can be active at a time.

See also:  setReadPlane:



setWriteSegment:
(void)setWriteSegment:(unsigned char)segmentNum

Implemented by the subclass to set the 64KB segment the display subsystem will read from.

See also:  setReadSegment:



showCursor:frame:token:
showCursor:(Point *)cursorLoc
frame:(int)frame
token:(int)token

Implements this method, as described in the IOScreenEvents protocol specification. You should never need to invoke or implement this method.