--- xc/programs/Xserver/hw/xfree86/drivers/ati/aticonfig.c	2004-04-12 07:45:20.000000000 +0300
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/aticonfig.c	2004-11-20 03:22:57.000000000 +0200
@@ -125,6 +125,13 @@
 
 #endif /* XF86DRI */
 
+#ifdef TV_OUT
+
+#   define TvOut        PublicOption[ATI_OPTION_TV_OUT].value.bool
+#   define TvStd        PublicOption[ATI_OPTION_TV_STD].value.str
+
+#endif /* TV_OUT */
+
 #   define CacheMMIO     PublicOption[ATI_OPTION_MMIO_CACHE].value.bool
 #   define TestCacheMMIO PublicOption[ATI_OPTION_TEST_MMIO_CACHE].value.bool
 #   define PanelDisplay  PublicOption[ATI_OPTION_PANEL_DISPLAY].value.bool
@@ -156,6 +163,11 @@
 
 #endif /* AVOID_CPIO */
 
+#ifdef TV_OUT
+
+	TvStd = "None";  /* No tv standard change requested */
+
+#endif
     }
 
     ReferenceClock = ((double)157500000.0) / ((double)11.0);
@@ -204,6 +216,31 @@
 
 #endif /* AVOID_CPIO */
 
+#ifdef TV_OUT
+
+    if (TvOut && pATI->Chip < ATI_CHIP_264GT) {
+       /* Only allow this for 3D Rage (I) or greater chip ID
+	* AFAIK, no chips before this supported TV-Out
+	* mach64VT has support for TV tuner, but no TV-Out
+	*/
+	xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
+                "TV Out not supported for this chip.\n");
+    } else {
+	ATITVStandard std;
+	pATI->OptionTvOut = TvOut;
+	pATI->OptionTvStd = ATI_TV_STD_INVALID;
+	for (std = 0; std < ATI_TV_STDS_MAX_VALID; std++) {
+	    if (std != ATI_TV_STD_RESERVED1 && std != ATI_TV_STD_RESERVED2) {
+		if (strncasecmp(TvStd, ATITVStandardNames[std], ATI_TV_STDS_NAME_MAXLEN)==0) {
+		    pATI->OptionTvStd = std;
+		    break;
+		}
+	    }
+	}
+    }
+
+#endif /* TV_OUT */
+
     pATI->OptionMMIOCache = CacheMMIO;
     pATI->OptionTestMMIOCache = TestCacheMMIO;
     pATI->OptionProbeClocks = ProbeClocks;
--- xc/programs/Xserver/hw/xfree86/drivers/ati/aticonsole.c	2004-04-12 07:45:20.000000000 +0300
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/aticonsole.c	2004-11-20 03:22:57.000000000 +0200
@@ -44,6 +44,20 @@
 
 #include "xf86.h"
 
