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

📄 devpnp.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
/* *	ISA PNP 1.0 support + access to PCI configuration space * *	TODO *		- implement PNP card configuration (setting io bases etc) *		- write user program to drive PNP configuration... *		- extend PCI raw access to configuration space (writes, byte/short access?) *		- implement PCI access to memory/io space/BIOS ROM *		- use c->aux instead of performing lookup on each read/write? */#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h"#include	"../port/error.h"typedef struct Pnp Pnp;typedef struct Card Card;struct Pnp{	QLock;	int		rddata;	int		debug;	Card		*cards;};struct Card{	int		csn;	ulong	id1;	ulong	id2;	char		*cfgstr;	int		ncfg;	Card*	next;};static Pnp	pnp;#define	DPRINT	if(pnp.debug) print#define	XPRINT	if(1) printenum {	Address = 0x279,	WriteData = 0xa79,	Qtopdir = 0,	Qpnpdir,	Qpnpctl,	Qcsnctl,	Qcsnraw,	Qpcidir,	Qpcictl,	Qpciraw,};#define TYPE(q)		((ulong)(q).path & 0x0F)#define CSN(q)		(((ulong)(q).path>>4) & 0xFF)#define QID(c, t)	(((c)<<4)|(t))static Dirtab topdir[] = {	".",	{ Qtopdir, 0, QTDIR },	0,	0555,	"pnp",	{ Qpnpdir, 0, QTDIR },	0,	0555,	"pci",	{ Qpcidir, 0, QTDIR },	0,	0555,};static Dirtab pnpdir[] = {	".",	{ Qpnpdir, 0, QTDIR },	0,	0555,	"ctl",	{ Qpnpctl, 0, 0 },	0,	0666,};extern Dev pnpdevtab;static int wrconfig(Card*, char*);static char key[32] ={	0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,	0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,	0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,	0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39,};static voidcmd(int reg, int val){	outb(Address, reg);	outb(WriteData, val);}/* Send initiation key, putting each card in Sleep state */static voidinitiation(void){	int i;	/* ensure each card's LFSR is reset */	outb(Address, 0x00);	outb(Address, 0x00);	/* send initiation key */	for (i = 0; i < 32; i++)		outb(Address, key[i]);}/* isolation protocol... */static intreadbit(int rddata){	int r1, r2;	r1 = inb(rddata);	r2 = inb(rddata);	microdelay(250);	return (r1 == 0x55) && (r2 == 0xaa);}static intisolate(int rddata, ulong *id1, ulong *id2){	int i, csum, bit;	uchar *p, id[9];	outb(Address, 0x01);	/* point to serial isolation register */	delay(1);	csum = 0x6a;	for(i = 0; i < 64; i++){		bit = readbit(rddata);		csum = (csum>>1) | (((csum&1) ^ ((csum>>1)&1) ^ bit)<<7);		p = &id[i>>3];		*p = (*p>>1) | (bit<<7);	}	for(; i < 72; i++){		p = &id[i>>3];		*p = (*p>>1) | (readbit(rddata)<<7);	}	*id1 = (id[3]<<24)|(id[2]<<16)|(id[1]<<8)|id[0];	*id2 = (id[7]<<24)|(id[6]<<16)|(id[5]<<8)|id[4];	if(*id1 == 0)		return 0;	if(id[8] != csum)		DPRINT("pnp: bad checksum id1 %lux id2 %lux csum %x != %x\n", *id1, *id2, csum, id[8]); /**/	return id[8] == csum;}static intgetresbyte(int rddata){	int tries = 0;	outb(Address, 0x05);	while ((inb(rddata) & 1) == 0)		if (tries++ > 1000000)			error("pnp: timeout waiting for resource data\n");	outb(Address, 0x04);	return inb(rddata);}static char *serial(ulong id1, ulong id2){	int i1, i2, i3;	ulong x;	static char buf[20];	i1 = (id1>>2)&31;	i2 = ((id1<<3)&24)+((id1>>13)&7);	i3 = (id1>>8)&31;	x = (id1>>8)&0xff00|(id1>>24)&0x00ff;	if (i1 > 0 && i1 < 27 && i2 > 0 && i2 < 27 && i3 > 0 && i3 < 27 && (id1 & (1<<7)) == 0)		snprint(buf, sizeof(buf), "%c%c%c%.4lux.%lux", 'A'+i1-1, 'A'+i2-1, 'A'+i3-1, x, id2);	else		snprint(buf, sizeof(buf), "%.4lux%.4lux.%lux", (id1<<8)&0xff00|(id1>>8)&0x00ff, x, id2);	return buf;}static Card *findcsn(int csn, int create, int dolock){	Card *c, *nc, **l;	if(dolock)		qlock(&pnp);	l = &pnp.cards;	for(c = *l; c != nil; c = *l) {		if(c->csn == csn)			goto done;		if(c->csn > csn)			break;		l = &c->next;	}	if(create) {		*l = nc = malloc(sizeof(Card));		nc->next = c;		nc->csn = csn;		c = nc;	}done:	if(dolock)		qunlock(&pnp);	return c;}static intnewcsn(void){	int csn;	Card *c;	csn = 1;	for(c = pnp.cards; c != nil; c = c->next) {		if(c->csn > csn)			break;		csn = c->csn+1;	}	return csn;}static intpnpncfg(int rddata){	int i, n, x, ncfg, n1, n2;	ncfg = 0;	for (;;) {		x = getresbyte(rddata);		if((x & 0x80) == 0) {			n = (x&7)+1;			for(i = 1; i < n; i++)				getresbyte(rddata);		}		else {			n1 = getresbyte(rddata);			n2 = getresbyte(rddata);			n = (n2<<8)|n1 + 3;			for (i = 3; i < n; i++)				getresbyte(rddata);		}		ncfg += n;		if((x>>3) == 0x0f)			break;	}	return ncfg;}/* look for cards, and assign them CSNs */static intpnpscan(int rddata, int dawn){	Card *c;	int csn;	ulong id1, id2;	initiation();				/* upsilon sigma */	cmd(0x02, 0x04+0x01);		/* reset CSN on all cards and reset logical devices */	delay(1);					/* delay after resetting cards */	cmd(0x03, 0);				/* Wake all cards with a CSN of 0 */	cmd(0x00, rddata>>2);		/* Set the READ_DATA port on all cards */	while(isolate(rddata, &id1, &id2)) {		for(c = pnp.cards; c != nil; c = c->next)			if(c->id1 == id1 && c->id2 == id2)				break;		if(c == nil) {			csn = newcsn();			c = findcsn(csn, 1, 0);			c->id1 = id1;			c->id2 = id2;		}		else if(c->cfgstr != nil) {			if(!wrconfig(c, c->cfgstr))				print("pnp%d: bad cfg: %s\n", c->csn, c->cfgstr);			c->cfgstr = nil;		}		cmd(0x06, c->csn);		/* set the card's csn */		if(dawn)			print("pnp%d: %s\n", c->csn, serial(id1, id2));		c->ncfg = pnpncfg(rddata);		cmd(0x03, 0);		/* Wake all cards with a CSN of 0, putting this card to sleep */	}	cmd(0x02, 0x02);			/* return cards to Wait for Key state */	if(pnp.cards != 0) {		pnp.rddata = rddata;		return 1;	}	return 0;}static voidpnpreset(void){	Card *c;	ulong id1, id2;	int csn, i1, i2, i3, x;	char *s, *p, buf[20];	ISAConf isa;	memset(&isa, 0, sizeof(ISAConf));	pnp.rddata = -1;	if (isaconfig("pnp", 0, &isa) == 0)		return;	if(isa.port < 0x203 || isa.port > 0x3ff)		return;	for(csn = 1; csn < 256; csn++) {		sprint(buf, "pnp%d", csn);		s = getconf(buf);		if(s == 0)			continue;		if(strlen(s) < 8 || s[7] != '.' || s[0] < 'A' || s[0] > 'Z' || s[1] < 'A' || s[1] > 'Z' || s[2] < 'A' || s[2] > 'Z') {bad:			print("pnp%d: bad conf string %s\n", csn, s);			continue;			}		i1 = s[0]-'A'+1;		i2 = s[1]-'A'+1;		i3 = s[2]-'A'+1;		x = strtoul(&s[3], 0, 16);		id1 = (i1<<2)|((i2>>3)&3)|((i2&7)<<13)|(i3<<8)|((x&0xff)<<24)|((x&0xff00)<<8);		id2 = strtoul(&s[8], &p, 16);		if(*p == ' ')			p++;		else if(*p == '\0')			p = nil;		else			goto bad;		c = findcsn(csn, 1, 0);		c->id1 = id1;		c->id2 = id2;		c->cfgstr = p;	}	pnpscan(isa.port, 1);}static intcsngen(Chan *c, int t, int csn, Card *cp, Dir *dp){	Qid q;	switch(t) {	case Qcsnctl:		q = (Qid){QID(csn, Qcsnctl), 0, 0};		sprint(up->genbuf, "csn%dctl", csn);		devdir(c, q, up->genbuf, 0, eve, 0664, dp);		return 1;	case Qcsnraw:		q = (Qid){QID(csn, Qcsnraw), 0, 0};		sprint(up->genbuf, "csn%draw", csn);		devdir(c, q, up->genbuf, cp->ncfg, eve, 0444, dp);		return 1;	}	return -1;}static intpcigen(Chan *c, int t, int tbdf, Dir *dp){	Qid q;	q = (Qid){BUSBDF(tbdf)|t, 0, 0};	switch(t) {	case Qpcictl:		sprint(up->genbuf, "%d.%d.%dctl", BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));		devdir(c, q, up->genbuf, 0, eve, 0444, dp);		return 1;	case Qpciraw:		sprint(up->genbuf, "%d.%d.%draw", BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf));		devdir(c, q, up->genbuf, 128, eve, 0660, dp);		return 1;	}	return -1;}static intpnpgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp){	Qid q;	Card *cp;	Pcidev *p;	int csn, tbdf;	switch(TYPE(c->qid)){	case Qtopdir:		if(s == DEVDOTDOT){			q = (Qid){QID(0, Qtopdir), 0, QTDIR};			sprint(up->genbuf, "#%C", pnpdevtab.dc);			devdir(c, q, up->genbuf, 0, eve, 0555, dp);			return 1;		}		return devgen(c, nil, topdir, nelem(topdir), s, dp);	case Qpnpdir:		if(s == DEVDOTDOT){			q = (Qid){QID(0, Qtopdir), 0, QTDIR};			sprint(up->genbuf, "#%C", pnpdevtab.dc);			devdir(c, q, up->genbuf, 0, eve, 0555, dp);			return 1;		}		if(s < nelem(pnpdir)-1)			return devgen(c, nil, pnpdir, nelem(pnpdir), s, dp);		s -= nelem(pnpdir)-1;		qlock(&pnp);		cp = pnp.cards;		while(s >= 2 && cp != nil) {			s -= 2;			cp = cp->next;		}		qunlock(&pnp);		if(cp == nil)			return -1;		return csngen(c, s+Qcsnctl, cp->csn, cp, dp);	case Qpnpctl:		return devgen(c, nil, pnpdir, nelem(pnpdir), s, dp);	case Qcsnctl:	case Qcsnraw:		csn = CSN(c->qid);		cp = findcsn(csn, 0, 1);		if(cp == nil)			return -1;		return csngen(c, TYPE(c->qid), csn, cp, dp);	case Qpcidir:		if(s == DEVDOTDOT){			q = (Qid){QID(0, Qtopdir), 0, QTDIR};			sprint(up->genbuf, "#%C", pnpdevtab.dc);			devdir(c, q, up->genbuf, 0, eve, 0555, dp);			return 1;		}		p = pcimatch(nil, 0, 0);		while(s >= 2 && p != nil) {			p = pcimatch(p, 0, 0);			s -= 2;		}		if(p == nil)			return -1;		return pcigen(c, s+Qpcictl, p->tbdf, dp);	case Qpcictl:	case Qpciraw:		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);		p = pcimatchtbdf(tbdf);		if(p == nil)			return -1;		return pcigen(c, TYPE(c->qid), tbdf, dp);	default:		break;	}	return -1;}static Chan*pnpattach(char *spec){	return devattach(pnpdevtab.dc, spec);}Walkqid*pnpwalk(Chan* c, Chan *nc, char** name, int nname){	return devwalk(c, nc, name, nname, (Dirtab *)0, 0, pnpgen);}static intpnpstat(Chan* c, uchar* dp, int n){	return devstat(c, dp, n, (Dirtab *)0, 0L, pnpgen);}static Chan*pnpopen(Chan *c, int omode){	c = devopen(c, omode, (Dirtab*)0, 0, pnpgen);	switch(TYPE(c->qid)){	default:		break;	}	return c;}static voidpnpclose(Chan*){}static longpnpread(Chan *c, void *va, long n, vlong offset){	ulong x;	Card *cp;	Pcidev *p;	char buf[256], *ebuf, *w;	char *a = va;	int csn, i, tbdf, r;	switch(TYPE(c->qid)){	case Qtopdir:	case Qpnpdir:	case Qpcidir:		return devdirread(c, a, n, (Dirtab *)0, 0L, pnpgen);	case Qpnpctl:		if(pnp.rddata > 0)			sprint(up->genbuf, "enabled 0x%x\n", pnp.rddata);		else			sprint(up->genbuf, "disabled\n");		return readstr(offset, a, n, up->genbuf);	case Qcsnraw:		csn = CSN(c->qid);		cp = findcsn(csn, 0, 1);		if(cp == nil)			error(Egreg);		if(offset+n > cp->ncfg)			n = cp->ncfg - offset;		qlock(&pnp);		initiation();		cmd(0x03, csn);				/* Wake up the card */		for(i = 0; i < offset+9; i++)		/* 9 == skip serial + csum */			getresbyte(pnp.rddata);		for(i = 0; i < n; i++)			a[i] = getresbyte(pnp.rddata);		cmd(0x03, 0);					/* Wake all cards with a CSN of 0, putting this card to sleep */		cmd(0x02, 0x02);				/* return cards to Wait for Key state */		qunlock(&pnp);		break;	case Qcsnctl:		csn = CSN(c->qid);		cp = findcsn(csn, 0, 1);		if(cp == nil)			error(Egreg);		sprint(up->genbuf, "%s\n", serial(cp->id1, cp->id2));		return readstr(offset, a, n, up->genbuf);	case Qpcictl:		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);		p = pcimatchtbdf(tbdf);		if(p == nil)			error(Egreg);		ebuf = buf+sizeof buf-1;	/* -1 for newline */		w = seprint(buf, ebuf, "%.2x.%.2x.%.2x %.4x/%.4x %3d",			p->ccrb, p->ccru, p->ccrp, p->vid, p->did, p->intl);		for(i=0; i<nelem(p->mem); i++){			if(p->mem[i].size == 0)				continue;			w = seprint(w, ebuf, " %d:%.8lux %d", i, p->mem[i].bar, p->mem[i].size);		}		*w++ = '\n';		*w = '\0';		return readstr(offset, a, n, buf);	case Qpciraw:		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);		p = pcimatchtbdf(tbdf);		if(p == nil)			error(Egreg);		if(offset > 256)			return 0;		if(n+offset > 256)			n = 256-offset;		r = offset;		if(!(r & 3) && n == 4){			x = pcicfgr32(p, r);			PBIT32(a, x);			return 4;		}		if(!(r & 1) && n == 2){			x = pcicfgr16(p, r);			PBIT16(a, x);			return 2;		}		for(i = 0; i <  n; i++){			x = pcicfgr8(p, r);			PBIT8(a, x);			a++;			r++;		}		return i;	default:		error(Egreg);	}	return n;}static longpnpwrite(Chan *c, void *va, long n, vlong offset){	Card *cp;	Pcidev *p;	ulong port, x;	char *a, buf[256];	int csn, i, r, tbdf;	if(n >= sizeof(buf))		n = sizeof(buf)-1;	a = va;	strncpy(buf, a, n);	buf[n] = 0;	switch(TYPE(c->qid)){	case Qpnpctl:		if(strncmp(buf, "port ", 5) == 0) {			port = strtoul(buf+5, 0, 0);			if(port < 0x203 || port > 0x3ff)				error("bad value for rddata port");			qlock(&pnp);			if(waserror()) {				qunlock(&pnp);				nexterror();			}			if(pnp.rddata > 0)				error("pnp port already set");			if(!pnpscan(port, 0))				error("no cards found");			qunlock(&pnp);			poperror();		}		else if(strncmp(buf, "debug ", 6) == 0)			pnp.debug = strtoul(buf+6, 0, 0);		else			error(Ebadctl);		break;	case Qcsnctl:		csn = CSN(c->qid);		cp = findcsn(csn, 0, 1);		if(cp == nil)			error(Egreg);		if(!wrconfig(cp, buf))			error(Ebadctl);		break;	case Qpciraw:		tbdf = MKBUS(BusPCI, 0, 0, 0)|BUSBDF((ulong)c->qid.path);		p = pcimatchtbdf(tbdf);		if(p == nil)			error(Egreg);		if(offset > 256)			return 0;		if(n+offset > 256)			n = 256-offset;		r = offset;		if(!(r & 3) && n == 4){			x = GBIT32(a);			pcicfgw32(p, r, x);			return 4;		}		if(!(r & 1) && n == 2){			x = GBIT16(a);			pcicfgw16(p, r, x);			return 2;		}		for(i = 0; i <  n; i++){			x = GBIT8(a);			pcicfgw8(p, r, x);			a++;			r++;		}		return i;	default:		error(Egreg);	}	return n;}static intwrconfig(Card *c, char *cmd){	/* This should implement setting of I/O bases, etc */	USED(c, cmd);	return 1;}Dev pnpdevtab = {	'$',	"pnp",	pnpreset,	devinit,	devshutdown,	pnpattach,	pnpwalk,	pnpstat,	pnpopen,	devcreate,	pnpclose,	pnpread,	devbread,	pnpwrite,	devbwrite,	devremove,	devwstat,};

⌨️ 快捷键说明

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