1340e3fbdSmrg/* 2340e3fbdSmrg * Copyright 2001 Ani Joshi <ajoshi@unixbox.com> 3340e3fbdSmrg * 4340e3fbdSmrg * XFree86 4.x driver for S3 chipsets 5340e3fbdSmrg * 6340e3fbdSmrg * 7340e3fbdSmrg * Permission to use, copy, modify, distribute, and sell this software and its 8340e3fbdSmrg * documentation for any purpose is hereby granted without fee, provided that 9340e3fbdSmrg * the above copyright notice appear in all copies and that both that copyright 10340e3fbdSmrg * notice and this permission notice appear in supporting documentation and 11340e3fbdSmrg * that the name of Ani Joshi not be used in advertising or 12340e3fbdSmrg * publicity pertaining to distribution of the software without specific, 13340e3fbdSmrg * written prior permission. Ani Joshi makes no representations 14340e3fbdSmrg * about the suitability of this software for any purpose. It is provided 15340e3fbdSmrg * "as-is" without express or implied warranty. 16340e3fbdSmrg * 17340e3fbdSmrg * ANI JOSHI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 18340e3fbdSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 19340e3fbdSmrg * EVENT SHALL ANI JOSHI BE LIABLE FOR ANY SPECIAL, INDIRECT OR 20340e3fbdSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21340e3fbdSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 22340e3fbdSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 23340e3fbdSmrg * PERFORMANCE OF THIS SOFTWARE. 24340e3fbdSmrg * 25340e3fbdSmrg * 26340e3fbdSmrg */ 27340e3fbdSmrg 28340e3fbdSmrg#ifdef HAVE_CONFIG_H 29340e3fbdSmrg#include "config.h" 30340e3fbdSmrg#endif 31340e3fbdSmrg 32340e3fbdSmrg#include "xf86.h" 33340e3fbdSmrg#include "xf86_OSproc.h" 34340e3fbdSmrg 35340e3fbdSmrg#include "compiler.h" 36340e3fbdSmrg 37340e3fbdSmrg#include "IBM.h" 38340e3fbdSmrg 39340e3fbdSmrg#include "s3.h" 40340e3fbdSmrg 41340e3fbdSmrg 42340e3fbdSmrg#define IBMRGB_WRITE_ADDR 0x3C8 /* CR55 low bit == 0 */ 43340e3fbdSmrg#define IBMRGB_RAMDAC_DATA 0x3C9 /* CR55 low bit == 0 */ 44340e3fbdSmrg#define IBMRGB_PIXEL_MASK 0x3C6 /* CR55 low bit == 0 */ 45340e3fbdSmrg#define IBMRGB_READ_ADDR 0x3C7 /* CR55 low bit == 0 */ 46340e3fbdSmrg#define IBMRGB_INDEX_LOW 0x3C8 /* CR55 low bit == 1 */ 47340e3fbdSmrg#define IBMRGB_INDEX_HIGH 0x3C9 /* CR55 low bit == 1 */ 48340e3fbdSmrg#define IBMRGB_INDEX_DATA 0x3C6 /* CR55 low bit == 1 */ 49340e3fbdSmrg#define IBMRGB_INDEX_CONTROL 0x3C7 /* CR55 low bit == 1 */ 50340e3fbdSmrg 51340e3fbdSmrg 52340e3fbdSmrgstatic void S3OutIBMRGBIndReg(ScrnInfoPtr pScrn, CARD32 reg, 53340e3fbdSmrg unsigned char mask, unsigned char data) 54340e3fbdSmrg{ 55340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 56340e3fbdSmrg unsigned char tmp, tmp2 = 0x00; 57340e3fbdSmrg int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 58340e3fbdSmrg 59340e3fbdSmrg outb(vgaCRIndex, 0x55); 60340e3fbdSmrg tmp = inb(vgaCRReg) & 0xfc; 61340e3fbdSmrg outb(vgaCRReg, tmp | 0x01); 62340e3fbdSmrg 63340e3fbdSmrg outb(IBMRGB_INDEX_LOW, reg); 64340e3fbdSmrg 65340e3fbdSmrg if (mask != 0x00) 66340e3fbdSmrg tmp2 = inb(IBMRGB_INDEX_DATA) & mask; 67340e3fbdSmrg outb(IBMRGB_INDEX_DATA, tmp2 | data); 68340e3fbdSmrg 69340e3fbdSmrg outb(vgaCRIndex, 0x55); 70340e3fbdSmrg outb(vgaCRReg, tmp); 71340e3fbdSmrg} 72340e3fbdSmrg 73340e3fbdSmrg 74340e3fbdSmrgstatic unsigned char S3InIBMRGBIndReg(ScrnInfoPtr pScrn, CARD32 reg) 75340e3fbdSmrg{ 76340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 77340e3fbdSmrg unsigned char tmp, ret; 78340e3fbdSmrg int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 79340e3fbdSmrg 80340e3fbdSmrg outb(vgaCRIndex, 0x55); 81340e3fbdSmrg tmp = inb(vgaCRReg) & 0xfc; 82340e3fbdSmrg outb(vgaCRReg, tmp | 0x01); 83340e3fbdSmrg 84340e3fbdSmrg outb(IBMRGB_INDEX_LOW, reg); 85340e3fbdSmrg ret = inb(IBMRGB_INDEX_DATA); 86340e3fbdSmrg 87340e3fbdSmrg outb(vgaCRIndex, 0x55); 88340e3fbdSmrg outb(vgaCRReg, tmp); 89340e3fbdSmrg 90340e3fbdSmrg return ret; 91340e3fbdSmrg} 92340e3fbdSmrg 93340e3fbdSmrg 94340e3fbdSmrgstatic void S3IBMWriteAddress(ScrnInfoPtr pScrn, CARD32 index) 95340e3fbdSmrg{ 96340e3fbdSmrg outb(IBMRGB_WRITE_ADDR, index); 97340e3fbdSmrg} 98340e3fbdSmrg 99340e3fbdSmrgstatic void S3IBMWriteData(ScrnInfoPtr pScrn, unsigned char data) 100340e3fbdSmrg{ 101340e3fbdSmrg outb(IBMRGB_INDEX_DATA, data); 102340e3fbdSmrg} 103340e3fbdSmrg 104340e3fbdSmrgstatic void S3IBMReadAddress(ScrnInfoPtr pScrn, CARD32 index) 105340e3fbdSmrg{ 106340e3fbdSmrg outb(IBMRGB_READ_ADDR, index); 107340e3fbdSmrg} 108340e3fbdSmrg 109340e3fbdSmrgstatic unsigned char S3IBMReadData(ScrnInfoPtr pScrn) 110340e3fbdSmrg{ 111340e3fbdSmrg return inb(IBMRGB_RAMDAC_DATA); 112340e3fbdSmrg} 113340e3fbdSmrg 114340e3fbdSmrg 115340e3fbdSmrgBool S3ProbeIBMramdac(ScrnInfoPtr pScrn) 116340e3fbdSmrg{ 117340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 118340e3fbdSmrg 119340e3fbdSmrg if (pS3->Chipset != PCI_CHIP_968) 120340e3fbdSmrg return FALSE; 121340e3fbdSmrg 122340e3fbdSmrg pS3->RamDacRec = RamDacCreateInfoRec(); 123340e3fbdSmrg pS3->RamDacRec->ReadDAC = S3InIBMRGBIndReg; 124340e3fbdSmrg pS3->RamDacRec->WriteDAC = S3OutIBMRGBIndReg; 125340e3fbdSmrg pS3->RamDacRec->ReadAddress = S3IBMReadAddress; 126340e3fbdSmrg pS3->RamDacRec->WriteAddress = S3IBMWriteAddress; 127340e3fbdSmrg pS3->RamDacRec->ReadData = S3IBMReadData; 128340e3fbdSmrg pS3->RamDacRec->WriteData = S3IBMWriteData; 129340e3fbdSmrg pS3->RamDacRec->LoadPalette = NULL; 130340e3fbdSmrg 131340e3fbdSmrg if (!RamDacInit(pScrn, pS3->RamDacRec)) { 132340e3fbdSmrg RamDacDestroyInfoRec(pS3->RamDacRec); 133340e3fbdSmrg xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RamDacInit failed\n"); 134340e3fbdSmrg return FALSE; 135340e3fbdSmrg } 136340e3fbdSmrg 137340e3fbdSmrg pS3->RamDac = IBMramdacProbe(pScrn, S3IBMRamdacs); 138340e3fbdSmrg if (pS3->RamDac) 139340e3fbdSmrg return TRUE; 140340e3fbdSmrg 141340e3fbdSmrg return FALSE; 142340e3fbdSmrg} 143340e3fbdSmrg 144340e3fbdSmrgstatic void S3ProgramIBMRGBClock(ScrnInfoPtr pScrn, int clk, unsigned char m, 145340e3fbdSmrg unsigned char n, unsigned char df) 146340e3fbdSmrg{ 147340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_misc_clock, ~1, 1); 148340e3fbdSmrg 149340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_m0+2*clk, 0, (df<<6)|(m&0x3f)); 150340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_n0+2*clk, 0, n); 151340e3fbdSmrg 152340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_pll_ctrl2, 0xf0, clk); 153340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_pll_ctrl1, 0xf8, 3); 154340e3fbdSmrg} 155340e3fbdSmrg 156340e3fbdSmrg 157340e3fbdSmrgstatic void S3IBMRGBSetClock(ScrnInfoPtr pScrn, long freq, int clk, long dacspeed, 158340e3fbdSmrg long fref) 159340e3fbdSmrg{ 1601d3211a3Smrg volatile double ffreq, ffref; 161340e3fbdSmrg volatile int df, n, m, max_n, min_df; 162340e3fbdSmrg volatile int best_m=69, best_n=17, best_df=0; 163340e3fbdSmrg volatile double diff, mindiff; 164340e3fbdSmrg 165340e3fbdSmrg#define FREQ_MIN 16250 166340e3fbdSmrg#define FREQ_MAX dacspeed 167340e3fbdSmrg 168340e3fbdSmrg if (freq < FREQ_MIN) 169340e3fbdSmrg ffreq = FREQ_MIN / 1000.0; 170340e3fbdSmrg else if (freq > FREQ_MAX) 171340e3fbdSmrg ffreq = FREQ_MAX / 1000.0; 172340e3fbdSmrg else 173340e3fbdSmrg ffreq = freq / 1000.0; 174340e3fbdSmrg 175340e3fbdSmrg ffref = fref / 1e3; 176340e3fbdSmrg 177340e3fbdSmrg ffreq /= ffref; 178340e3fbdSmrg ffreq *= 16; 179340e3fbdSmrg mindiff = ffreq; 180340e3fbdSmrg 181340e3fbdSmrg if (freq <= dacspeed/4) 182340e3fbdSmrg min_df = 0; 183340e3fbdSmrg else if (freq <= dacspeed/2) 184340e3fbdSmrg min_df = 1; 185340e3fbdSmrg else 186340e3fbdSmrg min_df = 2; 187340e3fbdSmrg 188340e3fbdSmrg for (df=0; df<4; df++) { 189340e3fbdSmrg ffreq /= 2; 190340e3fbdSmrg mindiff /= 2; 191340e3fbdSmrg if (df < min_df) 192340e3fbdSmrg continue; 193340e3fbdSmrg 194340e3fbdSmrg if (df < 3) 195340e3fbdSmrg max_n = fref / 1000 / 2; 196340e3fbdSmrg else 197340e3fbdSmrg max_n = fref / 1000; 198340e3fbdSmrg if (max_n > 31) 199340e3fbdSmrg max_n = 31; 200340e3fbdSmrg 201340e3fbdSmrg for (n=2; n <= max_n; n++) { 202340e3fbdSmrg m = (int)(ffreq * n + 0.5) - 65; 203340e3fbdSmrg if (m < 0) 204340e3fbdSmrg m = 0; 205340e3fbdSmrg else if (m > 63) 206340e3fbdSmrg m = 63; 207340e3fbdSmrg diff = (m+65.0)/n-ffreq; 208340e3fbdSmrg if (diff < 0) 209340e3fbdSmrg diff = -diff; 210340e3fbdSmrg if (diff < mindiff) { 211340e3fbdSmrg mindiff = diff; 212340e3fbdSmrg best_n = n; 213340e3fbdSmrg best_m = m; 214340e3fbdSmrg best_df = df; 215340e3fbdSmrg } 216340e3fbdSmrg } 217340e3fbdSmrg } 218340e3fbdSmrg 219340e3fbdSmrg S3ProgramIBMRGBClock(pScrn, clk, best_m, best_n, best_df); 220340e3fbdSmrg} 221340e3fbdSmrg 222340e3fbdSmrgvoid S3IBMRGB_Restore(ScrnInfoPtr pScrn) 223340e3fbdSmrg{ 224340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 225340e3fbdSmrg S3RegPtr restore = &pS3->SavedRegs; 226340e3fbdSmrg int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 227340e3fbdSmrg int i; 228340e3fbdSmrg 229340e3fbdSmrg for(i=0; i<0x100; i++) 230340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, i, 0, restore->dacregs[i]); 231340e3fbdSmrg 232340e3fbdSmrg outb(vgaCRIndex, 0x22); 233340e3fbdSmrg outb(vgaCRReg, restore->dacregs[0x100]); 234340e3fbdSmrg} 235340e3fbdSmrg 236340e3fbdSmrg 237340e3fbdSmrgvoid S3IBMRGB_Save(ScrnInfoPtr pScrn) 238340e3fbdSmrg{ 239340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 240340e3fbdSmrg S3RegPtr save = &pS3->SavedRegs; 241340e3fbdSmrg int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 242340e3fbdSmrg int i; 243340e3fbdSmrg 244340e3fbdSmrg for (i=0; i<0x100; i++) 245340e3fbdSmrg save->dacregs[i] = S3InIBMRGBIndReg(pScrn, i); 246340e3fbdSmrg 247340e3fbdSmrg outb(vgaCRIndex, 0x22); 248340e3fbdSmrg save->dacregs[0x100] = inb(vgaCRReg); 249340e3fbdSmrg} 250340e3fbdSmrg 251340e3fbdSmrg 252340e3fbdSmrgvoid S3IBMRGB_PreInit(ScrnInfoPtr pScrn) 253340e3fbdSmrg{ 254340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 255340e3fbdSmrg int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 256340e3fbdSmrg unsigned char cr55, tmp; 257340e3fbdSmrg 258340e3fbdSmrg outb(vgaCRIndex, 0x43); 259340e3fbdSmrg tmp = inb(vgaCRReg); 260340e3fbdSmrg outb(vgaCRReg, tmp & ~0x02); 261340e3fbdSmrg 262340e3fbdSmrg outb(vgaCRIndex, 0x55); 263340e3fbdSmrg cr55 = inb(vgaCRReg); 264340e3fbdSmrg outb(vgaCRReg, (cr55 & ~0x03) | 0x01); /* set rs2 */ 265340e3fbdSmrg 266340e3fbdSmrg tmp = inb(IBMRGB_INDEX_CONTROL); 267340e3fbdSmrg outb(IBMRGB_INDEX_CONTROL, tmp & ~1); 268340e3fbdSmrg outb(IBMRGB_INDEX_HIGH, 0); 269340e3fbdSmrg 270340e3fbdSmrg outb(vgaCRIndex, 0x55); 271340e3fbdSmrg outb(vgaCRReg, cr55 & ~0x03); 272340e3fbdSmrg 273340e3fbdSmrg { 274340e3fbdSmrg int m, n, df, mclk=0; 275340e3fbdSmrg 276340e3fbdSmrg m = S3InIBMRGBIndReg(pScrn, IBMRGB_sysclk_vco_div); 277340e3fbdSmrg n = S3InIBMRGBIndReg(pScrn, IBMRGB_sysclk_ref_div) & 0x1f; 278340e3fbdSmrg df = m >> 6; 279340e3fbdSmrg m &= 0x3f; 280340e3fbdSmrg if (!n) { 281340e3fbdSmrg m = 0; 282340e3fbdSmrg n = 1; 283340e3fbdSmrg } 284340e3fbdSmrg mclk = ((pS3->RefClock*100 * (m+65)) / n / (8 >> df) + 50) / 100; 285340e3fbdSmrg pS3->mclk = mclk; 286340e3fbdSmrg xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MCLK %1.3f MHz\n", 287340e3fbdSmrg mclk / 1000.0); 288340e3fbdSmrg } 289340e3fbdSmrg} 290340e3fbdSmrg 291340e3fbdSmrg 292340e3fbdSmrgvoid S3IBMRGB_Init(ScrnInfoPtr pScrn, DisplayModePtr mode) 293340e3fbdSmrg{ 294340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 295340e3fbdSmrg unsigned char tmp, blank; 296340e3fbdSmrg int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 297340e3fbdSmrg 298340e3fbdSmrg S3IBMRGBSetClock(pScrn, mode->Clock, 2, pS3->MaxClock, 299340e3fbdSmrg pS3->RefClock); 300340e3fbdSmrg 301340e3fbdSmrg outb(0x3c4, 1); 302340e3fbdSmrg blank = inb(0x3c5); 303340e3fbdSmrg outb(0x3c5, blank | 0x20); 304340e3fbdSmrg 305340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_misc_clock, 0xf0, 0x03); 306340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_sync, 0, 0); 307340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_hsync_pos, 0, 0); 308340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_pwr_mgmt, 0, 0); 309340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_dac_op, ~8, 0); 310340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_dac_op, ~2, 2); 311340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_pal_ctrl, 0, 0); 312340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_misc1, ~0x43, 1); 313340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_misc2, 0, 0x47); 314340e3fbdSmrg 315340e3fbdSmrg outb(vgaCRIndex, 0x22); 316340e3fbdSmrg tmp = inb(vgaCRReg); 317340e3fbdSmrg if (pS3->s3Bpp == 1) 318340e3fbdSmrg outb(vgaCRReg, tmp | 8); 319340e3fbdSmrg else 320340e3fbdSmrg outb(vgaCRReg, tmp & ~8); 321340e3fbdSmrg 322340e3fbdSmrg outb(vgaCRIndex, 0x65); 323340e3fbdSmrg outb(vgaCRReg, 0x00); /* ! 528 */ 324340e3fbdSmrg 325340e3fbdSmrg outb(vgaCRIndex, 0x40); 326340e3fbdSmrg outb(vgaCRReg, 0x11); 327340e3fbdSmrg outb(vgaCRIndex, 0x55); 328340e3fbdSmrg outb(vgaCRReg, 0x00); 329340e3fbdSmrg 330340e3fbdSmrg switch (pScrn->depth) { 331340e3fbdSmrg case 8: 332340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_pix_fmt, 0xf8, 3); 333340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_8bpp, 0, 0); 334340e3fbdSmrg break; 335340e3fbdSmrg case 15: 336340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_pix_fmt, 0xf8, 4); 337340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_16bpp, 0, 0xc0); 338340e3fbdSmrg break; 339340e3fbdSmrg case 16: 340340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_pix_fmt, 0xf8, 4); 341340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_16bpp, 0, 0xc2); 342340e3fbdSmrg break; 343340e3fbdSmrg } 344340e3fbdSmrg 345340e3fbdSmrg outb(vgaCRIndex, 0x66); 346340e3fbdSmrg tmp = inb(vgaCRReg) & 0xf8; 347340e3fbdSmrg outb(vgaCRReg, tmp); 348340e3fbdSmrg 349340e3fbdSmrg outb(vgaCRIndex, 0x58); 350340e3fbdSmrg tmp = (inb(vgaCRReg) & 0xbf) | 0x40; 351340e3fbdSmrg outb(vgaCRReg, tmp); 352340e3fbdSmrg 353340e3fbdSmrg outb(vgaCRIndex, 0x67); 354340e3fbdSmrg outb(vgaCRReg, 0x11); 355340e3fbdSmrg 356340e3fbdSmrg switch (pScrn->bitsPerPixel) { 357340e3fbdSmrg case 8: 358340e3fbdSmrg tmp = 0x21; 359340e3fbdSmrg break; 360340e3fbdSmrg case 16: 361340e3fbdSmrg tmp = 0x10; 362340e3fbdSmrg break; 363340e3fbdSmrg } 364340e3fbdSmrg outb(vgaCRIndex, 0x6d); 365340e3fbdSmrg outb(vgaCRReg, tmp); 366340e3fbdSmrg 367340e3fbdSmrg outb(0x3c4, 1); 368340e3fbdSmrg outb(0x3c5, blank); 369340e3fbdSmrg} 370340e3fbdSmrg 371340e3fbdSmrg 372340e3fbdSmrg/* hardware cursor */ 373340e3fbdSmrg 374340e3fbdSmrgstatic void S3IBMRGBSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) 375340e3fbdSmrg{ 376340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 377340e3fbdSmrg int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 378340e3fbdSmrg unsigned char tmp; 379340e3fbdSmrg 380340e3fbdSmrg /* unlock sys regs */ 381340e3fbdSmrg outb(vgaCRIndex, 0x39); 382340e3fbdSmrg outb(vgaCRReg, 0xa5); 383340e3fbdSmrg 384340e3fbdSmrg outb(vgaCRIndex, 0x55); 385340e3fbdSmrg tmp = inb(vgaCRReg) & 0xfc; 386340e3fbdSmrg outb(vgaCRReg, tmp | 0x01); 387340e3fbdSmrg 388340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col1_r); 389340e3fbdSmrg outb(IBMRGB_INDEX_DATA, (bg & 0x00ff0000) >> 16); 390340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col1_g); 391340e3fbdSmrg outb(IBMRGB_INDEX_DATA, (bg & 0x0000ff00) >> 8); 392340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col1_b); 393340e3fbdSmrg outb(IBMRGB_INDEX_DATA, (bg & 0x000000ff)); 394340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col2_r); 395340e3fbdSmrg outb(IBMRGB_INDEX_DATA, (fg & 0x00ff0000) >> 16); 396340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col2_g); 397340e3fbdSmrg outb(IBMRGB_INDEX_DATA, (fg & 0x0000ff00) >> 8); 398340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col2_b); 399340e3fbdSmrg outb(IBMRGB_INDEX_DATA, (fg & 0x000000ff)); 400340e3fbdSmrg 401340e3fbdSmrg outb(vgaCRReg, tmp); 402340e3fbdSmrg} 403340e3fbdSmrg 404340e3fbdSmrg 405340e3fbdSmrgstatic void S3IBMRGBSetCursorPosition(ScrnInfoPtr pScrn, int x, int y) 406340e3fbdSmrg{ 407340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 408340e3fbdSmrg int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 409340e3fbdSmrg unsigned char tmp; 410340e3fbdSmrg 411340e3fbdSmrg /* unlock sys regs */ 412340e3fbdSmrg outb(vgaCRIndex, 0x39); 413340e3fbdSmrg outb(vgaCRReg, 0xa5); 414340e3fbdSmrg 415340e3fbdSmrg outb(vgaCRIndex, 0x55); 416340e3fbdSmrg tmp = inb(vgaCRReg) & 0xfc; 417340e3fbdSmrg outb(vgaCRReg, tmp | 0x01); 418340e3fbdSmrg 419340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_xl); 420340e3fbdSmrg outb(IBMRGB_INDEX_DATA, x); 421340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_xh); 422340e3fbdSmrg outb(IBMRGB_INDEX_DATA, x >> 8); 423340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_yl); 424340e3fbdSmrg outb(IBMRGB_INDEX_DATA, y); 425340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_yh); 426340e3fbdSmrg outb(IBMRGB_INDEX_DATA, y >> 8); 427340e3fbdSmrg 428340e3fbdSmrg outb(vgaCRReg, tmp); 429340e3fbdSmrg} 430340e3fbdSmrg 431340e3fbdSmrg 432340e3fbdSmrgstatic void S3IBMRGBHideCursor(ScrnInfoPtr pScrn) 433340e3fbdSmrg{ 434340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 435340e3fbdSmrg int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 436340e3fbdSmrg 437340e3fbdSmrg /* unlock sys regs */ 438340e3fbdSmrg outb(vgaCRIndex, 0x39); 439340e3fbdSmrg outb(vgaCRReg, 0xa5); 440340e3fbdSmrg 441340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_curs, ~3, 0x00); 442340e3fbdSmrg} 443340e3fbdSmrg 444340e3fbdSmrg 445340e3fbdSmrgstatic void S3IBMRGBShowCursor(ScrnInfoPtr pScrn) 446340e3fbdSmrg{ 447340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 448340e3fbdSmrg int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 449340e3fbdSmrg unsigned char tmp; 450340e3fbdSmrg 451340e3fbdSmrg /* unlock sys regs */ 452340e3fbdSmrg outb(vgaCRIndex, 0x39); 453340e3fbdSmrg outb(vgaCRReg, 0xa5); 454340e3fbdSmrg 455340e3fbdSmrg outb(vgaCRIndex, 0x55); 456340e3fbdSmrg tmp = (inb(vgaCRReg) & 0xdf) | 0x20; 457340e3fbdSmrg outb(vgaCRReg, tmp); 458340e3fbdSmrg 459340e3fbdSmrg outb(vgaCRIndex, 0x45); 460340e3fbdSmrg tmp = inb(vgaCRReg) & ~0x20; 461340e3fbdSmrg outb(vgaCRReg, tmp); 462340e3fbdSmrg 463340e3fbdSmrg S3OutIBMRGBIndReg(pScrn, IBMRGB_curs, 0, 0x27); 464340e3fbdSmrg} 465340e3fbdSmrg 466340e3fbdSmrg 467340e3fbdSmrgstatic void S3IBMRGBLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image) 468340e3fbdSmrg{ 469340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 470340e3fbdSmrg int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg; 471340e3fbdSmrg unsigned char tmp, tmp2; 472340e3fbdSmrg register int i; 473340e3fbdSmrg 474340e3fbdSmrg /* unlock sys regs */ 475340e3fbdSmrg outb(vgaCRIndex, 0x39); 476340e3fbdSmrg outb(vgaCRReg, 0xa5); 477340e3fbdSmrg 478340e3fbdSmrg outb(vgaCRIndex, 0x55); 479340e3fbdSmrg tmp = inb(vgaCRReg) & 0xfc; 480340e3fbdSmrg outb(vgaCRReg, tmp | 0x01); 481340e3fbdSmrg 482340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_hot_x); 483340e3fbdSmrg outb(IBMRGB_INDEX_DATA, 0); 484340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_hot_y); 485340e3fbdSmrg outb(IBMRGB_INDEX_DATA, 0); 486340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_xl); 487340e3fbdSmrg outb(IBMRGB_INDEX_DATA, 0xff); 488340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_xh); 489340e3fbdSmrg outb(IBMRGB_INDEX_DATA, 0x7f); 490340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_yl); 491340e3fbdSmrg outb(IBMRGB_INDEX_DATA, 0xff); 492340e3fbdSmrg outb(IBMRGB_INDEX_LOW, IBMRGB_curs_yh); 493340e3fbdSmrg outb(IBMRGB_INDEX_DATA, 0x7f); 494340e3fbdSmrg 495340e3fbdSmrg tmp2 = inb(IBMRGB_INDEX_CONTROL) & 0xfe; 496340e3fbdSmrg outb(IBMRGB_INDEX_CONTROL, tmp2 | 1); /* enable auto increment */ 497340e3fbdSmrg 498340e3fbdSmrg outb(IBMRGB_INDEX_HIGH, (unsigned char) (IBMRGB_curs_array >> 8)); 499340e3fbdSmrg outb(IBMRGB_INDEX_LOW, (unsigned char) (IBMRGB_curs_array)); 500340e3fbdSmrg 501340e3fbdSmrg for (i=0; i<1024; i++) 502340e3fbdSmrg outb(IBMRGB_INDEX_DATA, *image++); 503340e3fbdSmrg 504340e3fbdSmrg outb(IBMRGB_INDEX_HIGH, 0); 505340e3fbdSmrg outb(IBMRGB_INDEX_CONTROL, tmp2); /* disable auto increment */ 506340e3fbdSmrg outb(vgaCRIndex, 0x55); 507340e3fbdSmrg outb(vgaCRReg, tmp); 508340e3fbdSmrg} 509340e3fbdSmrg 510340e3fbdSmrg 511340e3fbdSmrgstatic Bool S3IBMRGBUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) 512340e3fbdSmrg{ 513b27e1915Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 514340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 515340e3fbdSmrg return (pS3->hwCursor); 516340e3fbdSmrg} 517340e3fbdSmrg 518340e3fbdSmrg 519340e3fbdSmrgBool S3IBMRGB_CursorInit(ScreenPtr pScreen) 520340e3fbdSmrg{ 521b27e1915Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 522340e3fbdSmrg S3Ptr pS3 = S3PTR(pScrn); 523340e3fbdSmrg xf86CursorInfoPtr pCurs; 524340e3fbdSmrg 525340e3fbdSmrg if (!(pCurs = pS3->pCurs = xf86CreateCursorInfoRec())) 526340e3fbdSmrg return FALSE; 527340e3fbdSmrg 528340e3fbdSmrg pCurs->MaxWidth = 64; 529340e3fbdSmrg pCurs->MaxHeight = 64; 530340e3fbdSmrg pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | 531340e3fbdSmrg HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 | 532340e3fbdSmrg HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | 533340e3fbdSmrg HARDWARE_CURSOR_NIBBLE_SWAPPED | 534340e3fbdSmrg HARDWARE_CURSOR_BIT_ORDER_MSBFIRST; 535340e3fbdSmrg 536340e3fbdSmrg pCurs->SetCursorColors = S3IBMRGBSetCursorColors; 537340e3fbdSmrg pCurs->SetCursorPosition = S3IBMRGBSetCursorPosition; 538340e3fbdSmrg pCurs->LoadCursorImage = S3IBMRGBLoadCursorImage; 539340e3fbdSmrg pCurs->HideCursor = S3IBMRGBHideCursor; 540340e3fbdSmrg pCurs->ShowCursor = S3IBMRGBShowCursor; 541340e3fbdSmrg pCurs->UseHWCursor = S3IBMRGBUseHWCursor; 542340e3fbdSmrg 543340e3fbdSmrg return xf86InitCursor(pScreen, pCurs); 544340e3fbdSmrg} 545340e3fbdSmrg 546340e3fbdSmrg 547