+#ifdef TV_OUT
+
+#include "atichip.h"
+#include "atiprint.h"
+#include "atioption.h"
+#include "vbe.h"
+
+static const char *vbeSymbols[] = {
+    "VBEGetVBEMode",
+    NULL
+};
+
+#endif /* TV_OUT */
+
 /*
  * ATISaveScreen --
  *
@@ -137,6 +151,398 @@
     }
 }
 
+#ifdef TV_OUT
+
+static void
+ATIProbeAndSetActiveDisplays
+(
+    ScrnInfoPtr pScreenInfo,
+    ATIPtr      pATI
+)
+{
+    vbeInfoPtr pVbe;
+    Bool tv_attached, crt_attached, lcd_attached;
+    int disp_request;
+    ATITVStandard tv_std, tv_std_request;
+
+    xf86LoaderRefSymLists(vbeSymbols, NULL);
+
+    if (xf86GetVerbosity() > 3) {
+	xf86ErrorFVerb(4, "\n Before TV-Out queries\n\n",
+		       pScreenInfo->currentMode->name);
+	ATIPrintRegisters(pATI);
+    }
+
+    pATI->tvActive = FALSE;
+    pVbe = pATI->pVBE;
+    if (pVbe) {
+	/* 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: ax=0x%04x, cx=0x%04x\n",
+		       pVbe->pInt10->ax, pVbe->pInt10->cx);
+
+	    tv_attached = crt_attached = lcd_attached = FALSE;
+	    if (pVbe->pInt10->ax & 0xff00) {
+		xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+			   "Failed to detect attached displays\n");
+	    } else {
+			
+		if (pVbe->pInt10->cx & 0x3)
+		{
+			xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+				   "   CRT attached\n");
+			crt_attached = TRUE;
+		}
+		else
+		    crt_attached = FALSE;
+
+		if ((pVbe->pInt10->cx >> 2) & 0x3)
+		{
+		    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+			       "   DFP/LCD attached\n");
+		    lcd_attached = TRUE;
+		}
+		else
+		    lcd_attached = FALSE;
+
+		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 (composite connector)\n");
+		    tv_attached = TRUE;
+		    break;
+		case 2:
+		    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+			       "   TV attached (S-video connector)\n");
+		    tv_attached = TRUE;
+		    break;
+		case 3:
+		    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+			       "   TV attached (S-video/composite connectors)\n");
+		    tv_attached = TRUE;
+		    break;
+		default:
+		    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+			       "Unrecognized return code: 0x%04x\n", 
+			       pVbe->pInt10->cx);
+		}
+
+	    }
+
+	    /* 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 displays: 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_WARNING, 
+			   "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 */
+			disp_request = 0x00;
+			if (crt_attached)
+			    disp_request |= 0x02; /* enable CRT */
+			if (lcd_attached && pATI->OptionPanelDisplay)
+			    disp_request |= 0x01; /* enable DFP/LCD */
+
+			pVbe->pInt10->num = 0x10;
+			pVbe->pInt10->ax = 0xa084;
+			pVbe->pInt10->bx = 0x0100; /* bh=0x01 set active */
+			pVbe->pInt10->cx = disp_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);
+			if (pVbe->pInt10->ax & 0xff00) {
+			    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+				       "Disabling TV failed\n");
+			}
+		    } else {
+			pATI->tvActive = TRUE;
+		    }
+
+		} else if (tv_attached && (pVbe->pInt10->bx & 0x0400)) {
+		    /* tv connected and available - enable TV */
+		    disp_request = 0x04;          /* enable TV */
+
+#if 0
+		    /* This works, but CRT image is vertically compressed */
+		    if (crt_attached)
+			    disp_request |= 0x02; /* enable CRT */
+		    /* NOTE: For me, LCD+TV does NOT work */
+		    /*if (lcd_attached && pATI->OptionPanelDisplay)
+			    disp_request |= 0x01; * enable DFP/LCD */
+#endif
+
+		    pVbe->pInt10->num = 0x10;
+		    pVbe->pInt10->ax = 0xa084;
+		    pVbe->pInt10->bx = 0x0100; /* bh=0x01 set active */
+		    pVbe->pInt10->cx = disp_request; /* 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);
+		    if (pVbe->pInt10->ax & 0xff00) {
+			xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+				   "Setting TV active failed\n");
+		    } else {
+			pATI->tvActive = TRUE;
+		    }
+		}
+	    }
+
+	} else { /* pATI->Chip < ATI_CHIP_264LTPRO */
+	    /* TVOut Hooks - Check for TVOut BIOS/hardware */
+	    pVbe->pInt10->num = 0x10;
+	    pVbe->pInt10->ax = 0xa019;
+	    pVbe->pInt10->cx = 0x0000; /* TVOut BIOS query */
+	    xf86ExecX86int10(pVbe->pInt10);
+
+	    tv_attached = FALSE;
+
+	    if (pVbe->pInt10->ax & 0xff00) {
+		xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+			   "Failed to detect TV-Out BIOS\n");
+	    } else {
+		switch (pVbe->pInt10->ax & 0x0003) {
+		case 3:
+		    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+			       "TV-Out BIOS detected and active\n");
+
+		    /* TV attached query */
+		    pVbe->pInt10->num = 0x10;
+		    pVbe->pInt10->ax = 0xa070;
+		    pVbe->pInt10->bx = 0x0002; /* Sub-function: return tv attached info */
+		    xf86ExecX86int10(pVbe->pInt10);
+
+		    if (pVbe->pInt10->ax & 0xff00) {
+			xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+				   "Failed to detect if TV is attached\n");
+		    } else {
+			switch (pVbe->pInt10->cx & 0x0003) {
+			case 3:
+			    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+				       "TV attached to composite and S-video connectors\n");
+			    tv_attached = TRUE;
+			    break;
+			case 2:
+			    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+				       "TV attached to S-video connector\n");
+			    tv_attached = TRUE;
+			    break;
+			case 1:
+			    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+				       "TV attached to composite connector\n");
+			    tv_attached = TRUE;
+			    break;
+			default:
+			    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+				       "TV is not attached\n");
+			}
+		    }
+		    break;
+		case 1:
+		    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+			       "TV-Out BIOS service is not available due to" 
+			       "a system BIOS error or TV-Out hardware not being installed\n");
+		    break;
+		default:
+		    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+			       "No TV-Out BIOS or hardware detected\n");
+		}
+	    }
+	}
+
+	/* 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: 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_WARNING, 
+		       "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");
+	    if (tv_attached && pATI->Chip < ATI_CHIP_264LTPRO) {
+		/* Try to enable TV-Out */
+		pVbe->pInt10->num = 0x10;
+		pVbe->pInt10->ax = 0xa070;
+		pVbe->pInt10->bx = 0x0001; /* Sub-function: Select TV Out */
+		/* cl=0x001 enable, cl=0x000 disable, 
+		 * cl=0x080 disable with feature connector bit preserved 
+		 */
+		pVbe->pInt10->cx = 0x0001;
+			
+		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);
+
+		if (pVbe->pInt10->ax & 0xff00) {
+		    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+			       "Setting TV active failed\n");
+		} else {
+		    pATI->tvActive = TRUE;
+		}
+	    }
+
+	} else {
+	    pATI->tvActive = TRUE;
+
+	    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_WARNING, 
+			   "Failed to return TV standard.\n");
+	    } else {
+		tv_std = pVbe->pInt10->cx & 0x00ff;
+		switch (tv_std) {
+		case ATI_TV_STD_NTSC:
+		case ATI_TV_STD_PAL:
+		case ATI_TV_STD_PALM:
+		case ATI_TV_STD_PAL60:
+		case ATI_TV_STD_NTSCJ:
+		case ATI_TV_STD_PALCN:
+		case ATI_TV_STD_PALN:
+		case ATI_TV_STD_SCARTPAL:
+		    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+			       "Current TV standard: %s\n", ATITVStandardNames[tv_std]);
+		    break;
+		default:
+		    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+			       "Unrecognized TV standard return code cx=0x%04x\n", 
+			       pVbe->pInt10->cx);
+		}
+
+		tv_std_request = pATI->OptionTvStd;
+		if (tv_std_request < 0 || 
+		    tv_std_request > ATI_TV_STD_NONE || 
+		    tv_std_request == ATI_TV_STD_RESERVED1 || 
+		    tv_std_request == ATI_TV_STD_RESERVED2) {
+		    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+			       "Invalid TV standard requested, please check configuration file\n");
+		} else if (tv_std_request != ATI_TV_STD_NONE) {
+		    /* Set TV standard if requested (LT Pro not supported) */
+		    if (pATI->Chip != ATI_CHIP_264LTPRO &&
+			tv_std_request != tv_std) {
+				
+			pVbe->pInt10->num = 0x10;
+			pVbe->pInt10->ax = 0xa070;
+			pVbe->pInt10->bx = 0x0003; /* sub-function: set TV standard */
+			pVbe->pInt10->cx = tv_std_request;
+			xf86ExecX86int10(pVbe->pInt10);
+			if (pVbe->pInt10->ax & 0xff00)
+			    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+				       "Failed to set TV standard\n");
+			else
+			    xf86DrvMsg(pScreenInfo->scrnIndex, X_CONFIG, 
+				       "Set TV standard to %s\n", ATITVStandardNames[tv_std_request]);
+		    } else {
+			xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, 
+				   "Setting TV standard not supported on ATI Rage LT Pro\n");
+		    }
+		}
+	    }
+	    
+	}
+    } else {
+	xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "VBE module not loaded\n");
+    }
+}
+
+#endif /* TV_OUT */
+
 /*
  * ATIEnterGraphics --
  *
@@ -165,9 +571,28 @@
 
     pScreenInfo->vtSema = TRUE;
 
+#ifdef TV_OUT
+    if (pATI->OptionTvOut) {
+
+	xf86LoaderRefSymLists(vbeSymbols, NULL);
+
+	if (pATI->pVBE) {
+	    if (VBEGetVBEMode(pATI->pVBE, &pATI->vbemode)) {
+		xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Saving VESA mode: 0x%x\n", 
+			   pATI->vbemode);
+	    }
+	}
+    }
+#endif /* TV_OUT */
+
     /* Save current state */
     ATIModeSave(pScreenInfo, pATI, &pATI->OldHW);
 
