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