9os

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit f3afd8162fad9e712b67ada1eb07763230154d78
parent a074501aeb8c9764eb13c50813cf51fcf5142792
Author: Dimitris Papastamos <dimitris.papastamos@arm.com>
Date:   Wed, 20 Feb 2019 13:04:55 +0000

Merge "[uart] Implement remaining bits"
Diffstat:
Mdrivers/devuart.c | 80+++++++++++++++++++++++++++++++++++--------------------------------------------
Mdrivers/pl011.c | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/uart.h | 32+++++++++++---------------------
3 files changed, 252 insertions(+), 66 deletions(-)

diff --git a/drivers/devuart.c b/drivers/devuart.c @@ -91,16 +91,16 @@ uartstatus(Uart *up, void *buf, long long offset, int n) len = ksnprint(tmp, sizeof(tmp), "b%ld c%d d%d e%d l%d m%d p%c r%d s%d i%d\n", - st.rate, - (st.hang & SIG_DCD) != 0, - st.dtr, - (st.hang & SIG_DSR) != 0, - st.nbits, - st.ctsflow, - st.parity, - st.rts, - st.stop, - st.fifo); + up->rate, + (up->hang & SIG_DCD) != 0, + up->dtr, + (up->hang & SIG_DSR) != 0, + up->nbits, + up->ctsflow, + up->parity, + up->rts, + up->nstop, + up->fifo); if (offset >= len) return 0; @@ -123,7 +123,6 @@ uartdrain(Uart *up) * cn Set hangup on DCD if n is non-zero; else clear it. * dn Set DTR if n is non-zero; else clear it. * f Flush output queue. - * h Close input and output queues. * in Enable/disable the FIFOs. If n is zero the FIFOs are * disabled; otherwise n is taken as a trigger level for * the FIFOs. The trigger levels supported are device @@ -131,17 +130,13 @@ uartdrain(Uart *up) * nised, but non-zero, value of n causes the maximum- * supported trigger level to be set. * en Set hangup on DSR if n is non-zero; else clear it. - * kn Send a break lasting n milliseconds. * ln Set number of bits per byte to n. Legal values are 5, * 6, 7, or 8. * mn Obey modem CTS signal if n is non-zero; else clear it. - * n Make writes non-blocking. * pc Set parity to odd if c is o, to even if c is e; else * set no parity. - * qn Set input and output queue limits to n. * rn Set RTS if n is non-zero; else clear it. * sn Set number of stop bits to n. Legal values are 1 or 2. - * wn Set the uart clock timer to n times 100us. */ static int uartctl(Uart *up, char *cfg, int n) @@ -150,8 +145,8 @@ uartctl(Uart *up, char *cfg, int n) Uartphy *phy = up->phy; unsigned char *s = (unsigned char *) cfg; - for (cnt = i = 0; i < n; cnt = i++) { - int par, c = s[i]; + for (cnt = i = 0; i < n; cnt = ++i) { + int sig, par, c = s[i]; if (isspace(c)) continue; @@ -165,51 +160,47 @@ uartctl(Uart *up, char *cfg, int n) uartdrain(up); r = (*phy->setbauds)(up, par); break; + case 'e': + up->hang &= ~ (1 << SIG_DSR); + up->hang |= (par != 0) << SIG_DSR; + r = 0; + break; case 'c': + up->hang &= ~ (1 << SIG_DCD); + up->hang |= (par != 0) << SIG_DCD; r = 0; - up->hang = par; break; + case 'r': + par = (par != 0) << SIG_RTS; + sig = SIG_RTS; + goto signal; case 'd': - par = (par != 0) << SIG_DTR; - r = (*phy->setsignal)(up, SIG_DTR, par); + par = (par != 0) << SIG_DCD; + sig = SIG_DCD; + signal: + r = (*phy->signal)(up, sig, par); break; case 'f': - // r = drv->flush(drv); - case 'h': - // r = drv->cleanqueues(drv); - case 'i': - // r = drv->setfifo(drv, par); + r = (*phy->flush)(up); break; - case 'k': - // r = drv->break(drv, par); + case 'i': + r = (*phy->setfifo)(up, par); break; case 'l': - // r = drv->numbits(drv, par); + r = (*phy->numbits)(up, par); break; case 'm': - // r = drv->obey(drv, CTS, par); - break; - case 'n': - // r = drv->wrmode(drv, par); + r = (*phy->obey)(up, SIG_CTS, par != 0); break; case 'p': if (par != OPARITY && par != EPARITY) par = NPARITY; - // r = drv->parity(drv, par); - break; - case 'q': - // r = drv->queuesiz(drv, par); - break; - case 'r': - // r = drv->signal(drv, RTS); + r = (*phy->parity)(up, par); break; case 's': if (par != 1 && par != 2) return -1; - // r = drv->bitstop(drv, par); - break; - case 'w': - // r = drv->timer(drv, par); + r = (*phy->bitstop)(up, par); break; default: r = -1; @@ -312,8 +303,7 @@ uartlink(Uartphy *phy, Attr *attr) siz = strlen(cfg); if (uartctl(up, cfg, siz) != siz) - //panic("uartlink"); - ; + panic("uartlink"); } const Dev uartdevtab = { diff --git a/drivers/pl011.c b/drivers/pl011.c @@ -62,6 +62,7 @@ enum uartlcr_h { WLEN_6 = 1 << 5, /* word lenght (6 bits) */ WLEN_7 = 2 << 5, /* word lenght (7 bits) */ WLEN_8 = 3 << 5, /* word lenght (8 bits) */ + WLEN = 3 << 5, /* clean mask for word length */ SPS = 1 << 7, /* Stick parity select */ }; @@ -95,6 +96,11 @@ enum uartfr { FR_RI = 1 << 8, /* Ring indicator */ }; +enum uartifls { + TXIFLSEL = 0, + RXIFLSEL = 3, +}; + static unsigned long plin(Uart *up, int reg) { @@ -147,6 +153,14 @@ pl011init(Uart *up, Attr *attr) plout(up, UARTIBRD, 0); plout(up, UARTFBRD, 0); plout(up, UARTCR, cr | UARTEN | TXE | RXE); + + up->rate = 0; + up->nbits = 8; + up->nstop = 1; + up->hang = 0; + up->ctsflow = 0; + up->parity = NPARITY; + up->fifo = 0; } static int @@ -177,9 +191,201 @@ pl011write(Uart *up, void *buf, int n) return n; } +static int +pl011signal(Uart *up, int sign, int val) +{ + unsigned cr; + + cr = plin(up, UARTCR); + + switch (sign) { + case SIG_DTR: + cr &= ~RTS; + if (val) + cr |= RTS; + up->dtr = (val != 0); + break; + case SIG_RTS: + cr &= ~RTS; + if (val) + cr |= RTS; + up->rts = (val != 0); + break; + default: + return -1; + } + + plout(up, UARTCR, cr); + + return 1; +} + +static int +pl011flush(Uart *up) +{ + unsigned crl; + + crl = plin(up, UARTLCR_H); + + plout(up, UARTLCR_H, crl & ~FEN); + plout(up, UARTLCR_H, crl); + + return 0; +} + +static int +pl011fifo(Uart *up, int trigger) +{ + unsigned fil, cr, val; + + cr = plin(up, UARTCR); + + up->fifo = trigger; + switch (trigger) { + case 0: + case 1: + plout(up, UARTCR, cr & ~FEN); + return 0; + case 4: + val = 1; + case 8: + val = 2; + break; + default: + val = 4; + break; + } + fil = (val << TXIFLSEL) | (val << RXIFLSEL); + + plout(up, UARTCR, cr | FEN); + plout(up, UARTIFLS, fil); + + return 0; +} + +static int +pl011bits(Uart *up, int nbits) +{ + unsigned lcr_h, val; + + lcr_h = plin(up, UARTLCR_H); + + switch (nbits) { + case 5: + val = WLEN_5; + break; + case 6: + val = WLEN_6; + break; + case 7: + val = WLEN_7; + break; + case 8: + val = WLEN_8; + break; + default: + return -1; + } + + up->nbits = val; + lcr_h &= ~WLEN; + lcr_h |= val; + plout(up, UARTLCR_H, lcr_h); + + return 0; +} + +static int +pl011parity(Uart *up, int mode) +{ + unsigned lcr_h; + + lcr_h = plin(up, UARTLCR_H); + lcr_h &= ~(SPS | EPS | PEN); + + switch (mode) { + case OPARITY: + lcr_h |= PEN; + break; + case EPARITY: + lcr_h |= PEN | EPS; + break; + case NPARITY: + break; + default: + return -1; + } + + plout(up, UARTLCR_H, lcr_h); + + return 0; +} + +static int +pl011stop(Uart *up, int nbits) +{ + unsigned lcr_h; + + lcr_h = plin(up, UARTLCR_H); + lcr_h &= ~STP2; + + switch (nbits) { + case 1: + break; + case 2: + lcr_h |= STP2; + break; + default: + return -1; + } + + up->nbits = nbits; + plout(up, UARTLCR_H, lcr_h); + + return 0; +} + +static int +pl011obey(Uart *up, int signal, int ena) +{ + unsigned cr; + + cr = plin(up, UARTCR); + ena = (ena != 0); + + switch (signal) { + case SIG_CTS: + cr &= ~CTSEN; + if (ena) + cr |= CTSEN; + up->ctsflow = ena; + break; + default: + return -1; + } + + plout(up, UARTCR, cr); + + return 0; +} + +static int +pl011status(Uart *up, struct uartstat *st) +{ + return 0; +} + const Uartphy pl011phy = { .init = pl011init, .setbauds = setbauds, .read = pl011read, .write = pl011write, + .signal = pl011signal, + .flush = pl011flush, + .setfifo = pl011fifo, + .numbits = pl011bits, + .parity = pl011parity, + .bitstop = pl011stop, + .obey = pl011obey, + .status = pl011status, }; diff --git a/drivers/uart.h b/drivers/uart.h @@ -18,17 +18,9 @@ enum parity { NPARITY = 'n', }; - struct uartstat { - long rate; - int nbits; - int hang; - int ctsflow; - int parity; - int rts; - int dtr; - int stop; - int fifo; + /* TODO: add stats */ + int dummy; }; struct uart { @@ -36,9 +28,13 @@ struct uart { int nbits; int nstop; int hang; + int ctsflow; + int parity; + int fifo; + int dtr; + int rts; long clk; void *base; - void *phydata; mutex_t m; Uartphy *phy; @@ -47,23 +43,17 @@ struct uart { struct uartphy { void (*init)(Uart *up, Attr *attr); int (*setbauds)(Uart *up, long rate); - int (*setsignal)(Uart *up, int mask, int val); - int (*getsignal)(Uart *up, int mask, int *val); + int (*signal)(Uart *up, int mask, int val); int (*read)(Uart *up, void *buf, int n); int (*write)(Uart *up, void *buf, int n); - int (*status)(Uart *up, struct uartstat *st); - int (*flush)(Uart *uart); - int (*cleanqueues)(Uart *uart); int (*setfifo)(Uart *uart, int size); - int (*dobreak)(Uart *uart, int mils); int (*numbits)(Uart *uart, int nbits); - int (*flow)(Uart *uart, int type, int ena); - int (*nonblocking)(Uart *uart, int ena); int (*parity)(Uart *uart, int type); - int (*queuesize)(Uart *up, int size); int (*bitstop)(Uart *up, int nstops); - int (*settimer)(Uart *up, int ntimes); + int (*obey)(Uart *uart, int type, int ena); + + int (*status)(Uart *up, struct uartstat *st); }; extern void uartlink(Uartphy *phy, Attr *attr);