+#ifdef TV_OUT
+    if (pATI->OptionTvOut) 
+	ATIProbeAndSetActiveDisplays(pScreenInfo, pATI);
+#endif /* TV_OUT */
+
     /* Set graphics state */
     ATIModeSet(pScreenInfo, pATI, &pATI->NewHW);
 
@@ -202,6 +627,11 @@
         if (!xf86ServerIsExiting())
             ATIModeSave(pScreenInfo, pATI, &pATI->NewHW);
 
+#ifdef TV_OUT
+	if (pATI->OptionTvOut) 
+	    ATIProbeAndSetActiveDisplays(pScreenInfo, pATI);
+#endif /* TV_OUT */
+
         /* Restore mode in effect on server entry */
         ATIModeSet(pScreenInfo, pATI, &pATI->OldHW);
 
--- xc/programs/Xserver/hw/xfree86/drivers/ati/atilock.c	2004-04-12 07:45:20.000000000 +0300
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/atilock.c	2004-11-20 03:22:57.000000000 +0200
@@ -154,9 +154,14 @@
              */
             if (pATI->Chip != ATI_CHIP_264XL)
             {
-                pATI->LockData.scratch_reg3 = inr(SCRATCH_REG3);
-                outr(SCRATCH_REG3,
-                    pATI->LockData.scratch_reg3 | DISPLAY_SWITCH_DISABLE);
+#ifdef TV_OUT
+		pATI->LockData.scratch_reg3 = inr(SCRATCH_REG3) & ~DISPLAY_SWITCH_DISABLE;
+		outr(SCRATCH_REG3, pATI->LockData.scratch_reg3);
+#else
+		pATI->LockData.scratch_reg3 = inr(SCRATCH_REG3);
+		outr(SCRATCH_REG3,
+		     pATI->LockData.scratch_reg3 | DISPLAY_SWITCH_DISABLE);
+#endif /* TV_OUT */
             }
         }
 
