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