コード例 #1
0
/*
 * Open the serial port
 */
static int rs_open(struct tty_struct * tty, struct file * filp)
{
    int retval;

    func_enter();

    if(!rs_initialized) {
        return -EIO;
    }

    if(MINOR(tty->device) - tty->driver.minor_start) {
        return -ENODEV;
    }

    rs_dprintk(TX3912_UART_DEBUG_OPEN, "Serial opening...\n");

    tty->driver_data = rs_port;
    rs_port->gs.tty = tty;
    rs_port->gs.count++;

    /*
     * Start up serial port
     */
    retval = gs_init_port(&rs_port->gs);
    rs_dprintk(TX3912_UART_DEBUG_OPEN, "Finished gs_init...\n");
    if(retval) {
        rs_port->gs.count--;
        return retval;
    }

    rs_port->gs.flags |= GS_ACTIVE;
    if(rs_port->gs.count == 1) {
        MOD_INC_USE_COUNT;
    }

    rs_enable_rx_interrupts(rs_port);
    rs_enable_tx_interrupts(rs_port);

    retval = gs_block_til_ready(&rs_port->gs, filp);
    if(retval) {
        MOD_DEC_USE_COUNT;
        rs_port->gs.count--;
        return retval;
    }

    if((rs_port->gs.count == 1) &&
            (rs_port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
        if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
            *tty->termios = rs_port->gs.normal_termios;
        else
            *tty->termios = rs_port->gs.callout_termios;
        rs_set_real_termios(rs_port);
    }

    rs_port->gs.session = current->session;
    rs_port->gs.pgrp = current->pgrp;
    func_exit();

    return 0;
}
コード例 #2
0
/*
 * TX interrupt handler
 */
static inline void rs_tx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
    unsigned long flags, status;

    save_and_cli(flags);

    rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "rs_tx_interrupt...");

    /* Get the interrupts */
    status = inl(TX3912_INT2_STATUS);

    if(!rs_port || !rs_port->gs.tty) {
        restore_flags(flags);
        return;
    }

    /* Clear interrupts */
    outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR);

    /* TX holding register empty - transmit a byte */
    if(status & TX3912_INT2_UARTAEMPTYINT) {
        transmit_char_pio(rs_port);
    }

    /* TX Transmit Holding Register Overrun (shouldn't happen) */
    if(status & TX3912_INT2_UARTATXOVERRUNINT) {
        printk( "rs_tx_interrupt: TX overrun\n");
    }

    restore_flags(flags);

    rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "end.\n");
}
コード例 #3
0
static int rs_init_portstructs(void)
{
	struct rs_port *port;
	int i;

	/* Debugging */
	func_enter();

	rs_ports          = ckmalloc(TX3912_UART_NPORTS * sizeof (struct rs_port));
	if (!rs_ports)
		return -ENOMEM;

	rs_termios        = ckmalloc(TX3912_UART_NPORTS * sizeof (struct termios *));
	if (!rs_termios) {
		kfree (rs_ports);
		return -ENOMEM;
	}

	rs_termios_locked = ckmalloc(TX3912_UART_NPORTS * sizeof (struct termios *));
	if (!rs_termios_locked) {
		kfree (rs_ports);
		kfree (rs_termios);
		return -ENOMEM;
	}

	/* Adjust the values in the "driver" */
	rs_driver.termios = rs_termios;
	rs_driver.termios_locked = rs_termios_locked;

	port = rs_ports;
	for (i=0; i < TX3912_UART_NPORTS;i++) {
		rs_dprintk (TX3912_UART_DEBUG_INIT, "initing port %d\n", i);
		port->gs.callout_termios = tty_std_termios;
		port->gs.normal_termios	= tty_std_termios;
		port->gs.magic = SERIAL_MAGIC;
		port->gs.close_delay = HZ/2;
		port->gs.closing_wait = 30 * HZ;
		port->gs.rd = &rs_real_driver;
#ifdef NEW_WRITE_LOCKING
		port->gs.port_write_sem = MUTEX;
#endif
#ifdef DECLARE_WAITQUEUE
		init_waitqueue_head(&port->gs.open_wait);
		init_waitqueue_head(&port->gs.close_wait);
#endif
		port->base = (i == 0) ? TX3912_UARTA_BASE : TX3912_UARTB_BASE;
		port->intshift = (i == 0) ? UARTA_SHIFT : UARTB_SHIFT;
		rs_dprintk (TX3912_UART_DEBUG_INIT, "base 0x%08lx intshift %d\n",
			    port->base, port->intshift);
		port++;
	}

	func_exit();
	return 0;
}
コード例 #4
0
static inline void rs_tx_interrupt(int irq, void *dev_id,
				  struct pt_regs * regs, int intshift)
{
	struct rs_port * port;
	unsigned long int2status;
	unsigned long flags;
	unsigned long ints;

