home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / D / SVGALIB / _SVGALIB.TAR / usr / doc / svgalib / mach32 / mach32info.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-18  |  33.5 KB  |  1,125 lines

  1. /* mach32info.c prints out some info about your mach32card        */
  2.  
  3. /* Please report the info it produces if the mach32driver of svgalib    */
  4. /* works not like expected.                        */
  5.  
  6. /* This tool is part of svgalib. Although it's output maybe useful to   */
  7. /* debug Xfree86 Mach32 Servers, I am NOT related to Xfree86!!          */
  8. /* PLEASE DO NOT SEND ME (MICHAEL WELLER) ANY XFREE86 BUG REPORTS!!!    */
  9. /* Thanx in advance.                                                    */
  10.  
  11. /* This tool is free software; you can redistribute it and/or        */
  12. /* modify it without any restrictions. This tool is distributed    */
  13. /* in the hope that it will be useful, but without any warranty.    */
  14.  
  15. /* Copyright 1994 by Michael Weller                    */
  16. /* eowmob@exp-math.uni-essen.de mat42b@aixrs1.hrz.uni-essen.de       */
  17. /* eowmob@pollux.exp-math.uni-essen.de                     */
  18.  
  19. /*
  20.  *
  21.  * MICHAEL WELLER DISCLAIMS ALL WARRANTIES WITH REGARD
  22.  * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  23.  * FITNESS, IN NO EVENT SHALL MICHAEL WELLER BE LIABLE
  24.  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  25.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  26.  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  27.  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  28.  *
  29.  */
  30.  
  31. /* This tool contains one routine out of Xfree86, therefore I repeat    */
  32. /* its copyright here: (Actually it is longer than the copied code)     */
  33.  
  34. /*
  35.  * Copyright 1992 by Orest Zborowski <obz@Kodak.com>
  36.  * Copyright 1993 by David Wexelblat <dwex@goblin.org>
  37.  *
  38.  * Permission to use, copy, modify, distribute, and sell this software and its
  39.  * documentation for any purpose is hereby granted without fee, provided that
  40.  * the above copyright notice appear in all copies and that both that
  41.  * copyright notice and this permission notice appear in supporting
  42.  * documentation, and that the names of Orest Zborowski and David Wexelblat 
  43.  * not be used in advertising or publicity pertaining to distribution of 
  44.  * the software without specific, written prior permission.  Orest Zborowski
  45.  * and David Wexelblat make no representations about the suitability of this 
  46.  * software for any purpose.  It is provided "as is" without express or 
  47.  * implied warranty.
  48.  *
  49.  * OREST ZBOROWSKI AND DAVID WEXELBLAT DISCLAIMS ALL WARRANTIES WITH REGARD 
  50.  * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 
  51.  * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID WEXELBLAT BE LIABLE 
  52.  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
  53.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
  54.  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
  55.  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  56.  *
  57.  * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
  58.  * Copyright 1993 by Kevin E. Martin, Chapel Hill, North Carolina.
  59.  *
  60.  * Permission to use, copy, modify, distribute, and sell this software and its
  61.  * documentation for any purpose is hereby granted without fee, provided that
  62.  * the above copyright notice appear in all copies and that both that
  63.  * copyright notice and this permission notice appear in supporting
  64.  * documentation, and that the name of Thomas Roell not be used in
  65.  * advertising or publicity pertaining to distribution of the software without
  66.  * specific, written prior permission.  Thomas Roell makes no representations
  67.  * about the suitability of this software for any purpose.  It is provided
  68.  * "as is" without express or implied warranty.
  69.  *
  70.  * THOMAS ROELL, KEVIN E. MARTIN, AND RICKARD E. FAITH DISCLAIM ALL
  71.  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
  72.  * WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE AUTHORS
  73.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  74.  * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  75.  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  76.  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  77.  *
  78.  * Author:  Thomas Roell, roell@informatik.tu-muenchen.de
  79.  *
  80.  * Rewritten for the 8514/A by Kevin E. Martin (martin@cs.unc.edu)
  81.  * Modified for the Mach-8 by Rickard E. Faith (faith@cs.unc.edu)
  82.  * Rewritten for the Mach32 by Kevin E. Martin (martin@cs.unc.edu)
  83.  *
  84.  */
  85.  
  86. #include <stdio.h>
  87. #include <stdlib.h>
  88. #include <unistd.h>
  89. #include <string.h>
  90.  
  91. /* Some stuff for the ATI VGA */
  92. #define ATIPORT         0x1ce
  93. #define ATIOFF          0x80
  94. #define ATISEL(reg)     (ATIOFF+reg)
  95. /* Ports we use: */
  96. #define SUBSYS_CNTL     0x42E8
  97. #define GE_STAT         0x9AE8
  98. #define CONF_STAT1      0x12EE
  99. #define CONF_STAT2      0x16EE
  100. #define MISC_OPTIONS    0x36EE
  101. #define MEM_CFG         0x5EEE
  102. #define MEM_BNDRY       0x42EE
  103. #define SCRATCH_PAD_0   0x52EE
  104. #define DESTX_DIASTP    0x8EE8
  105. #define R_SRC_X         0xDAEE
  106. #define R_EXT_GE_CONF   0x8EEE
  107. #define CHIP_ID        0xFAEE
  108. #define MAX_WAITSTATES    0x6AEE
  109. #define LOCAL_CNTL    0x32EE
  110. #define R_MISC_CNTL    0x92EE
  111. #define PCI_CNTL    0x22EE
  112. #define DISP_STATUS    0x2E8
  113. #define DISP_CNTL    0x22E8
  114. #define CLOCK_SEL    0x4AEE
  115. #define H_DISP        0x06E8
  116. #define H_TOTAL        0x02E8
  117. #define H_SYNC_WID    0x0EE8
  118. #define H_SYNC_STRT    0x0AE8
  119. #define V_DISP        0x16E8
  120. #define V_SYNC_STRT    0x1AE8
  121. #define V_SYNC_WID    0x1EE8
  122. #define V_TOTAL        0x12E8
  123. #define    R_H_TOTAL    0xB2EE
  124. #define    R_H_SYNC_STRT    0xB6EE
  125. #define    R_H_SYNC_WID    0xBAEE
  126. #define    R_V_TOTAL    0xC2EE
  127. #define    R_V_DISP    0xC6EE
  128. #define    R_V_SYNC_STRT    0xCAEE
  129. #define    R_V_SYNC_WID    0xD2EE
  130.  
  131.  
  132.  
  133. /* Bit masks: */
  134. #define GE_BUSY         0x0200
  135.  
  136. /* Chip_id's */
  137. #define ATI68800_3    ('A'*256+'A')
  138. #define ATI68800_6    ('X'*256+'X')
  139. #define ATI68800_6HX    ('H'*256+'X')
  140. #define ATI68800LX    ('L'*256+'X')
  141. #define ATI68800AX    ('A'*256+'X')
  142.  
  143. static inline void port_out( int value, int port )
  144. {
  145. __asm__ volatile ("outb %0,%1"
  146. : : "a" ((unsigned char)value), "d" ((unsigned short)port));
  147. }
  148.  
  149. static inline void port_outw( int value, int port ) {
  150. __asm__ volatile("outw %0,%1"
  151. : : "a" ((unsigned short)value), "d" ((unsigned short)port));
  152. }
  153.  
  154. static inline int port_in( int port )
  155. {
  156. unsigned char value;
  157. __asm__ volatile ("inb %1,%0"
  158.     : "=a" (value)
  159.     : "d" ((unsigned short)port));
  160. return value;
  161. }
  162.  
  163. static inline int port_inw( int port )
  164. {
  165. unsigned short value;
  166. __asm__ volatile ("inw %1,%0"
  167.     : "=a" (value)
  168.     : "d" ((unsigned short)port));
  169. return value;
  170. }
  171.  
  172. #define inb port_in
  173. #define inw port_inw
  174. #define outb(port, value) port_out(value, port)
  175. #define outw(port, value) port_outw(value, port)
  176.  
  177. int force=0,chip_id,bus;
  178. unsigned short eeprom[128];
  179. char *pel_width[]={"  4bpp","  8bpp","  16bpp","  24bpp"};
  180. char *bpp16mode[]={"  5-5-5","  5-6-5","  6-5-5","  6-6-4"};
  181. char *bpp24mode[]={"  RGB","  RGBa","  BGR","  aBGR"};
  182. char *bustype[]={"  16-bit ISA","  EISA","  16-bit MicroChannel",
  183.         "  32-bit MicroChannel","  LocalBus SX, 386SX",
  184.         "  LocalBus 1/2, 386DX",
  185.         "  LocalBus 1/2, 486DX","  PCI"};
  186. char *memtype3[]={"  256Kx4 DRAM", "  256Kx4 VRAM, 512 bit serial transfer",
  187.         "  256Kx4 VRAM, 256 bit serial transfer", "  256Kx16 DRAM",
  188.         "  invalid", "  invalid", "  invalid", "  invalid"};
  189. char *memtype6[]={"  256Kx4 DRAM", "  256Kx4 VRAM, 512 bit serial transfer",
  190.         "  256Kx16 VRAM, 256 bit serial transfer", "  256Kx16 DRAM",
  191.         "  256Kx4 Graphics DRAM",
  192.         "  256Kx4 VRAM, 512 bit split transfer",
  193.         "  256Kx16 VRAM, 256 bit split transfer",
  194.         "  invalid"};
  195. char *dactype[]={"  ATI-68830 (Type 0)", "  SC-11483 (Type 1)",
  196.          "  ATI-68875 (Type 2)", "  Bt-476 (Type 3)",
  197.          "  Bt-481 (Type 4)", "  ATI-68860 (Type 5)",
  198.          "  Unknown type 6", "  Unknown type 7"};
  199. char *localbus[]={"  reserved","  LOCAL#2","  LOCAL#3","  LOCAL#1"};
  200. char *aperture[]={"  memory aperture disabled","  1 MB memory aperture",
  201.           "  4 MB memory aperture","  reserved"};
  202. char *mono_color[]={"  white","  green","  amber"," reserved"};
  203. char *videomonames[]={"lores color - secondary",
  204.               "(hires) color - secondary",
  205.               "monochrome - secondary",
  206.               "lores color - primary",
  207.               "hires color - primary",
  208.               "monochrome - primary"};
  209. char *clockdiv[]={"  1","  2","  reserved","  reserved"};
  210. char *transwid[]={"  auto select","  16 bit","  8 bit","  8 bit hostdata/16 bit other"};
  211. char *vgabound[]={"  shared","  256 KB","  512 KB","  1 MB"};
  212. char *maxpix[]={"  8 bpp","  16 bpp","  24 bpp","  reserved"};
  213. static int mach32_clocks[16];
  214.  
  215. void puttable(int table);
  216.  
  217. void usage(void)
  218. {
  219.       fputs("Usage: mach32info {info|force}\n"
  220. "    prints out almost all the info about your mach32 card from configuration\n"
  221. "    registers and Mach32 EEPROM.  It also measures the Mach32 clocks.  A\n"
  222. "    completely idle system is required when these measurements are being\n"
  223. "    performed.  During these measurements, the video signals will be screwed up\n"
  224. "    for about 3-4 seconds.\n"
  225. "*   If your monitor does not switch off when getting a video signal it can't\n"
  226. "    stand (fixed freq. monitors) better switch it off before starting\n"
  227. "    mach32info.  Your computer will beep when it is finished probing.\n"
  228. "      You can redirect the 'stdout' of 'mach32info' to some file for viewing\n"
  229. "    the results easier.  Do not redirect 'stderr' as you won't hear the beep.\n"
  230. "*   The 'force' option disables the sanity check that tries to detect the\n"
  231. "    presence of the mach32.  Do not use this option unless you are really,\n"
  232. "    really sure that you have a Mach32 compatible vga card installed.\n"
  233. "*   This tool is part of svgalib. Although it's output maybe useful to debug\n"
  234. "    Xfree86 Mach32 Servers, I am NOT related to Xfree86!  PLEASE DO NOT SEND\n"
  235. "    ME (MICHAEL WELLER) ANY XFREE86 BUG REPORTS!  Thanx in advance.\n"
  236. "*   Note that this tool comes WITHOUT ANY WARRANTY! Use it at your OWN risk!\n"
  237. "*   Warning, this tool does not check for VC changes etc.. Just let it run in\n"
  238. "    its own virtual console and don't try to fool it.\n"
  239. "Please report any problems with running 'mach32info' or with config-\n"
  240. "uring the 'svgalib' mach32 driver to 'eowmob@exp-math.uni-essen.de'.\n"
  241. "Include the results from running this test with your report.\n",
  242.     stderr);
  243. exit(2);
  244. }
  245.  
  246. static void mach32_i_bltwait()
  247. {
  248. int i;
  249.  
  250. for (i=0; i < 100000; i++)
  251.         if(!(inw(GE_STAT) & (GE_BUSY | 1)))
  252.                 break;
  253. if(i>=100000)
  254.     puts("GE idled out");
  255. }
  256.  
  257. static int mach32_test()
  258. {
  259. int result=0;
  260. short tmp;
  261.  
  262. tmp = inw(SCRATCH_PAD_0);
  263. outw(SCRATCH_PAD_0, 0x5555);
  264. mach32_i_bltwait();
  265. if(inw(SCRATCH_PAD_0) == 0x5555)
  266.         {
  267.         outw(SCRATCH_PAD_0, 0x2a2a);
  268.         mach32_i_bltwait();
  269.         if(inw(SCRATCH_PAD_0) == 0x2a2a)
  270.                 {
  271.                 /* Aha.. 8514/a detected.. */
  272.                 result=1;
  273.                 }
  274.         }
  275. outw(SCRATCH_PAD_0,tmp);
  276. if(!result)
  277.         goto quit;
  278. /* Now ensure it is not a plain 8514/a: */
  279. result=0;
  280. outw(DESTX_DIASTP, 0xaaaa);
  281. mach32_i_bltwait();
  282. if(inw(R_SRC_X)==0x02aa)
  283.         {
  284.         outw(DESTX_DIASTP, 0x5555);
  285.         mach32_i_bltwait();
  286.         if(inw(R_SRC_X)==0x0555)
  287.                 result=1;
  288.         }
  289. quit:
  290. return result;
  291. }
  292.  
  293. static void mach32_wait()
  294. {
  295. /* Wait for at least 22 us.. (got that out of a BIOS disassemble on my 486/50 ;-) ) ... */
  296. register int i;
  297. volatile dummy;
  298.  
  299. for(i=0;i<16;i++)
  300.         dummy++;        /*Dummy is volatile..*/
  301. }
  302.  
  303. static int mach32_eeclock(register int ati33)
  304. {
  305. outw(ATIPORT,ati33|=0x200);     /* clock on */
  306. mach32_wait();
  307. outw(ATIPORT,ati33&= ~0x200); /* clock off */
  308. mach32_wait();
  309. return ati33;
  310. }
  311.  
  312. static void mach32_eekeyout(register int ati33, register int offset, register int mask)
  313. {
  314. do      {
  315.         if(mask&offset)
  316.                 ati33|= 0x100;
  317.         else    ati33&=~0x100;
  318.         outw(ATIPORT,ati33);
  319.         mach32_eeclock(ati33);
  320.         }
  321. while(mask>>=1);
  322. }
  323.  
  324. static int mach32_eeget(int offset)
  325. {
  326. register int ati33;
  327. register int result,i;
  328.  
  329. /* get current ATI33 */
  330. outb(ATIPORT,ATISEL(0x33));
  331. ati33=((int)inw(ATIPORT+1))<<8;
  332. ati33|=ATISEL(0x33);
  333. /* prepare offset.. cut and add header and trailer */
  334. offset=(0x600|(offset&0x7f))<<1;
  335.  
  336. /* enable eeprom sequence */
  337. ati33=mach32_eeclock(ati33);
  338. /*input to zero..*/
  339. outw(ATIPORT,ati33&=~0x100);
  340. /*enable to one*/
  341. outw(ATIPORT,ati33|= 0x400);
  342. mach32_eeclock(ati33);
  343. /*select to one*/
  344. outw(ATIPORT,ati33|= 0x800);
  345. mach32_eeclock(ati33);
  346. mach32_eekeyout(ati33,offset,0x800);
  347. for(i=0,result=0;i<16;i++)
  348.         {
  349.         result<<=1;
  350.         outb(ATIPORT,ATISEL(0x37));
  351.         if(inb(ATIPORT+1)&0x8)
  352.                 result|=1;
  353.         mach32_eeclock(ati33);
  354.         }
  355. /*deselect...*/
  356. outw(ATIPORT,ati33&=~0x800);
  357. mach32_eeclock(ati33);
  358. /*disable...*/
  359. outw(ATIPORT,ati33&=~0x400);
  360. mach32_eeclock(ati33);
  361. return result;
  362. }
  363.  
  364. void putflag(char *str,int flag)
  365. {
  366. int i;
  367.  
  368. i=72-strlen(str)-10;
  369. printf("   %s  ",str);
  370. while(i-- >0)
  371.     putchar('.');
  372. puts(flag?".  enabled":"  disabled");
  373. }
  374.  
  375. void putint(char *str,char *format,int value)
  376. {
  377. char buffer[128];
  378. int i;
  379.  
  380. sprintf(buffer,format,value);
  381. i=72-strlen(str)-strlen(buffer);
  382. printf("   %s  ",str);
  383. while(i-- >0)
  384.     putchar('.');
  385. puts(buffer);
  386. }
  387.  
  388. void putstr(char *str,char *strval)
  389. {
  390. putint(str,strval,0);
  391. }
  392.  
  393. unsigned short putword(int word)
  394. {
  395. printf("\n EEPROM Word %02xh:\t%04x\n",word,eeprom[word]);
  396. return eeprom[word];
  397. }
  398.  
  399. char *offset(char *buffer,int word)
  400. {
  401. int tab;
  402.  
  403. word>>=8;
  404. if((word<0x0d)||(word>0x67))
  405.     {
  406.     illegal:
  407.     sprintf(buffer,"  %02xh words (no table there)",word);
  408.     }
  409. else    {
  410.     tab=word-0x0d;
  411.     if(tab%(0x1c-0x0d))
  412.         goto illegal;
  413.     sprintf(buffer,"  %02xh words (table %d)",word,tab/(0x1c-0x0d)+1);
  414.     }
  415. return buffer;
  416. }
  417.  
  418. char *hsyncstr(int pixels,int clock, double fclock)
  419. {
  420. static char buffer[50];
  421.  
  422. if(!clock)
  423.     sprintf(buffer,"  %d pixels",pixels);
  424. else    sprintf(buffer,"  %d pixels, %.3f us",
  425.         pixels,pixels/fclock);
  426. return buffer;
  427. }
  428.  
  429. char *vsyncstr(int lines,int clock, double lilen)
  430. {
  431. static char buffer[50];
  432.  
  433. if(!clock)
  434.     sprintf(buffer,"  %d lines",lines);
  435. else    sprintf(buffer,"  %d lines, %.3f ms",
  436.         lines,lines/lilen);
  437. return buffer;
  438. }
  439.  
  440. /* Shamelessly ripped out of Xfree2.1 (with slight changes) : */
  441.  
  442. static void mach32_scan_clocks(void)
  443. {
  444. const int knownind=7;
  445. const double knownfreq=44.9;
  446.  
  447. char hstrt,hsync;
  448. int htotndisp,vdisp,vtotal,vstrt,vsync,clck,i;
  449.  
  450. int count, saved_nice, loop;
  451. double scale;
  452.  
  453. saved_nice=nice(0);
  454. nice(-20 - saved_nice);
  455.  
  456. puts(
  457. "Warning, about to measure clocks. Wait until system is completely idle!\n"
  458. "Any activity will disturb measuring, and therefor hinder correct driver\n"
  459. "function. Test will need about 3-4 seconds." );
  460. #if 0
  461. puts("\n(Enter Y<Return> to continue, any other text to bail out)");
  462.  
  463. if(getchar()!='Y')
  464.     exit(0);
  465. if(getchar()!='\n')
  466.     exit(0);
  467. #endif
  468.  
  469. htotndisp=inw(R_H_TOTAL);
  470. hstrt=inb(R_H_SYNC_STRT);
  471. hsync=inb(R_H_SYNC_WID);
  472. vdisp=inw(R_V_DISP);
  473. vtotal=inw(R_V_TOTAL);
  474. vstrt=inw(R_V_SYNC_STRT);
  475. vsync=inw(R_V_SYNC_WID);
  476. clck=inw(CLOCK_SEL);
  477.  
  478. outb(DISP_CNTL,0x63);
  479.  
  480. outb(H_TOTAL,0x63);
  481. outb(H_DISP,0x4f);
  482. outb(H_SYNC_STRT,0x52);
  483. outb(H_SYNC_WID,0x2c);
  484. outw(V_TOTAL,0x418);
  485. outw(V_DISP,0x3bf);
  486. outw(V_SYNC_STRT,0x3d6);
  487. outw(V_SYNC_WID,0x22);
  488.  
  489. for(i=0;i<16;i++)
  490.     {
  491.     outw(CLOCK_SEL, (i << 2) | 0xac1);
  492.     outb(DISP_CNTL,0x23);
  493.  
  494.     usleep(50000);
  495.  
  496.     count = 0;
  497.     loop = 200000;
  498.  
  499.     while (!(inb(DISP_STATUS) & 2)) 
  500.         if (loop-- == 0) goto done;
  501.     while (inb(DISP_STATUS) & 2) 
  502.         if (loop-- == 0) goto done;
  503.     while (!(inb(DISP_STATUS) & 2)) 
  504.         if (loop-- == 0) goto done;
  505.     
  506.     for (loop = 0; loop < 5; loop++) 
  507.         {
  508.         while (!(inb(DISP_STATUS) & 2)) 
  509.             count++;
  510.         while ((inb(DISP_STATUS) & 2)) 
  511.             count++;
  512.         }
  513.     done:
  514.     mach32_clocks[i]=count;
  515.  
  516.     outb(DISP_CNTL,0x63);
  517.     }
  518.  
  519. outw(CLOCK_SEL,clck);
  520.  
  521. outw(H_DISP,htotndisp);
  522. outb(H_SYNC_STRT,hstrt);
  523. outb(H_SYNC_WID,hsync);
  524. outw(V_DISP,vdisp);
  525. outw(V_TOTAL,vtotal);
  526. outw(V_SYNC_STRT,vstrt);
  527. outw(V_SYNC_WID,vsync);
  528. nice(20 + saved_nice);
  529.  
  530. /*Recalculation:*/
  531. scale=((double)mach32_clocks[knownind])*knownfreq;
  532. for(i=0;i<16;i++)
  533.     {
  534.     if(i==knownind)
  535.         continue;
  536.     if(mach32_clocks[i])
  537.         mach32_clocks[i]=0.5+scale/((double)mach32_clocks[i]);
  538.     }
  539. mach32_clocks[knownind]=knownfreq+0.5;
  540. }
  541.  
  542. int main(int argc, char *argv[])
  543. {
  544. char *ptr,buffer[40];
  545. int i,j,lastfound,mask,index,flag;
  546.  
  547. memset(eeprom,0,sizeof(unsigned short)*(size_t)256);
  548.  
  549. if(argc!=2)
  550.     usage();
  551. if(strcmp(argv[1],"info"))
  552.     {
  553.     if(strcmp(argv[1],"force"))
  554.         usage();
  555.     force=1;
  556.     }
  557. if(iopl(3)<0)
  558.     {
  559.     fputs("mach32info needs to be run as root!\n",stderr);
  560.     exit(1);
  561.     }
  562. if(!force)    
  563.     {
  564.     if(mach32_test())
  565.         puts("Mach32 succesful detected.");
  566.     else    {
  567.         fputs("Sorry, no Mach32 detected.\n",stderr);
  568.         exit(1);
  569.         }
  570.     }
  571. else    puts("Mach32 autodetection skipped.");
  572.  
  573. puts("\nThis tool is part of svgalib. Although this output maybe useful\n"
  574. "to debug Xfree86 Mach32 Servers, I am NOT related to Xfree86!!\n"
  575. "PLEASE DO NOT SEND ME (MICHAEL WELLER) ANY XFREE86 BUG REPORTS!!!\n"
  576. "Thanx in advance.\n");
  577.  
  578. mach32_scan_clocks();
  579.  
  580. puts("\nResulting clocks command for your libvga.config should be:\n");
  581. fputs("clocks",stdout);
  582. for(i=0;i<16;i++)
  583.         printf(" %3d",mach32_clocks[i]);
  584.  
  585. fputs("\a",stderr);
  586. fflush(stderr);
  587. puts("\n\nParsing for chip id...");
  588. lastfound=inb(CHIP_ID)&0xff;
  589. flag=0;
  590. for(i=0;i<10240;i++)
  591.     {
  592.     j=inb(CHIP_ID)&0xff;
  593.     index=(j>>4);
  594.     mask=1<<(j&15);
  595.     if(!(eeprom[index]&mask))
  596.         printf("\tfound id: %c%c\n",
  597.             0x41+((j>>5)&0x1f),0x41+(j&0x1f));
  598.     eeprom[index]|=mask;
  599.     if(lastfound!=j)
  600.         flag=1;
  601.     }
  602. /* Build chip_id from last found id: */
  603. chip_id=(j&0x1f)+((j<<3)&0x1f00);
  604. chip_id+=ATI68800_3;
  605.  
  606. switch(chip_id)
  607.     {
  608.     case ATI68800_3:
  609.         ptr="ATI68800-3 (guessed)";
  610.         break;
  611.     case ATI68800_6:
  612.         ptr="ATI68800-6";
  613.         break;
  614.     case ATI68800_6HX:
  615.         ptr="ATI68800-6 (HX-id)";
  616.         break;
  617.     case ATI68800LX:
  618.         ptr="ATI68800LX";
  619.         break;
  620.     case ATI68800AX:
  621.         ptr="ATI68800AX";
  622.         break;
  623.     default:
  624.         ptr="Unknown (assuming ATI68800-3)";
  625.         chip_id=ATI68800_3;
  626.         flag=1;
  627.         break;
  628.     }
  629. printf("Chipset: %s, Class: %d, Revision: %d\n",
  630.          ptr, (j >> 10) & 3, (j >> 12) & 15);
  631. if (flag) {
  632.     puts(
  633. "WARNING! Strange chipset id! Please report all output of this utility\n"
  634. "together with exact type of your card / type printed on your videochips\n"
  635. "to me, Michael Weller, eowmob@exp-math.uni-essen.de.  Alternate\n"
  636. "email-addresses are in the source of this utility and in 'README.mach32'.\n"
  637.         );
  638.     }
  639. j=inw(MAX_WAITSTATES);
  640. if(chip_id==ATI68800AX)
  641.     {
  642.     printf("\nAPERTURE_CNTL:\t\t%04x\n",j);
  643.     putflag("Zero waitstates for PCI aperture",j&0x400);
  644.     putflag("Fifo read ahead for PCI aperture",j&0x800);
  645.     putflag("Pixel stream 1 SCLK delay",j&0x1000);
  646.     putflag("Decrement burst",j&0x2000);
  647.     putstr("Direction of burst",(j&0x4000)?
  648.         "Increments burst":"Decrements burst");
  649.     putflag("Bus timeout on burst read/writes",!(j&0x8000));
  650.     }
  651. else    {
  652.     printf("\nMAX_WAITSTATES:\t\t%04x\n",j);
  653.     putint("Max. I/O waitstates","  %d",4*(j&15));
  654.     putint("BIOS-ROM waitstates","  %d",(j>>4)&15);
  655.     putflag("Linedraw optimizations",j&0x100);
  656.     }
  657. j=inw(MISC_OPTIONS);
  658. printf("\nMISC_OPTIONS:\t\t%04x\n",j);
  659. putflag("Waitstates if FIFO is half full",j&0x0001);
  660. putstr("Host data I/O size", (j & 0x0002) ? "8-bit" : "16-bit");
  661. putint("Memory size","  %d KB",(1<<((j>>2)&3))*512);
  662. putflag("VGA-controller",!(j&0x0010));
  663. putflag("16-bit 8514 I/O cycles",j&0x0020);
  664. putflag("Local RAMDAC",!(j&0x0040));
  665. putflag("VRAM-serial/DRAM-memory(bits 63:0) data delay latch",j&0x0080);
  666. putflag("Test-mode",j&0x0100);
  667. putflag("Non ATI68800-3: Block-write",j&0x0400);
  668. putflag("Non ATI68800-3: 64-bit Draw",j&0x0800);
  669. putflag("Latch video memory read data",j&0x1000);
  670. putflag("Memory data delay latch(bits 63:0)",j&0x2000);
  671. putflag("Memory data latch full clock pulse",j&0x4000);
  672.  
  673.  
  674. j=inw(R_EXT_GE_CONF);
  675. printf("\nR_EXT_GE_CONF:\t\t%04x\n",j);
  676. putint("Monitor alias id","  %d",j&7);
  677. putflag("Monitor alias",j&0x0008);
  678. putstr("Pixel width",pel_width[(j>>4)&3]);
  679. putstr("16 bit per plane organization",bpp16mode[(j>>6)&3]);
  680. putflag("Multiplex pixels",j&0x0100);
  681. putstr("24 bit per plane organization",bpp24mode[(j>>9)&3]);
  682. putstr("Reserved (11)",(j&0x0800)?"  1":"  0");
  683. putint("Extended RAMDAC address","  %d",(j>>12)&3);
  684. putflag("8 bit RAMDAC operation",j&0x4000);
  685. putstr("Reserved (15)",(j&0x8000)?"  1":"  0");
  686.  
  687. j=inw(CONF_STAT1);
  688. printf("\nCONF_STAT1:\t\t%04x\n",j);
  689. putflag("VGA circuitry",!(j&0x0001));
  690. putstr("Bus Type",bustype[bus=((j>>1)&7)]);
  691. putstr("Memory Type",(chip_id==ATI68800_3)?memtype3[(j>>4)&7]:
  692.                 memtype6[(j>>4)&7]);
  693. putflag("Chip",!(j&0x0080));
  694. putflag("Delay memory write for tests",(j&0x0100));
  695. putstr("RAMDAC Type",dactype[(j>>9)&7]);
  696. putflag("Internal MicroChannel address decode",!(j&0x1000));
  697. putint("Controller id (0 if unsupported)","  %d",(j>>13)&7);
  698.  
  699. j=inw(CONF_STAT2);
  700. printf("\nCONF_STAT2:\t\t%04x\n",j);
  701. if (chip_id == ATI68800_3 )
  702.     putflag("ATI68800-3: 2 clock sequencer timing", j & 0x0001);
  703. else    putstr("Reserved (0)", (j&0x0001) ? "  1" : "  0");
  704. putflag("Memory address range FE0000-FFFFFF",!(j&0x0002));
  705. if (!bus)
  706.     putflag("16-bit ISA Bus (ISA cards only)", (j & 0x0004));
  707. else    putstr("Reserved (2)", (j&0x0004) ? "  1" : "  0");
  708. putflag("Korean character font support",(j&0x0008));
  709. putstr("Local Bus signal (Local Bus only)",localbus[(j>>4)&3]);
  710. putflag("Local Bus 2 (non multiplexed) configuration",(j&0x0040));
  711. putflag("Read data 1 clk after RDY (Local Bus only)",(j&0x0080));
  712. putflag("Local decode of RAMDAC write (Local Bus only)",!(j&0x0100));
  713. putflag("1 clk RDY delay for write (Local Bus only)",!(j&0x0200));
  714. putstr("BIOS EPROM at",(j&0x0400)?"  C000:0-C7FF:F":"  E000:0-E7FF:F");
  715. switch(bus)
  716.     {
  717.     case 1:
  718.         putflag("Enable POS register function (EISA)",(j&0x0800));
  719.         break;
  720.     case 4:
  721.     case 5:
  722.     case 6:
  723.         putflag("Local decode of 102h register (Local Bus only)",
  724.             !(j & 0x0800) );
  725.         break;
  726.     default:
  727.         putstr("Reserved (11)", (j&0x0800)?"  1":"  0");
  728.         break;
  729.     }
  730. putflag("VESA compliant RDY format (Local Bus only)",!(j&0x1000));
  731. putflag("Non ATI68800-3: 4 GB aperture address",(j&0x2000));
  732. putstr("Non ATI68800-3: Memory support in LBus 2 config",
  733.     (j&0x4000)?"  2MB DRAM":"  1MB DRAM");
  734. putstr("Reserved (15)",(j&0x8000)?"  1":"  0");
  735.  
  736. j=inw(MEM_BNDRY);
  737. printf("\nMEM_BNDRY:\t\t%04x\n",j);
  738. putint("Video memory partition (VGA <, Mach32 >=)","  %d KB",(j&15)*256);
  739. putflag("Video memory partition write protection",j&0x0010);
  740. putint("Reserved (15:5)","  %03xh",(j>>5));
  741.  
  742.  
  743. j=inw(MEM_CFG);
  744. printf("\nMEM_CFG:\t\t%04x\n",j);
  745. putstr("Memory aperture",aperture[j&3]);
  746. putint("Memory aperture page (for 1MB aperture)","  %d",(j>>2)&3);
  747. if( (bus==7) || ( ((bus==5)||(bus==6)) && (inw(CONF_STAT2)&0x2000) ) )
  748.     putint("Memory aperture location (0-4 GB)","  %d MB",j>>4);
  749. else    {
  750.     putint("Reserved (7:4)","  %x",(j>>4)&0xf);
  751.     putint("Memory aperture location (0-128 MB)","  %d MB",j>>8);
  752.     }
  753.  
  754. j=inw(LOCAL_CNTL);
  755. printf("\nLOCAL_CNTL:\t\t%04x\n",j);
  756. putflag("6 clock non page cycle",j&0x0001);
  757. putflag("7 clock non page cycle",j&0x0002);
  758. putflag("1/2 memory clock CAS precharge time",j&0x0004);
  759. putflag("RAMDAC clocked on positive clock edge",j&0x0008);
  760. putflag("FIFO testing",j&0x0010);
  761. if(chip_id==ATI68800_3)
  762.     putint("Filtering of 1 clock IOW low or high pulse","  %d",(j>>5)&3);
  763. else    {
  764.     putflag("Memory mapped registers",j&0x0020);
  765.     putflag("Local Bus BIOS ROM decode",j&0x0040);
  766.     }
  767. putint("ROM wait states","  %d",(j>>7)&7);
  768. putint("Memory read wait states","  %d",(j>>10)&3);
  769. if(chip_id==ATI68800AX)
  770.     putint("Additional I/O waitstates","  %d",(j>>12)&15);
  771. else    putint("Minimum Local Bus waistates","  %d",(j>>12)&15);
  772.  
  773. j=inw(R_MISC_CNTL);
  774. printf("\nR_MISC_CNTL:\t\t%04x\n",j);
  775. putint("Reserved (3:0)","  %x",j&15);
  776. putint("ROM page select","  %d KB",(j>>3)&0x1e);
  777. putint("Blank adjust (delays BLANK_1_PCLK for RAMDAC type 2)
  778.     ","  %d",(j>>8)&3);
  779. putint("Pixel data skew from PCLK (pixel delay)","  %d",(j>>10)&3);
  780. putint("Reserved (15:12)","  %x",(j>>12)&15);
  781.  
  782. j=inw(PCI_CNTL);
  783. printf("\nPCI_CNTL:\t\t%04x\n",j);
  784. putint("RAMDAC read/write waitstates","  %d",j&7);
  785. putflag("Target abort cycle",j&0x0004);
  786. putflag("PCI RAMDAC delay",j&0x0010);
  787. putflag("Snooping on DAC read",j&0x0020);
  788. putflag("0 waitstates on aperture burst write",j&0x0040);
  789. putflag("Fast memory mapped I/O read/write",j&0x0080);
  790. putint("Reserved (15:8)","  %02x",(j>>8)&0xff);
  791.  
  792. fputs("\nReading in EEPROM... (some screen flicker will occur)",stdout);
  793. fflush(stdout);
  794. for(i=0;i<128;i++)
  795.     eeprom[i]=mach32_eeget(i);
  796. puts(" ...done.\n");
  797. fputs("EEPROM contents:",stdout);
  798. for(i=0;i<128;i++)
  799.     {
  800.     if(i&7)    putchar(' ');
  801.     else    fputs("\n   ",stdout);
  802.     printf(" %02x-%04x",i,eeprom[i]);
  803.     }    
  804. puts("\n\nDecoded info out of EEPROM:");
  805. putword(0);
  806. putint("EEPROM write counter","  %d",eeprom[0]);
  807. putword(1);
  808. switch(eeprom[1]&0xff)
  809.     {
  810.     case 0x00:
  811.         ptr="  disabled";
  812.         break;
  813.     case 0x08:
  814.         ptr="  secondary address";
  815.         break;
  816.     case 0x18:
  817.         ptr="  primary address";
  818.         break;
  819.     default:
  820.         ptr="  reserved";
  821.     }
  822. putstr("Mouse address select",ptr);
  823. switch((eeprom[1]>>8)&0xff)
  824.     {
  825.     case 0x20:
  826.         ptr="  IRQ 5";
  827.         break;
  828.     case 0x28:
  829.         ptr="  IRQ 4";
  830.         break;
  831.     case 0x30:
  832.         ptr="  IRQ 3";
  833.         break;
  834.     case 0x38:
  835.         ptr="  IRQ 2";
  836.         break;
  837.     default:
  838.         ptr="  reserved";
  839.     }
  840. putstr("Mouse interrupt handler select",ptr);
  841. j=putword(2);
  842. switch((j>>8)&0xff)
  843.     {
  844.     case 0x03:
  845.     case 0x05:
  846.     case 0x07:
  847.     case 0x09:
  848.     case 0x0b:
  849.     case 0x12:
  850.     case 0x13:
  851.     case 0x15:
  852.     case 0x17:
  853.     case 0x19:
  854.     case 0x1b:
  855.         sprintf(ptr=buffer,"  %cGA %s",(j&0x1000)?'E':'V',
  856.             videomonames[(((j>>8)&0xf)-1)>>1]);
  857.         break;
  858.     case 0x20:
  859.         ptr="  CGA";
  860.         break;
  861.     case 0x30:
  862.         ptr="  Hercules 720x348";
  863.         break;
  864.     case 0x40:
  865.         ptr="  Hercules 640x400";
  866.         break;
  867.     default:
  868.         ptr="  reserved";
  869.     }
  870. putstr("Power up video mode",ptr);
  871. putstr("Monochrome color",mono_color[(j>>6)&3]);
  872. putflag("Dual monitor",j&0x0020);
  873. putstr("Power up font",(j&0x0010)?"  8x16 or 9x16":"  8x14 or 9x14");
  874. putint("VGA Bus I/O","  %d bits",(j&0x0008)+8);
  875. putflag("0 waitstates RAM read/write",j&0x0004);
  876. putflag("0 waitstates ROM read",j&0x0002);
  877. putflag("ROM 16 bit",j&0x0001);
  878. j=putword(3);
  879. putflag("Scrolling fix",j&0x8000);
  880. putflag("Korean BIOS support",j&0x4000);
  881. putint("Reserved (13:4)","  %03xh",(j>>4)&0x3ff);
  882. putint("EEPROM table revision","  %d",j&15);
  883. j=putword(4);
  884. putint("Custom monitor indices","  %04x",j);
  885. j=putword(5);
  886. putstr("Host data transfer width",transwid[(j>>14)&3]);
  887. putint("Monitor code","  %02xh",(j>>8)&0x3f);
  888. putint("Reserved (7)","  %d",(j>>7)&1);
  889. putstr("VGA boundary",vgabound[(j>>4)&3]);
  890. putflag("Monitor alias",j&0x0008);
  891. putint("Monitor alias setting","  %d",j&0x0007);
  892. j=putword(6);
  893. putint("Memory aperture location","  %d MB",(j>>4));
  894. j&=15;
  895. putstr("Memory aperture size",aperture[(j>3)?3:j]);
  896. j=putword(7);
  897. putstr("Offset to 640x480 mode table",offset(buffer,j));
  898. putint("Reserved (7:2)","  %02xh",(j>>2)&0x3f);
  899. putflag("Use stored params for 640x480",j&2);
  900. putflag("640x480 72Hz",j&1);
  901. j=putword(8);
  902. putstr("Offset to 800x600 mode table",offset(buffer,j));
  903. putflag("Use stored params for 800x600",j&0x80);
  904. putint("Reserved (6)","  %d",(j>>6)&1);
  905. putflag("800x600 72Hz",j&0x20);
  906. putflag("800x600 70Hz",j&0x10);
  907. putflag("800x600 60Hz",j&8);
  908. putflag("800x600 56Hz",j&4);
  909. putflag("800x600 89Hz Interlaced",j&2);
  910. putflag("800x600 95Hz Interlaced",j&1);
  911. j=putword(9);
  912. putstr("Offset to 1024x768 mode table",offset(buffer,j));
  913. putflag("Use stored params for 1024x768",j&0x80);
  914. putint("Reserved (6:5)","  %d",(j>>5)&3);
  915. putflag("1024x768 66Hz",j&0x10);
  916. putflag("1024x768 72Hz",j&8);
  917. putflag("1024x768 70Hz",j&4);
  918. putflag("1024x768 60Hz",j&2);
  919. putflag("1024x768 87Hz Interlaced",j&1);
  920. j=putword(10);
  921. putstr("Offset to 1280x1024 mode table",offset(buffer,j));
  922. putflag("Use stored params for 1280x1024",j&0x80);
  923. putint("Reserved (6:2)","  %02xh",(j>>2)&0x1f);
  924. putflag("1280x1024 95Hz Interlaced",j&2);
  925. putflag("1280x1024 87Hz Interlaced",j&1);
  926. j=putword(11);
  927. putstr("Offset to alternate mode table",offset(buffer,j));
  928. putflag("Use stored params for alternate",j&0x80);
  929. putint("Reserved (6:2)","  %02xh",(j>>2)&0x1f);
  930. putflag("1152x900",j&2);
  931. putflag("1120x760",j&1);
  932. for(j=0;j<7;j++)
  933.     puttable(j);
  934. puts( "\n EEPROM Words 76h-7dh:  reserved.\n" );
  935. j=putword(0x7e);
  936. putint("Reserved (15)","  %d",j>>15);
  937. putflag("VGA circuitry",j&0x4000);
  938. putint("Memory size","  %d KB",1<< ( ((j>>11)&7) + 8 ) );
  939. putstr("DAC type",dactype[(j>>8)&7]);
  940. putint("Reserved (7:0)","  %02xh",j&0xff);
  941. j=putword(0x7f);
  942. putint("EEPROM Checksum","  %04x",j);
  943. j=0;
  944. for(i=0;i<=0x7f;)
  945.     j+=eeprom[i++];
  946. printf("\nEEPROM contents sum up to %04x:%04x.\n",j>>16,j&0xffff);
  947. if( ! (j & 0xffff) )
  948.     {
  949.     puts("ATI style checksum.");
  950.     }
  951. else    {
  952.     j-= (eeprom[0x7f]<<1)-1;
  953.     if( ! (j & 0xffff) )
  954.         puts("AST style checksum.");
  955.     else puts(
  956. "WARNING! Strange EEPROM checksum!\n"
  957. "Be sure that:\n"
  958. "1. You installed the Mach32 correctly with the ATI install tool from\n"
  959. "   DOS (yuck!).\n"
  960. "2. Wrote the proper config to the EEPROM with it.\n"
  961. "3. DOS bios reads out the Mach32 EEPROM with out problems and obeys\n"
  962. "   all settings (for example, power up video mode).\n"
  963. "If you can't get a correct checksum, read the section \"EEPROM woes\"\n"
  964. "in \"README.mach32\" of your svgalib distribution.\n"
  965.         );
  966.     }
  967. return 0;
  968. }
  969.  
  970. void puttable(int table)
  971. {
  972. int i;
  973. int clock;
  974. char buffer[80];
  975.  
  976. unsigned short *tab;
  977.  
  978. tab=eeprom+(table*15+0xd);
  979. printf("\n EEPROM Words %02xh-%02xh:\tCRT Parameter table %d",table*15+0xd,
  980.     (table+1)*15+0xc,table+1);
  981. if(tab[10]&0x3f00)
  982.     puts(":");
  983. else    {
  984.     puts("  .....................  invalid");
  985.     return;
  986.     }
  987. table=tab[0];
  988. putstr("Vertical sync polarity",(table&0x8000)?"  -":"  +");
  989. putstr("Horizontal sync polarity",(table&0x4000)?"  -":"  +");
  990. putflag("Interlace",table&0x2000);
  991. putflag("Multiplex pixels",table&0x1000);
  992. i=(table>>9)&7;
  993. putstr("Maximum pixel depth",maxpix[(i>3)?3:i]);
  994. putstr("Parameter type",(table&0x0100)?"  8514/Mach32":"  VGA");
  995. putstr("Dotclock select",(table&0x0080)?"  user supplied":"  default");
  996. putstr("Usage of CRTC parameters",(table&0x0040)?"  all"
  997.     :"  sync polarities only");
  998. putint("Dotclock chip select","  #%d",table&15);
  999. clock=mach32_clocks[table&15];
  1000. putstr("Dotclock divide by",clockdiv[(table>>4)&3]);
  1001. if(!(table&0x20))
  1002.     if(table&0x10)
  1003.         clock/=2;
  1004. if(clock)
  1005.     putint("Pixel clock (approximate value)","  %d MHz",(int)(clock+0.5));
  1006. else    putstr("Pixel clock","  (sorry, don't know the frequency)");
  1007. if(table&0x0100)
  1008.     { /*8514/Mach32*/
  1009.     double fclock,lilen;
  1010.     int xpels=((tab[3]&0xff)+1)<<3,
  1011.         ypels=tab[6],
  1012.         xtotal=((tab[3]>>8)+1)<<3,
  1013.         ytotal=tab[5],
  1014.         xstart=((tab[4]>>8)+1)<<3,
  1015.         ystart=tab[7],xsync=(tab[4]&0x1f)*8,
  1016.         ysync=(tab[8]>>8)&0x1f;
  1017.     puts("  Mach32 / 8514/A CRT parameters:");
  1018.     putint("Video fifo 16bpp","  %d",tab[2]&0xff);
  1019.     putint("Video fifo 24bpp","  %d",tab[2]>>8);
  1020.     putint("H_TOTAL","  %d",tab[3]>>8);
  1021.     putint("H_DISP","  %d",tab[3]&0xff);
  1022.     putint("H_SYNC_STRT","  %d",tab[4]>>8);
  1023.     putint("H_SYNC_WID","  %02xh",tab[4]&0xff);
  1024.     putint("V_TOTAL","  %xh",tab[5]);
  1025.     putint("V_DISP","  %xh",tab[6]);
  1026.     putint("V_SYNC_STRT","  %xh",tab[7]);
  1027.     putint("V_SYNC_WID","  %02xh",tab[8]>>8);
  1028.     putint("DISP_CNTL","  %02xh",tab[8]&0xff);
  1029.     putint("CLOCK_SEL","  %xh",tab[9]);
  1030.     clock=mach32_clocks[(tab[9]>>2)&15];
  1031.     if(!(tab[9]&0x40))
  1032.         clock*=2;
  1033.     puts("  Resulting video timings:");
  1034.     if(clock)
  1035.         {
  1036.         sprintf(buffer,"  %.1f MHz",fclock=((double)clock)/2);
  1037.         }
  1038.     else    {
  1039.         sprintf(buffer,"  #%d, don't know clock frequency, so no timings",
  1040.             (tab[9]>>2)&15);
  1041.         fclock=0;
  1042.         }
  1043.     putstr("Pixel clock",buffer);
  1044.     switch(tab[8]&0x6)
  1045.         {
  1046.         case 0:
  1047.             ypels=((ypels>>2)&~1)|(ypels&1);
  1048.             ytotal=((ytotal>>2)&~1)|(ytotal&1);
  1049.             ystart=((ystart>>2)&~1)|(ystart&1);
  1050.             break;
  1051.         case 2:
  1052.             ypels=((ypels>>1)&0xFFFC)|(ypels&3);
  1053.             ytotal=((ytotal>>1)&0xFFFC)|(ytotal&3);
  1054.             ystart=((ystart>>1)&0xFFFC)|(ystart&3);
  1055.             break;
  1056.         default:
  1057.             puts("  Unknown DISP_CNTL, vertical values are probably wrong.");
  1058.         }
  1059.     ypels++;
  1060.     ytotal++;
  1061.     ystart++;
  1062.     sprintf(buffer,"  %d x %d%s",xpels,ypels,(tab[8]&0x10)?", Interlaced":
  1063.                                 "" );
  1064.     putstr("Resolution",buffer);
  1065.     if(clock)
  1066.         {
  1067.         sprintf(buffer,"  %.3f KHz",lilen=(fclock*1e3)/xtotal);
  1068.         putstr("Horizontal frequency",buffer);
  1069.         sprintf(buffer,"  %.2f Hz",(lilen*1000)/ytotal);
  1070.         putstr("Vertical frequency",buffer);
  1071.         }
  1072.     else    lilen=0;
  1073.     putstr("Horizontal sync polarity",(tab[4]&0x20)?"  -":"  +");
  1074.     putstr("Horizontal sync width",hsyncstr(xsync,clock,fclock));
  1075.     putstr("Horizontal front porch",hsyncstr(xstart-xpels,clock,fclock));
  1076.     putstr("Horizontal back porch",hsyncstr(xtotal-xsync-xstart,
  1077.                             clock,fclock));
  1078.     putstr("Horizontal active time",hsyncstr(xpels,clock,fclock));
  1079.     putstr("Horizontal blank time",hsyncstr(xtotal-xpels,clock,fclock));
  1080.     putstr("Vertical sync polarity",(tab[8]&0x2000)?"  -":"  +");
  1081.     putstr("Vertical sync width",vsyncstr(ysync,clock,lilen));
  1082.     putstr("Vertical front porch",vsyncstr(ystart-ypels,clock,lilen));
  1083.     putstr("Vertical back porch",vsyncstr(ytotal-ysync-ystart,
  1084.                             clock,lilen));
  1085.     putstr("Vertical active time",vsyncstr(ypels,clock,lilen));
  1086.     putstr("Vertical blank time",vsyncstr(ytotal-ypels,clock,lilen));
  1087.     }
  1088. else    { /*VGA mode*/
  1089.     puts("  VGA CRT parameters:");
  1090.     putint("VIDEO_MODE_SEL_1","  %02xh",tab[1]>>8);
  1091.     putint("VIDEO_MODE_SEL_2","  %02xh",tab[1]&0xff);
  1092.     putint("VIDEO_MODE_SEL_3","  %02xh",tab[2]>>8);
  1093.     putint("VIDEO_MODE_SEL_4","  %02xh",tab[2]&0xff);
  1094.     putint("H_TOTAL (CRT00)","  %02xh",tab[3]>>8);
  1095.     putint("V_TOTAL (CRT06)","  %02xh",tab[3]&0xff);
  1096.     putint("H_RETRACE_START (CRT04)","  %02xh",tab[4]>>8);
  1097.     putint("H_RETRACE_END (CRT05)","  %02xh",tab[4]&0xff);
  1098.     putint("V_RETRACE_START (CRT10)","  %02xh",tab[5]>>8);
  1099.     putint("V_RETRACE_END (CRT11)","  %02xh",tab[5]&0xff);
  1100.     putint("H_BLANK_START (CRT02)","  %02xh",tab[6]>>8);
  1101.     putint("H_BLANK_END (CRT03)","  %02xh",tab[6]&0xff);
  1102.     putint("V_BLANK_START (CRT15)","  %02xh",tab[7]>>8);
  1103.     putint("V_BLANK_END (CRT16)","  %02xh",tab[7]&0xff);
  1104.     putint("CRT_OVERFLOW (CRT07)","  %02xh",tab[8]>>8);
  1105.     putint("MAX_SCANLINE (CRT09)","  %02xh",tab[8]&0xff);
  1106.     putint("V_DISPLAYED (CRT12)","  %02xh",tab[9]>>8);
  1107.     putint("CRT_MODE (CRT17)","  %02xh",tab[9]&0xff);
  1108.     puts(
  1109. "  Resulting video timings  .........................  not implemented for VGA"
  1110.         );
  1111.     }
  1112. table=tab[10];
  1113. puts("  Additional mode flags:");
  1114. putflag("Pixel clock divide by 2",table&0x8000);
  1115. putflag("Multiplex (MUX flag)",table&0x4000);
  1116. putint("Size of mode table","  %d words",(table>>8)&0x3f);
  1117. putstr("Offset to alternate table",offset(buffer,(table<<8)&0xff00));
  1118. putint("Horizontal overscan","  %d",tab[11]);
  1119. putint("Vertival overscan","  %d",tab[12]);
  1120. putint("Overscan color blue","  %d",tab[13]>>8);
  1121. putint("Overscan color index 8bpp","  %d",tab[13]&0xff);
  1122. putint("Overscan color red","  %d",tab[14]>>8);
  1123. putint("Overscan color green","  %d",tab[14]&0xff);
  1124. }
  1125.