#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "msaturn.h" enum{ UartAoffs = Saturn + 0x0a00, UartBoffs = Saturn + 0x0b00, Nuart = 2, Baudfreq = 14745600 / 16, Lcr_div = RBIT(1, uchar), Lcr_peven = RBIT(3, uchar), Lcr_pen = RBIT(4, uchar), Lcr_stop = RBIT(5, uchar), Lcr_wrdlenmask = RBIT(6, uchar) | RBIT(7, uchar), Lcr_wrdlenshift = 0, Lsr_tbre = RBIT(2, uchar), Fcr_txreset = RBIT(5, uchar), Fcr_rxreset = RBIT(6, uchar), Iir_txempty = RBIT(5, uchar), Iir_rxfull = RBIT(6, uchar), Iir_rxerr = RBIT(7, uchar), Ier_rxerr = RBIT(5, uchar), Ier_txempty = RBIT(6, uchar), Ier_rxfull = RBIT(7, uchar), Lsr_rxavail = RBIT(7, uchar), Txsize = 16, Rxsize = 16, }; typedef struct Saturnuart Saturnuart; struct Saturnuart { uchar rxb; #define txb rxb #define dll rxb uchar ier; // Interrupt enable, divisor latch #define dlm ier uchar iir; // Interrupt identification, fifo control #define fcr iir uchar lcr; // Line control register uchar f1; uchar lsr; // Line status register ushort f2; }; typedef struct UartData UartData; struct UartData { int suno; /* saturn uart number: 0 or 1 */ Saturnuart *su; char *rxbuf; char *txbuf; int initialized; int enabled; } uartdata[Nuart]; extern PhysUart saturnphysuart; Uart suart[Nuart] = { { .name = "SaturnUart1", .baud = 19200, .bits = 8, .stop = 1, .parity = 'n', .phys = &saturnphysuart, .special = 0, }, { .name = "SaturnUart2", .baud = 115200, .bits = 8, .stop = 1, .parity = 'n', .phys = &saturnphysuart, .special = 0, }, }; static void suinterrupt(Ureg*, void*); static Uart* supnp(void) { int i; for (i = 0; i < nelem(suart)-1; i++) suart[i].next = &suart[i + 1]; suart[nelem(suart)-1].next=nil; return suart; } static void suinit(Uart*uart) { UartData *ud; Saturnuart *su; ud = uart->regs; su = ud->su; su->fcr=Fcr_txreset|Fcr_rxreset; ud->initialized=1; } static void suenable(Uart*uart, int ie) { Saturnuart *su; UartData *ud; int nr; nr = uart - suart; if (nr < 0 || nr > Nuart) panic("No uart %d", nr); ud = uartdata + nr; ud->suno = nr; su=ud->su = (Saturnuart*)((nr == 0)? UartAoffs: UartBoffs); uart->regs = ud; if(ud->initialized==0) suinit(uart); if(!ud->enabled && ie){ intrenable(Vecuart0+nr , suinterrupt, uart, uart->name); su->ier=Ier_txempty|Ier_rxfull; ud->enabled=1; } } static long sustatus(Uart* uart, void* buf, long n, long offset) { Saturnuart *su; char p[128]; su = ((UartData*)uart->regs)->su; snprint(p, sizeof p, "b%d c%d e%d l%d m0 p%c s%d i1\n" "dev(%d) type(%d) framing(%d) overruns(%d)\n", uart->baud, uart->hup_dcd, uart->hup_dsr, Txsize, (su->lcr & Lcr_pen)? ((su->lcr & Lcr_peven) ? 'e': 'o'): 'n', (su->lcr & Lcr_stop)? 2: 1, uart->dev, uart->type, uart->ferr, uart->oerr); n = readstr(offset, buf, n, p); free(p); return n; } static void sufifo(Uart*, int) {} static void sudtr(Uart*, int) {} static void surts(Uart*, int) {} static void sumodemctl(Uart*, int) {} static int suparity(Uart*uart, int parity) { int lcr; Saturnuart *su; su = ((UartData*)uart->regs)->su; lcr = su->lcr & ~(Lcr_pen|Lcr_peven); switch(parity){ case 'e': lcr |= (Lcr_pen|Lcr_peven); break; case 'o': lcr |= Lcr_pen; break; case 'n': default: break; } su->lcr = lcr; uart->parity = parity; return 0; } static int sustop(Uart* uart, int stop) { int lcr; Saturnuart *su; su = ((UartData*)uart->regs)->su; lcr = su->lcr & ~Lcr_stop; switch(stop){ case 1: break; case 2: lcr |= Lcr_stop; break; default: return -1; } /* Set new value and reenable if device was previously enabled */ su->lcr = lcr; uart->stop = stop; return 0; } static int subits(Uart*uart, int n) { Saturnuart *su; uchar lcr; su = ((UartData*)uart->regs)->su; if(n<5||n>8) return -1; lcr = su->lcr & ~Lcr_wrdlenmask; lcr |= (n-5) << Lcr_wrdlenshift; su->lcr = lcr; return 0; } static int subaud(Uart* uart, int baud) { ushort v; Saturnuart *su; if (uart->enabled){ su = ((UartData*)uart->regs)->su; if(baud <= 0) return -1; v = Baudfreq / baud; su->lcr |= Lcr_div; su->dll = v; su->dlm = v >> 8; su->lcr &= ~Lcr_div; } uart->baud = baud; return 0; } static void subreak(Uart*, int) {} static void sukick(Uart *uart) { Saturnuart *su; int i; if(uart->blocked) return; su = ((UartData*)uart->regs)->su; if((su->iir & Iir_txempty) == 0) return; for(i = 0; i < Txsize; i++){ if(uart->op >= uart->oe && uartstageoutput(uart) == 0) break; su->txb = *(uart->op++); su->ier |= Ier_txempty; break; } } static void suputc(Uart *uart, int c) { Saturnuart *su; su = ((UartData*)uart->regs)->su; while((su->lsr&Lsr_tbre) == 0) ; su->txb=c; while((su->lsr&Lsr_tbre) == 0) ; } static int getchars(Uart *uart, uchar *cbuf) { int nc; UartData *ud; Saturnuart *su; ud = uart->regs; su = ud->su; while((su->lsr&Lsr_rxavail) == 0) ; *cbuf++ = su->rxb; nc = 1; while(su->lsr&Lsr_rxavail){ *cbuf++ = su->rxb; nc++; } return nc; } static int sugetc(Uart *uart) { static uchar buf[128], *p; static int cnt; char c; if (cnt <= 0) { cnt = getchars(uart, buf); p = buf; } c = *p++; cnt--; return c; } static void suinterrupt(Ureg*, void*u) { Saturnuart *su; Uart *uart; uchar iir; uart = u; if (uart == nil) panic("uart is nil"); su = ((UartData*)uart->regs)->su; iir = su->iir; if(iir&Iir_rxfull) while(su->lsr&Lsr_rxavail) uartrecv(uart, su->rxb); if(iir & Iir_txempty){ su->ier&=~Ier_txempty; uartkick(uart); } if (iir & Iir_rxerr) uart->oerr++; intack(); } static void sudisable(Uart* uart) { Saturnuart *su; su = ((UartData*)uart->regs)->su; su->ier&=~(Ier_txempty|Ier_rxfull); } PhysUart saturnphysuart = { .name = "su", .pnp = supnp, .enable = suenable, .disable = sudisable, .kick = sukick, .dobreak = subreak, .baud = subaud, .bits = subits, .stop = sustop, .parity = suparity, .modemctl = sumodemctl, .rts = surts, .dtr = sudtr, .status = sustatus, .fifo = sufifo, .getc = sugetc, .putc = suputc, }; void console(void) { Uart *uart; int n; char *cmd, *p; if((p = getconf("console")) == nil) return; n = strtoul(p, &cmd, 0); if(p == cmd) return; if(n < 0 || n >= nelem(suart)) return; uart = suart + n; /* uartctl(uart, "b115200 l8 pn s1"); */ if(*cmd != '\0') uartctl(uart, cmd); (*uart->phys->enable)(uart, 0); consuart = uart; uart->console = 1; } Saturnuart*uart = (Saturnuart*)UartAoffs; void dbgputc(int c) { while((uart->lsr&Lsr_tbre) == 0) ; uart->txb=c; while((uart->lsr&Lsr_tbre) == 0) ; } void dbgputs(char*s) { while(*s) dbgputc(*s++); } void dbgputx(ulong x) { int i; char c; for(i=0; i < sizeof(ulong) * 2; i++){ c = ((x >> (28 - i * 4))) & 0xf; if(c >= 0 && c <= 9) c += '0'; else c += 'a' - 10; while((uart->lsr&Lsr_tbre) == 0) ; uart->txb=c; } while((uart->lsr&Lsr_tbre) == 0) ; uart->txb='\n'; while((uart->lsr&Lsr_tbre) == 0) ; }