/* $XFree86: xc/programs/Xserver/hw/xfree86/accel/s3/s3ELSA.c,v 3.20.2.1 1997/05/06 13:25:40 dawes Exp $ */ /* * s3ELSA.c * * compile standalone program with * rm -f s3ELSA.o make DEFINES=-DELSA_MAIN "LDLIBS=../../os-support/libxf86_os.a" s3ELSA rm -f s3ELSA.o * * */ /* $XConsortium: s3ELSA.c /main/10 1996/10/28 04:55:10 kaleb $ */ #ifdef linux #include #endif #include "s3.h" #include "s3ELSA.h" #include "xf86_OSlib.h" #ifdef ELSA_MAIN #include #ifdef linux #include #endif /* linux */ #ifndef SVR4 #include #endif /* SVR4 */ #ifdef xalloc #undef xalloc #endif #define xalloc(_p) malloc(_p) #ifdef xrealloc #undef xrealloc #endif #define xrealloc(_o,_s) realloc(_o,_s) #ifdef xfree #undef xfree #endif #define xfree(_p) free(_p) #endif /* ELSA_MAIN */ #define BIOS_BSIZE 512 #define BIOS_BASE 0xc0000 elsa_board_types_t elsa_board_types[] = { { ELSA_WINNER_1000, "ELSA Winner 1000", 0 }, { ELSA_WINNER_1000VL, "ELSA Winner 1000VL", 0 }, { ELSA_WINNER_1000PCI, "ELSA Winner 1000PCI", 0 }, { ELSA_WINNER_1000ISA, "ELSA Winner 1000ISA", 0 }, { ELSA_WINNER_2000, "ELSA Winner 2000", 0 }, { ELSA_WINNER_2000VL, "ELSA Winner 2000VL", 0 }, { ELSA_WINNER_2000PCI, "ELSA Winner 2000PCI", 0 }, { ELSA_WINNER_1000PRO, "ELSA Winner 1000PRO", 0 }, { ELSA_WINNER_1000PRO_TRIO32,"ELSA Winner 1000PRO Trio32", 0 }, { ELSA_WINNER_1000PRO_TRIO64,"ELSA Winner 1000PRO Trio64", 0 }, { ELSA_WINNER_1000AVI, "ELSA Winner 1000AVI", 0 }, { ELSA_WINNER_1000PRO_X, "ELSA Winner 1000PRO/X", 0 }, { ELSA_WINNER_2000PRO, "ELSA Winner 2000PRO", 0 }, { ELSA_WINNER_2000PRO_X, "ELSA Winner 2000PRO/X", 0 }, { ELSA_WINNER_2000AVI, "ELSA Winner 2000AVI", 0 }, { ELSA_WINNER_2000PRO_X8, "ELSA Winner 2000PRO/X-8", 0 }, { ELSA_GLORIA_4, "ELSA Gloria-4", 0 }, { ELSA_GLORIA_8, "ELSA Gloria-8", 0 }, { 0, 0, 0 } }; static __inline__ void shift_out(int b) { int i,j; outb(0x3d4,0x5c); i = (inb(0x3d5) & 0xaf) | ((b)?0x10:0x00); j = i; outb(0x3d5,j); outb(0x3d5,j); outb(0x3d5,j); outb(0x3d5,j); j = i | 0x40; outb(0x3d5,j); outb(0x3d5,j); outb(0x3d5,j); outb(0x3d5,j); } static __inline__ int shift_in() { int i,j; outb(0x3d4,0x5c); i = inb(0x3d5) & 0xaf; j = i; outb(0x3d5,j); outb(0x3d5,j); outb(0x3d5,j); outb(0x3d5,j); j = i | 0x40; outb(0x3d5,j); outb(0x3d5,j); outb(0x3d5,j); outb(0x3d5,j); return (inb(0x3c2) & 0x10) != 0; } static int read_eeprom_byte(int r) { int i,j; outb(0x3d4,0x5c); i = inb(0x3d5) | 0x20; outb(0x3d5,i); outb(0x3d5,i); outb(0x3d5,i); outb(0x3d5,i); shift_out(1); shift_out(1); shift_out(0); for(i=5; i>=0; i--) shift_out((r>>i) & 1); #if 0 shift_out(0); #endif j=0; for(i=0; i<16; i++) j = (j<<1) | shift_in(); outb(0x3d4,0x5c); i = inb(0x3d5) & ~0x20; outb(0x3d5,i); outb(0x3d5,i); outb(0x3d5,i); outb(0x3d5,i); return j; } static int read_eeprom_data(unsigned short **pdata) { int i; int sr01, cr45, cr50, cr55, cr5c; int ndata=6; unsigned short *data; elsa_eeprom_data_t *eedata; #ifdef ELSA_MAIN #ifdef linux iopl(3); #endif #endif outb(0x3d4,0x38); outb(0x3d5,0x48); outb(0x3d4,0x39); outb(0x3d5,0xa5); outb(0x3c4,0x01); sr01 = inb(0x3c5); outb(0x3d4,0x45); cr45 = inb(0x3d5); outb(0x3d4,0x50); cr50 = inb(0x3d5); outb(0x3d4,0x55); cr55 = inb(0x3d5); outb(0x3d4,0x5c); cr5c = inb(0x3d5); outb(0x3c4,0x01); i = inb(0x3c5) | 0x20; outb(0x3c5,i); outb(0x3d4,0x45); i = inb(0x3d5) & ~0x20; outb(0x3d5,i); outb(0x3d4,0x50); i = inb(0x3d5) & ~0x04; outb(0x3d5,i); outb(0x3d4,0x55); i = inb(0x3d5) & ~0x20; outb(0x3d5,i); outb(0x3d4,0x5c); i = inb(0x3d5) | 0x80; outb(0x3d5,i); outb(0x3d5,i); outb(0x3d5,i); outb(0x3d5,i); for(i=0; i<64; i++) shift_out(0); data = (unsigned short*) xalloc(ndata*sizeof(unsigned short)); for (i=0; iwnr_type == ('S' | '3'<<8)) { if (eedata->eeprom_size > ndata) { ndata = eedata->eeprom_size; data = (unsigned short*) xrealloc(data, ndata*sizeof(unsigned short)); for (; iwnr_type == ('S' | '3'<<8)) { *pdata = data; } else { xfree(data); ndata = -1; } return ndata; } static int calc_crc16(int ndata, unsigned short *data) { int i,j,s,crc16; unsigned short d; crc16 = 0; for(i=1; i>1) + (crc16>>14) + (crc16>>15) + d + 1; crc16 = (crc16<<1) | (s&1); d >>= 1; } } return crc16; } static int check_ELSA_bios(int BIOSbase) { unsigned char bios[BIOS_BSIZE]; char *match = " ELSA GmbH"; int i,l; if (xf86ReadBIOS(BIOSbase, 0, bios, BIOS_BSIZE) != BIOS_BSIZE) return -1; if ((bios[0] != 0x55) || (bios[1] != 0xaa)) return -2; l = strlen(match); for (i=0; icrc16 == crc16) printf("CRC ok (%04x)\n",crc16); else printf("CRC not ok (%04x != %04x)\n",eedata->crc16,crc16); printf("Chip type %s\n" ,(eedata->wnr_type == 'S' | '3'<<8) ? "S3" : "unknown"); for (i=0; elsa_board_types[i].code; i++) if (elsa_board_types[i].code == eedata->board_code) break; if (elsa_board_types[i].code) printf("%s\n",elsa_board_types[i].name); else printf("unknown ELSA board code %x, please report\n", eedata->board_code); serno = (eedata->serno_h<<16) | eedata->serno_l; printf("Ser.No. %c-%04ld.%03ld.%03ld\n", (char)('A' + ((serno>>27) & 0x0f)), ((serno>>17) & 0x3ff) | ((serno>>21) & 0x400), (serno & 0x1ffff) / 1000, (serno & 0x1ffff) % 1000); printf("max pixel clock %7.3f MHz\n" ,(eedata->max_pixclock,eedata->max_pixclock*4)/1000.0); printf("max memory clock %7.3f MHz\n" ,(eedata->max_memclock,eedata->max_memclock*4)/1000.0); printf("monitor size %d %d\n",eedata->xsize,eedata->ysize); printf("software version %d\n",eedata->sw_vers); printf("hardware config %d\n",eedata->hw_conf); for (i= 26; i0 ? BIOSbase : BIOS_BASE) <= 0) { return -1; } ndata = read_eeprom_data(&data); if (ndata<0) return -2; crc16 = calc_crc16(ndata,data); eedata = (elsa_eeprom_data_t *) data; if (eedata->crc16 != crc16) { xfree(data); return -3; } if (eedata->wnr_type != ('S' | '3'<<8)) { xfree(data); return -4; } for (i=0; elsa_board_types[i].code; i++) if (elsa_board_types[i].code == eedata->board_code) break; if (pcard) { *pcard = (char*) xalloc(80); if (elsa_board_types[i].code) sprintf(*pcard,"%s detected",elsa_board_types[i].name); else sprintf(*pcard,"unknown ELSA Winner board code %04x detected, please report\n" , eedata->board_code); } if (modes) { char *p; p = *modes = (char*) xalloc(80 * ((ndata-9-26)/9 +1)); *p = '\0'; for (i= 26; iserno_h<<16) | eedata->serno_l; sprintf(*pserno,"%c-%04ld.%03ld.%03ld", (char)('A' + ((serno>>27) & 0x0f)), ((serno>>17) & 0x3ff) | ((serno>>21) & 0x400), (serno & 0x1ffff) / 1000, (serno & 0x1ffff) % 1000); } if (max_pix_clock) *max_pix_clock = eedata->max_pixclock * 4; if (max_mem_clock) *max_mem_clock = eedata->max_memclock * 4; if (hwconfig) *hwconfig = eedata->hw_conf; i = eedata->board_code; xfree(data); return i; } #endif