	save_and_cli(flags);

	port = (struct rs_port *)dev_id;
	rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift);

	/* Get the interrrupts we have enabled */
	int2status = IntStatus2 & IntEnable2;

	if (!port || !port->gs.tty) {
		restore_flags(flags);
		return;
	}

	/* Get interrupts in easy to use form */
	ints = int2status >> intshift;

	/* Clear any interrupts we might be about to handle */
	IntClear2 = int2status & (
		(INTTYPE(UART_TX_INT) |
		 INTTYPE(UART_EMPTY_INT) |
		 INTTYPE(UART_TXOVERRUN_INT)) << intshift);

	/* TX holding register empty, so transmit byte (non-DMA) */
	if (ints & (INTTYPE(UART_TX_INT) | INTTYPE(UART_EMPTY_INT))) {
		transmit_char_pio(port);
	}

	/* TX Transmit Holding Register Overrun (shouldn't happen) */
	if (ints & INTTYPE(UART_TXOVERRUN_INT)) {
		printk ( "rs: TX overrun\n");
	}

	/*
	check_modem_status();
	*/

	restore_flags(flags);

	rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "end.\n");
}
コード例 #5
0
/*
 * RX interrupt handler
 */
static inline void rs_rx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
    unsigned long flags, status;

    save_and_cli(flags);

    rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "rs_rx_interrupt...");

    /* Get the interrupts */
    status = inl(TX3912_INT2_STATUS);

    /* Clear any interrupts we might be about to handle */
    outl(TX3912_INT2_UARTA_RX_BITS, TX3912_INT2_CLEAR);

    if(!rs_port || !rs_port->gs.tty) {
        restore_flags(flags);
        return;
    }

    /* RX Receiver Holding Register Overrun */
    if(status & TX3912_INT2_UARTATXOVERRUNINT) {
        rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "overrun");
        rs_port->icount.overrun++;
    }

    /* RX Frame Error */
    if(status & TX3912_INT2_UARTAFRAMEERRINT) {
        rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "frame error");
        rs_port->icount.frame++;
    }

    /* Break signal received */
    if(status & TX3912_INT2_UARTABREAKINT) {
        rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "break");
        rs_port->icount.brk++;
    }

    /* RX Parity Error */
    if(status & TX3912_INT2_UARTAPARITYINT) {
        rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "parity error");
        rs_port->icount.parity++;
    }

    /* Byte received */
    if(status & TX3912_INT2_UARTARXINT) {
        receive_char_pio(rs_port);
    }

    restore_flags(flags);

    rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "end.\n");
}
コード例 #6
0
/*
 * Transmit a character
 */
