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

📄 devuart.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h"#include	"../port/error.h"#include	"../port/netif.h"enum{	/* soft flow control chars */	CTLS= 023,	CTLQ= 021,};extern Dev uartdevtab;extern PhysUart* physuart[];static Uart* uartlist;static Uart** uart;static int uartnuart;static Dirtab *uartdir;static int uartndir;static Timer *uarttimer;struct Uartalloc {	Lock;	Uart *elist;	/* list of enabled interfaces */} uartalloc;static void	uartclock(void);static void	uartflow(void*);/* *  enable/disable uart and add/remove to list of enabled uarts */static Uart*uartenable(Uart *p){	Uart **l;	if(p->iq == nil){		if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil)			return nil;	}	else		qreopen(p->iq);	if(p->oq == nil){		if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){			qfree(p->iq);			p->iq = nil;			return nil;		}	}	else		qreopen(p->oq);	p->ir = p->istage;	p->iw = p->istage;	p->ie = &p->istage[Stagesize];	p->op = p->ostage;	p->oe = p->ostage;	p->hup_dsr = p->hup_dcd = 0;	p->dsr = p->dcd = 0;	/* assume we can send */	p->cts = 1;	p->ctsbackoff = 0;	if(p->bits == 0)		uartctl(p, "l8");	if(p->stop == 0)		uartctl(p, "s1");	if(p->parity == 0)		uartctl(p, "pn");	if(p->baud == 0)		uartctl(p, "b9600");	(*p->phys->enable)(p, 1);	lock(&uartalloc);	for(l = &uartalloc.elist; *l; l = &(*l)->elist){		if(*l == p)			break;	}	if(*l == 0){		p->elist = uartalloc.elist;		uartalloc.elist = p;	}	p->enabled = 1;	unlock(&uartalloc);	return p;}static voiduartdisable(Uart *p){	Uart **l;	(*p->phys->disable)(p);	lock(&uartalloc);	for(l = &uartalloc.elist; *l; l = &(*l)->elist){		if(*l == p){			*l = p->elist;			break;		}	}	p->enabled = 0;	unlock(&uartalloc);}voiduartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200){	qlock(p);	if(p->opens++ == 0 && uartenable(p) == nil){		qunlock(p);		error(Enodev);	}	if(setb1200)		uartctl(p, "b1200");	p->putc = putc;	p->special = 1;	qunlock(p);}voiduartsetmouseputc(Uart* p, int (*putc)(Queue*, int)){	qlock(p);	if(p->opens == 0 || p->special == 0){		qunlock(p);		error(Enodev);	}	p->putc = putc;	qunlock(p);}static voidsetlength(int i){	Uart *p;	if(i > 0){		p = uart[i];		if(p && p->opens && p->iq)			uartdir[1+3*i].length = qlen(p->iq);	} else for(i = 0; i < uartnuart; i++){		p = uart[i];		if(p && p->opens && p->iq)			uartdir[1+3*i].length = qlen(p->iq);	}}/* *  set up the '#t' directory */static voiduartreset(void){	int i;	Dirtab *dp;	Uart *p, *tail;	tail = nil;	for(i = 0; physuart[i] != nil; i++){		if(physuart[i]->pnp == nil)			continue;		if((p = physuart[i]->pnp()) == nil)			continue;		if(uartlist != nil)			tail->next = p;		else			uartlist = p;		for(tail = p; tail->next != nil; tail = tail->next)			uartnuart++;		uartnuart++;	}	if(uartnuart)		uart = xalloc(uartnuart*sizeof(Uart*));	uartndir = 1 + 3*uartnuart;	uartdir = xalloc(uartndir * sizeof(Dirtab));	dp = uartdir;	strcpy(dp->name, ".");	mkqid(&dp->qid, 0, 0, QTDIR);	dp->length = 0;	dp->perm = DMDIR|0555;	dp++;	p = uartlist;	for(i = 0; i < uartnuart; i++){		/* 3 directory entries per port */		sprint(dp->name, "eia%d", i);		dp->qid.path = NETQID(i, Ndataqid);		dp->perm = 0660;		dp++;		sprint(dp->name, "eia%dctl", i);		dp->qid.path = NETQID(i, Nctlqid);		dp->perm = 0660;		dp++;		sprint(dp->name, "eia%dstatus", i);		dp->qid.path = NETQID(i, Nstatqid);		dp->perm = 0444;		dp++;		uart[i] = p;		p->dev = i;		if(p->console || p->special){			if(uartenable(p) != nil){				if(p->console){					kbdq = p->iq;					serialoq = p->oq;					p->putc = kbdcr2nl;				}				p->opens++;			}		}		p = p->next;	}	if(uartnuart){		/*		 * at 115200 baud, the 1024 char buffer takes 56 ms to process,		 * processing it every 22 ms should be fine.		 */		uarttimer = addclock0link(uartclock, 22);	}}static Chan*uartattach(char *spec){	return devattach('t', spec);}static Walkqid*uartwalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, uartdir, uartndir, devgen);}static intuartstat(Chan *c, uchar *dp, int n){	if(NETTYPE(c->qid.path) == Ndataqid)		setlength(NETID(c->qid.path));	return devstat(c, dp, n, uartdir, uartndir, devgen);}static Chan*uartopen(Chan *c, int omode){	Uart *p;	c = devopen(c, omode, uartdir, uartndir, devgen);	switch(NETTYPE(c->qid.path)){	case Nctlqid:	case Ndataqid:		p = uart[NETID(c->qid.path)];		qlock(p);		if(p->opens++ == 0 && uartenable(p) == nil){			qunlock(p);			c->flag &= ~COPEN;			error(Enodev);		}		qunlock(p);		break;	}	c->iounit = qiomaxatomic;	return c;}static intuartdrained(void* arg){	Uart *p;	p = arg;	return qlen(p->oq) == 0 && p->op == p->oe;}static voiduartdrainoutput(Uart *p){	if(!p->enabled)		return;	p->drain = 1;	if(waserror()){		p->drain = 0;		nexterror();	}	sleep(&p->r, uartdrained, p);	poperror();}static voiduartclose(Chan *c){	Uart *p;	if(c->qid.type & QTDIR)		return;	if((c->flag & COPEN) == 0)		return;	switch(NETTYPE(c->qid.path)){	case Ndataqid:	case Nctlqid:		p = uart[NETID(c->qid.path)];		qlock(p);		if(--(p->opens) == 0){			qclose(p->iq);			ilock(&p->rlock);			p->ir = p->iw = p->istage;			iunlock(&p->rlock);			/*			 */			qhangup(p->oq, nil);			if(!waserror()){				uartdrainoutput(p);				poperror();			}			qclose(p->oq);			uartdisable(p);			p->dcd = p->dsr = p->dohup = 0;		}		qunlock(p);		break;	}}static longuartread(Chan *c, void *buf, long n, vlong off){	Uart *p;	ulong offset = off;	if(c->qid.type & QTDIR){		setlength(-1);		return devdirread(c, buf, n, uartdir, uartndir, devgen);	}	p = uart[NETID(c->qid.path)];	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 (*p->phys->status)(p, buf, n, offset);	}	return 0;}intuartctl(Uart *p, char *cmd){	char *f[16];	int i, n, nf;	nf = tokenize(cmd, f, nelem(f));	for(i = 0; i < nf; i++){		if(strncmp(f[i], "break", 5) == 0){			(*p->phys->dobreak)(p, 0);			continue;		}		n = atoi(f[i]+1);		switch(*f[i]){		case 'B':		case 'b':			uartdrainoutput(p);			if((*p->phys->baud)(p, n) < 0)				return -1;			break;		case 'C':		case 'c':			p->hup_dcd = n;			break;		case 'D':		case 'd':			uartdrainoutput(p);			(*p->phys->dtr)(p, n);			break;		case 'E':		case 'e':			p->hup_dsr = n;			break;		case 'f':		case 'F':			if(p->oq != nil)				qflush(p->oq);			break;		case 'H':		case 'h':			if(p->iq != nil)				qhangup(p->iq, 0);			if(p->oq != nil)				qhangup(p->oq, 0);			break;		case 'i':		case 'I':			uartdrainoutput(p);			(*p->phys->fifo)(p, n);			break;		case 'K':		case 'k':			uartdrainoutput(p);			(*p->phys->dobreak)(p, n);			break;		case 'L':		case 'l':			uartdrainoutput(p);			if((*p->phys->bits)(p, n) < 0)				return -1;			break;		case 'm':		case 'M':			uartdrainoutput(p);			(*p->phys->modemctl)(p, n);			break;		case 'n':		case 'N':			if(p->oq != nil)				qnoblock(p->oq, n);			break;		case 'P':		case 'p':			uartdrainoutput(p);			if((*p->phys->parity)(p, *(f[i]+1)) < 0)				return -1;			break;		case 'Q':		case 'q':			if(p->iq != nil)				qsetlimit(p->iq, n);			if(p->oq != nil)				qsetlimit(p->oq, n);			break;		case 'R':		case 'r':			uartdrainoutput(p);			(*p->phys->rts)(p, n);			break;		case 'S':		case 's':			uartdrainoutput(p);			if((*p->phys->stop)(p, n) < 0)				return -1;			break;		case 'W':		case 'w':			if(uarttimer == nil || n < 1)				return -1;			uarttimer->tns = (vlong)n * 100000LL;			break;		case 'X':		case 'x':			if(p->enabled){				ilock(&p->tlock);				p->xonoff = n;				iunlock(&p->tlock);			}			break;		}	}	return 0;}static longuartwrite(Chan *c, void *buf, long n, vlong){	Uart *p;	char *cmd;	if(c->qid.type & QTDIR)		error(Eperm);	p = uart[NETID(c->qid.path)];	switch(NETTYPE(c->qid.path)){	case Ndataqid:		qlock(p);		if(waserror()){			qunlock(p);			nexterror();		}		n = qwrite(p->oq, buf, n);		qunlock(p);		poperror();		break;	case Nctlqid:		cmd = malloc(n+1);		memmove(cmd, buf, n);		cmd[n] = 0;		qlock(p);		if(waserror()){			qunlock(p);			free(cmd);			nexterror();		}		/* let output drain */		if(uartctl(p, cmd) < 0)			error(Ebadarg);		qunlock(p);		poperror();		free(cmd);		break;	}	return n;}static intuartwstat(Chan *c, uchar *dp, int n){	Dir d;	Dirtab *dt;	if(!iseve())		error(Eperm);	if(QTDIR & c->qid.type)		error(Eperm);	if(NETTYPE(c->qid.path) == Nstatqid)		error(Eperm);	dt = &uartdir[1 + 3 * NETID(c->qid.path)];	n = convM2D(dp, n, &d, nil);	if(n == 0)		error(Eshortstat);	if(d.mode != ~0UL)		dt[0].perm = dt[1].perm = d.mode;	return n;}voiduartpower(int on){	Uart *p;	for(p = uartlist; p != nil; p = p->next) {		if(p->phys->power)			(*p->phys->power)(p, on);	}}Dev uartdevtab = {	't',	"uart",	uartreset,	devinit,	devshutdown,	uartattach,	uartwalk,	uartstat,	uartopen,	devcreate,	uartclose,	uartread,	devbread,	uartwrite,	devbwrite,	devremove,	uartwstat,	uartpower,};/* *  restart input if it's off */static voiduartflow(void *v){	Uart *p;	p = v;	if(p->modem)		(*p->phys->rts)(p, 1);}/* *  put some bytes into the local queue to avoid calling *  qconsume for every character */intuartstageoutput(Uart *p){	int n;	n = qconsume(p->oq, p->ostage, Stagesize);	if(n <= 0)		return 0;	p->op = p->ostage;	p->oe = p->ostage + n;	return n;}/* *  restart output */voiduartkick(void *v){	Uart *p = v;	if(p->blocked)		return;	ilock(&p->tlock);	(*p->phys->kick)(p);	iunlock(&p->tlock);	if(p->drain && uartdrained(p)){		p->drain = 0;		wakeup(&p->r);	}}/* * Move data from the interrupt staging area to * the input Queue. */static voiduartstageinput(Uart *p){	int n;	uchar *ir, *iw;	while(p->ir != p->iw){		ir = p->ir;		if(p->ir > p->iw){			iw = p->ie;			p->ir = p->istage;		}		else{			iw = p->iw;			p->ir = p->iw;		}		if((n = qproduce(p->iq, ir, iw - ir)) < 0){			p->serr++;			(*p->phys->rts)(p, 0);		}		else if(n == 0)			p->berr++;	}}/* *  receive a character at interrupt time */voiduartrecv(Uart *p,  char ch){	uchar *next;	/* software flow control */	if(p->xonoff){		if(ch == CTLS){			p->blocked = 1;		}else if(ch == CTLQ){			p->blocked = 0;			p->ctsbackoff = 2; /* clock gets output going again */		}	}	/* receive the character */	if(p->putc)		p->putc(p->iq, ch);	else if (p->iw) {		/* maybe the line isn't enabled yet */		ilock(&p->rlock);		next = p->iw + 1;		if(next == p->ie)			next = p->istage;		if(next == p->ir)			uartstageinput(p);		if(next != p->ir){			*p->iw = ch;			p->iw = next;		}		iunlock(&p->rlock);	}}/* *  we save up input characters till clock time to reduce *  per character interrupt overhead. */static voiduartclock(void){	Uart *p;	lock(&uartalloc);	for(p = uartalloc.elist; p; p = p->elist){		/* this hopefully amortizes cost of qproduce to many chars */		if(p->iw != p->ir){			ilock(&p->rlock);			uartstageinput(p);			iunlock(&p->rlock);		}		/* hang up if requested */		if(p->dohup){			qhangup(p->iq, 0);			qhangup(p->oq, 0);			p->dohup = 0;		}		/* this adds hysteresis to hardware/software flow control */		if(p->ctsbackoff){			ilock(&p->tlock);			if(p->ctsbackoff){				if(--(p->ctsbackoff) == 0)					(*p->phys->kick)(p);			}			iunlock(&p->tlock);		}	}	unlock(&uartalloc);}/* * polling console input, output */Uart* consuart;intuartgetc(void){	if(consuart == nil || consuart->phys->getc == nil)		return -1;	return consuart->phys->getc(consuart);}voiduartputc(int c){	if(consuart == nil || consuart->phys->putc == nil)		return;	consuart->phys->putc(consuart, c);}voiduartputs(char *s, int n){	char *e;	if(consuart == nil || consuart->phys->putc == nil)		return;	e = s+n;	for(; s<e; s++){		if(*s == '\n')			consuart->phys->putc(consuart, '\r');		consuart->phys->putc(consuart, *s);	}}

⌨️ 快捷键说明

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