1114402Sru/*-
2104862Sru * Copyright (c) 2012 NetApp, Inc.
3104862Sru * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
4104862Sru * All rights reserved.
5104862Sru *
6151497Sru * Redistribution and use in source and binary forms, with or without
7151497Sru * modification, are permitted provided that the following conditions
8151497Sru * are met:
9104862Sru * 1. Redistributions of source code must retain the above copyright
10104862Sru *    notice, this list of conditions and the following disclaimer.
11104862Sru * 2. Redistributions in binary form must reproduce the above copyright
12104862Sru *    notice, this list of conditions and the following disclaimer in the
13104862Sru *    documentation and/or other materials provided with the distribution.
14104862Sru *
15151497Sru * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
16151497Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17151497Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18114402Sru * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
19151497Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20151497Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21151497Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22114402Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23104862Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24104862Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25114402Sru * SUCH DAMAGE.
26104862Sru *
27104862Sru * $FreeBSD$
28114402Sru */
29104862Sru
30104862Sru#include <sys/cdefs.h>
31114402Sru__FBSDID("$FreeBSD$");
32104862Sru
33104862Sru#include <sys/types.h>
34114402Sru#include <dev/ic/ns16550.h>
35104862Sru
36104862Sru#include <stdio.h>
37114402Sru#include <stdlib.h>
38114402Sru#include <assert.h>
39114402Sru#include <fcntl.h>
40114402Sru#include <termios.h>
41114402Sru#include <unistd.h>
42114402Sru#include <stdbool.h>
43151497Sru#include <string.h>
44151497Sru#include <pthread.h>
45151497Sru
46114402Sru#include "mevent.h"
47104862Sru#include "uart_emul.h"
48104862Sru
49114402Sru#define	COM1_BASE      	0x3F8
50104862Sru#define COM1_IRQ	4
51104862Sru#define	COM2_BASE      	0x2F8
52114402Sru#define COM2_IRQ	3
53114402Sru
54114402Sru#define	DEFAULT_RCLK	1843200
55104862Sru#define	DEFAULT_BAUD	9600
56104862Sru
57104862Sru#define	FCR_RX_MASK	0xC0
58114402Sru
59104862Sru#define	MCR_OUT1	0x04
60104862Sru#define	MCR_OUT2	0x08
61151497Sru
62151497Sru#define	MSR_DELTA_MASK	0x0f
63151497Sru
64114402Sru#ifndef REG_SCR
65104862Sru#define REG_SCR		com_scr
66104862Sru#endif
67114402Sru
68104862Sru#define	FIFOSZ	16
69104862Sru
70114402Srustatic bool uart_stdio;		/* stdio in use for i/o */
71114402Srustatic struct termios tio_stdio_orig;
72114402Sru
73114402Srustatic struct {
74104862Sru	int	baseaddr;
75104862Sru	int	irq;
76114402Sru	bool	inuse;
77104862Sru} uart_lres[] = {
78104862Sru	{ COM1_BASE, COM1_IRQ, false},
79114402Sru	{ COM2_BASE, COM2_IRQ, false},
80104862Sru};
81104862Sru
82114402Sru#define	UART_NLDEVS	(sizeof(uart_lres) / sizeof(uart_lres[0]))
83104862Sru
84104862Srustruct fifo {
85114402Sru	uint8_t	buf[FIFOSZ];
86104862Sru	int	rindex;		/* index to read from */
87104862Sru	int	windex;		/* index to write to */
88114402Sru	int	num;		/* number of characters in the fifo */
89104862Sru	int	size;		/* size of the fifo */
90104862Sru};
91114402Sru
92104862Srustruct ttyfd {
93104862Sru	bool	opened;
94114402Sru	int	fd;		/* tty device file descriptor */
95104862Sru	struct termios tio_orig, tio_new;    /* I/O Terminals */
96104862Sru};
97114402Sru
98104862Srustruct uart_softc {
99104862Sru	pthread_mutex_t mtx;	/* protects all softc elements */
100114402Sru	uint8_t	data;		/* Data register (R/W) */
101104862Sru	uint8_t ier;		/* Interrupt enable register (R/W) */
102104862Sru	uint8_t lcr;		/* Line control register (R/W) */
103104862Sru	uint8_t mcr;		/* Modem control register (R/W) */
104104862Sru	uint8_t lsr;		/* Line status register (R/W) */
105104862Sru	uint8_t msr;		/* Modem status register (R/W) */
106114402Sru	uint8_t fcr;		/* FIFO control register (W) */
107104862Sru	uint8_t scr;		/* Scratch register (R/W) */
108104862Sru
109151497Sru	uint8_t dll;		/* Baudrate divisor latch LSB */
110104862Sru	uint8_t dlh;		/* Baudrate divisor latch MSB */
111104862Sru
112151497Sru	struct fifo rxfifo;
113104862Sru	struct mevent *mev;
114104862Sru
115114402Sru	struct ttyfd tty;
116114402Sru	bool	thre_int_pending;	/* THRE interrupt pending */
117114402Sru
118114402Sru	void	*arg;
119104862Sru	uart_intr_func_t intr_assert;
120104862Sru	uart_intr_func_t intr_deassert;
121114402Sru};
122114402Sru
123114402Srustatic void uart_drain(int fd, enum ev_type ev, void *arg);
124114402Sru
125104862Srustatic void
126104862Sruttyclose(void)
127151497Sru{
128151497Sru
129151497Sru	tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig);
130104862Sru}
131104862Sru
132104862Srustatic void
133104862Sruttyopen(struct ttyfd *tf)
134104862Sru{
135104862Sru
136104862Sru	tcgetattr(tf->fd, &tf->tio_orig);
137104862Sru
138104862Sru	tf->tio_new = tf->tio_orig;
139104862Sru	cfmakeraw(&tf->tio_new);
140104862Sru	tf->tio_new.c_cflag |= CLOCAL;
141104862Sru	tcsetattr(tf->fd, TCSANOW, &tf->tio_new);
142104862Sru
143104862Sru	if (tf->fd == STDIN_FILENO) {
144104862Sru		tio_stdio_orig = tf->tio_orig;
145104862Sru		atexit(ttyclose);
146104862Sru	}
147104862Sru}
148104862Sru
149104862Srustatic int
150104862Sruttyread(struct ttyfd *tf)
151114402Sru{
152114402Sru	unsigned char rb;
153114402Sru
154114402Sru	if (read(tf->fd, &rb, 1) == 1)
155114402Sru		return (rb);
156114402Sru	else
157114402Sru		return (-1);
158114402Sru}
159114402Sru
160104862Srustatic void
161104862Sruttywrite(struct ttyfd *tf, unsigned char wb)
162104862Sru{
163104862Sru
164104862Sru	(void)write(tf->fd, &wb, 1);
165104862Sru}
166151497Sru
167151497Srustatic void
168151497Srurxfifo_reset(struct uart_softc *sc, int size)
169151497Sru{
170151497Sru	char flushbuf[32];
171151497Sru	struct fifo *fifo;
172114402Sru	ssize_t nread;
173114402Sru	int error;
174114402Sru
175114402Sru	fifo = &sc->rxfifo;
176114402Sru	bzero(fifo, sizeof(struct fifo));
177114402Sru	fifo->size = size;
178114402Sru
179114402Sru	if (sc->tty.opened) {
180114402Sru		/*
181114402Sru		 * Flush any unread input from the tty buffer.
182114402Sru		 */
183114402Sru		while (1) {
184114402Sru			nread = read(sc->tty.fd, flushbuf, sizeof(flushbuf));
185114402Sru			if (nread != sizeof(flushbuf))
186114402Sru				break;
187104862Sru		}
188104862Sru
189104862Sru		/*
190104862Sru		 * Enable mevent to trigger when new characters are available
191104862Sru		 * on the tty fd.
192104862Sru		 */
193104862Sru		error = mevent_enable(sc->mev);
194104862Sru		assert(error == 0);
195104862Sru	}
196114402Sru}
197114402Sru
198114402Srustatic int
199104862Srurxfifo_available(struct uart_softc *sc)
200104862Sru{
201104862Sru	struct fifo *fifo;
202104862Sru
203104862Sru	fifo = &sc->rxfifo;
204104862Sru	return (fifo->num < fifo->size);
205104862Sru}
206151497Sru
207151497Srustatic int
208151497Srurxfifo_putchar(struct uart_softc *sc, uint8_t ch)
209104862Sru{
210104862Sru	struct fifo *fifo;
211104862Sru	int error;
212104862Sru
213104862Sru	fifo = &sc->rxfifo;
214104862Sru
215104862Sru	if (fifo->num < fifo->size) {
216104862Sru		fifo->buf[fifo->windex] = ch;
217104862Sru		fifo->windex = (fifo->windex + 1) % fifo->size;
218		fifo->num++;
219		if (!rxfifo_available(sc)) {
220			if (sc->tty.opened) {
221				/*
222				 * Disable mevent callback if the FIFO is full.
223				 */
224				error = mevent_disable(sc->mev);
225				assert(error == 0);
226			}
227		}
228		return (0);
229	} else
230		return (-1);
231}
232
233static int
234rxfifo_getchar(struct uart_softc *sc)
235{
236	struct fifo *fifo;
237	int c, error, wasfull;
238
239	wasfull = 0;
240	fifo = &sc->rxfifo;
241	if (fifo->num > 0) {
242		if (!rxfifo_available(sc))
243			wasfull = 1;
244		c = fifo->buf[fifo->rindex];
245		fifo->rindex = (fifo->rindex + 1) % fifo->size;
246		fifo->num--;
247		if (wasfull) {
248			if (sc->tty.opened) {
249				error = mevent_enable(sc->mev);
250				assert(error == 0);
251			}
252		}
253		return (c);
254	} else
255		return (-1);
256}
257
258static int
259rxfifo_numchars(struct uart_softc *sc)
260{
261	struct fifo *fifo = &sc->rxfifo;
262
263	return (fifo->num);
264}
265
266static void
267uart_opentty(struct uart_softc *sc)
268{
269
270	ttyopen(&sc->tty);
271	sc->mev = mevent_add(sc->tty.fd, EVF_READ, uart_drain, sc);
272	assert(sc->mev != NULL);
273}
274
275static uint8_t
276modem_status(uint8_t mcr)
277{
278	uint8_t msr;
279
280	if (mcr & MCR_LOOPBACK) {
281		/*
282		 * In the loopback mode certain bits from the MCR are
283		 * reflected back into MSR.
284		 */
285		msr = 0;
286		if (mcr & MCR_RTS)
287			msr |= MSR_CTS;
288		if (mcr & MCR_DTR)
289			msr |= MSR_DSR;
290		if (mcr & MCR_OUT1)
291			msr |= MSR_RI;
292		if (mcr & MCR_OUT2)
293			msr |= MSR_DCD;
294	} else {
295		/*
296		 * Always assert DCD and DSR so tty open doesn't block
297		 * even if CLOCAL is turned off.
298		 */
299		msr = MSR_DCD | MSR_DSR;
300	}
301	assert((msr & MSR_DELTA_MASK) == 0);
302
303	return (msr);
304}
305
306/*
307 * The IIR returns a prioritized interrupt reason:
308 * - receive data available
309 * - transmit holding register empty
310 * - modem status change
311 *
312 * Return an interrupt reason if one is available.
313 */
314static int
315uart_intr_reason(struct uart_softc *sc)
316{
317
318	if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0)
319		return (IIR_RLS);
320	else if (rxfifo_numchars(sc) > 0 && (sc->ier & IER_ERXRDY) != 0)
321		return (IIR_RXTOUT);
322	else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0)
323		return (IIR_TXRDY);
324	else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0)
325		return (IIR_MLSC);
326	else
327		return (IIR_NOPEND);
328}
329
330static void
331uart_reset(struct uart_softc *sc)
332{
333	uint16_t divisor;
334
335	divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16;
336	sc->dll = divisor;
337	sc->dlh = divisor >> 16;
338	sc->msr = modem_status(sc->mcr);
339
340	rxfifo_reset(sc, 1);	/* no fifo until enabled by software */
341}
342
343/*
344 * Toggle the COM port's intr pin depending on whether or not we have an
345 * interrupt condition to report to the processor.
346 */
347static void
348uart_toggle_intr(struct uart_softc *sc)
349{
350	uint8_t intr_reason;
351
352	intr_reason = uart_intr_reason(sc);
353
354	if (intr_reason == IIR_NOPEND)
355		(*sc->intr_deassert)(sc->arg);
356	else
357		(*sc->intr_assert)(sc->arg);
358}
359
360static void
361uart_drain(int fd, enum ev_type ev, void *arg)
362{
363	struct uart_softc *sc;
364	int ch;
365
366	sc = arg;
367
368	assert(fd == sc->tty.fd);
369	assert(ev == EVF_READ);
370
371	/*
372	 * This routine is called in the context of the mevent thread
373	 * to take out the softc lock to protect against concurrent
374	 * access from a vCPU i/o exit
375	 */
376	pthread_mutex_lock(&sc->mtx);
377
378	if ((sc->mcr & MCR_LOOPBACK) != 0) {
379		(void) ttyread(&sc->tty);
380	} else {
381		while (rxfifo_available(sc) &&
382		       ((ch = ttyread(&sc->tty)) != -1)) {
383			rxfifo_putchar(sc, ch);
384		}
385		uart_toggle_intr(sc);
386	}
387
388	pthread_mutex_unlock(&sc->mtx);
389}
390
391void
392uart_write(struct uart_softc *sc, int offset, uint8_t value)
393{
394	int fifosz;
395	uint8_t msr;
396
397	pthread_mutex_lock(&sc->mtx);
398
399	/*
400	 * Take care of the special case DLAB accesses first
401	 */
402	if ((sc->lcr & LCR_DLAB) != 0) {
403		if (offset == REG_DLL) {
404			sc->dll = value;
405			goto done;
406		}
407
408		if (offset == REG_DLH) {
409			sc->dlh = value;
410			goto done;
411		}
412	}
413
414        switch (offset) {
415	case REG_DATA:
416		if (sc->mcr & MCR_LOOPBACK) {
417			if (rxfifo_putchar(sc, value) != 0)
418				sc->lsr |= LSR_OE;
419		} else if (sc->tty.opened) {
420			ttywrite(&sc->tty, value);
421		} /* else drop on floor */
422		sc->thre_int_pending = true;
423		break;
424	case REG_IER:
425		/*
426		 * Apply mask so that bits 4-7 are 0
427		 * Also enables bits 0-3 only if they're 1
428		 */
429		sc->ier = value & 0x0F;
430		break;
431		case REG_FCR:
432			/*
433			 * When moving from FIFO and 16450 mode and vice versa,
434			 * the FIFO contents are reset.
435			 */
436			if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) {
437				fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1;
438				rxfifo_reset(sc, fifosz);
439			}
440
441			/*
442			 * The FCR_ENABLE bit must be '1' for the programming
443			 * of other FCR bits to be effective.
444			 */
445			if ((value & FCR_ENABLE) == 0) {
446				sc->fcr = 0;
447			} else {
448				if ((value & FCR_RCV_RST) != 0)
449					rxfifo_reset(sc, FIFOSZ);
450
451				sc->fcr = value &
452					 (FCR_ENABLE | FCR_DMA | FCR_RX_MASK);
453			}
454			break;
455		case REG_LCR:
456			sc->lcr = value;
457			break;
458		case REG_MCR:
459			/* Apply mask so that bits 5-7 are 0 */
460			sc->mcr = value & 0x1F;
461			msr = modem_status(sc->mcr);
462
463			/*
464			 * Detect if there has been any change between the
465			 * previous and the new value of MSR. If there is
466			 * then assert the appropriate MSR delta bit.
467			 */
468			if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS))
469				sc->msr |= MSR_DCTS;
470			if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR))
471				sc->msr |= MSR_DDSR;
472			if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD))
473				sc->msr |= MSR_DDCD;
474			if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0)
475				sc->msr |= MSR_TERI;
476
477			/*
478			 * Update the value of MSR while retaining the delta
479			 * bits.
480			 */
481			sc->msr &= MSR_DELTA_MASK;
482			sc->msr |= msr;
483			break;
484		case REG_LSR:
485			/*
486			 * Line status register is not meant to be written to
487			 * during normal operation.
488			 */
489			break;
490		case REG_MSR:
491			/*
492			 * As far as I can tell MSR is a read-only register.
493			 */
494			break;
495		case REG_SCR:
496			sc->scr = value;
497			break;
498		default:
499			break;
500	}
501
502done:
503	uart_toggle_intr(sc);
504	pthread_mutex_unlock(&sc->mtx);
505}
506
507uint8_t
508uart_read(struct uart_softc *sc, int offset)
509{
510	uint8_t iir, intr_reason, reg;
511
512	pthread_mutex_lock(&sc->mtx);
513
514	/*
515	 * Take care of the special case DLAB accesses first
516	 */
517	if ((sc->lcr & LCR_DLAB) != 0) {
518		if (offset == REG_DLL) {
519			reg = sc->dll;
520			goto done;
521		}
522
523		if (offset == REG_DLH) {
524			reg = sc->dlh;
525			goto done;
526		}
527	}
528
529	switch (offset) {
530	case REG_DATA:
531		reg = rxfifo_getchar(sc);
532		break;
533	case REG_IER:
534		reg = sc->ier;
535		break;
536	case REG_IIR:
537		iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0;
538
539		intr_reason = uart_intr_reason(sc);
540
541		/*
542		 * Deal with side effects of reading the IIR register
543		 */
544		if (intr_reason == IIR_TXRDY)
545			sc->thre_int_pending = false;
546
547		iir |= intr_reason;
548
549		reg = iir;
550		break;
551	case REG_LCR:
552		reg = sc->lcr;
553		break;
554	case REG_MCR:
555		reg = sc->mcr;
556		break;
557	case REG_LSR:
558		/* Transmitter is always ready for more data */
559		sc->lsr |= LSR_TEMT | LSR_THRE;
560
561		/* Check for new receive data */
562		if (rxfifo_numchars(sc) > 0)
563			sc->lsr |= LSR_RXRDY;
564		else
565			sc->lsr &= ~LSR_RXRDY;
566
567		reg = sc->lsr;
568
569		/* The LSR_OE bit is cleared on LSR read */
570		sc->lsr &= ~LSR_OE;
571		break;
572	case REG_MSR:
573		/*
574		 * MSR delta bits are cleared on read
575		 */
576		reg = sc->msr;
577		sc->msr &= ~MSR_DELTA_MASK;
578		break;
579	case REG_SCR:
580		reg = sc->scr;
581		break;
582	default:
583		reg = 0xFF;
584		break;
585	}
586
587done:
588	uart_toggle_intr(sc);
589	pthread_mutex_unlock(&sc->mtx);
590
591	return (reg);
592}
593
594int
595uart_legacy_alloc(int which, int *baseaddr, int *irq)
596{
597
598	if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse)
599		return (-1);
600
601	uart_lres[which].inuse = true;
602	*baseaddr = uart_lres[which].baseaddr;
603	*irq = uart_lres[which].irq;
604
605	return (0);
606}
607
608struct uart_softc *
609uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,
610    void *arg)
611{
612	struct uart_softc *sc;
613
614	sc = calloc(1, sizeof(struct uart_softc));
615
616	sc->arg = arg;
617	sc->intr_assert = intr_assert;
618	sc->intr_deassert = intr_deassert;
619
620	pthread_mutex_init(&sc->mtx, NULL);
621
622	uart_reset(sc);
623
624	return (sc);
625}
626
627static int
628uart_tty_backend(struct uart_softc *sc, const char *opts)
629{
630	int fd;
631	int retval;
632
633	retval = -1;
634
635	fd = open(opts, O_RDWR | O_NONBLOCK);
636	if (fd > 0 && isatty(fd)) {
637		sc->tty.fd = fd;
638		sc->tty.opened = true;
639		retval = 0;
640	}
641
642	return (retval);
643}
644
645int
646uart_set_backend(struct uart_softc *sc, const char *opts)
647{
648	int retval;
649
650	retval = -1;
651
652	if (opts == NULL)
653		return (0);
654
655	if (strcmp("stdio", opts) == 0) {
656		if (!uart_stdio) {
657			sc->tty.fd = STDIN_FILENO;
658			sc->tty.opened = true;
659			uart_stdio = true;
660			retval = 0;
661		}
662	} else if (uart_tty_backend(sc, opts) == 0) {
663		retval = 0;
664	}
665
666	/* Make the backend file descriptor non-blocking */
667	if (retval == 0)
668		retval = fcntl(sc->tty.fd, F_SETFL, O_NONBLOCK);
669
670	if (retval == 0)
671		uart_opentty(sc);
672
673	return (retval);
674}
675