static inline void transmit_char_pio(struct rs_port *port)
{
    /* TX while bytes available */
    for (;;) {
        if (!(inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_EMPTY))
            break;
        else if (port->x_char) {
            outb(port->x_char, TX3912_UARTA_DATA);
            port->icount.tx++;
            port->x_char = 0;
        }
        else if (port->gs.xmit_cnt <= 0 || port->gs.tty->stopped ||
                 port->gs.tty->hw_stopped) {
            break;
        }
        else {
            outb(port->gs.xmit_buf[port->gs.xmit_tail++],
                 TX3912_UARTA_DATA);
            port->icount.tx++;
            port->gs.xmit_tail &= SERIAL_XMIT_SIZE-1;
            if (--port->gs.xmit_cnt <= 0) {
                break;
            }
        }
        udelay(10);
    }

    if (port->gs.xmit_cnt <= 0 || port->gs.tty->stopped ||
            port->gs.tty->hw_stopped) {
        rs_disable_tx_interrupts(port);
    }

    if (port->gs.xmit_cnt <= port->gs.wakeup_chars) {
        if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
                port->gs.tty->ldisc.write_wakeup)
            (port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
        rs_dprintk(TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
                   port->gs.wakeup_chars);
        wake_up_interruptible(&port->gs.tty->write_wait);
    }
}
コード例 #7
0
/*
 * Initialize the serial port
 */
void __init tx3912_rs_init(void)
{
    func_enter();
    rs_dprintk(TX3912_UART_DEBUG_INIT, "Initializing serial...\n");

    /* Allocate critical structures */
    if(!(rs_tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL))) {
        return;
    }
    if(!(rs_port = kmalloc(sizeof(struct rs_port), GFP_KERNEL))) {
        kfree(rs_tty);
        return;
    }
    if(!(rs_termios = kmalloc(sizeof(struct termios), GFP_KERNEL))) {
        kfree(rs_port);
        kfree(rs_tty);
        return;
    }
    if(!(rs_termios_locked = kmalloc(sizeof(struct termios), GFP_KERNEL))) {
        kfree(rs_termios);
        kfree(rs_port);
        kfree(rs_tty);
        return;
    }

    /* Zero out the structures */
    memset(rs_tty, 0, sizeof(struct tty_struct));
    memset(rs_port, 0, sizeof(struct rs_port));
    memset(rs_termios, 0, sizeof(struct termios));
    memset(rs_termios_locked, 0, sizeof(struct termios));
    memset(&rs_driver, 0, sizeof(rs_driver));
    memset(&rs_callout_driver, 0, sizeof(rs_callout_driver));

    /* Fill in hardware specific port structure */
    rs_port->gs.callout_termios = tty_std_termios;
    rs_port->gs.normal_termios	= tty_std_termios;
    rs_port->gs.magic = SERIAL_MAGIC;
    rs_port->gs.close_delay = HZ/2;
    rs_port->gs.closing_wait = 30 * HZ;
    rs_port->gs.rd = &rs_real_driver;
#ifdef NEW_WRITE_LOCKING
    rs_port->gs.port_write_sem = MUTEX;
#endif
#ifdef DECLARE_WAITQUEUE
    init_waitqueue_head(&rs_port->gs.open_wait);
    init_waitqueue_head(&rs_port->gs.close_wait);
#endif

    /* Fill in generic serial driver structures */
    rs_driver.magic = TTY_DRIVER_MAGIC;
    rs_driver.driver_name = "serial";
    rs_driver.name = "ttyS";
    rs_driver.major = TTY_MAJOR;
    rs_driver.minor_start = 64;
    rs_driver.num = 1;
    rs_driver.type = TTY_DRIVER_TYPE_SERIAL;
    rs_driver.subtype = SERIAL_TYPE_NORMAL;
    rs_driver.init_termios = tty_std_termios;
    rs_driver.init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
    rs_driver.refcount = &rs_refcount;
    rs_driver.table = rs_tty;
    rs_driver.termios = rs_termios;
    rs_driver.termios_locked = rs_termios_locked;
    rs_driver.open	= rs_open;
    rs_driver.close = gs_close;
    rs_driver.write = gs_write;
    rs_driver.put_char = gs_put_char;
    rs_driver.flush_chars = gs_flush_chars;
    rs_driver.write_room = gs_write_room;
    rs_driver.chars_in_buffer = gs_chars_in_buffer;
    rs_driver.flush_buffer = gs_flush_buffer;
    rs_driver.ioctl = rs_ioctl;
    rs_driver.throttle = rs_throttle;
    rs_driver.unthrottle = rs_unthrottle;
    rs_driver.set_termios = gs_set_termios;
    rs_driver.stop = gs_stop;
    rs_driver.start = gs_start;
    rs_driver.hangup = gs_hangup;
    rs_callout_driver = rs_driver;
    rs_callout_driver.name = "cua";
    rs_callout_driver.major = TTYAUX_MAJOR;
    rs_callout_driver.subtype = SERIAL_TYPE_CALLOUT;

    /* Register serial and callout drivers */
    if(tty_register_driver(&rs_driver)) {
        printk(KERN_ERR "Unable to register serial driver\n");
        goto error;
    }
    if(tty_register_driver(&rs_callout_driver)) {
        tty_unregister_driver(&rs_driver);
        printk(KERN_ERR "Unable to register callout driver\n");
        goto error;
    }

    /* Assign IRQs */
    if(request_irq(2, rs_tx_interrupt, SA_SHIRQ,
                   "uarta_tx", rs_port)) {
        printk(KERN_ERR "Cannot allocate IRQ for UARTA_TX.\n");
        goto error;
    }

    if(request_irq(3, rs_rx_interrupt, SA_SHIRQ,
                   "uarta_rx", rs_port)) {
        printk(KERN_ERR "Cannot allocate IRQ for UARTA_RX.\n");
        goto error;
    }

    /* Enable the serial receive interrupt */
    rs_enable_rx_interrupts(rs_port);

