How to add an (S)VGA driver to XFree86 : The Bank-Switching Functions
Previous: Setting Up The Build Information
Next: The Driver Itself

5. The Bank-Switching Functions

The normal VGA memory map is 64k starting at address 0xA0000. To access more than 64k of memory, SuperVGA chipsets implement ``bank switching'' - the high-order address bits are used to select the bank of memory in which operations will take place. The size and number of these banks varies, and will be spelled out in the chipset documentation. A chipset will have zero, one or two bank registers. Likely the ONLY case of zero bank registers is a generic VGA, and hence is not a concern.

Note that some of the newer chipsets (e.g. Trident 8900CL, Cirrus) allow for a linear mapping of the video memory. While using such a scheme would improve the performance of the server, it is not currently supported. Hence there is no way to use such features for a new chipset.

Most SVGA chipsets have two bank registers. This is the most desirable structure (if any banking structure can be called ``desirable''), because data can be moved from one area of the screen to another with a simple `mov' instruction. There are two forms of dual-banking - one where the two bank operations define a read-only bank and a write-only bank, and one with two read/write windows. With the first form, the entire SVGA memory window is used for both read a write operations, and the two bank registers determine which bank is actually used (e.g. ET3000, ET4000). With the second form, the SVGA memory window is split into two read/write banks, with each bank pointer being used to control one window. In this case, one window is used for read operations and the other for write operations (e.g. PVGA1/Western Digital, Cirrus).

A chipset that has a single bank register uses that one bank for both read and write access. This is problematic, because copying information from one part of the screen to another requires that the data be read in, stored, and then written out. Fortunately, the server is able to handle both one-bank and two-bank chipsets; the determination of behavior is defined by an entry in the driver data structure described below.

A driver requires that three assembly-language functions be written, in the file `sdc_bank.s'. These functions set the read bank - SDCSetRead(), the write bank - SDCSetWrite(), and set both banks - SDCSetReadWrite(). For a chipset with only one bank, all three will be declared as entry points to the same function (see the ``tvga8900'' driver for an example).

The functions are fairly simple - the bank number is passed to the function in register %al. The function will shift, bitmask, etc - whatever is required to put the bank number into the correct form - and then write it to the correct I/O port. For chipsets where the two banks are read-only HERE and write-only, the SetReadWrite() function will have to do this twice - once for each bank. For chipsets with two independent read/write windows, the SetReadWrite() function should use the same bank as the SetWrite() function.

A special note - these functions MUST be written in the macroized assembler format defined in the header file ``assyntax.h''. This will ensure that the correct assembler code will be generated, regardless of OS. This macroized format currently supports USL, GNU, and Intel assembler formats.

That's all there is to the banking functions. Usually the chipset reference will give examples of this code; if not, it is not difficult to figure out, especially using the other drivers as examples.


How to add an (S)VGA driver to XFree86 : The Bank-Switching Functions
Previous: Setting Up The Build Information
Next: The Driver Itself