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