⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sis_main.c

📁 linux下的VIDEO接口驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
		   case SIS550_DRAM_SIZE_128MB:			ivideo.video_size = 0x8000000;	break;		   case SIS550_DRAM_SIZE_256MB:			ivideo.video_size = 0x10000000;	break;		   default:		        /* TW: Some 550 BIOSes don't seem to initialize SR14 correctly (if at all),			 *     do it the hard way ourselves in this case. Unfortunately, we don't			 *     support 24, 48, 96 and other "odd" amounts here. I don't know if			 *     this work-around is required for 650/740 as well, but do it in case			 *     for now.			 */		        printk(KERN_INFO			       "sisfb: Warning: Could not determine memory size, "			       "now reading from PCI config\n");			pdev_valid = 0;			pci_for_each_dev(pdev) {			   if ( (pdev->vendor == PCI_VENDOR_ID_SI)			         && (    (pdev->device == PCI_DEVICE_ID_SI_550)				      || (pdev->device == PCI_DEVICE_ID_SI_650) ) ) {				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,				                     &pci_data);				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;				ivideo.video_size = (unsigned int)(1 << (pci_data+21));				pdev_valid = 1;				/* TW: Initialize SR14=IND_SIS_DRAM_SIZE */				vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);				reg = vgarb(SEQ_DATA) & 0xC0;				switch (pci_data) {				   case BRI_DRAM_SIZE_4MB:					reg |= SIS550_DRAM_SIZE_4MB;  break;				   case BRI_DRAM_SIZE_8MB:					reg |= SIS550_DRAM_SIZE_8MB;  break;				   case BRI_DRAM_SIZE_16MB:					reg |= SIS550_DRAM_SIZE_16MB; break;				   case BRI_DRAM_SIZE_32MB:					reg |= SIS550_DRAM_SIZE_32MB; break;				   case BRI_DRAM_SIZE_64MB:					reg |= SIS550_DRAM_SIZE_64MB; break;				   /* case BRI_DRAM_SIZE_128MB:					reg |= (SIS315_DRAM_SIZE_128MB << 4); break; */				   default:				   	printk(KERN_INFO "sisfb: Unable to determine memory size, giving up.\n");					return -1;				}				vgawb(SEQ_DATA, reg);			   }			}			if (!pdev_valid) {				printk(KERN_INFO "sisfb: Total confusion - No SiS PCI VGA device found?!\n");				return -1;			}			return 0;		}#endif		return 0;	} else {	/* 315 */		vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);		reg = vgarb(SEQ_DATA);		switch ((reg & SIS315_DRAM_SIZE_MASK) >> 4) {		   case SIS315_DRAM_SIZE_2MB:			ivideo.video_size = 0x200000;			break;		   case SIS315_DRAM_SIZE_4MB:			ivideo.video_size = 0x400000;			break;		   case SIS315_DRAM_SIZE_8MB:			ivideo.video_size = 0x800000;			break;		   case SIS315_DRAM_SIZE_16MB:			ivideo.video_size = 0x1000000;			break;		   case SIS315_DRAM_SIZE_32MB:			ivideo.video_size = 0x2000000;			break;		   case SIS315_DRAM_SIZE_64MB:			ivideo.video_size = 0x4000000;			break;		   case SIS315_DRAM_SIZE_128MB:			ivideo.video_size = 0x8000000;			break;		   default:			return -1;		}	}	reg &= SIS315_DUAL_CHANNEL_MASK;	reg >>= 2;	switch (reg) {	   case SIS315_SINGLE_CHANNEL_2_RANK:		ivideo.video_size <<= 1;		break;	   case SIS315_DUAL_CHANNEL_1_RANK:		ivideo.video_size <<= 1;		break;	   case SIS315_ASYM_DDR:		/* TW: DDR asymentric */		ivideo.video_size += ivideo.video_size/2;		break;	}	return 0;}static void sisfb_detect_VB_connect_315(void){	u8 sr17, cr32, temp;	vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR32);	cr32 = vgarb(CRTC_DATA);	ivideo.TV_plug = ivideo.TV_type = 0;	if ((cr32 & SIS_CRT1) && !sisfb_crt1off)		sisfb_crt1off = 0;	else {		if (cr32 & 0x5F)   			sisfb_crt1off = 1;		else			sisfb_crt1off = 0;	}	if (sisfb_crt2type != -1)		/* TW: Override with option */		ivideo.disp_state = sisfb_crt2type;	else if (cr32 & SIS_VB_CRT2)		ivideo.disp_state = DISPTYPE_CRT2;	else if (cr32 & SIS_VB_LCD)		ivideo.disp_state = DISPTYPE_LCD;	else if (cr32 & SIS_VB_TV)		ivideo.disp_state = DISPTYPE_TV;	else		ivideo.disp_state = 0;	if (cr32 & SIS_VB_HIVISION) {		ivideo.TV_type = TVMODE_HIVISION;		ivideo.TV_plug = TVPLUG_SVIDEO;	} else if (cr32 & SIS_VB_SVIDEO)		ivideo.TV_plug = TVPLUG_SVIDEO;	else if (cr32 & SIS_VB_COMPOSITE)		ivideo.TV_plug = TVPLUG_COMPOSITE;	else if (cr32 & SIS_VB_SCART)		ivideo.TV_plug = TVPLUG_SCART;	if (ivideo.TV_type == 0) {		vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP);		temp = vgarb(SEQ_DATA);		if (temp & 0x01)			ivideo.TV_type = TVMODE_PAL;		else			ivideo.TV_type = TVMODE_NTSC;	}	/* TW: Copy forceCRT1 option to CRT1off if option is given */    	if (sisfb_forcecrt1 != -1) {		vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_17);    		sr17 = vgarb(SEQ_DATA);    		if (sisfb_forcecrt1) {			sisfb_crt1off=0;			sr17 |= 0x80;		} else {			sisfb_crt1off=1;			sr17 &= ~0x80;		}		vgawb(SEQ_DATA, sr17);    	}}static void sisfb_get_VB_type_315(void){	u8 reg;	/* 550 has LVDS-like FSTN bridge (?) */	if (ivideo.chip == SIS_550) {		if (!sisfb_has_VB_315()) {			vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR37);			reg = vgarb(CRTC_DATA);			switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {			   case SIS_EXTERNAL_CHIP_SIS301:				ivideo.hasVB = HASVB_301;				break;			   case SIS_EXTERNAL_CHIP_LVDS:				ivideo.hasVB = HASVB_LVDS;				break;			   case SIS_EXTERNAL_CHIP_TRUMPION:				ivideo.hasVB = HASVB_TRUMPION;				break;			   case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:				ivideo.hasVB = HASVB_LVDS_CHRONTEL;				break;			   case SIS_EXTERNAL_CHIP_CHRONTEL:				ivideo.hasVB = HASVB_CHRONTEL;				break;			   default:				break;			}		}	} else {		sisfb_has_VB_315();	}}static int sisfb_has_VB_315(void){	u8 vb_chipid;	vgawb(VB_PART4_ADR, 0x0);	vb_chipid = vgarb(VB_PART4_DATA);	switch (vb_chipid) {	   case 0x01:		ivideo.hasVB = HASVB_301;		break;	   case 0x02:		ivideo.hasVB = HASVB_302;		break;	   case 0x03:		ivideo.hasVB = HASVB_303;		break;	   default:		ivideo.hasVB = HASVB_NONE;		return FALSE;	}	// Eden Chen	//sishw_ext.hasVB = ivideo.hasVB;	// ~Eden Chen	return TRUE;}#endif   /* CONFIG_FB_SIS_315 *//* --------------------- Heap Routines ------------------------------- */static int sisfb_heap_init(void){	SIS_OH *poh;	u8 temp=0;#ifdef CONFIG_FB_SIS_315	int            agp_enabled = 1;	u32            agp_size;	unsigned long *cmdq_baseport = 0;	unsigned long *read_port = 0;	unsigned long *write_port = 0;	SIS_CMDTYPE    cmd_type;#ifndef AGPOFF	agp_kern_info  *agp_info;	agp_memory     *agp;	u32            agp_phys;#endif#endif/* TW: If more than 8MB videoRAM detected, let our heap start at 8MB. If *     there is less RAM available, let it start at 4MB. This can be overruled *     by mem parameter. *     This is for avoiding a clash with X driver which uses the beginning *     of the videoRAM. To limit size of X framebuffer, use Option MaxXFBMem *     in XF86Config-4. *     The heap start can also be specified by parameter "mem" when starting the sisfb *     driver. sisfb mem=1024 lets heap starts at 1MB, etc. */      /*karl:10/01/2001*/      if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {	if (ivideo.video_size > 0x800000) {		sisfb_heap_start =		    (unsigned long) ivideo.video_vbase + 0x800000;		printk(KERN_INFO "sisfb: Memory heap starting at 8192K\n");	} else {		sisfb_heap_start =		    (unsigned long) ivideo.video_vbase + 0x400000;		printk(KERN_INFO "sisfb: Memory heap starting at 4096K\n");	}     } else {   	   sisfb_heap_start =	       (unsigned long) (ivideo.video_vbase + (sisfb_mem * 1024));	   printk(KERN_INFO "sisfb: Memory heap starting at %dK\n", sisfb_mem);     }     sisfb_heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;     sisfb_heap_size = sisfb_heap_end - sisfb_heap_start;#ifdef CONFIG_FB_SIS_315     if (sisvga_engine == SIS_315_VGA) {        /* TW: Now initlalize the 310 series' command queue mode.	 * On 310, there are three queue modes available which	 *     are chosen by setting bits 7:5 in SR26:	 * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep	 *    track of the queue, the FIFO, command parsing and so	 *    on. This is the one comparable to the 300 series.	 * 2. VRAM queue mode (bit 6, 0x40). In this case, one will	 *    have to do queue management himself. Register 0x85c4 will	 *    hold the location of the next free queue slot, 0x85c8	 *    is the "queue read pointer" whose way of working is	 *    unknown to me. Anyway, this mode would require a	 *    translation of the MMIO commands to some kind of	 *    accelerator assembly and writing these commands	 *    to the memory location pointed to by 0x85c4.	 *    We will not use this, as nobody knows how this	 *    "assembly" works, and as it would require a complete	 *    re-write of the accelerator code.	 * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the	 *    queue in AGP memory space.	 *	 * SR26 bit 4 is called "Bypass H/W queue".	 * SR26 bit 1 is called "Enable Command Queue Auto Correction"	 * SR26 bit 0 resets the queue	 * Size of queue memory is encoded in bits 3:2 like this:	 *    00  (0x00)  512K	 *    01  (0x04)  1M	 *    10  (0x08)  2M	 *    11  (0x0C)  4M	 * The queue location is to be written to 0x85C0.	 *         */	cmdq_baseport = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_PHYBASE);	write_port    = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_WRITEPORT);	read_port     = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_READPORT);	DPRINTK("AGP base: 0x%p, read: 0x%p, write: 0x%p\n", cmdq_baseport, read_port, write_port);	agp_size  = COMMAND_QUEUE_AREA_SIZE;#ifndef AGPOFF	if (sisfb_queuemode == AGP_CMD_QUEUE) {		agp_info = vmalloc(sizeof(agp_kern_info));		memset((void*)agp_info, 0x00, sizeof(agp_kern_info));		agp_copy_info(agp_info);		agp_backend_acquire();		agp = agp_allocate_memory(COMMAND_QUEUE_AREA_SIZE/PAGE_SIZE,					  AGP_NORMAL_MEMORY);		if (agp == NULL) {			DPRINTK("sisfb: Allocating AGP buffer failed.\n");			agp_enabled = 0;		} else {			if (agp_bind_memory(agp, agp->pg_start) != 0) {				DPRINTK("sisfb: AGP: Failed to bind memory\n");				/* TODO: Free AGP memory here */				agp_enabled = 0;			} else {				agp_enable(0);			}		}	}#else	agp_enabled= 0;#endif	/* TW: Now select the queue mode */	if ((agp_enabled) && (sisfb_queuemode == AGP_CMD_QUEUE)) {		cmd_type = AGP_CMD_QUEUE;		printk(KERN_INFO "sisfb: Using AGP queue mode\n");/*	} else if (sisfb_heap_size >= COMMAND_QUEUE_AREA_SIZE)  */        } else if (sisfb_queuemode == VM_CMD_QUEUE) {		cmd_type = VM_CMD_QUEUE;		printk(KERN_INFO "sisfb: Using VRAM queue mode\n");	} else {		printk(KERN_INFO "sisfb: Using MMIO queue mode\n");		cmd_type = MMIO_CMD;	}	switch (agp_size) {	   case 0x80000:		temp = SIS_CMD_QUEUE_SIZE_512k;		break;	   case 0x100000:		temp = SIS_CMD_QUEUE_SIZE_1M;		break;	   case 0x200000:		temp = SIS_CMD_QUEUE_SIZE_2M;		break;	   case 0x400000:		temp = SIS_CMD_QUEUE_SIZE_4M;		break;	}	switch (cmd_type) {	   case AGP_CMD_QUEUE:#ifndef AGPOFF		DPRINTK("sisfb: AGP buffer base:0x%lx, offset:0x%x, size: %dK\n",			agp_info->aper_base, agp->physical, agp_size/1024);		agp_phys = agp_info->aper_base + agp->physical;		vgawb(CRTC_ADR, IND_SIS_AGP_IO_PAD);		vgawb(CRTC_DATA, 0);		vgawb(CRTC_DATA, SIS_AGP_2X);		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD);		vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD);		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);		vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET);		*write_port = *read_port;		temp |= SIS_AGP_CMDQUEUE_ENABLE;		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);		vgawb(SEQ_DATA, temp);		*cmdq_baseport = agp_phys;		sisfb_caps |= AGP_CMD_QUEUE_CAP;#endif		break;	   case VM_CMD_QUEUE:		sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;		sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD);		vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD);		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);		vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET);		*write_port = *read_port;		temp |= SIS_VRAM_CMDQUEUE_ENABLE;		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);		vgawb(SEQ_DATA, temp);		*cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;		sisfb_caps |= VM_CMD_QUEUE_CAP;		DPRINTK("sisfb: VM Cmd Queue offset = 0x%lx, size is %dK\n",			*cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);		break;	   default:  /* MMIO */	   	/* TW: This previously only wrote SIS_MMIO_CMD_ENABLE		 * to IND_SIS_CMDQUEUE_SET. I doubt that this is		 * enough. Reserve memory in any way.		 */	   	sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;		sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD);		vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD);		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);		vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET);		*write_port = *read_port;		/* TW: Set Auto_Correction bit; this works in sisfb lite,		 * so why not.		 */		temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);		vgawb(SEQ_DATA, temp);		*cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;		DPRINTK("sisfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n",			*cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);		break;	}     } /* sisvga_engine = 315 */#endif#ifdef CONFIG_FB_SIS_300     if (sisvga_engine == SIS_300_VGA) {  	    /* TW: Now initialize TurboQueue. TB is always located at the very	     * top of the video RAM. */	    if (sisfb_heap_size >= TURBO_QUEUE_AREA_SIZE) {		unsigned int  tqueue_pos;		u8 tq_state;		tqueue_pos = (ivideo.video_size -		       TURBO_QUEUE_AREA_SIZE) / (64 * 1024);		temp = (u8) (tqueue_pos & 0xff);		vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET);		tq_state = vgarb(SEQ_DATA);		tq_state |= 0xf0;		tq_state &= 0xfc;		tq_state |= (u8) (tqueue_pos >> 8);		vgawb(SEQ_DATA, tq_state);		vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR);		vgawb(SEQ_DATA, temp);		sisfb_caps |= TURBO_QUEUE_CAP;		sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;		sisfb_heap_size -= TURBO_QUEUE_AREA_SIZE;		DPRINTK("sisfb: TurboQueue start at 0x%lx, size is %dK\n",			sisfb_heap_end, TURBO_QUEUE_AREA_SIZE/1024);	    }     }#endif        /* TW: Now reserve memory for the HWCursor. It is always located at the very               top of the videoRAM, right below the TB memory area (if used). */	if (sisfb_heap_size >= sisfb_hwcursor_size) {		sisfb_heap_end -= sisfb_hwcursor_size;		sisfb_heap_size -= sisfb_hwcursor_size;		sisfb_hwcursor_vbase = sisfb_heap_end;		sisfb_caps |= HW_CURSOR_CAP;		DPRINTK("sisfb: Hardware Cursor start at 0x%lx, size is %dK\n",			sisfb_heap_end, sisfb_hwcursor_size/1024);	}	sisfb_heap.poha_chain = NULL;	sisfb_heap.poh_freelist = NULL;	poh = sisfb_poh_new_node();	if (poh == NULL)		return 1;		poh->poh_next = &sisfb_heap.oh_free;	poh->poh_prev = &sisfb_heap.oh_free;	poh->size = sisfb_heap_end - sisfb_heap_start + 1;	poh->offset = sisfb_heap_start - (unsigned long) ivideo.video_vbase;	DPRINTK("sisfb: Heap start:0x%p, end:0x%p, len=%dk\n",		(char *) sisfb_heap_start, (char *) sisfb_heap_end,		(unsigned int) poh->size / 1024);	DPRINTK("sisfb: First Node offset:0x%x, size:%dk\n",		(unsigned int) poh->offset, (unsigned int) poh->size / 1024);		sisfb_heap.oh_free.poh_next = poh;	sisfb_heap.oh_free.poh_prev = poh;	sisfb_heap.oh_free.size = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -