devns16552.c

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

C
1,209
字号
#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"/* *  Driver for the ns16552. */enum{	/*	 *  register numbers	 */	Data=	0,		/* xmit/rcv buffer */	Iena=	1,		/* interrupt enable */	 Ircv=	(1<<0),		/*  for char rcv'd */	 Ixmt=	(1<<1),		/*  for xmit buffer empty */	 Irstat=(1<<2),		/*  for change in rcv'er status */	 Imstat=(1<<3),		/*  for change in modem status */	 Isleep=(1<<4),		/*  put in sleep mode; 16C650 */	 Ixoff=	(1<<5),		/*  for xoff received; 16C650 */	 Irts=	(1<<6),		/*  for !rts asserted in auto mode; 16C650 */	 Icts=	(1<<7),		/*  for !cts asserted in auto mode; 16C650 */	Istat=	2,		/* interrupt flag (read) */	 Fenabd=(3<<6),		/*  on if fifo's enabled */	 Irctsd=(1<<4),		/*  auto rts or cts changed state */	Fifoctl=2,		/* fifo control (write) */	 Fena=	(1<<0),		/*  enable xmit/rcv fifos */	 Ftrig4=	(1<<6),		/*  trigger after 4 input characters */	 Ftrig24=	(2<<6),		/*  trigger after 24 input characters */	 Fclear=(3<<1),		/*  clear xmit & rcv fifos */	Format=	3,		/* byte format */	 Bits8=	(3<<0),		/*  8 bits/byte */	 Stop2=	(1<<2),		/*  2 stop bits */	 Pena=	(1<<3),		/*  generate parity */	 Peven=	(1<<4),		/*  even parity */	 Pforce=(1<<5),		/*  force parity */	 Break=	(1<<6),		/*  generate a break */	 Dra=	(1<<7),		/*  address the divisor */	 Ers=	0xbf,		/*  enable enhaced register set on 16C650 */	Mctl=	4,		/* modem control */	 Dtr=	(1<<0),		/*  data terminal ready */	 Rts=	(1<<1),		/*  request to send */	 Ri=	(1<<2),		/*  ring */	 Inton=	(1<<3),		/*  turn on interrupts */	 Loop=	(1<<4),		/*  loop back */	 Intsel=(1<<5),		/*  NO! open source interrupts; 16C650 */	 Irda=	(1<<6),		/*  infrared interface; 16C650 */	 Cdiv=	(1<<7),		/*  divide clock by four; 16C650 */	Lstat=	5,		/* line status */	 Inready=(1<<0),	/*  receive buffer full */	 Oerror=(1<<1),		/*  receiver overrun */	 Perror=(1<<2),		/*  receiver parity error */	 Ferror=(1<<3),		/*  rcv framing error */	 Outready=(1<<5),	/*  output buffer full */	Mstat=	6,		/* modem status */	 Ctsc=	(1<<0),		/*  clear to send changed */	 Dsrc=	(1<<1),		/*  data set ready changed */	 Rire=	(1<<2),		/*  rising edge of ring indicator */	 Dcdc=	(1<<3),		/*  data carrier detect changed */	 Cts=	(1<<4),		/*  complement of clear to send line */	 Dsr=	(1<<5),		/*  complement of data set ready line */	 Ring=	(1<<6),		/*  complement of ring indicator line */	 Dcd=	(1<<7),		/*  complement of data carrier detect line */	Scratch=7,		/* scratchpad */	Dlsb=	0,		/* divisor lsb */	Dmsb=	1,		/* divisor msb */	Efr=	2,		/* enhanced features for 16C650 */	 Eena=	(1<<4),		/* enable enhanced bits in normal registers */	 Arts=	(1<<6),		/* auto rts */	 Acts=	(1<<7),		/* auto cts */	CTLS= 023,	CTLQ= 021,	Stagesize= 1024,	Nuart=	32,		/* max per machine */	Ns450=	0,	Ns550,	Ns650,};typedef struct Uart Uart;struct Uart{	QLock;	int	opens;	int	enabled;	Uart	*elist;			/* next enabled interface */	char	name[NAMELEN];	uchar	sticky[8];		/* sticky write register values */	uchar	osticky[8];		/* kernel saved sticky write register values */	ulong	port;			/* io ports */	ulong	freq;			/* clock frequency */	uchar	mask;			/* bits/char */	int	dev;	int	baud;			/* baud rate */	uchar	istat;			/* last istat read */	int	frame;			/* framing errors */	int	overrun;		/* rcvr overruns */	/* buffers */	int	(*putc)(Queue*, int);	Queue	*iq;	Queue	*oq;	Lock	flock;			/* fifo */	uchar	fifoon;			/* fifo's enabled */	uchar	type;			/* chip version */	Lock	rlock;			/* receive */	uchar	istage[Stagesize];	uchar	*ip;	uchar	*ie;	int	haveinput;	Lock	tlock;			/* transmit */	uchar	ostage[Stagesize];	uchar	*op;	uchar	*oe;	int	modem;			/* hardware flow control on */	int	xonoff;			/* software flow control on */	int	blocked;	int	cts, dsr, dcd, dcdts;		/* keep track of modem status */ 	int	ctsbackoff;	int	hup_dsr, hup_dcd;	/* send hangup upstream? */	int	dohup;	int	kinuse;		/* device in use by kernel */	Rendez	r;};static Uart *uart[Nuart];static int nuart;struct Uartalloc {	Lock;	Uart *elist;	/* list of enabled interfaces */} uartalloc;void ns16552intr(int);/* * means the kernel is using this for debugging output */static char	Ekinuse[] = "device in use by kernel";/* *  pick up architecture specific routines and definitions */#include "ns16552.h"/* *  set the baud rate by calculating and setting the baudrate *  generator constant.  This will work with fairly non-standard *  baud rates. */static voidns16552setbaud(Uart *p, int rate){	ulong brconst;	if(rate <= 0)		return;	brconst = (p->freq+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->baud = rate;}/* * decide if we should hangup when dsr or dcd drops. */static voidns16552dsrhup(Uart *p, int n){	p->hup_dsr = n;}static voidns16552dcdhup(Uart *p, int n){	p->hup_dcd = n;}static voidns16552parity(Uart *p, char type){	switch(type){	case 'e':		p->sticky[Format] |= Pena|Peven;		break;	case 'o':		p->sticky[Format] &= ~Peven;		p->sticky[Format] |= Pena;		break;	default:		p->sticky[Format] &= ~(Pena|Peven);		break;	}	uartwrreg(p, Format, 0);}/* *  set bits/character, default 8 */voidns16552bits(Uart *p, int bits){	if(bits < 5 || bits > 8)		error(Ebadarg);	p->sticky[Format] &= ~3;	p->sticky[Format] |= bits-5;	uartwrreg(p, Format, 0);}/* *  toggle DTR */voidns16552dtr(Uart *p, int n){	if(n)		p->sticky[Mctl] |= Dtr;	else		p->sticky[Mctl] &= ~Dtr;	uartwrreg(p, Mctl, 0);}/* *  toggle RTS */voidns16552rts(Uart *p, int n){	if(n)		p->sticky[Mctl] |= Rts;	else		p->sticky[Mctl] &= ~Rts;	uartwrreg(p, Mctl, 0);}/* *  save dcd timestamps for gps clock */static voidns16552dcdts(Uart *p, int n){	p->dcdts = n;}/* *  send break */static voidns16552break(Uart *p, int ms){	if(ms == 0)		ms = 200;	uartwrreg(p, Format, Break);	tsleep(&up->sleep, return0, 0, ms);	uartwrreg(p, Format, 0);}static voidns16552fifoon(Uart *p){	ulong i, x;	if(p->type < Ns550)		return;	x = splhi();	/* reset fifos */	uartwrreg(p, Fifoctl, Fclear);	/* empty buffer and interrupt conditions */	for(i = 0; i < 16; i++){		if(uartrdreg(p, Istat))			;		if(uartrdreg(p, Data))			;	}	/* turn on fifo */	p->fifoon = 1;	if(p->type == Ns650)		uartwrreg(p, Fifoctl, Fena|Ftrig24);	else		uartwrreg(p, Fifoctl, Fena|Ftrig4);	if((p->istat & Fenabd) == 0){		/* didn't work, must be an earlier chip type */		p->type = Ns450;	}	splx(x);}/* *  modem flow control on/off (rts/cts) */static voidns16552mflow(Uart *p, int n){	ilock(&p->tlock);	if(n){		if(p->type == Ns650){			outb(p->port + Format, 0xbf);			outb(p->port + Efr, Eena|Arts|Acts);			uartwrreg(p, Format, 0);			p->cts = 1;		} else {			p->sticky[Iena] |= Imstat;			uartwrreg(p, Iena, 0);			p->modem = 1;			p->cts = uartrdreg(p, Mstat) & Cts;		}	} else {		if(p->type == Ns650){			outb(p->port + Format, 0xbf);			outb(p->port + Efr, Eena|Arts|Acts);			uartwrreg(p, Format, 0);		} else {			p->sticky[Iena] &= ~Imstat;			uartwrreg(p, Iena, 0);			p->modem = 0;		}		p->cts = 1;	}	iunlock(&p->tlock);	ilock(&p->flock);	if(n)		/* turn on fifo's */		ns16552fifoon(p);	else {		/* turn off fifo's */		p->fifoon = 0;		uartwrreg(p, Fifoctl, 0);	}	iunlock(&p->flock);}/* *  turn on a port's interrupts.  set DTR and RTS */static voidns16552enable(Uart *p){	Uart **l;	if(p->enabled)		return;	uartpower(p->dev, 1);	p->hup_dsr = p->hup_dcd = 0;	p->cts = p->dsr = p->dcd = 0;	/* 	 *  turn on interrupts	 */	p->sticky[Iena] = Ircv | Ixmt | Irstat;	uartwrreg(p, Iena, 0);	/*	 *  turn on DTR and RTS	 */	ns16552dtr(p, 1);	ns16552rts(p, 1);	/*	 *  assume we can send	 */	ilock(&p->tlock);	p->cts = 1;	p->blocked = 0;	iunlock(&p->tlock);	/*	 *  set baud rate to the last used	 */	ns16552setbaud(p, p->baud);	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);}/* *  turn off a port's interrupts.  reset DTR and RTS */static voidns16552disable(Uart *p){	Uart **l;	/* 	 *  turn off interrupts	 */	p->sticky[Iena] = 0;	uartwrreg(p, Iena, 0);	/*	 *  revert to default settings	 */	p->sticky[Format] = Bits8;	uartwrreg(p, Format, 0);	/*	 *  turn off DTR, RTS, hardware flow control & fifo's	 */	ns16552dtr(p, 0);	ns16552rts(p, 0);	ns16552mflow(p, 0);	ilock(&p->tlock);	p->xonoff = p->blocked = 0;	iunlock(&p->tlock);	uartpower(p->dev, 0);	lock(&uartalloc);	for(l = &uartalloc.elist; *l; l = &(*l)->elist){		if(*l == p){			*l = p->elist;			break;		}	}	p->enabled = 0;	unlock(&uartalloc);}/* *  put some bytes into the local queue to avoid calling *  qconsume for every character */static intstageoutput(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;}/* *  (re)start output */static voidns16552kick0(void *v){	int i;	Uart *p;	p = v;	if(p->cts == 0 || p->blocked)		return;	/*	 *  128 here is an arbitrary limit to make sure	 *  we don't stay in this loop too long.  If the	 *  chips output queue is longer than 128, too	 *  bad -- presotto	 */	for(i = 0; i < 128; i++){		if(!(uartrdreg(p, Lstat) & Outready))			break;		if(p->op >= p->oe && stageoutput(p) == 0)			break;		outb(p->port + Data, *(p->op++));	}}static voidns16552kick(void *v){	Uart *p;	p = v;	ilock(&p->tlock);	ns16552kick0(p);	iunlock(&p->tlock);}/* *  restart input if it's off */static voidns16552flow(void *v){	Uart *p;	p = v;	if(p->modem){		ns16552rts(p, 1);		ilock(&p->rlock);		p->haveinput = 1;		iunlock(&p->rlock);	}}/* *  default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts, *  transmit and receive enabled, interrupts disabled. */static voidns16552setup0(Uart *p){	memset(p->sticky, 0, sizeof(p->sticky));	/*	 *  set rate to 9600 baud.	 *  8 bits/character.	 *  1 stop bit.	 *  interrupts enabled.	 */	p->sticky[Format] = Bits8;	uartwrreg(p, Format, 0);	p->sticky[Mctl] |= Inton;	uartwrreg(p, Mctl, 0x0);	ns16552setbaud(p, 9600);	p->iq = qopen(4*1024, 0, ns16552flow, p);	p->oq = qopen(4*1024, 0, ns16552kick, p);	if(p->iq == nil || p->oq == nil)		panic("ns16552setup0");	p->ip = p->istage;	p->ie = &p->istage[Stagesize];	p->op = p->ostage;	p->oe = p->ostage;}/* *  called by main() to create a new duart */voidns16552setup(ulong port, ulong freq, char *name, int type){	Uart *p;	if(nuart >= Nuart)		return;	p = xalloc(sizeof(Uart));	uart[nuart] = p;	strcpy(p->name, name);	p->dev = nuart;	nuart++;	p->port = port;	p->freq = freq;	p->type = type;	ns16552setup0(p);}/* *  called by main() to configure a duart port as a console or a mouse */voidns16552special(int port, int baud, Queue **in, Queue **out, int (*putc)(Queue*, int)){	Uart *p = uart[port];	ns16552enable(p);	if(baud)		ns16552setbaud(p, baud);	p->putc = putc;	if(in)

⌨️ 快捷键说明

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