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

📄 hiqvideo.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include "pci.h"#include "vga.h"/* * Chips and Technologies HiQVideo. * Extensions in the 69000 over the 65550 are not fully taken into account. * Depths other than 8 are too slow. */enum {	Frx		= 0x3D0,	/* Flat Panel Extensions Index */	Mrx		= 0x3D2,	/* Multimedia Extensions Index */	Xrx		= 0x3D6,	/* Configuration Extensions Index */};typedef struct {	Pcidev* pci;	uchar	fr[256];	uchar	mr[256];	uchar	xr[256];} HiQVideo;static ucharhiqvideoxi(long port, uchar index){	uchar data;	outportb(port, index);	data = inportb(port+1);	return data;}static voidhiqvideoxo(long port, uchar index, uchar data){	outportb(port, index);	outportb(port+1, data);}static voidsnarf(Vga* vga, Ctlr* ctlr){	int i;	Pcidev *p;	HiQVideo *hqv;	if(vga->private == nil){		vga->private = alloc(sizeof(HiQVideo));		hqv = vga->private;		if((p = pcimatch(nil, 0x102C, 0)) == nil)			error("%s: not found\n", ctlr->name);		switch(p->did){		case 0x00C0:		/* 69000 HiQVideo */			vga->f[1] = 135000000;			vga->vmz = 2048*1024;			break;		case 0x00E0:		/* 65550 HiQV32 */		case 0x00E4:		/* 65554 HiQV32 */		case 0x00E5:		/* 65555 HiQV32 */			vga->f[1] = 90000000;			vga->vmz = 2048*1024;			break;		default:			error("%s: DID %4.4uX unsupported\n",				ctlr->name, p->did);		}		hqv->pci = p;	}	hqv = vga->private;	for(i = 0; i < 0x50; i++)		hqv->fr[i] = hiqvideoxi(Frx, i);	for(i = 0; i < 0x60; i++)		hqv->mr[i] = hiqvideoxi(Mrx, i);	for(i = 0x30; i < 0x80; i++)		vga->crt[i] = vgaxi(Crtx, i);	for(i = 0; i < 0x100; i++)		hqv->xr[i] = hiqvideoxi(Xrx, i);	switch(hqv->pci->did){	case 0x00C0:			/* 69000 HiQVideo */		vga->f[1] = 135000000;		vga->vmz = 2048*1024;		break;	case 0x00E0:			/* 65550 HiQV32 */	case 0x00E4:			/* 65554 HiQV32 */	case 0x00E5:			/* 65555 HiQV32 */		/*		 * Check VCC to determine max clock.		 * 5V allows a higher rate.		 */		if(hqv->fr[0x0A] & 0x02)			vga->f[1] = 110000000;		else			vga->f[1] = 80000000;		switch((hqv->xr[0x43]>>1) & 0x03){		case 0:			vga->vmz = 1*1024*1024;			break;		case 1:			vga->vmz = 2*1024*1024;			break;		default:			vga->vmz = 16*1024*1024;			break;		}		break;	}	ctlr->flag |= Fsnarf;}static voidoptions(Vga*, Ctlr* ctlr){	ctlr->flag |= Hlinear|Foptions;}static voidclock(Vga* vga, Ctlr* ctlr){	double f, fmin, fvco, m;	ulong n, nmin, nmax, pd, rd;	/*	 * Constraints:	 *  1.	1MHz <= Fref <= 60MHz	 *  2.	150KHz <= Fref/(RD*N) <= 2MHz	 *  3.	48MHz < Fvco <= 220MHz	 *  4.	3 <= M <= 1023	 *  5.	3 <= N <= 1023	 */	f = vga->f[0];	/*	 * Although pd = 0 is valid, things seems more stable	 * starting at 1.	 */	for(pd = 1; pd < 6; pd++){		f = vga->f[0]*(1<<pd);		if(f > 48000000 && f <= 220000000)			break;	}	if(pd >= 6)		error("%s: dclk %lud out of range\n", ctlr->name, vga->f[0]);	vga->p[0] = pd;	/*	 * The reference divisor has only two possible values, 1 and 4.	 */	fmin = f;	for(rd = 1; rd <= 4; rd += 3){		/*		 * Find the range for n (constraint 2).		 */		for(nmin = 3; nmin <= 1023; nmin++){			if(RefFreq/(rd*nmin) <= 2000000)				break;		}		for(nmax = 1023; nmax >= 3; nmax--){			if(RefFreq/(rd*nmax) >= 150000)				break;		}		/*		 * Now find the closest match for M and N.		 */		for(n = nmin; n < nmax; n++){			for(m = 3; m <= vga->m[1]; m++){				fvco = (RefFreq*4*m)/(rd*n);				if(fvco < 48000000 || fvco > 220000000)					continue;				fvco -= f;				if(fvco < 0)					fvco = -fvco;				if(fvco < fmin){					fmin = fvco;					vga->m[0] = m;					vga->n[0] = n;					vga->p[0] = pd;					vga->r[0] = rd;				}			}		}	}}static voidinit(Vga* vga, Ctlr* ctlr){	HiQVideo *hqv;	hqv = vga->private;	if(vga->f[0] == 0)		vga->f[0] = vga->mode->frequency;	vga->misc &= ~0x0C;	hqv->fr[0x03] &= ~0x0C;	switch(vga->mode->z){	case 8:	case 16:	case 32:		break;	default:		error("depth %d not supported\n", vga->mode->z);	}	/*	 * FR[0x01] == 1 for CRT, 2 for LCD.	 * Don't programme the clock if it's an LCD.	 */	if((hqv->fr[0x01] & 0x03) == 0x02){		vga->misc |= 0x08;		hqv->fr[0x03] |= 0x08;	}	else{		/*		 * Clock bits. If the desired video clock is		 * one of the two standard VGA clocks it can just be		 * set using bits <3:2> of vga->misc or Fr03,		 * otherwise the DCLK PLL needs to be programmed.		 */		if(vga->f[0] == VgaFreq0){			/* nothing to do */;		}		else if(vga->f[0] == VgaFreq1){			vga->misc |= 0x04;			hqv->fr[0x03] |= 0x04;		}		else{			if(vga->f[0] > vga->f[1])				error("%s: invalid dclk - %lud\n",					ctlr->name, vga->f[0]);				if((hqv->fr[0x01] & 0x03) != 0x02){				vga->m[1] = 1023;				clock(vga, ctlr);				hqv->xr[0xC8] = (vga->m[0]-2) & 0xFF;				hqv->xr[0xCA] = ((vga->m[0]-2) & 0x300)>>8;				hqv->xr[0xC9] = (vga->n[0]-2) & 0xFF;				hqv->xr[0xCA] |= ((vga->n[0]-2) & 0x300)>>4;				hqv->xr[0xCB] = (vga->p[0]<<4)|(vga->r[0] == 1);			}			vga->misc |= 0x08;			hqv->fr[0x03] |= 0x08;		}	}	if(vga->mode->y >= 480)		vga->misc &= ~0xC0;	/*	 * 10 bits should be enough, but set the extended mode anyway.	 */	hqv->xr[0x09] |= 0x01;	vga->crt[0x30] = ((vga->mode->vt-2)>>8) & 0x0F;	vga->crt[0x31] = ((vga->mode->y-1)>>8) & 0x0F;	vga->crt[0x32] = (vga->mode->vrs>>8) & 0x0F;	vga->crt[0x33] = (vga->mode->vrs>>8) & 0x0F;	vga->crt[0x38] = (((vga->mode->ht>>3)-5)>>8) & 0x01;	vga->crt[0x3C] = (vga->mode->ehb>>3) & 0xC0;	vga->crt[0x41] = (vga->crt[0x13]>>8) & 0x0F;	vga->crt[0x40] = 0x80;	hqv->xr[0x40] |= 0x03;	hqv->xr[0x80] |= 0x10;	hqv->xr[0x81] &= ~0x0F;	switch(vga->mode->z){	case 8:		hqv->xr[0x81] |= 0x12;		break;	case 16:		hqv->xr[0x81] |= 0x15;		break;	case 32:		hqv->xr[0x81] |= 0x16;		break;	}	hqv->xr[0x0A] = 0x01;	if(vga->linear && (ctlr->flag & Hlinear))		ctlr->flag |= Ulinear;	vga->attribute[0x11] = 0;	ctlr->flag |= Finit;}static voidload(Vga* vga, Ctlr* ctlr){	HiQVideo *hqv;	hqv = vga->private;	hiqvideoxo(Xrx, 0x0E, 0x00);	while((vgai(Status1) & 0x08) == 0x08)		;	while((vgai(Status1) & 0x08) == 0)		;	vgaxo(Seqx, 0x07, 0x00);	/*	 * Set the clock if necessary.	 */	if((vga->misc & 0x0C) == 0x08 && (hqv->fr[0x01] & 0x03) != 0x02){		vgao(MiscW, vga->misc & ~0x0C);		hiqvideoxo(Frx, 0x03, hqv->fr[0x03] & ~0x0C);		hiqvideoxo(Xrx, 0xC8, hqv->xr[0xC8]);		hiqvideoxo(Xrx, 0xC9, hqv->xr[0xC9]);		hiqvideoxo(Xrx, 0xCA, hqv->xr[0xCA]);		hiqvideoxo(Xrx, 0xCB, hqv->xr[0xCB]);	}	hiqvideoxo(Frx, 0x03, hqv->fr[0x03]);	vgao(MiscW, vga->misc);	hiqvideoxo(Xrx, 0x09, hqv->xr[0x09]);	vgaxo(Crtx, 0x30, vga->crt[0x30]);	vgaxo(Crtx, 0x31, vga->crt[0x31]);	vgaxo(Crtx, 0x32, vga->crt[0x32]);	vgaxo(Crtx, 0x33, vga->crt[0x33]);	vgaxo(Crtx, 0x38, vga->crt[0x38]);	vgaxo(Crtx, 0x3C, vga->crt[0x3C]);	vgaxo(Crtx, 0x41, vga->crt[0x41]);	vgaxo(Crtx, 0x40, vga->crt[0x40]);	hiqvideoxo(Xrx, 0x40, hqv->xr[0x40]);	hiqvideoxo(Xrx, 0x80, hqv->xr[0x80]);	hiqvideoxo(Xrx, 0x81, hqv->xr[0x81]);	if(ctlr->flag & Ulinear){		hqv->xr[0x05] = vga->vmb>>16;		hqv->xr[0x06] = vga->vmb>>24;		hiqvideoxo(Xrx, 0x05, hqv->xr[0x05]);		hiqvideoxo(Xrx, 0x06, hqv->xr[0x06]);		hqv->xr[0x0A] = 0x02;	}	hiqvideoxo(Xrx, 0x0A, hqv->xr[0x0A]);	ctlr->flag |= Fload;}static ulongdumpmclk(uchar data[4]){	double f, m, n;	int pds, rds;	m = data[0] & 0x7F;	n = data[1] & 0x7F;	pds = 1<<((data[2] & 0x70)>>4);	if(data[2] & 0x01)		rds = 1;	else		rds = 4;	f = (RefFreq*4*(m+2))/(rds*(n+2));	f /= pds;	return f;}static ulongdumpvclk(uchar data[4]){	double f, m, n;	int pds, rds;	m = ((data[2] & 0x03)<<8)|data[0];	n = (((data[2] & 0x30)>>4)<<8)|data[1];	pds = 1<<((data[3] & 0x70)>>4);	if(data[3] & 0x01)		rds = 1;	else		rds = 4;	f = (RefFreq*4*(m+2))/(rds*(n+2));	f /= pds;	return f;}static voiddump(Vga* vga, Ctlr* ctlr){	int i;	char *name;	HiQVideo *hqv;	name = ctlr->name;	hqv = vga->private;	printitem(name, "Fr00");	for(i = 0; i < 0x50; i++)		printreg(hqv->fr[i]);	printitem(name, "Mr00");	for(i = 0; i < 0x60; i++)		printreg(hqv->mr[i]);	printitem(name, "Crt30");	for(i = 0x30; i < 0x80; i++)		printreg(vga->crt[i]);	printitem(name, "Xr00");	for(i = 0; i < 0x100; i++)		printreg(hqv->xr[i]);	printitem(ctlr->name, "CLK0");	for(i = 0; i < 4; i++)		printreg(hqv->xr[0xC0+i]);	Bprint(&stdout, "%23ld", dumpvclk(&hqv->xr[0xC0]));	printitem(ctlr->name, "CLK1");	for(i = 0; i < 4; i++)		printreg(hqv->xr[0xC4+i]);	Bprint(&stdout, "%23ld", dumpvclk(&hqv->xr[0xC4]));	printitem(ctlr->name, "CLK2");	for(i = 0; i < 4; i++)		printreg(hqv->xr[0xC8+i]);	Bprint(&stdout, "%23ld", dumpvclk(&hqv->xr[0xC8]));	printitem(ctlr->name, "MCLK");	for(i = 0; i < 4; i++)		printreg(hqv->xr[0xCC+i]);	Bprint(&stdout, "%23ld", dumpmclk(&hqv->xr[0xCC]));	printitem(ctlr->name, "m n pd rd");	Bprint(&stdout, "%9ld %8ld       - %8ld %8ld\n",		vga->m[0], vga->n[0], vga->p[0], vga->r[0]);}Ctlr hiqvideo = {	"hiqvideo",			/* name */	snarf,				/* snarf */	options,			/* options */	init,				/* init */	load,				/* load */	dump,				/* dump */};Ctlr hiqvideohwgc = {	"hiqvideohwgc",			/* name */	0,				/* snarf */	0,				/* options */	0,				/* init */	0,				/* load */	0,				/* dump */};

⌨️ 快捷键说明

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