Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/bitsy/sa1110uart.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname bitsy/sa1110uart.c 2000/1018
## diff -e /dev/null /n/emeliedump/2000/1018/sys/src/9/bitsy/sa1110uart.c
0a
#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"

/* this isn't strictly a sa1100 driver.  The rts/cts stuff is h3650 specific */

/* hardware registers */
typedef struct Uartregs Uartregs;
struct Uartregs
{
	ulong	ctl[4];
	ulong	dummya;
	ulong	data;
	ulong	dummyb;
	ulong	status[2];
};

enum
{
	/* ctl[0] bits */
	Parity=		1<<0,
	Even=		1<<1,
	Stop2=		1<<2,
	Bits8=		1<<3,
	SCE=		1<<4,	/* synchronous clock enable */
	RCE=		1<<5,	/* rx on falling edge of clock */
	TCE=		1<<6,	/* tx on falling edge of clock */

	/* ctl[3] bits */
	Rena=		1<<0,	/* receiver enable */
	Tena=		1<<1,	/* transmitter enable */
	Break=		1<<2,	/* force TXD3 low */
	Rintena=	1<<3,	/* enable receive interrupt */
	Tintena=	1<<4,	/* enable transmitter interrupt */
	Loopback=	1<<5,	/* loop back data */

	/* data bits */
	DEparity=	1<<8,	/* parity error */
	DEframe=	1<<9,	/* framing error */
	DEoverrun=	1<<10,	/* overrun error */

	/* status[0] bits */
	Tint=		1<<0,	/* transmit fifo half full interrupt */
	Rint0=		1<<1,	/* receiver fifo 1/3-2/3 full */
	Rint1=		1<<2,	/* receiver fifo not empty and receiver idle */
	Breakstart=	1<<3,
	Breakend=	1<<4,
	Fifoerror=	1<<5,	/* fifo error */

	/* status[1] bits */
	Tbusy=		1<<0,	/* transmitting */
	Rnotempty=	1<<1,	/* receive fifo not empty */
	Tnotfull=	1<<2,	/* transmit fifo not full */
	ParityError=	1<<3,
	FrameError=	1<<4,
	Overrun=	1<<5,
};

Uartregs *uart3regs = UART3REGS;

static void	sa1100_uartbaud(Uart *p, int rate);
static void	sa1100_uartkick(Uart *p);
static void	sa1100_uartrts(Uart *p, int on);
static void	sa1100_uartintr(Ureg*, void*);
static void	sa1100_uartbreak(Uart*, int);
static void	sa1100_uartbits(Uart*, int);
static void	sa1100_uartparity(Uart*, int);
static void	sa1100_uartmodemctl(Uart*, int);
static void	sa1100_uartstop(Uart*, int);
static void	sa1100_uartdtr(Uart*, int);
static long	sa1100_uartstatus(Uart*, void*, long, long);
static void	sa1100_uartenable(Uart*, int);
static void	sa1100_uartdisable(Uart*);

PhysUart sa1100_uart = {
	.enable=	sa1100_uartenable,
	.disable=	sa1100_uartdisable,
	.bits=		sa1100_uartbits,
	.kick=		sa1100_uartkick,
	.intr=		sa1100_uartintr,
	.modemctl=	sa1100_uartmodemctl,
	.baud=		sa1100_uartbaud,
	.stop=		sa1100_uartstop,
	.parity=	sa1100_uartparity,
	.dobreak=	sa1100_uartbreak,
	.rts=		sa1100_uartrts,
	.dtr=		sa1100_uartdtr,
	.status=	sa1100_uartstatus,
};

#define R(p) ((Uartregs*)(p->regs))

/*
 *  enable a port's interrupts.  set DTR and RTS
 */
static void
sa1100_uartenable(Uart *p, int intena)
{
	ulong s;

	s = R(p)->ctl[3] & ~(Rintena|Tintena|Rena|Tena);
	if(intena)
		R(p)->ctl[3] = s |Rintena|Tintena|Rena|Tena;
	else
		R(p)->ctl[3] = s | Rena|Tena;
}

/*
 *  disable interrupts. clear DTR, and RTS
 */
static void
sa1100_uartdisable(Uart *p)
{
	R(p)->ctl[3] &= ~(Rintena|Tintena|Rena|Tena);
}

static long
sa1100_uartstatus(Uart *p, void *buf, long n, long offset)
{
	char str[256];
	ulong ctl0;

	ctl0 = R(p)->ctl[0];
	snprint(str, sizeof(str),
		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
		"dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s\n",

		p->baud,
		p->hup_dcd, 
		0,
		p->hup_dsr,
		(ctl0 & Bits8) ? 8 : 7,
		0, 
		(ctl0 & Parity) ? ((ctl0 & Even) ? 'e' : 'o') : 'n',
		0,
		(ctl0 & Stop2) ? 2 : 1,
		1,

		p->dev,
		p->type,
		p->frame,
		p->overrun, 
		"",
		"",
		"",
		"" );
	return readstr(offset, buf, n, str);
}

