244 lines
3.2 KiB
C
244 lines
3.2 KiB
C
#include "u.h"
|
|
#include "../port/lib.h"
|
|
#include "mem.h"
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
#include "io.h"
|
|
|
|
enum {
|
|
RBR = 0,
|
|
IER,
|
|
FCR,
|
|
LCR,
|
|
MCR,
|
|
LSR,
|
|
MSR,
|
|
SCR,
|
|
|
|
IIR = FCR,
|
|
};
|
|
|
|
enum {
|
|
LSR_THRE = 1<<5,
|
|
LSR_DR = 1<<0,
|
|
|
|
ENTXIRQ = 1<<1,
|
|
ENRXIRQ = 1<<0
|
|
};
|
|
|
|
typedef struct Ctlr {
|
|
Lock;
|
|
ulong *r;
|
|
int irq, iena;
|
|
} Ctlr;
|
|
|
|
Uart* uartenable(Uart *);
|
|
|
|
extern PhysUart cycvphysuart;
|
|
|
|
static Ctlr vctlr[1] = {
|
|
{
|
|
.r = (void *) UART_BASE,
|
|
.irq = UART0IRQ,
|
|
}
|
|
};
|
|
|
|
static Uart vuart[1] = {
|
|
{
|
|
.regs = &vctlr[0],
|
|
.name = "UART1",
|
|
.freq = 25000000,
|
|
.phys = &cycvphysuart,
|
|
.console = 1,
|
|
.baud = 115200,
|
|
}
|
|
};
|
|
|
|
void
|
|
uartinit(void)
|
|
{
|
|
consuart = vuart;
|
|
}
|
|
|
|
static Uart *
|
|
vuartpnp(void)
|
|
{
|
|
return vuart;
|
|
}
|
|
|
|
static void
|
|
vuartkick(Uart *uart)
|
|
{
|
|
Ctlr *ct;
|
|
int i;
|
|
|
|
if(uart->blocked)
|
|
return;
|
|
ct = uart->regs;
|
|
if((ct->r[LSR] & LSR_THRE) == 0)
|
|
return;
|
|
for(i = 0; i < 128; i++){
|
|
if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
|
|
break;
|
|
ct->r[RBR] = *uart->op++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
vuartintr(Ureg *, void *arg)
|
|
{
|
|
Uart *uart;
|
|
Ctlr *c;
|
|
int ch, f;
|
|
|
|
uart = arg;
|
|
c = uart->regs;
|
|
for(;;){
|
|
f = c->r[IIR] & 15;
|
|
switch(f){
|
|
case 6: USED(c->r[LSR]); break;
|
|
case 4: case 8:
|
|
while((c->r[LSR] & LSR_DR) != 0){
|
|
ch = c->r[RBR];
|
|
uartrecv(uart, ch);
|
|
}
|
|
break;
|
|
case 2:
|
|
vuartkick(uart);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
vuartenable(Uart *uart, int ie)
|
|
{
|
|
Ctlr *c;
|
|
|
|
c = uart->regs;
|
|
ilock(c);
|
|
while((c->r[LSR] & LSR_THRE) == 0)
|
|
;
|
|
c->r[LCR] = 0x03;
|
|
c->r[FCR] = 0x1;
|
|
c->r[IER] = 0x0;
|
|
if(ie){
|
|
if(!c->iena){
|
|
intrenable(c->irq, vuartintr, uart, LEVEL, uart->name);
|
|
c->iena = 1;
|
|
}
|
|
c->r[IER] = ENTXIRQ | ENRXIRQ;
|
|
}
|
|
iunlock(c);
|
|
}
|
|
|
|
static int
|
|
vuartgetc(Uart *uart)
|
|
{
|
|
Ctlr *c;
|
|
|
|
c = uart->regs;
|
|
while((c->r[LSR] & LSR_DR) == 0)
|
|
;
|
|
return c->r[RBR];
|
|
}
|
|
|
|
static void
|
|
vuartputc(Uart *uart, int c)
|
|
{
|
|
Ctlr *ct;
|
|
|
|
ct = uart->regs;
|
|
while((ct->r[LSR] & LSR_THRE) == 0)
|
|
;
|
|
ct->r[RBR] = c;
|
|
return;
|
|
}
|
|
|
|
int
|
|
uartconsole(void)
|
|
{
|
|
Uart *uart = vuart;
|
|
|
|
if(up == nil)
|
|
return -1;
|
|
|
|
if(uartenable(uart) != nil){
|
|
serialoq = uart->oq;
|
|
uart->opens++;
|
|
consuart = uart;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
vuartbits(Uart *uart, int n)
|
|
{
|
|
Ctlr *c;
|
|
|
|
c = uart->regs;
|
|
switch(n){
|
|
case 5: c->r[LCR] = c->r[LCR] & ~3 | 0; return 0;
|
|
case 6: c->r[LCR] = c->r[LCR] & ~3 | 1; return 0;
|
|
case 7: c->r[LCR] = c->r[LCR] & ~3 | 2; return 0;
|
|
case 8: c->r[LCR] = c->r[LCR] & ~3 | 3; return 0;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int
|
|
vuartbaud(Uart *, int n)
|
|
{
|
|
print("uart baud %d\n", n);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
vuartparity(Uart *uart, int p)
|
|
{
|
|
Ctlr *c;
|
|
|
|
c = uart->regs;
|
|
switch(p){
|
|
case 'n': c->r[LCR] = c->r[LCR] & ~0x38; return 0;
|
|
case 'o': c->r[LCR] = c->r[LCR] & ~0x38 | 0x08; return 0;
|
|
case 'e': c->r[LCR] = c->r[LCR] & ~0x38 | 0x18; return 0;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
void
|
|
vuartnop(Uart *, int)
|
|
{
|
|
}
|
|
|
|
int
|
|
vuartnope(Uart *, int)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
|
|
PhysUart cycvphysuart = {
|
|
.pnp = vuartpnp,
|
|
.enable = vuartenable,
|
|
.kick = vuartkick,
|
|
.getc = vuartgetc,
|
|
.putc = vuartputc,
|
|
.bits = vuartbits,
|
|
.baud = vuartbaud,
|
|
.parity = vuartparity,
|
|
|
|
.stop = vuartnope,
|
|
.rts = vuartnop,
|
|
.dtr = vuartnop,
|
|
.dobreak = vuartnop,
|
|
.fifo = vuartnop,
|
|
.power = vuartnop,
|
|
.modemctl = vuartnop,
|
|
};
|