I've adapted the experimental tvout code for Radeon/r128 in gatos cvs to
Mach64 and I'm atttaching the patch (can be applied to atimode.c in ati.2
or the mach64 DRI branch).  It works for me, but it has the same problem
of garbling the text console and mode switching with Ctl-Atl-+/- doesn't
work correctly.  However, I did have success with enabling tv-out even if
it's not plugged in and detected by the BIOS at boot.  This uses card BIOS
functions specific to Rage LT Pro (which is what I have), Rage XL, and
Rage Mobility (mach64 variety), but only if one of these chips is
detected.  Since the VBE functions are called for each mode switch, I can
switch between my laptop LCD and TV by switching to a console, plugging in
or unplugging the TV cable, and switching back to X.  I changed the code
from Radeon to recognize a display width of 800 (rather than 832), so I
can use 640x480, 800x600 and 1024x768 without specifying custom modelines.  
However, it should also work with custom modelines as long as they use
640, 800, or 1024 width and 15, 16, or 32 bpp.

This patch is of course rough and experimental, and I've only tested it on
my setup, so the usual caveats apply -- your tv/monitor might blow up,
etc.  ;)  Peter, since you worked on the r128 patch, can you take a look
at this?

-- 
Leif Delgass 
http://www.retinalburn.net


Index: atimode.c
===================================================================
RCS file: /cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/drivers/ati/atimode.c,v
retrieving revision 1.1.1.5.4.2
diff -u -r1.1.1.5.4.2 atimode.c
--- atimode.c   2001/10/28 20:33:05     1.1.1.5.4.2
+++ atimode.c   2001/12/07 06:51:50
@@ -34,6 +34,15 @@
 #include "atiwonder.h"
 #include "atiwonderio.h"
 
+#include "vbe.h"
+
+static const char *vbeSymbols[] = {
+    "VBEInit",
+    "vbeDoEDID",
+    "vbeFree",
+    NULL
+};
+
 #ifndef AVOID_CPIO
 
 /*
@@ -869,6 +878,13 @@
 
 #ifndef AVOID_CPIO
 
+    int vbemode, modekey;
+    vbeInfoPtr pVbe;
+    pointer pVbeModule = NULL;
+    xf86Int10InfoPtr pInt10;
+    Bool tv_attached, crt_attached;
+    int displays_request;
+
     int Index;
 
     /* Get back to bank 0 */
@@ -1096,6 +1112,345 @@
 
     if (pATI->VGAAdapter != ATI_ADAPTER_NONE)
         ATIVGASaveScreen(pATI, SCREEN_SAVER_OFF);       /* Turn on screen */
