devns16552.c

来自「著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是」· C语言 代码 · 共 1,209 行 · 第 1/2 页

C
1,209
字号
		*in = p->iq;	if(out)		*out = p->oq;	p->opens++;}/* *  handle an interrupt to a single uart */voidns16552intr(int dev){	uchar ch;	int s, l, loops;	Uart *p = uart[dev];	for(loops = 0;; loops++){		p->istat = s = uartrdreg(p, Istat);		if(loops > 10000000){			print("lstat %ux mstat %ux istat %ux iena %ux ferr %d oerr %d",				uartrdreg(p, Lstat), uartrdreg(p, Mstat),				s, uartrdreg(p, Iena), p->frame, p->overrun);			panic("ns16552intr");		}		switch(s&0x3f){		case 6:	/* receiver line status */			l = uartrdreg(p, Lstat);			if(l & Ferror)				p->frame++;			if(l & Oerror)				p->overrun++;			break;		case 4:	/* received data available */		case 12:			ch = uartrdreg(p, Data) & 0xff;			if(p->xonoff){				if(ch == CTLS){					p->blocked = 1;				}else if (ch == CTLQ){					p->blocked = 0;					p->ctsbackoff = 2; /* clock gets output going again */				}			}			if(p->putc)				p->putc(p->iq, ch);			else {				ilock(&p->rlock);				if(p->ip < p->ie)					*p->ip++ = ch;				p->haveinput = 1;				iunlock(&p->rlock);			}			break;		case 2:	/* transmitter not full */			ns16552kick(p);			break;		case 0:	/* modem status */			ch = uartrdreg(p, Mstat);			if(ch & Ctsc){				l = p->cts;				p->cts = ch & Cts;				if(l == 0 && p->cts)					p->ctsbackoff = 2; /* clock gets output going again */			}	 		if (ch & Dsrc) {				l = ch & Dsr;				if(p->hup_dsr && p->dsr && !l)					p->dohup = 1;	 /* clock peforms hangup */				p->dsr = l;			}	 		if (ch & Dcdc) {				l = ch & Dcd;				if(l == 0 && p->dcd != 0 && p->dcdts && saveintrts != nil)					(*saveintrts)();				if(p->hup_dcd && p->dcd && !l)					p->dohup = 1;	 /* clock peforms hangup */				p->dcd = l;			}			break;		default:			if(s&1)				return;			print("weird modem interrupt #%2.2ux\n", s);			break;		}	}}/* *  we save up input characters till clock time * *  There's also a bit of code to get a stalled print going. *  It shouldn't happen, but it does.  Obviously I don't *  understand something.  Since it was there, I bundled a *  restart after flow control with it to give some hysteresis *  to the hardware flow control.  This makes compressing *  modems happier but will probably bother something else. *	 -- presotto */voiduartclock(void){	int n;	Uart *p;	for(p = uartalloc.elist; p; p = p->elist){		/* this amortizes cost of qproduce to many chars */		if(p->haveinput){			ilock(&p->rlock);			if(p->haveinput){				n = p->ip - p->istage;				if(n > 0 && p->iq){					if(n > Stagesize)						panic("uartclock");					if(qproduce(p->iq, p->istage, n) < 0)						ns16552rts(p, 0);					else						p->ip = p->istage;				}				p->haveinput = 0;			}			iunlock(&p->rlock);		}		if(p->dohup){			ilock(&p->rlock);			if(p->dohup){				qhangup(p->iq, 0);				qhangup(p->oq, 0);			}			p->dohup = 0;			iunlock(&p->rlock);		}		/* this adds hysteresis to hardware/software flow control */		if(p->ctsbackoff){			ilock(&p->tlock);			if(p->ctsbackoff){				if(--(p->ctsbackoff) == 0)					ns16552kick0(p);			}			iunlock(&p->tlock);		}	}}Dirtab *ns16552dir;int ndir;static voidsetlength(int i){	Uart *p;	if(i > 0){		p = uart[i];		if(p && p->opens && p->iq)			ns16552dir[3*i].length = qlen(p->iq);	} else for(i = 0; i < nuart; i++){		p = uart[i];		if(p && p->opens && p->iq)			ns16552dir[3*i].length = qlen(p->iq);	}}/* *  all uarts must be ns16552setup() by this point or inside of ns16552install() */static voidns16552reset(void){	int i;	Dirtab *dp;	ns16552install();	/* architecture specific */	ndir = 3*nuart;	ns16552dir = xalloc(ndir * sizeof(Dirtab));	dp = ns16552dir;	for(i = 0; i < nuart; i++){		/* 3 directory entries per port */		strcpy(dp->name, uart[i]->name);		dp->qid.path = NETQID(i, Ndataqid);		dp->perm = 0660;		dp++;		sprint(dp->name, "%sctl", uart[i]->name);		dp->qid.path = NETQID(i, Nctlqid);		dp->perm = 0660;		dp++;		sprint(dp->name, "%sstat", uart[i]->name);		dp->qid.path = NETQID(i, Nstatqid);		dp->perm = 0444;		dp++;	}}static Chan*ns16552attach(char *spec){	return devattach('t', spec);}static intns16552walk(Chan *c, char *name){	return devwalk(c, name, ns16552dir, ndir, devgen);}static voidns16552stat(Chan *c, char *dp){	if(NETTYPE(c->qid.path) == Ndataqid)		setlength(NETID(c->qid.path));	devstat(c, dp, ns16552dir, ndir, devgen);}static Chan*ns16552open(Chan *c, int omode){	Uart *p;	c = devopen(c, omode, ns16552dir, ndir, devgen);	switch(NETTYPE(c->qid.path)){	case Nctlqid:	case Ndataqid:		p = uart[NETID(c->qid.path)];		if(p->kinuse)			error(Ekinuse);		qlock(p);		if(p->opens++ == 0){			ns16552enable(p);			qreopen(p->iq);			qreopen(p->oq);		}		qunlock(p);		break;	}	return c;}static voidns16552close(Chan *c){	Uart *p;	if(c->qid.path & CHDIR)		return;	if((c->flag & COPEN) == 0)		return;	switch(NETTYPE(c->qid.path)){	case Ndataqid:	case Nctlqid:		p = uart[NETID(c->qid.path)];		if(p->kinuse)			error(Ekinuse);		qlock(p);		if(--(p->opens) == 0){			ns16552disable(p);			qclose(p->iq);			qclose(p->oq);			p->ip = p->istage;			p->dcd = p->dsr = p->dohup = 0;		}		qunlock(p);		break;	}}static longuartstatus(Chan*, Uart *p, void *buf, long n, long offset){	uchar mstat, fstat, istat, tstat;	char str[256];	str[0] = 0;	tstat = p->sticky[Mctl];	mstat = uartrdreg(p, Mstat);	istat = p->sticky[Iena];	fstat = p->sticky[Format];	snprint(str, sizeof str,		"b%d c%d d%d e%d l%d m%d p%c r%d s%d\n"		"%d %d %d%s%s%s%s%s\n",		p->baud,		p->hup_dcd, 		(tstat & Dtr) != 0,		p->hup_dsr,		(fstat & Bits8) + 5,		(istat & Imstat) != 0, 		(fstat & Pena) ? ((fstat & Peven) ? 'e' : 'o') : 'n',		(tstat & Rts) != 0,		(fstat & Stop2) ? 2 : 1,		p->dev,		p->frame,		p->overrun, 		p->fifoon       ? " fifo" : "",		(mstat & Cts)    ? " cts"  : "",		(mstat & Dsr)    ? " dsr"  : "",		(mstat & Dcd)    ? " dcd"  : "",		(mstat & Ring)   ? " ring" : ""	);	return readstr(offset, buf, n, str);}static longns16552read(Chan *c, void *buf, long n, vlong off){	Uart *p;	ulong offset = off;	if(c->qid.path & CHDIR){		setlength(-1);		return devdirread(c, buf, n, ns16552dir, ndir, devgen);	}	p = uart[NETID(c->qid.path)];	if(p->kinuse)		error(Ekinuse);	switch(NETTYPE(c->qid.path)){	case Ndataqid:		return qread(p->iq, buf, n);	case Nctlqid:		return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);	case Nstatqid:		return uartstatus(c, p, buf, n, offset);	}	return 0;}static voidns16552ctl(Uart *p, char *cmd){	int i, n;	/* let output drain for a while */	for(i = 0; i < 16 && qlen(p->oq); i++)		tsleep(&p->r, (int(*)(void*))qlen, p->oq, 125);	if(strncmp(cmd, "break", 5) == 0){		ns16552break(p, 0);		return;	}	n = atoi(cmd+1);	switch(*cmd){	case 'B':	case 'b':		ns16552setbaud(p, n);		break;	case 'C':	case 'c':		ns16552dcdhup(p, n);		break;	case 'D':	case 'd':		ns16552dtr(p, n);		break;	case 'E':	case 'e':		ns16552dsrhup(p, n);		break;	case 'f':	case 'F':		qflush(p->oq);		break;	case 'H':	case 'h':		qhangup(p->iq, 0);		qhangup(p->oq, 0);		break;	case 'L':	case 'l':		ns16552bits(p, n);		break;	case 'm':	case 'M':		ns16552mflow(p, n);		break;	case 'n':	case 'N':		qnoblock(p->oq, n);		break;	case 'P':	case 'p':		ns16552parity(p, *(cmd+1));		break;	case 'K':	case 'k':		ns16552break(p, n);		break;	case 'R':	case 'r':		ns16552rts(p, n);		break;	case 'Q':	case 'q':		qsetlimit(p->iq, n);		qsetlimit(p->oq, n);		break;	case 'T':	case 't':		ns16552dcdts(p, n);		break;	case 'W':	case 'w':		/* obsolete */		break;	case 'X':	case 'x':		ilock(&p->tlock);		p->xonoff = n;		iunlock(&p->tlock);		break;	}}static longns16552write(Chan *c, void *buf, long n, vlong){	Uart *p;	char cmd[32];	if(c->qid.path & CHDIR)		error(Eperm);	p = uart[NETID(c->qid.path)];	if(p->kinuse)		error(Ekinuse);	/*	 *  The fifo's turn themselves off sometimes.	 *  It must be something I don't understand. -- presotto	 */	lock(&p->flock);	if((p->istat & Fenabd) == 0 && p->fifoon && p->type < Ns550)		ns16552fifoon(p);	unlock(&p->flock);	switch(NETTYPE(c->qid.path)){	case Ndataqid:		return qwrite(p->oq, buf, n);	case Nctlqid:		if(n >= sizeof(cmd))			n = sizeof(cmd)-1;		memmove(cmd, buf, n);		cmd[n] = 0;		ns16552ctl(p, cmd);		return n;	}}static voidns16552wstat(Chan *c, char *dp){	Dir d;	Dirtab *dt;	if(!iseve())		error(Eperm);	if(CHDIR & c->qid.path)		error(Eperm);	if(NETTYPE(c->qid.path) == Nstatqid)		error(Eperm);	dt = &ns16552dir[3 * NETID(c->qid.path)];	convM2D(dp, &d);	d.mode &= 0666;	dt[0].perm = dt[1].perm = d.mode;}Dev ns16552devtab = {	't',	"ns16552",	ns16552reset,	devinit,	ns16552attach,	devclone,	ns16552walk,	ns16552stat,	ns16552open,	devcreate,	ns16552close,	ns16552read,	devbread,	ns16552write,	devbwrite,	devremove,	ns16552wstat,};/* * Polling I/O routines for kernel debugging helps. */static voidns16552setuppoll(Uart *p, int rate){	ulong brconst;	/*	 * 8 bits/character, 1 stop bit;	 * set rate to rate baud;	 * turn on Rts and Dtr.	 */	memmove(p->osticky, p->sticky, sizeof p->osticky);		p->sticky[Format] = Bits8;	uartwrreg(p, Format, 0);	brconst = (UartFREQ+8*rate-1)/(16*rate);	uartwrreg(p, Format, Dra);	outb(p->port+Dmsb, (brconst>>8) & 0xff);	outb(p->port+Dlsb, brconst & 0xff);	uartwrreg(p, Format, 0);	p->sticky[Mctl] = Rts|Dtr;	uartwrreg(p, Mctl, 0);	p->kinuse = 1;}/* * Restore serial state from before kernel took over. */static voidns16552restore(Uart *p){	ulong brconst;	memmove(p->sticky, p->osticky, sizeof p->sticky);	uartwrreg(p, Format, 0);	brconst = (UartFREQ+8*p->baud-1)/(16*p->baud);	uartwrreg(p, Format, Dra);	outb(p->port+Dmsb, (brconst>>8) & 0xff);	outb(p->port+Dlsb, brconst & 0xff);	uartwrreg(p, Format, 0);	uartwrreg(p, Mctl, 0);	p->kinuse = 0;}/* BUG should be configurable */enum {	WHICH = 0,	RATE = 9600,};intserialgetc(void){	Uart *p;	int c;	if((p=uart[WHICH]) == nil)		return -1;	if(!p->kinuse)		ns16552setuppoll(p, RATE);	while((uartrdreg(p, Lstat)&Inready) == 0)		;	c = inb(p->port+Data) & 0xFF;	return c;	// there should be a restore here but i think it will slow things down too much.}static voidserialputc(Uart *p, int c){	while((uartrdreg(p, Lstat)&Outready) == 0)		;	outb(p->port+Data, c);	while((uartrdreg(p, Lstat)&Outready) == 0)		;}voidserialputs(char *s, int n){	Uart *p;	if((p=uart[WHICH]) == nil)		return;	if(!p->kinuse)		ns16552setuppoll(p, RATE);	while(n-- > 0){		serialputc(p, *s);		if(*s == '\n')			serialputc(p, '\r');		s++;	}	ns16552restore(p);}

⌨️ 快捷键说明

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