@@ -575,14 +580,18 @@
         if ((pATI->LCDPanelID >= 0) && (pATI->Chip != ATI_CHIP_264LT))
         {
             outr(LCD_INDEX, pATI->LockData.lcd_index);
+#ifndef TV_OUT
             if (pATI->Chip != ATI_CHIP_264XL)
                 outr(SCRATCH_REG3, pATI->LockData.scratch_reg3);
+#endif /* TV_OUT */
         }
         if (pATI->Chip >= ATI_CHIP_264VTB)
         {
             outr(MPP_CONFIG, pATI->LockData.mpp_config);
             outr(MPP_STROBE_SEQ, pATI->LockData.mpp_strobe_seq);
+#ifndef TV_OUT
             outr(TVO_CNTL, pATI->LockData.tvo_cntl);
+#endif /* TV_OUT */
             if (pATI->Chip >= ATI_CHIP_264GT2C)
             {
                 outr(HW_DEBUG, pATI->LockData.hw_debug);
--- xc/programs/Xserver/hw/xfree86/drivers/ati/atimode.c	2003-09-12 23:07:15.000000000 +0300
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/atimode.c	2004-11-20 03:22:57.000000000 +0200
@@ -35,6 +35,18 @@
 #include "atiwonder.h"
 #include "atiwonderio.h"
 
+#ifdef TV_OUT
+
+#include "vbe.h"
+
+static const char *vbeSymbols[] = {
+    "VBESetVBEMode",
+    "vbeFree",
+    NULL
+};
+
+#endif /* TV_OUT */
+
 #ifndef AVOID_CPIO
 
 /*
@@ -908,11 +920,17 @@
         else
             MaxScalerClock = 80000;     /* Conservative */
         pATIHW->pll_vclk_cntl &= ~PLL_ECP_DIV;
-        /* XXX Don't do this for TVOut! */
-        ECPClock = pMode->SynthClock;
-        for (Index = 0;  (ECPClock > MaxScalerClock) && (Index < 2);  Index++)
-            ECPClock >>= 1;
-        pATIHW->pll_vclk_cntl |= SetBits(Index, PLL_ECP_DIV);
+#ifdef TV_OUT
+	if (!pATI->OptionTvOut) {
+#endif /* TV_OUT */
+	   /* XXX Don't do this for TVOut! */
+	   ECPClock = pMode->SynthClock;
+	   for (Index = 0;  (ECPClock > MaxScalerClock) && (Index < 2);  Index++)
+	      ECPClock >>= 1;
+	   pATIHW->pll_vclk_cntl |= SetBits(Index, PLL_ECP_DIV);
+#ifdef TV_OUT
+	}
+#endif /* TV_OUT */
     }
     else if (pATI->DAC == ATI_DAC_IBMRGB514)
     {
@@ -922,6 +940,108 @@
     return TRUE;
 }
 
+#ifdef TV_OUT
+
+static void
+ATISetVBEMode
+(
+    ScrnInfoPtr pScreenInfo,
+    ATIPtr      pATI,
+    ATIHWPtr    pATIHW
+)
+{
+
+    xf86LoaderRefSymLists(vbeSymbols, NULL);
+
+    if (pATIHW->crtc == ATI_CRTC_MACH64) {
+	int vbemode, modekey;
+
+	/* Find a suitable VESA VBE mode, if one exists */
+	modekey = (pScreenInfo->depth << 16) | 
+	    (pScreenInfo->currentMode->HDisplay);
+
+	switch (modekey) {
+	case (15<<16)|(640):
+	    vbemode = 0x110;
+	    break;
+	case (16<<16)|(640):
+	    vbemode = 0x111;
+	    break;
+#if 0
+	case (24<<16)|(640):
+	    vbemode = 0x112;
+	    break;
+#endif
+	case (15<<16)|(800):
+	    vbemode = 0x113;
+	    break;
+	case (16<<16)|(800):
+	    vbemode = 0x114;
+	    break;
+#if 0
+	case (24<<16)|(800):
+	    vbemode = 0x115;
+	    break;
+#endif
+	case (15<<16)|(1024):
+	    vbemode = 0x116;
+	    break;
+	case (16<<16)|(1024):
+	    vbemode = 0x117;
+	    break;
+#if 0
+	case (24<<16)|(1024):
+	    vbemode = 0x118;
+	    break;
+#endif
+	default:
+	    xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+		       "Mode not supported for TV-Out: depth: %ld HDisplay: %ld\n", 
+		       modekey>>16, modekey & 0xffff);
+	    return;
+	}
+
+	if (pATI->pVBE) {
+
+            /* Preserve video memory contents */
+            vbemode |= (1<<15);
+
+	    if (VBESetVBEMode(pATI->pVBE, vbemode, NULL)) {
+		xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, 
+			   "VBESetMode: 0x%X (width: %d, pitch: %d, depth: %d)\n",
+			   vbemode, 
+			   pScreenInfo->currentMode->HDisplay,     
+			   pScreenInfo->displayWidth,
+			   pScreenInfo->depth);
+		outr(CRTC_OFF_PITCH,
+		     SetBits(pScreenInfo->displayWidth>>3, CRTC_PITCH));
+	    } else {
+		xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "VBESetMode failed.\n");
+	    }
+	} else {
+	    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "VBE module not loaded.\n");
+	}
+    } else {
+	/* restore text mode with VBESetMode */
+	if (pATI->pVBE) {
+	    if (VBESetVBEMode(pATI->pVBE, pATI->vbemode, NULL)) {
+		xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Restoring VESA mode: 0x%x\n", 
+			   pATI->vbemode);
+	    } else {
+	        xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "VBESetMode failed.\n");
+	    }
+	} else {
+	    xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "VBE module not loaded.\n");
+	}
+    }
+    if (xf86ServerIsExiting()) {
+	if (pATI->pVBE) vbeFree(pATI->pVBE);
+	if (pATI->pInt10) xf86FreeInt10(pATI->pInt10);
+    }
+}
+
+#endif /* TV_OUT */
+
 /*
  * ATIModeSet --
  *
@@ -1165,6 +1285,14 @@
     /* Reset hardware cursor caching */
     pATI->CursorXOffset = pATI->CursorYOffset = (CARD16)(-1);
 
