/drivers/video/sis/sis_main.c
C | 6893 lines | 5707 code | 912 blank | 274 comment | 1588 complexity | b7a04ec041fc4b313d8bc981fab44fb9 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
Large files files are truncated, but you can click here to view the full file
- /*
- * SiS 300/540/630[S]/730[S],
- * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
- * XGI V3XT/V5/V8, Z7
- * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
- *
- * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the named License,
- * or any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
- *
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
- *
- * Author of (practically wiped) code base:
- * SiS (www.sis.com)
- * Copyright (C) 1999 Silicon Integrated Systems, Inc.
- *
- * See http://www.winischhofer.net/ for more information and updates
- *
- * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
- * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
- *
- */
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/kernel.h>
- #include <linux/spinlock.h>
- #include <linux/errno.h>
- #include <linux/string.h>
- #include <linux/mm.h>
- #include <linux/screen_info.h>
- #include <linux/slab.h>
- #include <linux/fb.h>
- #include <linux/selection.h>
- #include <linux/ioport.h>
- #include <linux/init.h>
- #include <linux/pci.h>
- #include <linux/vmalloc.h>
- #include <linux/capability.h>
- #include <linux/fs.h>
- #include <linux/types.h>
- #include <linux/uaccess.h>
- #include <asm/io.h>
- #ifdef CONFIG_MTRR
- #include <asm/mtrr.h>
- #endif
- #include "sis.h"
- #include "sis_main.h"
- #if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315)
- #warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
- #warning sisfb will not work!
- #endif
- static void sisfb_handle_command(struct sis_video_info *ivideo,
- struct sisfb_cmd *sisfb_command);
- /* ------------------ Internal helper routines ----------------- */
- static void __init
- sisfb_setdefaultparms(void)
- {
- sisfb_off = 0;
- sisfb_parm_mem = 0;
- sisfb_accel = -1;
- sisfb_ypan = -1;
- sisfb_max = -1;
- sisfb_userom = -1;
- sisfb_useoem = -1;
- sisfb_mode_idx = -1;
- sisfb_parm_rate = -1;
- sisfb_crt1off = 0;
- sisfb_forcecrt1 = -1;
- sisfb_crt2type = -1;
- sisfb_crt2flags = 0;
- sisfb_pdc = 0xff;
- sisfb_pdca = 0xff;
- sisfb_scalelcd = -1;
- sisfb_specialtiming = CUT_NONE;
- sisfb_lvdshl = -1;
- sisfb_dstn = 0;
- sisfb_fstn = 0;
- sisfb_tvplug = -1;
- sisfb_tvstd = -1;
- sisfb_tvxposoffset = 0;
- sisfb_tvyposoffset = 0;
- sisfb_nocrt2rate = 0;
- #if !defined(__i386__) && !defined(__x86_64__)
- sisfb_resetcard = 0;
- sisfb_videoram = 0;
- #endif
- }
- /* ------------- Parameter parsing -------------- */
- static void __devinit
- sisfb_search_vesamode(unsigned int vesamode, bool quiet)
- {
- int i = 0, j = 0;
- /* We don't know the hardware specs yet and there is no ivideo */
- if(vesamode == 0) {
- if(!quiet)
- printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
- sisfb_mode_idx = DEFAULT_MODE;
- return;
- }
- vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
- while(sisbios_mode[i++].mode_no[0] != 0) {
- if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
- (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
- if(sisfb_fstn) {
- if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
- sisbios_mode[i-1].mode_no[1] == 0x56 ||
- sisbios_mode[i-1].mode_no[1] == 0x53)
- continue;
- } else {
- if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
- sisbios_mode[i-1].mode_no[1] == 0x5b)
- continue;
- }
- sisfb_mode_idx = i - 1;
- j = 1;
- break;
- }
- }
- if((!j) && !quiet)
- printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
- }
- static void __devinit
- sisfb_search_mode(char *name, bool quiet)
- {
- unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
- int i = 0;
- char strbuf[16], strbuf1[20];
- char *nameptr = name;
- /* We don't know the hardware specs yet and there is no ivideo */
- if(name == NULL) {
- if(!quiet)
- printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
- sisfb_mode_idx = DEFAULT_MODE;
- return;
- }
- if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
- if(!quiet)
- printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
- sisfb_mode_idx = DEFAULT_MODE;
- return;
- }
- if(strlen(name) <= 19) {
- strcpy(strbuf1, name);
- for(i = 0; i < strlen(strbuf1); i++) {
- if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
- }
- /* This does some fuzzy mode naming detection */
- if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
- if((rate <= 32) || (depth > 32)) {
- j = rate; rate = depth; depth = j;
- }
- sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
- nameptr = strbuf;
- sisfb_parm_rate = rate;
- } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
- sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
- nameptr = strbuf;
- } else {
- xres = 0;
- if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
- sprintf(strbuf, "%ux%ux8", xres, yres);
- nameptr = strbuf;
- } else {
- sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
- return;
- }
- }
- }
- i = 0; j = 0;
- while(sisbios_mode[i].mode_no[0] != 0) {
- if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
- if(sisfb_fstn) {
- if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
- sisbios_mode[i-1].mode_no[1] == 0x56 ||
- sisbios_mode[i-1].mode_no[1] == 0x53)
- continue;
- } else {
- if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
- sisbios_mode[i-1].mode_no[1] == 0x5b)
- continue;
- }
- sisfb_mode_idx = i - 1;
- j = 1;
- break;
- }
- }
- if((!j) && !quiet)
- printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
- }
- #ifndef MODULE
- static void __devinit
- sisfb_get_vga_mode_from_kernel(void)
- {
- #ifdef CONFIG_X86
- char mymode[32];
- int mydepth = screen_info.lfb_depth;
- if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
- if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
- (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
- (mydepth >= 8) && (mydepth <= 32) ) {
- if(mydepth == 24) mydepth = 32;
- sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
- screen_info.lfb_height,
- mydepth);
- printk(KERN_DEBUG
-