]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/vga/notes.txt
abaco: cleanup, handle image/x-icon, don't use backspace as a hotkey, and remove...
[plan9front.git] / sys / src / cmd / aux / vga / notes.txt
1 The following is a sort of theory of operation for aux/vga and the
2 kernel vga drivers.
3
4 --- aux/vga and basic kernel drivers
5
6 Aux/vga consists of a number of modules each of which conforms to an
7 interface called a Ctlr.  The Ctlr provides functions snarf, options,
8 init, load, and dump, which are explained in more detail below.  Video
9 cards are internally represented as just a collection of Ctlrs.  When
10 we want to run one of the functions (snarf, etc.)  on the whole card,
11 we run it on each Ctlr piece in turn.
12
13 In the beginning of aux/vga, it was common for video cards to mix and
14 match different VGA controller chips, RAMDACs, clock generators, and
15 sometimes even hardware cursors.  The original use for vgadb was to
16 provide a recipe for how to deal with each card.  The ordering in the
17 ctlr sections was followed during initialization, so that if you said
18         ctlr
19                 0xC0076="Tseng Laboratories, Inc. 03/04/94 V8.00N"
20                 link=vga
21                 clock=ics2494a-324
22                 ctlr=et4000-w32p
23                 ramdac=stg1602-135
24 when aux/vga wanted to run, say, snarf on this card it would call the
25 snarf routines for the vga, ics2494a, et4000, and stg1602 Ctlrs, in
26 that order.  The special Ctlrs vga and ibm8514 take care of the
27 generic VGA register set and the extensions to that register set
28 introduced by the IBM 8514 chip.  Pretty much all graphics cards these
29 days still use the VGA register set with some extensions.  The only
30 exceptions currently in vgadb are the Ticket to Ride IV and the
31 Neomagic (both LCD cards).  The S3 line of chips tends to have the IBM
32 8514 extensions.
33
34 This "mix and match" diversity has settled down a bit, with one chip
35 now usually handling everything.  As a result, vgadb entries have
36 become a bit more formulaic, usually listing only the vga link, a
37 controller, and a hardware cursor.  For example:
38         ctlr
39                 0xC0039="CL-GD540"
40                 link=vga
41                 ctlr=clgd542x
42                 hwgc=clgd542xhwgc
43
44 On to the controller functions themselves.  The functions mentioned
45 earlier are supposed to do the following.
46
47 void snarf(Vga *vga, Ctlr *ctlr)
48         Read the ctlr's registers into memory, storing them
49         either in the vga structure (if there is an appropriate
50         place) or into a privately allocated structure, a pointer
51         to which can be stored in vga->private [sic]. 
52         [The use of vga->private rather than ctlr->private betrays
53         the fact that private data has only been added after we got
54         down to having cards with basically a single controller.]
55
56 void options(Vga *vga, Ctlr *ctlr)
57         This step prepares to edit the in-memory copy of the
58         registers to implement the mode given in vga->mode.
59         It's really the first half of init, and is often empty.
60         Basically, something goes here if you need to influence
61         one of the other init routines and can't depend on being
62         called before it.  For example, the virge Ctlr rounds
63         the pixel line width up to a multiple of 16 in its options routine.
64         This is necessary because the vga Ctlr uses the pixel line
65         width.  If we set it in virge.init, vga.init would already
66         have used the wrong value.
67
68 void init(Vga *vga, Ctlr *ctlr)
69         Edit the in-memory copy of the registers to implement
70         the mode given in vga->mode.
71
72 void load(Vga *vga, Ctlr *ctlr)
73         Write all the ctlr's registers, using the in-memory values.
74         This is the function actually used to switch modes.
75
76 void dump(Vga *vga, Ctlr *ctlr)
77         Print (to the Biobuf stdout) a description of all the
78         in-memory controller state.  This includes the in-memory
79         copy of the registers but often includes other calculated
80         state like the intended clock frequencies, etc.
81
82 Now we have enough framework to explain what aux/vga does.  It's
83 easiest to present it as a commented recipe.
84
85 1.  We sniff around in the BIOS memory looking for a match to
86 any of the strings given in vgadb.  (In the future, we intend also to
87 use the PCI configuration registers to identify cards.)
88
89 2.  Having identified the card and thus made the list of controller
90 structures, we snarf the registers and, if the -p flag was
91 given, dump them.
92
93 3.  If the -i or -l flag is given, aux/vga then locates the desired
94 mode in the vgadb and copies it into the vga structure.  It then does
95 any automatic frequency calculations if they need doing.  (See the
96 discussion of defaultclock in vgadb(6).)
97
98 For a good introduction to video modes, read Eric Raymond's XFree86
99 Video Timings HOWTO, which, although marked as obsolete for XFree86,
100 is still a good introduction to what's going on between the video card
101 and the monitor.
102 http://www.linuxdoc.org/HOWTO/XFree86-Video-Timings-HOWTO/
103
104 4.  Having copied the vgadb mode parameters into the vga structure,
105 aux/vga calls the options and then the init routines to twiddle the
106 in-memory registers appropriately.
107
108 5.  Now we are almost ready to switch video modes.  We dump the
109 registers to stdout if we're being verbose.
110
111 6.  We tell the kernel (via the "type" vga ctl message) what sort of
112 video card to look for.  Specifically, the kernel locates the named
113 kernel vga driver and runs its enable function.
114
115 7.  If we're using a frame buffer in direct-mapped linear mode (see
116 the section below), we express this intent with a "linear" vga ctl
117 message.  In response, the kernel calls the vga driver's linear
118 function.  This should map the video memory into the kernel's address
119 space.  Conventionally, it also creates a named memory segment for use
120 with segattach so that uesr-level programs can get at the video
121 memory.  If there is a separate memory-mapped i/o space, it too is
122 mapped and named.  These segments are only used for debugging,
123 specifically for debugging the hardware acceleration routines from
124 user space before putting them into the kernel.
125
126 8.  We tell the kernel the layout of video memory in a "size" ctl
127 message.  The arguments are the screen image resolution and the pixel
128 channel format string.
129
130 9.  Everything is set; we disable the video card, call the loads to
131 actally set the real registers, and reenable the card.
132
133 At this point there should be a reasonable picture on the screen.  It
134 will be of random memory contents and thus could be mostly garbage,
135 but there should be a distinct image on the screen rather than, say,
136 funny changing patterns due to having used an incorrect sync
137 frequency.
138
139 10.  We write "drawinit" into #v/vgactl, which will initialize the
140 screen and make console output from now on appear on the graphics
141 screen instead of being written to the CGA text video memory (as has
142 been happening).  This calls the kernel driver's drawinit function,
143 whose only job is to initialize hardware accelerated fills and scrolls
144 and hardware blanking if desired.
145
146 11.  We write "hwgc <hwgcname>" into #v/vgactl, which calls the enable
147 function on the named kernel hwgc driver.  (Plan 9 does not yet support
148 software graphics cursors.)
149
150 12.  We set the actual screen size with an "actualsize" ctl message.
151 The virtual screen size (which was used in the "size" message in step
152 8) controls how the video memory is laid out; the actual screen size
153 is how much fits on your monitor at a time.  Virtual screen size is
154 sometimes larger than actual screen size, either to implement panning
155 (which is really confusing and not recommended) or to round pixel
156 lines up to some boundary, as is done on the ViRGE and Matrox cards.
157 The only reason the kernel needs to know the actual screen size is to
158 make sure the mouse cursor stays on the actual screen.
159
160 13.  If we're being verbose, we dump the vga state again.
161
162 --- hardware acceleration and blanking
163
164 Hardware drawing acceleration is accomplished by calling the
165 kernel-driver-provided fill and scroll routines rather than
166 doing the memory operations ourselves.  For >8-bit pixel depths,
167 hardware acceleration is noticeably needed.  For typical Plan 9
168 applications, accelerating fill and scroll has been fast enough that we haven't
169 worried about doing anything else.  
170
171 The kernel driver's drawinit function should sniff the card
172 and decide whether it can use accelerated fill and scroll functions.
173 If so, it fills in the scr->fill and scr->scroll function pointers
174 with functions that implement the following:
175
176 int fill(VGAscr *scr, Rectangle r, ulong val);
177         Set every pixel in the given rectangle to val.
178         Val is a bit pattern already formatted for the screen's
179         pixel format (rather than being an RGBA quadruple).
180         Do not return until the operation has completed
181         (meaning video memory has been updated).
182         Usually this means a busy wait looping for a bit
183         in some status register.  Although slighty inefficient,
184         the net effect is still much faster than doing the work 
185         ourselves.  It's a good idea to break out of the busy
186         loop after a large number of iterations, so that
187         if the driver or the card gets confused we don't
188         lock up the system waiting for the bit.  Look at
189         any of the accelerated drivers for the conventional
190         method.
191         
192 int scroll(VGAscr *scr, Rectangle r, Rectangle sr);
193         Set the pixels in rectangle r with the pixels in sr.
194         r and sr are allowed to overlap, and the correct
195         thing must be done, just like memmove.
196         Like fill, scroll must not return until the operation
197         has completed.
198
199 Russ Cox <rsc@plan9.bell-labs.com> has a user-level scaffold
200 for testing fill and scroll routines before putting them into
201 the kernel.  You can mail him for them.
202
203 Finally, drawinit can set scr->blank to a hardware blanking
204 function.  On 8-bit displays we can set the colormap to all
205 black to get a sort of blanking, but for true-color displays
206 we need help from the hardware.
207
208 int blank(VGAscr *vga, int isblank);
209         If isblank is set, blank the screen.  Otherwise, restore it.
210         Implementing this function on CRT-based cards is known to
211         mess up the registers coming out of the blank.
212         We've had better luck with LCD-based cards although
213         still not great luck.  But there it is.
214
215 --- linear mode and soft screens
216
217 In the bad old days, the entire address space was only 1MB, but video
218 memory (640x480x1) was only 37.5kB, so everything worked out.  It got
219 its own 64kB segment and everyone was happy.  When screens got deeper
220 and then bigger, the initial solution was to use the 64kB segment as a
221 window onto a particular part of video memory.  The offset of the
222 window was controlled by setting a register on the card.  This works
223 okay but is a royal pain, especially if you're trying to copy from one
224 area of the screen to another and they don't fit in the same window.
225 When we are forced to cope with cards that require accessing memory
226 through the 64kB window, we allocate our own copy of the screen (a
227 so-called soft screen) in normal RAM, make changes there, and then
228 flush the changed portions of memory to video RAM through the window.
229 To do this, we call the kernel driver-provided page routine:
230
231 int pageset(VGAscr *scr, int page);
232         Set the base offset of the video window to point
233         page*64kB into video memory.
234
235 With the advent of 32-bit address spaces, we can map all of video
236 memory and avoid the soft screen.  We call this running the card
237 in linear mode, because the whole video memory is mapped linearly
238 into our address space.  Aux/vga is in charge of deciding
239 whether to do this.  (In turn, aux/vga more or less respects
240 vgadb, which controls it by having or not having "linear=1" in
241 the controller entry.)  If not, aux/vga doesn't do anything special,
242 and we use a soft screen.  If so, aux/vga writes "linear" and
243 an address space size into vgactl in step #7 above.  In response
244 the kernel calls the kernel driver's linear function, whose
245 job was described in step #7.
246
247 Most drivers only implement one or the other interface: if you've
248 got linear mode, you might as well use it and ignore the paging
249 capabilties of the card.  Paging is typically implemented only
250 when necessary.
251
252 --- from here
253
254 If you want to write a VGA driver, it's fairly essential that you get
255 documentation for the video chipset.  In a pinch, you might be able to
256 get by with the XFree86 driver for the chipset instead.  (The NVidia
257 driver was written this way.)  Another alternative is to use
258 documentation for a similar but earlier chipset and then tweak
259 registers until you figure out what is different.  (The SuperSavage
260 parts of the virge driver got written this way, starting with the
261 Savage4 parts, which in turn were written by referring to the Savage4
262 documentation and the Virge parts.)
263
264 Even if you do get documentation, the XFree86 driver is good to
265 have to double check.  Sometimes the documentation is incomplete,
266 misleading, or just plain wrong, whereas the XFree86 drivers, 
267 complicated beasts though they are, are known to work most of the time.
268
269 Another useful method for making sure you understand what is going on
270 is dumping the card's registers under another system like XFree86 or
271 Microsoft Windows.  The Plan 9 updates page contains an ANSI/POSIX
272 port of aux/vga that is useful only for dumping registers on various
273 systems.  It has been used under Linux, FreeBSD, and Windows 95/98.
274 It's not clear what to do on systems like Windows NT or Windows 2000
275 that both have reasonable memory protection and are hardware
276 programmer-unfriendly.
277
278 If you're going to write a driver, it's much easier with a real
279 Plan 9 network or at least with a do-everything cpu/auth/file server
280 terminal, so that you can have an editor and compiler going on a
281 usable machine while you continually frotz and reboot the machine
282 with the newfangled video card.  Booting this latter machine from
283 the network rather than its own disk makes life easier for you
284 (you don't have to explicitly copy aux/vga from the compiling machine to
285 the testing machine) and doesn't wreak havoc on the testing machine's
286 local kfs.
287
288 It's nice sometimes to have a command-line utility to poke
289 at the vga registers you care about.  We have one that perhaps
290 we can clean up and make available.  Otherwise, it's not hard
291 to roll your own.
292
293 The first step in writing an aux/vga driver is to write the
294 snarf and dump routines for the controller.  Then you can
295 run aux/vga -p and see whether the values you are getting
296 match what you expect from the documentation you have.
297
298 A good first resolution to try to get working is 640x480x8,
299 as it can use one of the standard clock modes rather than
300 require excessive clock fiddling.
301
302 /sys/src/cmd/aux/vga/template.c is a template for a new
303 vga controller driver.  There is no kernel template 
304 but any of the current drivers is a decent template.
305 /sys/src/9/pc/vga3dfx.c is the smallest one that supports
306 linear addressing mode.
307