/*
 *  set the buad rate
 */
static void
sa1100_uartbaud(Uart *p, int rate)
{
	ulong brconst;

	if(rate <= 0)
		return;

	brconst = p->freq/(16*rate) - 1;
	R(p)->ctl[1] = (brconst>>8) & 0xf;
	R(p)->ctl[2] = brconst;

	p->baud = rate;
}

/*
 *  send a break
 */
static void
sa1100_uartbreak(Uart *p, int ms)
{
	if(ms == 0)
		ms = 200;

	R(p)->ctl[3] |= Break;
	tsleep(&up->sleep, return0, 0, ms);
	R(p)->ctl[3] &= ~Break;
}

/*
 *  set bits/char
 */
static void
sa1100_uartbits(Uart *p, int n)
{
	switch(n){
	case 7:
		R(p)->ctl[0] &= ~Bits8;
		break;
	case 8:
		R(p)->ctl[0] |= Bits8;
		break;
	default:
		error(Ebadarg);
	}
}

/*
 *  set stop bits
 */
static void
sa1100_uartstop(Uart *p, int n)
{
	switch(n){
	case 1:
		R(p)->ctl[0] &= ~Stop2;
		break;
	case 2:
		R(p)->ctl[0] |= Stop2;
		break;
	default:
		error(Ebadarg);
	}
}

/*
 *  turn on/off rts
 */
static void
sa1100_uartrts(Uart*, int)
{
}

/*
 *  turn on/off dtr
 */
static void
sa1100_uartdtr(Uart*, int)
{
}

/*
 *  turn on/off modem flow control on/off (rts/cts)
 */
static void
sa1100_uartmodemctl(Uart *p, int on)
{
	if(on) {
	} else {
		p->cts = 1;
	}
}

/*
 *  set parity
 */
static void
sa1100_uartparity(Uart *p, int type)
{
	switch(type){
	case 'e':
		R(p)->ctl[0] |= Parity|Even;
		break;
	case 'o':
		R(p)->ctl[0] |= Parity;
		break;
	default:
		R(p)->ctl[0] &= ~(Parity|Even);
		break;
	}
}

/*
 *  restart output if not blocked and OK to send
 */
static void
sa1100_uartkick(Uart *p)
{
	int i;

	R(p)->ctl[3] &= ~Tintena;

	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(!(R(p)->status[1] & Tnotfull)){
			R(p)->ctl[3] |= Tintena;
			break;
		}
		if(p->op >= p->oe && uartstageoutput(p) == 0)
			break;
		R(p)->data = *p->op++;
	}
}

/*
 *  for iprint, just write it
 */
void
serialputs(char *str, int n)
{
	Uartregs *ur;

	ur = uart3regs;
	while(n-- > 0){
		/* wait for output ready */
		while((ur->status[1] & Tnotfull) == 0)
			;
		ur->data = *str++;
	}
	while((ur->status[1] & Tbusy))
		;
}

/*
 *  take an interrupt
 */
static void
sa1100_uartintr(Ureg*, void *x)
{
	Uart *p;
	ulong s;
	Uartregs *regs;

	p = x;
	regs = p->regs;

	/* remember and reset interrupt causes */
	s = regs->status[0];
	regs->status[0] |= s;

	if(s & Tint){
		/* transmitter interrupt, restart */
		uartkick(p);
	}

	/* receiver interrupt, snarf bytes */
	while(regs->status[1] & Rnotempty)
		uartrecv(p, regs->data);

	if(s & (ParityError|FrameError|Overrun)){
		if(s & ParityError)
			p->parity++;
		if(s & FrameError)
			p->frame++;
		if(s & Overrun)
			p->overrun++;
	}
}

typedef struct Gpclkregs Gpclkregs;
struct Gpclkregs
{
	ulong	r0;
	ulong	r1;
	ulong	dummya;
	ulong	r2;
	ulong	r3;
};

enum
{
	/* gpclk register 0 */
	Gpclk_sus=	1<<0,	/* set uart mode */
};

Gpclkregs *gpclkregs;

/*
 *  setup all uarts (called early by main() to allow debugging output to
 *  a serial port)
 */
