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