notes.txt 14 KB

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