+#ifdef TV_OUT
+
+    /* Set VBE mode for TV-Out */
+    if (pATI->OptionTvOut /* && pATI->tvActive */)
+	ATISetVBEMode(pScreenInfo, pATI, pATIHW);
+
+#endif /* TV_OUT */
+
 #ifndef AVOID_CPIO
 
     /* Restore video memory */
--- xc/programs/Xserver/hw/xfree86/drivers/ati/atioption.c	2004-04-12 07:45:20.000000000 +0300
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/atioption.c	2004-11-20 03:22:57.000000000 +0200
@@ -30,6 +30,28 @@
 #include "radeon_probe.h"
 #include "r128_probe.h"
 
+#ifdef TV_OUT
+
+/*
+ * List of supported TV standard names
+ */
+const char *ATITVStandardNames[ATI_TV_STDS_MAX_VALID+1] = {
+    "NTSC",
+    "PAL",
+    "PAL-M",
+    "PAL-60",
+    "NTSC-J",
+    "PAL-CN",
+    "PAL-N",
+    "Reserved1",
+    "Reserved2",
+    "SCART-PAL",
+    "None",
+    "Invalid"
+};
+
+#endif /* TV_OUT */
+
 /*
  * Recognised XF86Config options.
  */
@@ -76,6 +98,24 @@
 
 #endif /* AVOID_CPIO */
 