#ifndef CONFIG_SERIAL_TX3912_CONSOLE
    /* Write the control registers */
    outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_CTRL2);
    outl(0x00000000, TX3912_UARTA_DMA_CTRL1);
    outl(0x00000000, TX3912_UARTA_DMA_CTRL2);
    outl(inl(TX3912_UARTA_CTRL1) | TX3912_UART_CTRL1_ENUART,
         TX3912_UARTA_CTRL1);

    /* Loop until the UART is on */
    while(~inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_UARTON);
#endif

    rs_initialized = 1;
    func_exit();
    return;

error:
    kfree(rs_termios_locked);
    kfree(rs_termios);
    kfree(rs_port);
    kfree(rs_tty);
    func_exit();
}
コード例 #8
0
/*
 * ----------------------------------------------------------------------
 *
 * Here starts the interrupt handling routines.  All of the following
 * subroutines are declared as inline and are folded into
 * rs_interrupt().  They were separated out for readability's sake.
 *
 * Note: rs_interrupt() is a "fast" interrupt, which means that it
 * runs with interrupts turned off.  People who may want to modify
 * rs_interrupt() should try to keep the interrupt handler as fast as
 * possible.  After you are done making modifications, it is not a bad
 * idea to do:
 * 
 * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
 *
 * and look at the resulting assemble code in serial.s.
 *
 * 				- Ted Ts'o ([email protected]), 7-Mar-93
 * -----------------------------------------------------------------------
 */
static inline void receive_char_pio(struct rs_port *port)
{
	struct tty_struct *tty = port->gs.tty;
	unsigned char ch;
	int counter = 2048;

	/* While there are characters, get them ... */
	while (counter>0) {
		if (!(inl(port->base + TX3912_UART_CTRL1) & UART_RX_HOLD_FULL))
			break;
		ch = inb(port->base + TX3912_UART_DATA);
		if (tty->flip.count < TTY_FLIPBUF_SIZE) {
			*tty->flip.char_buf_ptr++ = ch;
			*tty->flip.flag_buf_ptr++ = 0;
			tty->flip.count++;
		}
		udelay(1); /* Allow things to happen - it take a while */
		counter--;
	}
	if (!counter)
		printk( "Ugh, looped in receive_char_pio!\n" );

	tty_flip_buffer_push(tty);

#if 0
	/* Now handle error conditions */
	if (*status & (INTTYPE(UART_RXOVERRUN_INT) |
			INTTYPE(UART_FRAMEERR_INT) |
			INTTYPE(UART_PARITYERR_INT) |
			INTTYPE(UART_BREAK_INT))) {

		/*
		 * Now check to see if character should be
		 * ignored, and mask off conditions which
		 * should be ignored.
	       	 */
		if (*status & port->ignore_status_mask) {
			goto ignore_char;
		}
		*status &= port->read_status_mask;
		
		if (*status & INTTYPE(UART_BREAK_INT)) {
			rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "handling break....");
			*tty->flip.flag_buf_ptr = TTY_BREAK;
		}
		else if (*status & INTTYPE(UART_PARITYERR_INT)) {
			*tty->flip.flag_buf_ptr = TTY_PARITY;
		}
		else if (*status & INTTYPE(UART_FRAMEERR_INT)) {
			*tty->flip.flag_buf_ptr = TTY_FRAME;
		}
		if (*status & INTTYPE(UART_RXOVERRUN_INT)) {
			/*
			 * Overrun is special, since it's
			 * reported immediately, and doesn't
			 * affect the current character
			 */
			if (tty->flip.count < TTY_FLIPBUF_SIZE) {
				tty->flip.count++;
				tty->flip.flag_buf_ptr++;
				tty->flip.char_buf_ptr++;
				*tty->flip.flag_buf_ptr = TTY_OVERRUN;
			}
		}
	}

	tty->flip.flag_buf_ptr++;
	tty->flip.char_buf_ptr++;
	tty->flip.count++;

