1239676Srwatson/*-
2239676Srwatson * Copyright (c) 2011-2012 Robert N. M. Watson
3239676Srwatson * All rights reserved.
4239676Srwatson *
5239676Srwatson * This software was developed by SRI International and the University of
6239676Srwatson * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7239676Srwatson * ("CTSRD"), as part of the DARPA CRASH research programme.
8239676Srwatson *
9239676Srwatson * Redistribution and use in source and binary forms, with or without
10239676Srwatson * modification, are permitted provided that the following conditions
11239676Srwatson * are met:
12239676Srwatson * 1. Redistributions of source code must retain the above copyright
13239676Srwatson *    notice, this list of conditions and the following disclaimer.
14239676Srwatson * 2. Redistributions in binary form must reproduce the above copyright
15239676Srwatson *    notice, this list of conditions and the following disclaimer in the
16239676Srwatson *    documentation and/or other materials provided with the distribution.
17239676Srwatson *
18239676Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19239676Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20239676Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21239676Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22239676Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23239676Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24239676Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25239676Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26239676Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27239676Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28239676Srwatson * SUCH DAMAGE.
29239676Srwatson */
30239676Srwatson
31239676Srwatson#include <sys/cdefs.h>
32239676Srwatson__FBSDID("$FreeBSD$");
33239676Srwatson
34239676Srwatson#include <sys/param.h>
35239676Srwatson#include <sys/bus.h>
36239676Srwatson#include <sys/cons.h>
37239676Srwatson#include <sys/endian.h>
38239676Srwatson#include <sys/kdb.h>
39239676Srwatson#include <sys/rman.h>
40239676Srwatson#include <sys/systm.h>
41239676Srwatson#include <sys/kernel.h>
42239676Srwatson#include <sys/reboot.h>
43239676Srwatson#include <sys/tty.h>
44239676Srwatson
45239676Srwatson#include <ddb/ddb.h>
46239676Srwatson
47239676Srwatson#include <machine/bus.h>
48239676Srwatson
49239676Srwatson#include <dev/altera/jtag_uart/altera_jtag_uart.h>
50239676Srwatson
51239676Srwatson/*
52239676Srwatson * If one of the Altera JTAG UARTs is currently the system console, register
53239676Srwatson * it here.
54239676Srwatson */
55239676Srwatsonstatic struct altera_jtag_uart_softc	*aju_cons_sc;
56239676Srwatson
57239676Srwatsonstatic tsw_outwakeup_t	aju_outwakeup;
58239676Srwatsonstatic void		aju_ac_callout(void *);
59239676Srwatsonstatic void		aju_io_callout(void *);
60239676Srwatson
61239676Srwatsonstatic struct ttydevsw aju_ttydevsw = {
62239676Srwatson	.tsw_flags	= TF_NOPREFIX,
63239676Srwatson	.tsw_outwakeup	= aju_outwakeup,
64239676Srwatson};
65239676Srwatson
66239676Srwatson/*
67239676Srwatson * When polling for the AC bit, the number of times we have to not see it
68239676Srwatson * before assuming JTAG has disappeared on us.  By default, one second.
69239676Srwatson */
70239676Srwatson#define	AJU_JTAG_MAXMISS		5
71239676Srwatson
72239676Srwatson/*
73239676Srwatson * Polling intervals for input/output and JTAG connection events.
74239676Srwatson */
75239676Srwatson#define	AJU_IO_POLLINTERVAL		(hz/100)
76239676Srwatson#define	AJU_AC_POLLINTERVAL		(hz/5)
77239676Srwatson
78239676Srwatson/*
79239676Srwatson * Low-level read and write register routines; the Altera UART is little
80239676Srwatson * endian, so we byte swap 32-bit reads and writes.
81239676Srwatson */
82239676Srwatsonstatic inline uint32_t
83239676Srwatsonaju_data_read(struct altera_jtag_uart_softc *sc)
84239676Srwatson{
85239676Srwatson
86239676Srwatson	return (le32toh(bus_read_4(sc->ajus_mem_res,
87239676Srwatson	    ALTERA_JTAG_UART_DATA_OFF)));
88239676Srwatson}
89239676Srwatson
90239676Srwatsonstatic inline void
91239676Srwatsonaju_data_write(struct altera_jtag_uart_softc *sc, uint32_t v)
92239676Srwatson{
93239676Srwatson
94239676Srwatson	bus_write_4(sc->ajus_mem_res, ALTERA_JTAG_UART_DATA_OFF, htole32(v));
95239676Srwatson}
96239676Srwatson
97239676Srwatsonstatic inline uint32_t
98239676Srwatsonaju_control_read(struct altera_jtag_uart_softc *sc)
99239676Srwatson{
100239676Srwatson
101239676Srwatson	return (le32toh(bus_read_4(sc->ajus_mem_res,
102239676Srwatson	    ALTERA_JTAG_UART_CONTROL_OFF)));
103239676Srwatson}
104239676Srwatson
105239676Srwatsonstatic inline void
106239676Srwatsonaju_control_write(struct altera_jtag_uart_softc *sc, uint32_t v)
107239676Srwatson{
108239676Srwatson
109239676Srwatson	bus_write_4(sc->ajus_mem_res, ALTERA_JTAG_UART_CONTROL_OFF,
110239676Srwatson	    htole32(v));
111239676Srwatson}
112239676Srwatson
113239676Srwatson/*
114239676Srwatson * Slightly higher-level routines aware of buffering and flow control.
115239676Srwatson */
116239676Srwatsonstatic inline int
117239676Srwatsonaju_writable(struct altera_jtag_uart_softc *sc)
118239676Srwatson{
119239676Srwatson
120239676Srwatson	return ((aju_control_read(sc) &
121239676Srwatson	    ALTERA_JTAG_UART_CONTROL_WSPACE) != 0);
122239676Srwatson}
123239676Srwatson
124239676Srwatsonstatic inline int
125239676Srwatsonaju_readable(struct altera_jtag_uart_softc *sc)
126239676Srwatson{
127239676Srwatson	uint32_t v;
128239676Srwatson
129239676Srwatson	AJU_LOCK_ASSERT(sc);
130239676Srwatson
131239676Srwatson	if (*sc->ajus_buffer_validp)
132239676Srwatson		return (1);
133239676Srwatson	v = aju_data_read(sc);
134239676Srwatson	if ((v & ALTERA_JTAG_UART_DATA_RVALID) != 0) {
135239676Srwatson		*sc->ajus_buffer_validp = 1;
136239676Srwatson		*sc->ajus_buffer_datap = (v & ALTERA_JTAG_UART_DATA_DATA);
137239676Srwatson		return (1);
138239676Srwatson	}
139239676Srwatson	return (0);
140239676Srwatson}
141239676Srwatson
142239676Srwatsonstatic char
143239676Srwatsonaju_read(struct altera_jtag_uart_softc *sc)
144239676Srwatson{
145239676Srwatson
146239676Srwatson	AJU_LOCK_ASSERT(sc);
147239676Srwatson
148239676Srwatson	while (!aju_readable(sc));
149239676Srwatson	*sc->ajus_buffer_validp = 0;
150239676Srwatson	return (*sc->ajus_buffer_datap);
151239676Srwatson}
152239676Srwatson
153239676Srwatson/*
154239676Srwatson * Routines for enabling and disabling interrupts for read and write.
155239676Srwatson */
156239676Srwatsonstatic void
157239676Srwatsonaju_intr_readable_enable(struct altera_jtag_uart_softc *sc)
158239676Srwatson{
159239676Srwatson	uint32_t v;
160239676Srwatson
161239676Srwatson	AJU_LOCK_ASSERT(sc);
162239676Srwatson
163239676Srwatson	v = aju_control_read(sc);
164239676Srwatson	v |= ALTERA_JTAG_UART_CONTROL_RE;
165239676Srwatson	aju_control_write(sc, v);
166239676Srwatson}
167239676Srwatson
168239676Srwatsonstatic void
169239676Srwatsonaju_intr_writable_enable(struct altera_jtag_uart_softc *sc)
170239676Srwatson{
171239676Srwatson	uint32_t v;
172239676Srwatson
173239676Srwatson	AJU_LOCK_ASSERT(sc);
174239676Srwatson
175239676Srwatson	v = aju_control_read(sc);
176239676Srwatson	v |= ALTERA_JTAG_UART_CONTROL_WE;
177239676Srwatson	aju_control_write(sc, v);
178239676Srwatson}
179239676Srwatson
180239676Srwatsonstatic void
181239676Srwatsonaju_intr_writable_disable(struct altera_jtag_uart_softc *sc)
182239676Srwatson{
183239676Srwatson	uint32_t v;
184239676Srwatson
185239676Srwatson	AJU_LOCK_ASSERT(sc);
186239676Srwatson
187239676Srwatson	v = aju_control_read(sc);
188239676Srwatson	v &= ~ALTERA_JTAG_UART_CONTROL_WE;
189239676Srwatson	aju_control_write(sc, v);
190239676Srwatson}
191239676Srwatson
192239676Srwatsonstatic void
193239676Srwatsonaju_intr_disable(struct altera_jtag_uart_softc *sc)
194239676Srwatson{
195239676Srwatson	uint32_t v;
196239676Srwatson
197239676Srwatson	AJU_LOCK_ASSERT(sc);
198239676Srwatson
199239676Srwatson	v = aju_control_read(sc);
200239676Srwatson	v &= ~(ALTERA_JTAG_UART_CONTROL_RE | ALTERA_JTAG_UART_CONTROL_WE);
201239676Srwatson	aju_control_write(sc, v);
202239676Srwatson}
203239676Srwatson
204239676Srwatson/*
205239676Srwatson * The actual work of checking for, and handling, available reads.  This is
206239676Srwatson * used in both polled and interrupt-driven modes, as JTAG UARTs may be hooked
207239676Srwatson * up with, or without, IRQs allocated.
208239676Srwatson */
209239676Srwatsonstatic void
210239676Srwatsonaju_handle_input(struct altera_jtag_uart_softc *sc, struct tty *tp)
211239676Srwatson{
212239676Srwatson	int c;
213239676Srwatson
214239676Srwatson	tty_lock_assert(tp, MA_OWNED);
215239676Srwatson	AJU_LOCK_ASSERT(sc);
216239676Srwatson
217239676Srwatson	while (aju_readable(sc)) {
218239676Srwatson		c = aju_read(sc);
219239676Srwatson		AJU_UNLOCK(sc);
220239676Srwatson#ifdef KDB
221239676Srwatson		if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE)
222239676Srwatson			kdb_alt_break(c, &sc->ajus_alt_break_state);
223239676Srwatson#endif
224239676Srwatson		ttydisc_rint(tp, c, 0);
225239676Srwatson		AJU_LOCK(sc);
226239676Srwatson	}
227239676Srwatson	AJU_UNLOCK(sc);
228239676Srwatson	ttydisc_rint_done(tp);
229239676Srwatson	AJU_LOCK(sc);
230239676Srwatson}
231239676Srwatson
232239676Srwatson/*
233239676Srwatson * Send output to the UART until either there's none left to send, or we run
234239676Srwatson * out of room and need to await an interrupt so that we can start sending
235239676Srwatson * again.
236239676Srwatson *
237239676Srwatson * XXXRW: It would be nice to query WSPACE at the beginning and write to the
238239676Srwatson * FIFO in bugger chunks.
239239676Srwatson */
240239676Srwatsonstatic void
241239676Srwatsonaju_handle_output(struct altera_jtag_uart_softc *sc, struct tty *tp)
242239676Srwatson{
243239676Srwatson	uint32_t v;
244239676Srwatson	uint8_t ch;
245239676Srwatson
246239676Srwatson	tty_lock_assert(tp, MA_OWNED);
247239676Srwatson	AJU_LOCK_ASSERT(sc);
248239676Srwatson
249239676Srwatson	AJU_UNLOCK(sc);
250239676Srwatson	while (ttydisc_getc_poll(tp) != 0) {
251239676Srwatson		AJU_LOCK(sc);
252239676Srwatson		v = aju_control_read(sc);
253239676Srwatson		if ((v & ALTERA_JTAG_UART_CONTROL_WSPACE) != 0) {
254239676Srwatson			AJU_UNLOCK(sc);
255239676Srwatson			if (ttydisc_getc(tp, &ch, sizeof(ch)) != sizeof(ch))
256239676Srwatson				panic("%s: ttydisc_getc", __func__);
257239676Srwatson			AJU_LOCK(sc);
258239676Srwatson			aju_data_write(sc, ch);
259239676Srwatson		} else {
260239676Srwatson			/*
261239676Srwatson			 * If JTAG is not present, then we will drop this
262239676Srwatson			 * character instead of perhaps scheduling an
263239676Srwatson			 * interrupt to let us know when there is buffer
264239676Srwatson			 * space.  Otherwise we might get a write interrupt
265239676Srwatson			 * later even though we aren't interested in sending
266239676Srwatson			 * anymore.  Loop to drain TTY-layer buffer.
267239676Srwatson			 */
268239676Srwatson			if (*sc->ajus_jtag_presentp == 0) {
269239676Srwatson				if (ttydisc_getc(tp, &ch, sizeof(ch)) !=
270239676Srwatson				    sizeof(ch))
271239676Srwatson					panic("%s: ttydisc_getc 2", __func__);
272239676Srwatson				AJU_UNLOCK(sc);
273239676Srwatson				continue;
274239676Srwatson			}
275239676Srwatson			if (sc->ajus_irq_res != NULL)
276239676Srwatson				aju_intr_writable_enable(sc);
277239676Srwatson			return;
278239676Srwatson		}
279239676Srwatson		AJU_UNLOCK(sc);
280239676Srwatson	}
281239676Srwatson	AJU_LOCK(sc);
282239676Srwatson	aju_intr_writable_disable(sc);
283239676Srwatson}
284239676Srwatson
285239676Srwatsonstatic void
286239676Srwatsonaju_outwakeup(struct tty *tp)
287239676Srwatson{
288239676Srwatson	struct altera_jtag_uart_softc *sc = tty_softc(tp);
289239676Srwatson
290239676Srwatson	tty_lock_assert(tp, MA_OWNED);
291239676Srwatson
292239676Srwatson	AJU_LOCK(sc);
293239676Srwatson	aju_handle_output(sc, tp);
294239676Srwatson	AJU_UNLOCK(sc);
295239676Srwatson}
296239676Srwatson
297239676Srwatsonstatic void
298239676Srwatsonaju_io_callout(void *arg)
299239676Srwatson{
300239676Srwatson	struct altera_jtag_uart_softc *sc = arg;
301239676Srwatson	struct tty *tp = sc->ajus_ttyp;
302239676Srwatson
303239676Srwatson	tty_lock(tp);
304239676Srwatson	AJU_LOCK(sc);
305239676Srwatson
306239676Srwatson	/*
307239676Srwatson	 * It would be convenient if we could share code with aju_intr() here
308239676Srwatson	 * by testing the control register for ALTERA_JTAG_UART_CONTROL_RI and
309239676Srwatson	 * ALTERA_JTAG_UART_CONTROL_WI.  Unfortunately, it's not clear that
310239676Srwatson	 * this is supported, so do all the work to poll for both input and
311239676Srwatson	 * output.
312239676Srwatson	 */
313239676Srwatson	aju_handle_input(sc, tp);
314239676Srwatson	aju_handle_output(sc, tp);
315239676Srwatson
316239676Srwatson	/*
317239676Srwatson	 * Reschedule next poll attempt.  There's some argument that we should
318239676Srwatson	 * do adaptive polling based on the expectation of I/O: is something
319239676Srwatson	 * pending in the output buffer, or have we recently had input, but we
320239676Srwatson	 * don't.
321239676Srwatson	 */
322239676Srwatson	callout_reset(&sc->ajus_io_callout, AJU_IO_POLLINTERVAL,
323239676Srwatson	    aju_io_callout, sc);
324239676Srwatson	AJU_UNLOCK(sc);
325239676Srwatson	tty_unlock(tp);
326239676Srwatson}
327239676Srwatson
328239676Srwatsonstatic void
329239676Srwatsonaju_ac_callout(void *arg)
330239676Srwatson{
331239676Srwatson	struct altera_jtag_uart_softc *sc = arg;
332239676Srwatson	struct tty *tp = sc->ajus_ttyp;
333239676Srwatson	uint32_t v;
334239676Srwatson
335239676Srwatson	tty_lock(tp);
336239676Srwatson	AJU_LOCK(sc);
337239676Srwatson	v = aju_control_read(sc);
338239676Srwatson	if (v & ALTERA_JTAG_UART_CONTROL_AC) {
339239676Srwatson		v &= ~ALTERA_JTAG_UART_CONTROL_AC;
340239676Srwatson		aju_control_write(sc, v);
341239676Srwatson		if (*sc->ajus_jtag_presentp == 0) {
342239676Srwatson			*sc->ajus_jtag_missedp = 0;
343239676Srwatson			*sc->ajus_jtag_presentp = 1;
344239676Srwatson			aju_handle_output(sc, tp);
345239676Srwatson		}
346239676Srwatson	} else if (*sc->ajus_jtag_presentp != 0) {
347239676Srwatson		(*sc->ajus_jtag_missedp)++;
348239676Srwatson		if (*sc->ajus_jtag_missedp >= AJU_JTAG_MAXMISS) {
349239676Srwatson			*sc->ajus_jtag_presentp = 0;
350239676Srwatson			aju_handle_output(sc, tp);
351239676Srwatson		}
352239676Srwatson	}
353239676Srwatson	callout_reset(&sc->ajus_ac_callout, AJU_AC_POLLINTERVAL,
354239676Srwatson	    aju_ac_callout, sc);
355239676Srwatson	AJU_UNLOCK(sc);
356239676Srwatson	tty_unlock(tp);
357239676Srwatson}
358239676Srwatson
359239676Srwatsonstatic void
360239676Srwatsonaju_intr(void *arg)
361239676Srwatson{
362239676Srwatson	struct altera_jtag_uart_softc *sc = arg;
363239676Srwatson	struct tty *tp = sc->ajus_ttyp;
364239676Srwatson	uint32_t v;
365239676Srwatson
366239676Srwatson	tty_lock(tp);
367239676Srwatson	AJU_LOCK(sc);
368239676Srwatson	v = aju_control_read(sc);
369239676Srwatson	if (v & ALTERA_JTAG_UART_CONTROL_RI)
370239676Srwatson		aju_handle_input(sc, tp);
371239676Srwatson	if (v & ALTERA_JTAG_UART_CONTROL_WI)
372239676Srwatson		aju_handle_output(sc, tp);
373239676Srwatson	AJU_UNLOCK(sc);
374239676Srwatson	tty_unlock(tp);
375239676Srwatson}
376239676Srwatson
377239676Srwatsonint
378239676Srwatsonaltera_jtag_uart_attach(struct altera_jtag_uart_softc *sc)
379239676Srwatson{
380239676Srwatson	struct tty *tp;
381239676Srwatson	int error;
382239676Srwatson
383239676Srwatson	AJU_LOCK_INIT(sc);
384239676Srwatson
385239676Srwatson	/*
386239676Srwatson	 * XXXRW: Currently, we detect the console solely based on it using a
387239676Srwatson	 * reserved address, and borrow console-level locks and buffer if so.
388239676Srwatson	 * Is there a better way?
389239676Srwatson	 */
390239676Srwatson	if (rman_get_start(sc->ajus_mem_res) == BERI_UART_BASE) {
391239676Srwatson		sc->ajus_lockp = &aju_cons_lock;
392239676Srwatson		sc->ajus_buffer_validp = &aju_cons_buffer_valid;
393239676Srwatson		sc->ajus_buffer_datap = &aju_cons_buffer_data;
394239676Srwatson		sc->ajus_jtag_presentp = &aju_cons_jtag_present;
395239676Srwatson		sc->ajus_jtag_missedp = &aju_cons_jtag_missed;
396239676Srwatson		sc->ajus_flags |= ALTERA_JTAG_UART_FLAG_CONSOLE;
397239676Srwatson	} else {
398239676Srwatson		sc->ajus_lockp = &sc->ajus_lock;
399239676Srwatson		sc->ajus_buffer_validp = &sc->ajus_buffer_valid;
400239676Srwatson		sc->ajus_buffer_datap = &sc->ajus_buffer_data;
401239676Srwatson		sc->ajus_jtag_presentp = &sc->ajus_jtag_present;
402239676Srwatson		sc->ajus_jtag_missedp = &sc->ajus_jtag_missed;
403239676Srwatson	}
404239676Srwatson
405239676Srwatson	/*
406239676Srwatson	 * Disable interrupts regardless of whether or not we plan to use
407239676Srwatson	 * them.  We will register an interrupt handler now if they will be
408239676Srwatson	 * used, but not re-enable intil later once the remainder of the tty
409239676Srwatson	 * layer is properly initialised, as we're not ready for input yet.
410239676Srwatson	 */
411239676Srwatson	AJU_LOCK(sc);
412239676Srwatson	aju_intr_disable(sc);
413239676Srwatson	AJU_UNLOCK(sc);
414239676Srwatson	if (sc->ajus_irq_res != NULL) {
415239676Srwatson		error = bus_setup_intr(sc->ajus_dev, sc->ajus_irq_res,
416239676Srwatson		    INTR_ENTROPY | INTR_TYPE_TTY | INTR_MPSAFE, NULL,
417239676Srwatson		    aju_intr, sc, &sc->ajus_irq_cookie);
418239676Srwatson		if (error) {
419239676Srwatson			device_printf(sc->ajus_dev,
420239676Srwatson			    "could not activate interrupt\n");
421239676Srwatson			AJU_LOCK_DESTROY(sc);
422239676Srwatson			return (error);
423239676Srwatson		}
424239676Srwatson	}
425239676Srwatson	tp = sc->ajus_ttyp = tty_alloc(&aju_ttydevsw, sc);
426239676Srwatson	if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE) {
427239676Srwatson		aju_cons_sc = sc;
428239676Srwatson		tty_init_console(tp, 0);
429239676Srwatson	}
430239676Srwatson	tty_makedev(tp, NULL, "%s%d", AJU_TTYNAME, sc->ajus_unit);
431239676Srwatson
432239676Srwatson	/*
433239676Srwatson	 * If we will be using interrupts, enable them now; otherwise, start
434239676Srwatson	 * polling.  From this point onwards, input can arrive.
435239676Srwatson	 */
436239676Srwatson	if (sc->ajus_irq_res != NULL) {
437239676Srwatson		AJU_LOCK(sc);
438239676Srwatson		aju_intr_readable_enable(sc);
439239676Srwatson		AJU_UNLOCK(sc);
440239676Srwatson	} else {
441239676Srwatson		callout_init(&sc->ajus_io_callout, CALLOUT_MPSAFE);
442239676Srwatson		callout_reset(&sc->ajus_io_callout, AJU_IO_POLLINTERVAL,
443239676Srwatson		    aju_io_callout, sc);
444239676Srwatson	}
445239676Srwatson	callout_init(&sc->ajus_ac_callout, CALLOUT_MPSAFE);
446239676Srwatson	callout_reset(&sc->ajus_ac_callout, AJU_AC_POLLINTERVAL,
447239676Srwatson	    aju_ac_callout, sc);
448239676Srwatson	return (0);
449239676Srwatson}
450239676Srwatson
451239676Srwatsonvoid
452239676Srwatsonaltera_jtag_uart_detach(struct altera_jtag_uart_softc *sc)
453239676Srwatson{
454239676Srwatson	struct tty *tp = sc->ajus_ttyp;
455239676Srwatson
456239676Srwatson	/*
457239676Srwatson	 * If we're using interrupts, disable and release the interrupt
458239676Srwatson	 * handler now.  Otherwise drain the polling timeout.
459239676Srwatson	 */
460239676Srwatson	if (sc->ajus_irq_res != NULL) {
461239676Srwatson		AJU_LOCK(sc);
462239676Srwatson		aju_intr_disable(sc);
463239676Srwatson		AJU_UNLOCK(sc);
464239676Srwatson		bus_teardown_intr(sc->ajus_dev, sc->ajus_irq_res,
465239676Srwatson		    sc->ajus_irq_cookie);
466239676Srwatson	} else
467239676Srwatson		callout_drain(&sc->ajus_io_callout);
468239676Srwatson	callout_drain(&sc->ajus_ac_callout);
469239676Srwatson	if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE)
470239676Srwatson		aju_cons_sc = NULL;
471239676Srwatson	tty_lock(tp);
472239676Srwatson	tty_rel_gone(tp);
473239676Srwatson	AJU_LOCK_DESTROY(sc);
474239676Srwatson}
475