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