ignore_char:
	tty_flip_buffer_push(tty);
#endif
}
コード例 #9
0
void __init tx3912_rs_init(void)
{
	int rc;


	func_enter();
	rs_dprintk (TX3912_UART_DEBUG_INIT, "Initing serial module... (rs_debug=%d)\n", rs_debug);

	rc = rs_init_portstructs ();
	rs_init_drivers ();
	if (request_irq(2, rs_tx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT,
			"serial", &rs_ports[0])) {
		printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n");
		rc = 0;
	}
	if (request_irq(3, rs_rx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT,
			"serial", &rs_ports[0])) {
		printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n");
		rc = 0;
	}

	IntEnable6 |= INT6_UARTARXINT; 
	rs_enable_rx_interrupts(&rs_ports[0]); 

#ifndef CONFIG_SERIAL_TX3912_CONSOLE
{
	unsigned int scratch = 0;

	/* Setup master clock for UART */
	scratch = inl(TX3912_CLK_CTRL_BASE);
	scratch &= ~TX3912_CLK_CTRL_SIBMCLKDIV_MASK;
	scratch |= ((0x2 << TX3912_CLK_CTRL_SIBMCLKDIV_SHIFT) &
				TX3912_CLK_CTRL_SIBMCLKDIV_MASK)
			| TX3912_CLK_CTRL_SIBMCLKDIR
			| TX3912_CLK_CTRL_ENSIBMCLK
			| TX3912_CLK_CTRL_CSERSEL;
	outl(scratch, TX3912_CLK_CTRL_BASE);

	/* Configure UARTA clock */
	scratch = inl(TX3912_CLK_CTRL_BASE);
	scratch |= ((0x3 << TX3912_CLK_CTRL_CSERDIV_SHIFT) &
				TX3912_CLK_CTRL_CSERDIV_MASK)
			| TX3912_CLK_CTRL_ENCSERCLK
			| TX3912_CLK_CTRL_ENUARTACLK;
	outl(scratch, TX3912_CLK_CTRL_BASE);
		
	/* Setup UARTA for 115200,8N1 */
	outl(0, TX3912_UARTA_BASE + TX3912_UART_CTRL1);
	outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_BASE + TX3912_UART_CTRL2);
	outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL1);
	outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL2);

	/* Enable UARTA */
	outl(TX3912_UART_CTRL1_ENUART, TX3912_UARTA_BASE + TX3912_UART_CTRL1);
	while (~inl(TX3912_UARTA_BASE + TX3912_UART_CTRL1) &
		TX3912_UART_CTRL1_UARTON);
}
#endif

	/* Note: I didn't do anything to enable the second UART */
	if (rc >= 0) 
		rs_initialized++;

	func_exit();
}
コード例 #10
0
/* ********************************************************************** *
 *                Here are the routines that actually                     *
 *               interface with the rest of the system                    *
 * ********************************************************************** */