+#ifdef TV_OUT
+    {
+        ATI_OPTION_TV_OUT,
+        "tv_out",
+        OPTV_BOOLEAN,
+        {0, },
+        FALSE
+    },
+    {
+        ATI_OPTION_TV_STD,
+        "tv_standard",
+        OPTV_STRING,
+        {0, },
+        FALSE
+    },
+
+#endif /* TV_OUT */
+
 #ifdef XF86DRI
 
     {
--- xc/programs/Xserver/hw/xfree86/drivers/ati/atioption.h	2004-04-12 07:45:20.000000000 +0300
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/atioption.h	2004-11-20 03:22:57.000000000 +0200
@@ -58,6 +58,13 @@
                                                                                                
 #endif /* XF86DRI */
 
+#ifdef TV_OUT
+
+    ATI_OPTION_TV_OUT,
+    ATI_OPTION_TV_STD,
+
+#endif /* TV_OUT */
+
     ATI_OPTION_MMIO_CACHE,
     ATI_OPTION_TEST_MMIO_CACHE,
     ATI_OPTION_PANEL_DISPLAY,
@@ -67,6 +74,30 @@
     ATI_OPTION_SWCURSOR
 } ATIPublicOptionType;
 
+#ifdef TV_OUT
+
+#define ATI_TV_STDS_MAX_VALID   11
+#define ATI_TV_STDS_NAME_MAXLEN 9
+
+typedef enum {
+    ATI_TV_STD_NTSC = 0,
+    ATI_TV_STD_PAL,
+    ATI_TV_STD_PALM,
+    ATI_TV_STD_PAL60,
+    ATI_TV_STD_NTSCJ,
+    ATI_TV_STD_PALCN,
+    ATI_TV_STD_PALN,
+    ATI_TV_STD_RESERVED1, /* NOT usable */
+    ATI_TV_STD_RESERVED2, /* NOT usable */
+    ATI_TV_STD_SCARTPAL,
+    ATI_TV_STD_NONE,      /* OK, means no tv standard change requested */
+    ATI_TV_STD_INVALID    /* Invalid tv standard requested */
+} ATITVStandard;
+
+extern const char          * ATITVStandardNames[];
+
+#endif /* TV_OUT */
+
 extern const OptionInfoRec   ATIPublicOptions[];
 extern const unsigned long   ATIPublicOptionSize;
 
--- xc/programs/Xserver/hw/xfree86/drivers/ati/atipreinit.c	2003-09-12 23:07:15.000000000 +0300
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/atipreinit.c	2004-11-20 03:22:57.000000000 +0200
@@ -597,6 +597,13 @@
 
 #else /* AVOID_CPIO */
 
+#ifdef TV_OUT
+
+    pATI->pVBE = NULL;
+    pATI->pInt10 = NULL;
+
+#endif /* TV_OUT */
+
     /*
      * If there is an ix86-style BIOS, ensure its initialisation entry point
      * has been executed, and retrieve DDC and VBE information from it.
@@ -629,9 +636,17 @@
             if ((pVBE = VBEInit(pInt10Info, pATI->iEntity)))
             {
                 ConfiguredMonitor = vbeDoEDID(pVBE, pDDCModule);
+#ifdef TV_OUT
+		pATI->pInt10 = pInt10Info;
+		pATI->pVBE = pVBE;
+		pVBE = NULL;
+#else
                 vbeFree(pVBE);
+#endif /* TV_OUT */
             }
