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