+
+    /* Set DBE mode for TV out */
+
+    if (pATIHW->crtc == ATI_CRTC_MACH64) {
+
+       if ((pVbeModule = xf86LoadSubModule(pScreenInfo, "vbe"))) {
+#ifdef XFree86LOADER
+           xf86LoaderReqSymLists(vbeSymbols,NULL);
+#endif
+           pInt10 = xf86InitInt10(pATI->iEntity);
+           pVbe = VBEInit(pInt10, pATI->iEntity);
+           if (pVbe) {
+               xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "VBEInit ok\n");
+
+               /* LT Pro, XL, Mobility specific BIOS functions */
+               if (pATI->Chip == ATI_CHIP_264LTPRO ||
+                   pATI->Chip == ATI_CHIP_264XL || 
+                   pATI->Chip == ATI_CHIP_MOBILITY) {
+                   
+                   /* Get attached display(s) - LTPro, XL, Mobility */
+                   pVbe->pInt10->num = 0x10;
+                   pVbe->pInt10->ax = 0xa083;
+                   pVbe->pInt10->cx = 0x0700; /* ch=0x07 - probe all, 0x01 CRT, 0x02 
+TV, 0x04 LCD */
+                   xf86ExecX86int10(pVbe->pInt10);
+
+                   xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                              "Attached displays query result: ax=0x%04x, 
+cx=0x%04x\n",
+                              pVbe->pInt10->ax, pVbe->pInt10->cx);
+
+                   tv_attached = crt_attached = FALSE;
+                   if (pVbe->pInt10->ax & 0xff00) {
+                       xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                  "Failed to detect attached displays\n");
+                   } else {
+                       switch ((pVbe->pInt10->cx >> 4) & 0x3) {
+                       case 0:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "No TV attached\n");
+                           break;
+                       case 1:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "TV attached to composite connector\n");
+                           tv_attached = TRUE;
+                           break;
+                       case 2:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "TV attached to S-video connector\n");
+                           tv_attached = TRUE;
+                           break;
+                       case 3:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "TV attached to S-video and composite 
+connectors\n");
+                           tv_attached = TRUE;
+                           break;
+                       default:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "Unrecognized return code: 0x%04x\n", 
+                                      pVbe->pInt10->cx);
+                       }
+
+                       if (pVbe->pInt10->cx & 0x3)
+                           crt_attached = TRUE;
+                       else
+                           crt_attached = FALSE;
+                   }
+
+                   /* Get active display  - LTPro, XL, Mobility */
+                   pVbe->pInt10->num = 0x10;
+                   pVbe->pInt10->ax = 0xa084;
+                   pVbe->pInt10->bx = 0x0000; /* bh=0x00 get active, bh=0x01 set 
+active */
+                   xf86ExecX86int10(pVbe->pInt10);
+
+                   xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                              "Active display query result: ax=0x%04x, bx=0x%04x, 
+cx=0x%04x\n",
+                              pVbe->pInt10->ax, pVbe->pInt10->bx, pVbe->pInt10->cx);
+
+                   if (pVbe->pInt10->ax & 0xff00) {
+                       xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                  "Failed to detect active display\n");
+                   } else {
+                       if (pVbe->pInt10->bx & 0x1) 
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO,                 
+
+                                      "DFP/LCD is active\n");
+
+                       if (pVbe->pInt10->bx & 0x2) 
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "CRT is active\n");
+
+                       if (pVbe->pInt10->bx & 0x4) {
+                          
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "TV is active\n");
+
+                           if (!tv_attached) {
+                               /* tv not connected - disable tv */
+                               
+                               displays_request = 0x00;
+                               if (crt_attached)
+                                   displays_request |= 0x02; /* enable CRT */
+                               if (!pATI->OptionCRT && (pATI->LCDPanelID >= 0))
+                                   displays_request |= 0x01; /* enable DFP/LCD */
+                               
+                               pVbe->pInt10->num = 0x10;
+                               pVbe->pInt10->ax = 0xa084;
+                               pVbe->pInt10->bx = 0x0100; /* bh=0x01 set active */
+                               pVbe->pInt10->cx = displays_request; 
+                               xf86ExecX86int10(pVbe->pInt10);
+
+                               xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                          "TV not present, disabling: ax=0x%04x, 
+bx=0x%04x, cx=0x%04x\n",
+                                          pVbe->pInt10->ax, pVbe->pInt10->bx, 
+pVbe->pInt10->cx);
+                           }
+
+                       } else if (tv_attached && (pVbe->pInt10->bx & 0x0400)) {
+                           /* tv connected and available - enable TV */
+                           pVbe->pInt10->num = 0x10;
+                           pVbe->pInt10->ax = 0xa084;
+                           pVbe->pInt10->bx = 0x0100; /* bh=0x01 set active */
+                           pVbe->pInt10->cx = 0x04; /* try to activate TV */
+                           xf86ExecX86int10(pVbe->pInt10);
+
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "Setting TV active: ax=0x%04x, bx=0x%04x, 
+cx=0x%04x\n",
+                                      pVbe->pInt10->ax, pVbe->pInt10->bx, 
+pVbe->pInt10->cx);
+                       }
+                   }
+
+               }
+
+               /* Return TV out configuration 
+                * see Programmer's Guide under "TV Out Specific Functions"
+                * It's not clear exactly which adapters support these
+                */
+               pVbe->pInt10->num = 0x10;
+               pVbe->pInt10->ax = 0xa070;
+               pVbe->pInt10->bx = 0x00;
+               xf86ExecX86int10(pVbe->pInt10);
+
+               xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                          "TV out query result: ax=0x%04x, bx=0x%04x, cx=0x%04x, 
+dx=0x%04x\n",
+                          pVbe->pInt10->ax, pVbe->pInt10->bx, pVbe->pInt10->cx, 
+pVbe->pInt10->dx);
+
+               if (pVbe->pInt10->ax & 0xff00) {
+
+                   xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                              "Failed to detect TV out configuration.\n");
+
+               } else if (pVbe->pInt10->bx == 0) {
+                   if (pVbe->pInt10->dx == 0) {
+                       xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                  "TV out is not detected.\n");
+                   } else {
+                       xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                  "TV out is detected but not supported.\n");
+                   }
+
+               } else if ((pVbe->pInt10->cx & 0xff) == 0) {
+
+                   xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                              "TV out is currently disabled.\n");
+
+               } else {
+
+                   xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                              "TV out is currently enabled (TV out revision code: 
+%d).\n",
+                              (pVbe->pInt10->dx >> 8) & 0xff);
+
+                   switch ((pVbe->pInt10->cx >> 8) & 0xff) {
+                   case 0:
+                       xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Reference 
+frequency 29.49892\n");
+                       break;
+                   case 1:
+                       xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Reference 
+frequency 28.63636\n");
+                       break;
+                   case 2:
+                       xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Reference 
+frequency 14.31818\n");
+                       break;
+                   case 3:
+                       xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Reference 
+frequency 27.00000\n");
+                       break;
+                   default:
+                       xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+                                  "Unknown reference frequency cx=0x%04x\n", 
+pVbe->pInt10->cx);
+                   
+                   }
+
+                   /* Return TV standard
+                    * see Programmer's Guide under "TV Out Specific Functions"
+                    * It's not clear exactly which adapters support these
+                    */
+                   pVbe->pInt10->num = 0x10;
+                   pVbe->pInt10->ax = 0xa071;
+                   pVbe->pInt10->bx = 0x00;
+                   xf86ExecX86int10(pVbe->pInt10);
+
+                   xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                              "TV standard query result: ax=0x%04x, bx=0x%04x, 
+cx=0x%04x\n",
+                              pVbe->pInt10->ax, pVbe->pInt10->bx, pVbe->pInt10->cx);
+
+                   if (pVbe->pInt10->ax & 0xff00) {
+
+                       xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                  "Failed to return TV standard.\n");
+                   } else {
+                   
+                       switch (pVbe->pInt10->cx & 0x00ff) {
+                       case 0:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "Current TV standard: NTSC\n");
+                           break;
+                       case 1:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "Current TV standard: PAL\n");
+                           break;
+                        case 2:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "Current TV standard: PAL-M\n");
+                           break;
+                        case 3:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "Current TV standard: PAL-60\n");
+                           break;
+                        case 4:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "Current TV standard: NTSC-J\n");
+                           break;
+                       case 5:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "Current TV standard: PAL-CN\n");
+                           break;
+                       case 6:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "Current TV standard: PAL-N\n");
+                           break;
+                        case 9:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "Current TV standard: SCART PAL\n");
+                           break;
+                       default:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+                                      "Unrecognized return code cx=0x%04x\n", 
+                                      pVbe->pInt10->cx);
+
+                       }
+
+                   }
+
+                   /* VBEGetMode - still needed? */
+                   pVbe->pInt10->num = 0x10;
+                   pVbe->pInt10->ax = 0x4f03;
+                   xf86ExecX86int10(pVbe->pInt10);
+
+                   if (pVbe->pInt10->ax == 0x4f) {
+
+                       xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "VBEGetMode ok\n");
+                       
+                       modekey = (pScreenInfo->bitsPerPixel << 16) | 
+                           (pScreenInfo->displayWidth);
+
+                       switch (modekey) {
+                       case (16<<16)|(640):
+                           vbemode = 0x111;
+                           break;
+                       case (15<<16)|(640):
+                           vbemode = 0x110;
+                           break;
+                       case (32<<16)|(640):
+                          vbemode = 0x112;
+                          break;
+                       case (16<<16)|(800):
+                           vbemode = 0x114;
+                           break;
+                       case (15<<16)|(800):
+                           vbemode = 0x113;
+                           break;
+                       case (32<<16)|(800):
+                           vbemode = 0x115;
+                           break;
+                       case (16<<16)|(1024):
+                           vbemode = 0x117;
+                           break;
+                       case (15<<16)|(1024):
+                           vbemode = 0x116;
+                           break;
+                       case (32<<16)|(1024):
+                           vbemode = 0x118;
+                           break;
+                       default:
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "Uknown mode key %ld %ld\n", 
+                                      modekey>>16, modekey & 0xffff);
+                           vbemode=0x0;
+                       }
+
+                       /* VBESetMode */
+                       pVbe->pInt10->num = 0x10;
+                       pVbe->pInt10->ax = 0x4f02;
+                       pVbe->pInt10->bx = vbemode;
+                       xf86ExecX86int10(pVbe->pInt10);
+
+                       if (pVbe->pInt10->ax == 0x4f) {
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "VBESetMode 
+ok\n");
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+                                      "Mode: 0x%X (width: %d, pitch: %d, depth: 
+%d)\n",
+                                      vbemode, 
+                                      pScreenInfo->displayWidth,     
+                                      GetBits(pATIHW->crtc_off_pitch, CRTC_PITCH)*8,
+                                      pScreenInfo->depth);
+                        
+                           outr(CRTC_OFF_PITCH, 
+                                SetBits(pScreenInfo->displayWidth>>3, CRTC_PITCH));
+                       } else {
+
+                           xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "VBESetMode 
+NOT ok\n");
+                       }
+                   } else {
+
+                       xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "VBEGetMode NOT 
+ok\n");
+                   }
+               }
+
+               vbeFree(pVbe);
+
+           } else {
+
+               xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "VBEInit NOT ok\n");
+
+           }
+
+            xf86UnloadSubModule(pVbeModule);
+           
+       } else {
+
+           xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Could not load vbe 
+module\n");
+
+       }
+
+    }
+       
 
 #endif /* AVOID_CPIO */
 

Reply via email to