+#ifndef TV_OUT
             xf86UnloadSubModule(pVBEModule);
+#endif /* TV_OUT */
         }
 
         if (!(flags & PROBE_DETECT))
@@ -654,9 +669,13 @@
         }
     }
 
+#ifndef TV_OUT
     /* De-activate int10 */
     xf86FreeInt10(pInt10Info);
     xf86UnloadSubModule(pInt10Module);
+#else
+    pInt10Info = NULL;
+#endif /* TV_OUT */
 
     if (flags & PROBE_DETECT)
     {
--- xc/programs/Xserver/hw/xfree86/drivers/ati/atiscreen.c	2004-04-12 07:45:20.000000000 +0300
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/atiscreen.c	2004-11-20 03:22:57.000000000 +0200
@@ -45,6 +45,12 @@
 #include "mach64_dri.h"
 #include "mach64_sarea.h"
 
+#ifdef TV_OUT
+
+#include "atichip.h"
+
+#endif /* TV_OUT */
+
 #include "shadowfb.h"
 #include "xf86cmap.h"
 
@@ -549,6 +555,14 @@
     if (serverGeneration == 1)
         xf86ShowUnusedOptions(pScreenInfo->scrnIndex, pScreenInfo->options);
 
+#ifdef TV_OUT
+
+    /* Fix-up TV out after ImpacTV probe */
+    if (pATI->OptionTvOut && pATI->Chip < ATI_CHIP_264GTPRO)
+       ATISwitchMode(0, pScreenInfo->currentMode, 0);
+
+#endif /* TV_OUT */
+
 #ifdef XF86DRI
 
     /* DRI finalization */
--- xc/programs/Xserver/hw/xfree86/drivers/ati/atistruct.h	2004-04-12 07:45:20.000000000 +0300
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/atistruct.h	2004-11-20 03:22:57.000000000 +0200
@@ -46,6 +46,12 @@
  
 #endif /* XF86DRI */
 
+#ifdef TV_OUT
+
+#include "vbe.h"
+
+#endif /* TV_OUT */
+
 #include "xaa.h"
 #include "xf86Cursor.h"
 #include "xf86Pci.h"
@@ -436,6 +442,13 @@
 
 #endif /* AVOID_CPIO */
 
+#ifdef TV_OUT
+
+    CARD8 OptionTvOut;          /* Enable TV out if TV is connected */
+    CARD8 OptionTvStd;          /* Requested TV standard - see ATITVStandard enum in atioption.h */
+
+#endif /* TV_OUT */
+
     CARD8 OptionMMIOCache;      /* Cache MMIO writes */
     CARD8 OptionTestMMIOCache;  /* Test MMIO cache integrity */
     CARD8 OptionPanelDisplay;   /* Prefer CRT over digital panel */
@@ -484,6 +497,13 @@
                                                                                 
 #endif /* XF86DRI */
 
+#ifdef TV_OUT
+    /* TV out */
+    vbeInfoPtr pVBE;
+    xf86Int10InfoPtr pInt10;
+    int vbemode; /* saved text mode */
+    Bool tvActive;
+#endif /* TV_OUT */
 } ATIRec;
 
 #define ATIPTR(_p) ((ATIPtr)((_p)->driverPrivate))
--- xc/programs/Xserver/hw/xfree86/drivers/ati/Imakefile	2004-06-01 19:15:58.000000000 +0300
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/Imakefile	2004-11-20 03:22:57.000000000 +0200
@@ -148,7 +148,24 @@
 
 #endif
 
-DEFINES = $(CPIODEFINES) $(DGADEFINES) $(NONPCIDEFINES) $(DRIDEFINES)
+/* 
+ * TV-out only supported on x86
+ */
+#if ATIAvoidCPIO
+# undef ATITVOut
+# define ATITVOut NO
+#elif defined(i386Architecture)
+# undef ATITVOut
+# define ATITVOut YES
+#endif
+
+#if ATITVOut
+
+TVOUTDEFINES = -DTV_OUT
+
+#endif
+
+DEFINES = $(CPIODEFINES) $(DGADEFINES) $(NONPCIDEFINES) $(DRIDEFINES) $(TVOUTDEFINES)
 
 SRCS1 = ati.c atiadapter.c atibus.c atichip.c atiident.c atioption.c \
         atiprobe.c atividmem.c $(CPIOSRCS1) $(MODSRCS1) \