static int rs_open  (struct tty_struct * tty, struct file * filp)
{
	struct rs_port *port;
	int retval, line;

	func_enter();

	if (!rs_initialized) {
		return -EIO;
	}

	line = MINOR(tty->device) - tty->driver.minor_start;
	rs_dprintk (TX3912_UART_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p)\n", 
	            (int) current->pid, line, tty, current->tty);

	if ((line < 0) || (line >= TX3912_UART_NPORTS))
		return -ENODEV;

	/* Pre-initialized already */
	port = & rs_ports[line];

	rs_dprintk (TX3912_UART_DEBUG_OPEN, "port = %p\n", port);

	tty->driver_data = port;
	port->gs.tty = tty;
	port->gs.count++;

	rs_dprintk (TX3912_UART_DEBUG_OPEN, "starting port\n");

	/*
	 * Start up serial port
	 */
	retval = gs_init_port(&port->gs);
	rs_dprintk (TX3912_UART_DEBUG_OPEN, "done gs_init\n");
	if (retval) {
		port->gs.count--;
		return retval;
	}

	port->gs.flags |= GS_ACTIVE;

	rs_dprintk (TX3912_UART_DEBUG_OPEN, "before inc_use_count (count=%d.\n", 
	            port->gs.count);
	if (port->gs.count == 1) {
		MOD_INC_USE_COUNT;
	}
	rs_dprintk (TX3912_UART_DEBUG_OPEN, "after inc_use_count\n");

	/* Jim: Initialize port hardware here */

	/* Enable high-priority interrupts for UARTA */
	IntEnable6 |= INT6_UARTARXINT; 
	rs_enable_rx_interrupts(&rs_ports[0]); 

	retval = gs_block_til_ready(&port->gs, filp);
	rs_dprintk (TX3912_UART_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n", 
	            retval, port->gs.count);

	if (retval) {
		MOD_DEC_USE_COUNT;
		port->gs.count--;
		return retval;
	}
	/* tty->low_latency = 1; */

	if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
			*tty->termios = port->gs.normal_termios;
		else 
			*tty->termios = port->gs.callout_termios;
		rs_set_real_termios (port);
	}

	port->gs.session = current->session;
	port->gs.pgrp = current->pgrp;
	func_exit();

	/* Jim */
/*	cli(); */

	return 0;

}
コード例 #11
0
static inline void rs_rx_interrupt(int irq, void *dev_id,
				  struct pt_regs * regs, int intshift)
{
	struct rs_port * port;
	unsigned long int2status;
	unsigned long flags;
	unsigned long ints;

	save_and_cli(flags);

	port = (struct rs_port *)dev_id;
	rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift);

	/* Get the interrrupts we have enabled */
	int2status = IntStatus2 & IntEnable2;

	/* Get interrupts in easy to use form */
	ints = int2status >> intshift;

	/* Clear any interrupts we might be about to handle */
	IntClear2 = int2status & (
		(INTTYPE(UART_RXOVERRUN_INT) |
		 INTTYPE(UART_FRAMEERR_INT) |
		 INTTYPE(UART_BREAK_INT) |
		 INTTYPE(UART_PARITYERR_INT) |
		 INTTYPE(UART_RX_INT)) << intshift);

	if (!port || !port->gs.tty) {
		restore_flags(flags);
		return;
	}

	/* RX Receiver Holding Register Overrun */
	if (ints & INTTYPE(UART_RXOVERRUN_INT)) {
		rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "overrun");
		port->icount.overrun++;
	}

	/* RX Frame Error */
	if (ints & INTTYPE(UART_FRAMEERR_INT)) {
		rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "frame error");
		port->icount.frame++;
	}

	/* Break signal received */
	if (ints & INTTYPE(UART_BREAK_INT)) {
		rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "break");
		port->icount.brk++;
      	}

	/* RX Parity Error */
	if (ints & INTTYPE(UART_PARITYERR_INT)) {
		rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "parity error");
		port->icount.parity++;
	}

	/* Receive byte (non-DMA) */
	if (ints & INTTYPE(UART_RX_INT)) {
		receive_char_pio(port);
	}

	restore_flags(flags);

	rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "end.\n");
}