Home | History | Annotate | Line # | Download | only in at91
at91usart.c revision 1.8
      1 /*	$Id: at91usart.c,v 1.8 2012/11/12 18:00:36 skrll Exp $	*/
      2 /*	$NetBSD: at91usart.c,v 1.8 2012/11/12 18:00:36 skrll Exp $ */
      3 
      4 /*
      5  * Copyright (c) 2007 Embedtronics Oy. All rights reserved.
      6  *
      7  * Copyright (c) 1998, 1999, 2001, 2002, 2004 The NetBSD Foundation, Inc.
      8  * All rights reserved.
      9  *
     10  * This code is derived from software contributed to The NetBSD Foundation
     11  * by Jesse Off
     12  *
     13  * This code is derived from software contributed to The NetBSD Foundation
     14  * by Ichiro FUKUHARA and Naoto Shimazaki.
     15  *
     16  * This code is derived from software contributed to The NetBSD Foundation
     17  * by IWAMOTO Toshihiro.
     18  *
     19  * This code is derived from software contributed to The NetBSD Foundation
     20  * by Charles M. Hannum.
     21  *
     22  * Redistribution and use in source and binary forms, with or without
     23  * modification, are permitted provided that the following conditions
     24  * are met:
     25  * 1. Redistributions of source code must retain the above copyright
     26  *    notice, this list of conditions and the following disclaimer.
     27  * 2. Redistributions in binary form must reproduce the above copyright
     28  *    notice, this list of conditions and the following disclaimer in the
     29  *    documentation and/or other materials provided with the distribution.
     30  *
     31  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     32  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     33  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     34  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     35  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     36  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     37  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     38  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     39  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     40  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     41  * POSSIBILITY OF SUCH DAMAGE.
     42  */
     43 
     44 /*
     45  * Copyright (c) 1991 The Regents of the University of California.
     46  * All rights reserved.
     47  *
     48  * Redistribution and use in source and binary forms, with or without
     49  * modification, are permitted provided that the following conditions
     50  * are met:
     51  * 1. Redistributions of source code must retain the above copyright
     52  *    notice, this list of conditions and the following disclaimer.
     53  * 2. Redistributions in binary form must reproduce the above copyright
     54  *    notice, this list of conditions and the following disclaimer in the
     55  *    documentation and/or other materials provided with the distribution.
     56  * 3. Neither the name of the University nor the names of its contributors
     57  *    may be used to endorse or promote products derived from this software
     58  *    without specific prior written permission.
     59  *
     60  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     61  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     62  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     63  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     64  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     65  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     66  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     67  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     68  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     69  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     70  * SUCH DAMAGE.
     71  *
     72  *      @(#)com.c       7.5 (Berkeley) 5/16/91
     73  */
     74 
     75 /*
     76  * TODO: hardware flow control
     77  */
     78 
     79 #include <sys/cdefs.h>
     80 __KERNEL_RCSID(0, "$NetBSD: at91usart.c,v 1.8 2012/11/12 18:00:36 skrll Exp $");
     81 
     82 #include "opt_ddb.h"
     83 #include "opt_kgdb.h"
     84 
     85 #include "rnd.h"
     86 #ifdef RND_COM
     87 #include <sys/rnd.h>
     88 #endif
     89 
     90 #ifdef	NOTYET
     91 /*
     92  * Override cnmagic(9) macro before including <sys/systm.h>.
     93  * We need to know if cn_check_magic triggered debugger, so set a flag.
     94  * Callers of cn_check_magic must declare int cn_trapped = 0;
     95  * XXX: this is *ugly*!
     96  */
     97 #define cn_trap()				\
     98 	do {					\
     99 		console_debugger();		\
    100 		cn_trapped = 1;			\
    101 	} while (/* CONSTCOND */ 0)
    102 #endif	/* NOTYET */
    103 
    104 
    105 #include <sys/param.h>
    106 #include <sys/systm.h>
    107 #include <sys/types.h>
    108 #include <sys/conf.h>
    109 #include <sys/file.h>
    110 #include <sys/device.h>
    111 #include <sys/kernel.h>
    112 #include <sys/tty.h>
    113 #include <sys/uio.h>
    114 #include <sys/vnode.h>
    115 #include <sys/kauth.h>
    116 
    117 #include <machine/intr.h>
    118 #include <sys/bus.h>
    119 
    120 #include <arm/at91/at91reg.h>
    121 #include <arm/at91/at91var.h>
    122 #include <arm/at91/at91usartreg.h>
    123 #include <arm/at91/at91usartvar.h>
    124 
    125 #include <dev/cons.h>
    126 
    127 static int	at91usart_param(struct tty *, struct termios *);
    128 static void	at91usart_start(struct tty *);
    129 static int	at91usart_hwiflow(struct tty *, int);
    130 
    131 #if 0
    132 static u_int	cflag2lcrhi(tcflag_t);
    133 #endif
    134 static void	at91usart_set(struct at91usart_softc *);
    135 
    136 #if	NOTYET
    137 int             at91usart_cn_getc(dev_t);
    138 void            at91usart_cn_putc(dev_t, int);
    139 void            at91usart_cn_pollc(dev_t, int);
    140 void            at91usart_cn_probe(struct consdev *);
    141 void            at91usart_cn_init(struct consdev *);
    142 
    143 static struct at91usart_cons_softc {
    144 	bus_space_tag_t		sc_iot;
    145 	bus_space_handle_t	sc_ioh;
    146 	bus_addr_t		sc_hwbase;
    147 	int			sc_ospeed;
    148 	tcflag_t		sc_cflag;
    149 	int			sc_attached;
    150 
    151 	uint8_t			*sc_rx_ptr;
    152 	uint8_t			sc_rx_fifo[64];
    153 } usart_cn_sc;
    154 
    155 static struct cnm_state at91usart_cnm_state;
    156 #endif	/* NOTYET */
    157 
    158 static void	at91usart_soft(void* arg);
    159 inline static void	at91usart_txsoft(struct at91usart_softc *, struct tty *);
    160 inline static void	at91usart_rxsoft(struct at91usart_softc *, struct tty *, unsigned csr);
    161 
    162 #define	PDC_BLOCK_SIZE	64
    163 
    164 //CFATTACH_DECL_NEW(at91usart, sizeof(struct at91usart_softc),
    165 //	      at91usart_match, at91usart_attach, NULL, NULL);
    166 
    167 //#define	USART_DEBUG	10
    168 
    169 #ifdef	USART_DEBUG
    170 int usart_debug = USART_DEBUG;
    171 #define	DPRINTFN(n,fmt) if (usart_debug >= (n)) printf fmt
    172 #else
    173 #define	DPRINTFN(n,fmt)
    174 #endif
    175 
    176 extern struct cfdriver at91usart_cd;
    177 
    178 dev_type_open(at91usart_open);
    179 dev_type_close(at91usart_close);
    180 dev_type_read(at91usart_read);
    181 dev_type_write(at91usart_write);
    182 dev_type_ioctl(at91usart_ioctl);
    183 dev_type_stop(at91usart_stop);
    184 dev_type_tty(at91usart_tty);
    185 dev_type_poll(at91usart_poll);
    186 
    187 const struct cdevsw at91usart_cdevsw = {
    188 	at91usart_open, at91usart_close, at91usart_read, at91usart_write, at91usart_ioctl,
    189 	at91usart_stop, at91usart_tty, at91usart_poll, nommap, ttykqfilter, D_TTY
    190 };
    191 
    192 #if	NOTYET
    193 struct consdev at91usart_cons = {
    194 	at91usart_cn_probe, NULL, at91usart_cn_getc, at91usart_cn_putc, at91usart_cn_pollc, NULL,
    195 	NULL, NULL, NODEV, CN_REMOTE
    196 };
    197 #endif	/* NOTYET */
    198 
    199 #ifndef DEFAULT_COMSPEED
    200 #define DEFAULT_COMSPEED 115200
    201 #endif
    202 
    203 #define COMUNIT_MASK    0x7ffff
    204 #define COMDIALOUT_MASK 0x80000
    205 
    206 #define COMUNIT(x)	(minor(x) & COMUNIT_MASK)
    207 #define COMDIALOUT(x)	(minor(x) & COMDIALOUT_MASK)
    208 
    209 #define COM_ISALIVE(sc)	((sc)->enabled != 0 && device_is_active((sc)->sc_dev))
    210 
    211 static inline void
    212 at91usart_writereg(struct at91usart_softc *sc, int reg, u_int val)
    213 {
    214 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val);
    215 }
    216 
    217 static inline u_int
    218 at91usart_readreg(struct at91usart_softc *sc, int reg)
    219 {
    220 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg);
    221 }
    222 #if 0
    223 static int
    224 at91usart_match(device_t parent, cfdata_t cf, void *aux)
    225 {
    226 	if (strcmp(cf->cf_name, "at91usart") == 0)
    227 		return 1;
    228 	return 0;
    229 }
    230 #endif
    231 static int at91usart_intr(void* arg);
    232 
    233 void
    234 at91usart_attach_subr(struct at91usart_softc *sc, struct at91bus_attach_args *sa)
    235 {
    236 	struct tty *tp;
    237 	int err;
    238 
    239 	printf("\n");
    240 
    241 	if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0, &sc->sc_ioh))
    242 		panic("%s: Cannot map registers", device_xname(sc->sc_dev));
    243 
    244 	sc->sc_iot = sa->sa_iot;
    245 	sc->sc_hwbase = sa->sa_addr;
    246 	sc->sc_dmat = sa->sa_dmat;
    247 	sc->sc_pid = sa->sa_pid;
    248 
    249 	/* allocate fifos */
    250 	err = at91pdc_alloc_fifo(sc->sc_dmat, &sc->sc_rx_fifo, AT91USART_RING_SIZE, BUS_DMA_READ | BUS_DMA_STREAMING);
    251 	if (err)
    252 		panic("%s: cannot allocate rx fifo", device_xname(sc->sc_dev));
    253 
    254 	err = at91pdc_alloc_fifo(sc->sc_dmat, &sc->sc_tx_fifo, AT91USART_RING_SIZE, BUS_DMA_WRITE | BUS_DMA_STREAMING);
    255 	if (err)
    256 		panic("%s: cannot allocate tx fifo", device_xname(sc->sc_dev));
    257 
    258 	/* initialize uart */
    259 	at91_peripheral_clock(sc->sc_pid, 1);
    260 
    261 	at91usart_writereg(sc, US_IDR, -1);
    262 	at91usart_writereg(sc, US_RTOR, 12);	// 12-bit timeout
    263 	at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
    264 	at91_intr_establish(sa->sa_pid, IPL_TTY, INTR_HIGH_LEVEL, at91usart_intr, sc);
    265 	USART_INIT(sc, 115200U);
    266 
    267 #ifdef	NOTYET
    268 	if (sc->sc_iot == usart_cn_sc.sc_iot
    269 	    && sc->sc_hwbase == usart_cn_sc.sc_hwbase) {
    270 		usart_cn_sc.sc_attached = 1;
    271 		/* Make sure the console is always "hardwired". */
    272 		delay(10000);	/* wait for output to finish */
    273 		SET(sc->sc_hwflags, COM_HW_CONSOLE);
    274 		SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
    275 		SET(sc->sc_ier, USART_INT_RXRDY);
    276 		USARTREG(USART_IER) = USART_INT_RXRDY; // @@@@@
    277 	}
    278 #endif	// NOTYET
    279 
    280 	tp = tty_alloc();
    281 	tp->t_oproc = at91usart_start;
    282 	tp->t_param = at91usart_param;
    283 	tp->t_hwiflow = at91usart_hwiflow;
    284 
    285 	sc->sc_tty = tp;
    286 
    287 	tty_attach(tp);
    288 
    289 #if	NOTYET
    290 	if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
    291 		int maj;
    292 
    293 		/* locate the major number */
    294 		maj = cdevsw_lookup_major(&at91usart_cdevsw);
    295 
    296 		cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev));
    297 
    298 		aprint_normal("%s: console (maj %u  min %u  cn_dev %u)\n",
    299 		    device_xname(sc->sc_dev), maj, device_unit(sc->sc_dev),
    300 		    cn_tab->cn_dev);
    301 	}
    302 #endif	/* NOTYET */
    303 
    304 	sc->sc_si = softint_establish(SOFTINT_SERIAL, at91usart_soft, sc);
    305 
    306 #ifdef RND_COM
    307 	rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
    308 			  RND_TYPE_TTY, 0);
    309 #endif
    310 
    311 	/* if there are no enable/disable functions, assume the device
    312 	   is always enabled */
    313 	if (!sc->enable)
    314 		sc->enabled = 1;
    315 
    316 	/* XXX configure register */
    317 	/* xxx_config(sc) */
    318 
    319 	SET(sc->sc_hwflags, COM_HW_DEV_OK);
    320 }
    321 
    322 static int
    323 at91usart_param(struct tty *tp, struct termios *t)
    324 {
    325 	struct at91usart_softc *sc
    326 		= device_lookup_private(&at91usart_cd, COMUNIT(tp->t_dev));
    327 	int s;
    328 
    329 	if (COM_ISALIVE(sc) == 0)
    330 		return (EIO);
    331 
    332 	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
    333 		return (EINVAL);
    334 
    335 	/*
    336 	 * For the console, always force CLOCAL and !HUPCL, so that the port
    337 	 * is always active.
    338 	 */
    339 	if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
    340 	    ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
    341 		SET(t->c_cflag, CLOCAL);
    342 		CLR(t->c_cflag, HUPCL);
    343 	}
    344 
    345 	/*
    346 	 * If there were no changes, don't do anything.  This avoids dropping
    347 	 * input and improves performance when all we did was frob things like
    348 	 * VMIN and VTIME.
    349 	 */
    350 	if (tp->t_ospeed == t->c_ospeed &&
    351 	    tp->t_cflag == t->c_cflag)
    352 		return (0);
    353 
    354 	s = spltty();
    355 
    356 	sc->sc_brgr = (AT91_MSTCLK / 16 + t->c_ospeed / 2) / t->c_ospeed;
    357 
    358 	/* And copy to tty. */
    359 	tp->t_ispeed = 0;
    360 	tp->t_ospeed = t->c_ospeed;
    361 	tp->t_cflag = t->c_cflag;
    362 	at91usart_set(sc);
    363 
    364 	splx(s);
    365 
    366 	/*
    367 	 * Update the tty layer's idea of the carrier bit.
    368 	 * We tell tty the carrier is always on.
    369 	 */
    370 	(void) (*tp->t_linesw->l_modem)(tp, 1);
    371 
    372 #ifdef COM_DEBUG
    373 	if (com_debug)
    374 		comstatus(sc, "comparam ");
    375 #endif
    376 
    377 	/* tell the upper layer about hwflow.. */
    378 	if (sc->hwflow)
    379 		(*sc->hwflow)(sc, t->c_cflag);
    380 
    381 	return (0);
    382 }
    383 
    384 static int
    385 at91usart_hwiflow(struct tty *tp, int block)
    386 {
    387 	if (block) {
    388 		/* tty discipline wants to block */
    389 	} else {
    390 		/* tty discipline wants to unblock */
    391 	}
    392 	return (0);
    393 }
    394 
    395 static __inline void
    396 at91usart_start_tx(struct at91usart_softc *sc)
    397 {
    398 	if (!sc->start_tx)
    399 		at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_TXTEN);
    400 	else
    401 		(*sc->start_tx)(sc);
    402 }
    403 
    404 static __inline void
    405 at91usart_stop_tx(struct at91usart_softc *sc)
    406 {
    407 	if (!sc->stop_tx)
    408 		at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_TXTDIS);
    409 	else
    410 		(*sc->stop_tx)(sc);
    411 }
    412 
    413 static __inline void
    414 at91usart_rx_started(struct at91usart_softc *sc)
    415 {
    416 	if (sc->rx_started)
    417 		(*sc->rx_started)(sc);
    418 }
    419 
    420 static __inline void
    421 at91usart_rx_stopped(struct at91usart_softc *sc)
    422 {
    423 	if (sc->rx_stopped)
    424 		(*sc->rx_stopped)(sc);
    425 }
    426 
    427 static __inline void
    428 at91usart_rx_rts_ctl(struct at91usart_softc *sc, int enabled)
    429 {
    430 	if (sc->rx_rts_ctl)
    431 		(*sc->rx_rts_ctl)(sc, enabled);
    432 }
    433 
    434 static void
    435 at91usart_filltx(struct at91usart_softc *sc)
    436 {
    437 	struct tty *tp = sc->sc_tty;
    438 	int len;
    439 	void *dst;
    440 
    441 	// post write handler
    442 	AT91PDC_FIFO_POSTWRITE(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC,
    443 				&sc->sc_tx_fifo);
    444 
    445 	// copy more data to fifo:
    446 	if (sc->sc_tbc > 0
    447 	    && (dst = AT91PDC_FIFO_WRPTR(&sc->sc_tx_fifo, &len)) != NULL) {
    448 		// copy data to fifo
    449 		if (len > sc->sc_tbc)
    450 			len = sc->sc_tbc;
    451 		memcpy(dst, sc->sc_tba, len);
    452 		sc->sc_tba += len;
    453 		if ((sc->sc_tbc -= len) <= 0)
    454 			CLR(tp->t_state, TS_BUSY);
    455 		// update fifo
    456 		AT91PDC_FIFO_WRITTEN(&sc->sc_tx_fifo, len);
    457 		// tell tty interface we've sent some bytes
    458 		ndflush(&tp->t_outq, len);
    459 	}
    460 
    461 	// start sending data...
    462 	if (AT91PDC_FIFO_PREWRITE(sc->sc_iot, sc->sc_ioh, sc->sc_dmat,
    463 				   US_PDC, &sc->sc_tx_fifo, PDC_BLOCK_SIZE)) {
    464 		at91usart_start_tx(sc);
    465 		SET(sc->sc_ier, US_CSR_TXEMPTY | US_CSR_ENDTX);
    466 	} else {
    467 		CLR(sc->sc_ier, US_CSR_ENDTX);
    468 	}
    469 }
    470 
    471 static void
    472 at91usart_start(struct tty *tp)
    473 {
    474 	struct at91usart_softc *sc
    475 		= device_lookup_private(&at91usart_cd, COMUNIT(tp->t_dev));
    476 	int s;
    477 
    478 	if (COM_ISALIVE(sc) == 0) {
    479 		DPRINTFN(5, ("%s: %s / COM_ISALIVE == 0\n", device_xname(sc->sc_dev), __FUNCTION__));
    480 		return;
    481 	}
    482 
    483 	s = spltty();
    484 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
    485 		DPRINTFN(5, ("%s: %s: TS_BUSY || TS_TIMEOUT || TS_TTSTOP\n", device_xname(sc->sc_dev), __FUNCTION__));
    486 		goto out;
    487 	}
    488 
    489 	if (!ttypull(tp))
    490 		goto out;
    491 
    492 	/* Grab the first contiguous region of buffer space. */
    493 	{
    494 		u_char *tba;
    495 		int tbc;
    496 
    497 		tba = tp->t_outq.c_cf;
    498 		tbc = ndqb(&tp->t_outq, 0);
    499 
    500 		sc->sc_tba = tba;
    501 		sc->sc_tbc = tbc;
    502 	}
    503 
    504 	SET(tp->t_state, TS_BUSY);
    505 
    506 	/* Output the first chunk of the contiguous buffer. */
    507 	at91usart_filltx(sc);
    508 	at91usart_writereg(sc, US_IER, sc->sc_ier);
    509 	DPRINTFN(5, ("%s: %s, ier=%08x (csr=%08x)\n", device_xname(sc->sc_dev), __FUNCTION__, sc->sc_ier, at91usart_readreg(sc, US_CSR)));
    510 
    511 out:
    512 	splx(s);
    513 
    514 	return;
    515 }
    516 
    517 static __inline__ void
    518 at91usart_break(struct at91usart_softc *sc, int onoff)
    519 {
    520 	at91usart_writereg(sc, US_CR, onoff ? US_CR_STTBRK : US_CR_STPBRK);
    521 }
    522 
    523 static void
    524 at91usart_shutdown(struct at91usart_softc *sc)
    525 {
    526 	int s;
    527 
    528 	s = spltty();
    529 
    530 	/* turn of dma */
    531 	at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
    532 	at91usart_writereg(sc, US_PDC + PDC_TNCR, 0);
    533 	at91usart_writereg(sc, US_PDC + PDC_TCR, 0);
    534 	at91usart_writereg(sc, US_PDC + PDC_RNCR, 0);
    535 	at91usart_writereg(sc, US_PDC + PDC_RCR, 0);
    536 
    537 	/* Turn off interrupts. */
    538 	at91usart_writereg(sc, US_IDR, -1);
    539 
    540 	/* Clear any break condition set with TIOCSBRK. */
    541 	at91usart_break(sc, 0);
    542 	at91usart_set(sc);
    543 
    544 	if (sc->disable) {
    545 #ifdef DIAGNOSTIC
    546 		if (!sc->enabled)
    547 			panic("at91usart_shutdown: not enabled?");
    548 #endif
    549 		(*sc->disable)(sc);
    550 		sc->enabled = 0;
    551 	}
    552 	splx(s);
    553 }
    554 
    555 int
    556 at91usart_open(dev_t dev, int flag, int mode, struct lwp *l)
    557 {
    558 	struct at91usart_softc *sc;
    559 	struct tty *tp;
    560 	int s;
    561 	int error;
    562 
    563 	sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
    564 	if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK))
    565 		return (ENXIO);
    566 
    567 	if (!device_is_active(sc->sc_dev))
    568 		return (ENXIO);
    569 
    570 #ifdef KGDB
    571 	/*
    572 	 * If this is the kgdb port, no other use is permitted.
    573 	 */
    574 	if (ISSET(sc->sc_hwflags, COM_HW_KGDB))
    575 		return (EBUSY);
    576 #endif
    577 
    578 	tp = sc->sc_tty;
    579 
    580 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
    581 		return (EBUSY);
    582 
    583 	s = spltty();
    584 
    585 	/*
    586 	 * Do the following iff this is a first open.
    587 	 */
    588 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    589 		struct termios t;
    590 
    591 		tp->t_dev = dev;
    592 
    593 		if (sc->enable) {
    594 			if ((*sc->enable)(sc)) {
    595 				splx(s);
    596 				printf("%s: device enable failed\n",
    597 				       device_xname(sc->sc_dev));
    598 				return (EIO);
    599 			}
    600 			sc->enabled = 1;
    601 #if 0
    602 /* XXXXXXXXXXXXXXX */
    603 			com_config(sc);
    604 #endif
    605 		}
    606 
    607 		/* reset fifos: */
    608 		AT91PDC_RESET_FIFO(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC, &sc->sc_rx_fifo, 0);
    609 		AT91PDC_RESET_FIFO(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC, &sc->sc_tx_fifo, 1);
    610 
    611 		/* reset receive */
    612 		at91usart_writereg(sc, US_CR, US_CR_RSTSTA | US_CR_STTTO);
    613 
    614 		/* Turn on interrupts. */
    615 		sc->sc_ier = US_CSR_ENDRX|US_CSR_RXBUFF|US_CSR_TIMEOUT|US_CSR_RXBRK;
    616 		at91usart_writereg(sc, US_IER, sc->sc_ier);
    617 
    618 		/* enable DMA: */
    619 		at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_RXTEN);
    620 
    621 		/*
    622 		 * Initialize the termios status to the defaults.  Add in the
    623 		 * sticky bits from TIOCSFLAGS.
    624 		 */
    625 		t.c_ispeed = 0;
    626 /*		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
    627 			t.c_ospeed = usart_cn_sc.sc_ospeed;
    628 			t.c_cflag = usart_cn_sc.sc_cflag;
    629 		} else*/ {
    630 			t.c_ospeed = TTYDEF_SPEED;
    631 			t.c_cflag = TTYDEF_CFLAG;
    632 		}
    633 		if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
    634 			SET(t.c_cflag, CLOCAL);
    635 		if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
    636 			SET(t.c_cflag, CRTSCTS);
    637 		if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
    638 			SET(t.c_cflag, MDMBUF);
    639 
    640 		/* Make sure at91usart_param() will do something. */
    641 		tp->t_ospeed = 0;
    642 		(void) at91usart_param(tp, &t);
    643 		tp->t_iflag = TTYDEF_IFLAG;
    644 		tp->t_oflag = TTYDEF_OFLAG;
    645 		tp->t_lflag = TTYDEF_LFLAG;
    646 		ttychars(tp);
    647 		ttsetwater(tp);
    648 
    649 		/* and unblock. */
    650 		CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
    651 
    652 #ifdef COM_DEBUG
    653 		if (at91usart_debug)
    654 			comstatus(sc, "at91usart_open  ");
    655 #endif
    656 
    657 	}
    658 
    659 	splx(s);
    660 
    661 	error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
    662 	if (error)
    663 		goto bad;
    664 
    665 	error = (*tp->t_linesw->l_open)(dev, tp);
    666 	if (error)
    667 		goto bad;
    668 
    669 	return (0);
    670 
    671 bad:
    672 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    673 		/*
    674 		 * We failed to open the device, and nobody else had it opened.
    675 		 * Clean up the state as appropriate.
    676 		 */
    677 		at91usart_shutdown(sc);
    678 	}
    679 
    680 	return (error);
    681 }
    682 
    683 int
    684 at91usart_close(dev_t dev, int flag, int mode, struct lwp *l)
    685 {
    686 	struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
    687 	struct tty *tp = sc->sc_tty;
    688 
    689 	/* XXX This is for cons.c. */
    690 	if (!ISSET(tp->t_state, TS_ISOPEN))
    691 		return (0);
    692 
    693 	(*tp->t_linesw->l_close)(tp, flag);
    694 	ttyclose(tp);
    695 
    696 	if (COM_ISALIVE(sc) == 0)
    697 		return (0);
    698 
    699 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    700 		/*
    701 		 * Although we got a last close, the device may still be in
    702 		 * use; e.g. if this was the dialout node, and there are still
    703 		 * processes waiting for carrier on the non-dialout node.
    704 		 */
    705 		at91usart_shutdown(sc);
    706 	}
    707 
    708 	return (0);
    709 }
    710 
    711 int
    712 at91usart_read(dev_t dev, struct uio *uio, int flag)
    713 {
    714 	struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
    715 	struct tty *tp = sc->sc_tty;
    716 
    717 	if (COM_ISALIVE(sc) == 0)
    718 		return (EIO);
    719 
    720 	return ((*tp->t_linesw->l_read)(tp, uio, flag));
    721 }
    722 
    723 int
    724 at91usart_write(dev_t dev, struct uio *uio, int flag)
    725 {
    726 	struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
    727 	struct tty *tp = sc->sc_tty;
    728 
    729 	if (COM_ISALIVE(sc) == 0)
    730 		return (EIO);
    731 
    732 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
    733 }
    734 
    735 int
    736 at91usart_poll(dev_t dev, int events, struct lwp *l)
    737 {
    738 	struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
    739 	struct tty *tp = sc->sc_tty;
    740 
    741 	if (COM_ISALIVE(sc) == 0)
    742 		return (EIO);
    743 
    744 	return ((*tp->t_linesw->l_poll)(tp, events, l));
    745 }
    746 
    747 struct tty *
    748 at91usart_tty(dev_t dev)
    749 {
    750 	struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
    751 	struct tty *tp = sc->sc_tty;
    752 
    753 	return (tp);
    754 }
    755 
    756 int
    757 at91usart_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    758 {
    759 	struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev));
    760 	struct tty *tp = sc->sc_tty;
    761 	int error;
    762 	int s;
    763 
    764 	if (COM_ISALIVE(sc) == 0)
    765 		return (EIO);
    766 
    767 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
    768 	if (error != EPASSTHROUGH)
    769 		return (error);
    770 
    771 	error = ttioctl(tp, cmd, data, flag, l);
    772 	if (error != EPASSTHROUGH)
    773 		return (error);
    774 
    775 	error = 0;
    776 
    777 	s = spltty();
    778 
    779 	switch (cmd) {
    780 	case TIOCSBRK:
    781 		at91usart_break(sc, 1);
    782 		break;
    783 
    784 	case TIOCCBRK:
    785 		at91usart_break(sc, 0);
    786 		break;
    787 
    788 	case TIOCGFLAGS:
    789 		*(int *)data = sc->sc_swflags;
    790 		break;
    791 
    792 	case TIOCSFLAGS:
    793 		error = kauth_authorize_device_tty(l->l_cred,
    794 		    KAUTH_DEVICE_TTY_PRIVSET, tp);
    795 		if (error)
    796 			break;
    797 		sc->sc_swflags = *(int *)data;
    798 		break;
    799 
    800 	default:
    801 		error = EPASSTHROUGH;
    802 		break;
    803 	}
    804 
    805 	splx(s);
    806 
    807 	return (error);
    808 }
    809 
    810 /*
    811  * Stop output on a line.
    812  */
    813 void
    814 at91usart_stop(struct tty *tp, int flag)
    815 {
    816 	struct at91usart_softc *sc
    817 		= device_lookup_private(&at91usart_cd, COMUNIT(tp->t_dev));
    818 	int s;
    819 
    820 	s = spltty();
    821 	if (ISSET(tp->t_state, TS_BUSY)) {
    822 		/* Stop transmitting at the next chunk. */
    823 		sc->sc_tbc = 0;
    824 		if (!ISSET(tp->t_state, TS_TTSTOP))
    825 			SET(tp->t_state, TS_FLUSH);
    826 	}
    827 	splx(s);
    828 }
    829 
    830 #if 0
    831 static u_int
    832 cflag2lcrhi(tcflag_t cflag)
    833 {
    834 	uint32_t	mr;
    835 
    836 	switch (cflag & CSIZE) {
    837 	default:
    838 		mr = 0x0;
    839 		break;
    840 	}
    841 #if 0
    842 	mr |= (cflag & PARENB) ? LinCtrlHigh_PEN : 0;
    843 	mr |= (cflag & PARODD) ? 0 : LinCtrlHigh_EPS;
    844 	mr |= (cflag & CSTOPB) ? LinCtrlHigh_STP2 : 0;
    845 	mr |= LinCtrlHigh_FEN;  /* FIFO always enabled */
    846 #endif
    847 	mr |= USART_MR_PAR_NONE;
    848 	return (mr);
    849 }
    850 #endif
    851 
    852 
    853 static void
    854 at91usart_set(struct at91usart_softc *sc)
    855 {
    856 	at91usart_writereg(sc, US_MR, US_MR_CHRL_8 | US_MR_PAR_NONE | US_MR_NBSTOP_1);
    857 	at91usart_writereg(sc, US_BRGR, sc->sc_brgr);
    858 	at91usart_writereg(sc, US_CR, US_CR_TXEN | US_CR_RXEN); // @@@ just in case
    859 }
    860 
    861 #if	NOTYET
    862 int
    863 at91usart_cn_attach(bus_space_tag_t iot, bus_addr_t iobase, bus_space_handle_t ioh,
    864 		    uint32_t mstclk, int ospeed, tcflag_t cflag)
    865 {
    866 	cn_tab = &at91usart_cons;
    867 	cn_init_magic(&at91usart_cnm_state);
    868 	cn_set_magic("\047\001");
    869 
    870 	usart_cn_sc.sc_iot = iot;
    871 	usart_cn_sc.sc_ioh = ioh;
    872 	usart_cn_sc.sc_hwbase = iobase;
    873 	usart_cn_sc.sc_ospeed = ospeed;
    874 	usart_cn_sc.sc_cflag = cflag;
    875 
    876 	USART_INIT(mstclk, ospeed);
    877 
    878 	return (0);
    879 }
    880 
    881 void
    882 at91usart_cn_probe(struct consdev *cp)
    883 {
    884 	cp->cn_pri = CN_REMOTE;
    885 }
    886 
    887 void
    888 at91usart_cn_pollc(dev_t dev, int on)
    889 {
    890 	if (on) {
    891 		// enable polling mode
    892 		USARTREG(US_IDR) = USART_INT_RXRDY;
    893 	} else {
    894 		// disable polling mode
    895 		USARTREG(US_IER) = USART_INT_RXRDY;
    896 	}
    897 }
    898 
    899 void
    900 at91usart_cn_putc(dev_t dev, int c)
    901 {
    902 	int			s;
    903 #if 0
    904 	bus_space_tag_t		iot = usart_cn_sc.sc_iot;
    905 	bus_space_handle_t	ioh = usart_cn_sc.sc_ioh;
    906 #endif
    907 	s = spltty();
    908 
    909 	USART_PUTC(c);
    910 
    911 #ifdef DEBUG
    912 	if (c == '\r') {
    913 		while((USARTREG(USART_SR) & USART_SR_TXEMPTY) == 0)
    914 			;
    915 	}
    916 #endif
    917 
    918 	splx(s);
    919 }
    920 
    921 int
    922 at91usart_cn_getc(dev_t dev)
    923 {
    924 	int			c, sr;
    925 	int			s;
    926 #if 0
    927 	bus_space_tag_t		iot = usart_cn_sc.sc_iot;
    928 	bus_space_handle_t	ioh = usart_cn_sc.sc_ioh;
    929 #endif
    930 
    931         s = spltty();
    932 
    933 	while ((c = USART_PEEKC()) == -1) {
    934 	  splx(s);
    935 	  s = spltty();
    936 	}
    937 		;
    938 	sr = USARTREG(USART_SR);
    939 	if (ISSET(sr, USART_SR_FRAME) && c == 0) {
    940 		USARTREG(USART_CR) = USART_CR_RSTSTA;	// reset status bits
    941 		c = CNC_BREAK;
    942 	}
    943 #ifdef DDB
    944 	extern int db_active;
    945 	if (!db_active)
    946 #endif
    947 	{
    948 		int cn_trapped = 0; /* unused */
    949 
    950 		cn_check_magic(dev, c, at91usart_cnm_state);
    951 	}
    952 	splx(s);
    953 
    954 	c &= 0xff;
    955 
    956 	return (c);
    957 }
    958 #endif	/* NOTYET */
    959 
    960 inline static void
    961 at91usart_rxsoft(struct at91usart_softc *sc, struct tty *tp, unsigned csr)
    962 {
    963 	u_char *start, *get, *end;
    964 	int cc;
    965 
    966 	AT91PDC_FIFO_POSTREAD(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC,
    967 			      &sc->sc_rx_fifo);
    968 
    969 	if (ISSET(csr, US_CSR_TIMEOUT | US_CSR_RXBRK))
    970 		at91usart_rx_stopped(sc);
    971 
    972 	while ((start = AT91PDC_FIFO_RDPTR(&sc->sc_rx_fifo, &cc)) != NULL) {
    973 		int (*rint)(int, struct tty *) = tp->t_linesw->l_rint;
    974 		int code;
    975 
    976 		if (!ISSET(csr, US_CSR_TIMEOUT | US_CSR_RXBRK))
    977 			at91usart_rx_started(sc);
    978 
    979 		for (get = start, end = start + cc; get < end; get++) {
    980 			code = *get;
    981 			if ((*rint)(code, tp) == -1) {
    982 				/*
    983 				 * The line discipline's buffer is out of space.
    984 				 */
    985 				if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
    986 					/*
    987 					 * We're either not using flow control, or the
    988 					 * line discipline didn't tell us to block for
    989 					 * some reason.  Either way, we have no way to
    990 					 * know when there's more space available, so
    991 					 * just drop the rest of the data.
    992 					 */
    993 					get = end;
    994 					printf("%s: receive missing data!\n",
    995 					     device_xname(sc->sc_dev));
    996 				} else {
    997 					/*
    998 					 * Don't schedule any more receive processing
    999 					 * until the line discipline tells us there's
   1000 					 * space available (through comhwiflow()).
   1001 					 * Leave the rest of the data in the input
   1002 					 * buffer.
   1003 					 */
   1004 					SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
   1005 				}
   1006 				break;
   1007 			}
   1008 		}
   1009 
   1010 		// tell we've read some bytes...
   1011 		AT91PDC_FIFO_READ(&sc->sc_rx_fifo, get - start);
   1012 
   1013 		if (ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED))
   1014 			break;
   1015 	}
   1016 
   1017 	// h/w flow control hook:
   1018 	if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
   1019 		at91usart_rx_rts_ctl(sc, (AT91PDC_FIFO_SPACE(&sc->sc_rx_fifo) > PDC_BLOCK_SIZE * 2));
   1020 
   1021 	// write next pointer if USART is ready:
   1022 	if (AT91PDC_FIFO_PREREAD(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC,
   1023 				  &sc->sc_rx_fifo, PDC_BLOCK_SIZE)) {
   1024 		SET(sc->sc_ier, US_CSR_ENDRX | US_CSR_RXBUFF | US_CSR_TIMEOUT | US_CSR_RXBRK);
   1025 	} else {
   1026 		CLR(sc->sc_ier, US_CSR_ENDRX | US_CSR_RXBUFF | US_CSR_TIMEOUT | US_CSR_RXBRK);
   1027 	}
   1028 }
   1029 
   1030 inline static void
   1031 at91usart_txsoft(struct at91usart_softc *sc, struct tty *tp)
   1032 {
   1033 	at91usart_filltx(sc);
   1034 	if (!ISSET(tp->t_state, TS_BUSY))
   1035 		(*tp->t_linesw->l_start)(tp);
   1036 }
   1037 
   1038 
   1039 static void
   1040 at91usart_soft(void* arg)
   1041 {
   1042 	struct at91usart_softc *sc = arg;
   1043 	int s;
   1044 	u_int csr;
   1045 
   1046 	if (COM_ISALIVE(sc) == 0)
   1047 		return;
   1048 
   1049 	s = spltty();
   1050 	csr = sc->sc_csr;
   1051 	while (csr != 0) {
   1052 		if ((csr &= sc->sc_ier) == 0)
   1053 			break;
   1054 //		splx(s);
   1055 		DPRINTFN(5, ("%s: %s / csr = 0x%08x\n", device_xname(sc->sc_dev), __FUNCTION__, csr));
   1056 		if (ISSET(csr, US_CSR_ENDRX | US_CSR_RXBUFF | US_CSR_TIMEOUT | US_CSR_RXBRK)) {
   1057 			/* receive interrupt */
   1058 			if (ISSET(csr, US_CSR_RXBRK)) {
   1059 				// break received!
   1060 				at91usart_writereg(sc, US_CR, US_CR_RSTSTA | US_CR_STTTO);
   1061 			} else if (ISSET(csr, US_CSR_TIMEOUT)) {
   1062 				// timeout received
   1063 				at91usart_writereg(sc, US_CR, US_CR_STTTO);
   1064 			}
   1065 			at91usart_rxsoft(sc, sc->sc_tty, csr);
   1066 		}
   1067 		if (ISSET(csr, US_CSR_TXEMPTY)) {
   1068 			at91usart_stop_tx(sc);
   1069 			CLR(sc->sc_ier, US_CSR_TXEMPTY);
   1070 			if (AT91PDC_FIFO_EMPTY(&sc->sc_tx_fifo)) {
   1071 				// everything sent!
   1072 				if (ISSET(sc->sc_tty->t_state, TS_FLUSH))
   1073 					CLR(sc->sc_tty->t_state, TS_FLUSH);
   1074 			}
   1075 		}
   1076 		if (ISSET(csr, US_CSR_TXEMPTY | US_CSR_ENDTX)) {
   1077 			/* transmit interrupt! */
   1078 			at91usart_txsoft(sc, sc->sc_tty);
   1079 		}
   1080 //		s = spltty();
   1081 		csr = at91usart_readreg(sc, US_CSR);
   1082 	}
   1083 	sc->sc_csr = 0;
   1084 	at91usart_writereg(sc, US_IER, sc->sc_ier);	// re-enable interrupts
   1085 	splx(s);
   1086 }
   1087 
   1088 
   1089 static int
   1090 at91usart_intr(void* arg)
   1091 {
   1092 	struct at91usart_softc *sc = arg;
   1093 	u_int csr, imr;
   1094 
   1095 	// get out if interrupts are not enabled
   1096 	imr = at91usart_readreg(sc, US_IMR);
   1097 	if (!imr)
   1098 		return 0;
   1099 	// get out if pending interrupt is not enabled
   1100 	csr = at91usart_readreg(sc, US_CSR);
   1101 	DPRINTFN(6,("%s: csr=%08X imr=%08X\n", device_xname(sc->sc_dev), csr, imr));
   1102 	if (!ISSET(csr, imr))
   1103 		return 0;
   1104 
   1105 	// ok, we DO have some interrupts to serve! let softint do it
   1106 	sc->sc_csr = csr;
   1107 	at91usart_writereg(sc, US_IDR, -1);
   1108 
   1109 	/* Wake up the poller. */
   1110 	softint_schedule(sc->sc_si);
   1111 
   1112 	/* we're done for now */
   1113 	return (1);
   1114 
   1115 }
   1116