void
sa1100_uartsetup(int console)
{
	Uart *p;
	Uartregs *uartregs;

	/* external serial port (eia0) */
	uart3regs = mapspecial(UART3REGS, 64);
	p = uartsetup(&sa1100_uart, uart3regs, ClockFreq, "serialport3");
	intrenable(IRQuart3, sa1100_uartintr, p, p->name);

	/* set eia0 up as a console */
	if(console)
		uartspecial(p, 115200, &kbdq, &printq, kbdcr2nl);

	/* port for talking to microcontroller (eia1) */
	gpclkregs = mapspecial(GPCLKREGS, 64);
	gpclkregs->r0 = Gpclk_sus;	/* set uart mode */
	uartregs = mapspecial(UART1REGS, 64);
	p = uartsetup(&sa1100_uart, uartregs, ClockFreq, "serialport1");
	sa1100_uartbaud(p, 115200);
	intrenable(IRQuart1b, sa1100_uartintr, p, p->name);
}
.
## diffname bitsy/sa1110uart.c 2000/1019
## diff -e /n/emeliedump/2000/1018/sys/src/9/bitsy/sa1110uart.c /n/emeliedump/2000/1019/sys/src/9/bitsy/sa1110uart.c
396,397c
	uart1regs = mapspecial(UART1REGS, 64);
	p = uartsetup(&sa1100_uart, uart1regs, ClockFreq, "serialport1");
.
382d
353a

	/* receiver interrupt, snarf bytes */
	while(regs->status[1] & Rnotempty)
		uartrecv(p, regs->data);
.
342,345d
332a
	/* receiver interrupt, snarf bytes */
	while(regs->status[1] & Rnotempty)
		uartrecv(p, regs->data);

.
268a

	/* reenable */
	R(p)->ctl[3] = ctl3;
.
257a
	ulong ctl3;

	/* disable */
	ctl3 = R(p)->ctl[3];
	R(p)->ctl[3] = 0;

.
221a

	/* reenable */
	R(p)->ctl[3] = ctl3;
.
211a
	ulong ctl3;

	/* disable */
	ctl3 = R(p)->ctl[3];
	R(p)->ctl[3] = 0;

.
203a

	/* reenable */
	R(p)->ctl[3] = ctl3;
.
193a
	ulong ctl3;

	/* disable */
	ctl3 = R(p)->ctl[3];
	R(p)->ctl[3] = 0;

.
170a
	/* reenable */
	R(p)->ctl[3] = ctl3;
.
169c
	R(p)->ctl[2] = brconst & 0xff;
.
166a
	/* disable */
	ctl3 = R(p)->ctl[3];
	R(p)->ctl[3] = 0;

.
162a
	ulong ctl3;
.
65a
Uartregs *uart1regs = UART1REGS ;
.
## diffname bitsy/sa1110uart.c 2000/1021
## diff -e /n/emeliedump/2000/1019/sys/src/9/bitsy/sa1110uart.c /n/emeliedump/2000/1021/sys/src/9/bitsy/sa1110uart.c
436c
	uartspecial(p, 115200, 0, 0, µcputc);
.
355a
 *  for iprint, just write it
 */
void
serialµcputs(uchar *str, int n)
{
	Uartregs *ur;

	ur = uart1regs;
	while(n-- > 0){
		/* wait for output ready */
		while((ur->status[1] & Tnotfull) == 0)
			;
		ur->data = *str++;
	}
	while((ur->status[1] & Tbusy))
		;
}

/*
.
## diffname bitsy/sa1110uart.c 2000/1106
## diff -e /n/emeliedump/2000/1021/sys/src/9/bitsy/sa1110uart.c /n/emeliedump/2000/1106/sys/src/9/bitsy/sa1110uart.c
319,325c
	for(i = 0; i < 1024; i++){
.
## diffname bitsy/sa1110uart.c 2000/1121
## diff -e /n/emeliedump/2000/1106/sys/src/9/bitsy/sa1110uart.c /n/emeliedump/2000/1121/sys/src/9/bitsy/sa1110uart.c
13,23d
## diffname bitsy/sa1110uart.c 2000/1205
## diff -e /n/emeliedump/2000/1121/sys/src/9/bitsy/sa1110uart.c /n/emeliedump/2000/1205/sys/src/9/bitsy/sa1110uart.c
439c
	intrenable(IRQ, IRQuart1b, sa1100_uartintr, p, p->name);
.
427c
	intrenable(IRQ, IRQuart3, sa1100_uartintr, p, p->name);
.
## diffname bitsy/sa1110uart.c 2001/0117
## diff -e /n/emeliedump/2000/1205/sys/src/9/bitsy/sa1110uart.c /n/emeliedump/2001/0117/sys/src/9/bitsy/sa1110uart.c
436a

.
## diffname bitsy/sa1110uart.c 2001/0529 # deleted
## diff -e /n/emeliedump/2001/0117/sys/src/9/bitsy/sa1110uart.c /n/emeliedump/2001/0529/sys/src/9/bitsy/sa1110uart.c
1,441d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].