|  | /* MN10300 On-chip serial port UART driver | 
|  | * | 
|  | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | 
|  | * Written by David Howells (dhowells@redhat.com) | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public Licence | 
|  | * as published by the Free Software Foundation; either version | 
|  | * 2 of the Licence, or (at your option) any later version. | 
|  | */ | 
|  |  | 
|  | static const char serial_name[] = "MN10300 Serial driver"; | 
|  | static const char serial_version[] = "mn10300_serial-1.0"; | 
|  | static const char serial_revdate[] = "2007-11-06"; | 
|  |  | 
|  | #if defined(CONFIG_MN10300_TTYSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) | 
|  | #define SUPPORT_SYSRQ | 
|  | #endif | 
|  |  | 
|  | #include <linux/module.h> | 
|  | #include <linux/serial.h> | 
|  | #include <linux/circ_buf.h> | 
|  | #include <linux/errno.h> | 
|  | #include <linux/signal.h> | 
|  | #include <linux/sched.h> | 
|  | #include <linux/timer.h> | 
|  | #include <linux/interrupt.h> | 
|  | #include <linux/tty.h> | 
|  | #include <linux/tty_flip.h> | 
|  | #include <linux/major.h> | 
|  | #include <linux/string.h> | 
|  | #include <linux/ioport.h> | 
|  | #include <linux/mm.h> | 
|  | #include <linux/slab.h> | 
|  | #include <linux/init.h> | 
|  | #include <linux/console.h> | 
|  | #include <linux/sysrq.h> | 
|  |  | 
|  | #include <asm/system.h> | 
|  | #include <asm/io.h> | 
|  | #include <asm/irq.h> | 
|  | #include <asm/bitops.h> | 
|  | #include <asm/serial-regs.h> | 
|  | #include <unit/timex.h> | 
|  | #include "mn10300-serial.h" | 
|  |  | 
|  | static inline __attribute__((format(printf, 1, 2))) | 
|  | void no_printk(const char *fmt, ...) | 
|  | { | 
|  | } | 
|  |  | 
|  | #define kenter(FMT, ...) \ | 
|  | printk(KERN_DEBUG "-->%s(" FMT ")\n", __func__, ##__VA_ARGS__) | 
|  | #define _enter(FMT, ...) \ | 
|  | no_printk(KERN_DEBUG "-->%s(" FMT ")\n", __func__, ##__VA_ARGS__) | 
|  | #define kdebug(FMT, ...) \ | 
|  | printk(KERN_DEBUG "--- " FMT "\n", ##__VA_ARGS__) | 
|  | #define _debug(FMT, ...) \ | 
|  | no_printk(KERN_DEBUG "--- " FMT "\n", ##__VA_ARGS__) | 
|  | #define kproto(FMT, ...) \ | 
|  | printk(KERN_DEBUG "### MNSERIAL " FMT " ###\n", ##__VA_ARGS__) | 
|  | #define _proto(FMT, ...) \ | 
|  | no_printk(KERN_DEBUG "### MNSERIAL " FMT " ###\n", ##__VA_ARGS__) | 
|  |  | 
|  | #define NR_UARTS 3 | 
|  |  | 
|  | #ifdef CONFIG_MN10300_TTYSM_CONSOLE | 
|  | static void mn10300_serial_console_write(struct console *co, | 
|  | const char *s, unsigned count); | 
|  | static int __init mn10300_serial_console_setup(struct console *co, | 
|  | char *options); | 
|  |  | 
|  | static struct uart_driver mn10300_serial_driver; | 
|  | static struct console mn10300_serial_console = { | 
|  | .name		= "ttySM", | 
|  | .write		= mn10300_serial_console_write, | 
|  | .device		= uart_console_device, | 
|  | .setup		= mn10300_serial_console_setup, | 
|  | .flags		= CON_PRINTBUFFER, | 
|  | .index		= -1, | 
|  | .data		= &mn10300_serial_driver, | 
|  | }; | 
|  | #endif | 
|  |  | 
|  | static struct uart_driver mn10300_serial_driver = { | 
|  | .owner		= NULL, | 
|  | .driver_name	= "mn10300-serial", | 
|  | .dev_name	= "ttySM", | 
|  | .major		= TTY_MAJOR, | 
|  | .minor		= 128, | 
|  | .nr		= NR_UARTS, | 
|  | #ifdef CONFIG_MN10300_TTYSM_CONSOLE | 
|  | .cons		= &mn10300_serial_console, | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | static unsigned int mn10300_serial_tx_empty(struct uart_port *); | 
|  | static void mn10300_serial_set_mctrl(struct uart_port *, unsigned int mctrl); | 
|  | static unsigned int mn10300_serial_get_mctrl(struct uart_port *); | 
|  | static void mn10300_serial_stop_tx(struct uart_port *); | 
|  | static void mn10300_serial_start_tx(struct uart_port *); | 
|  | static void mn10300_serial_send_xchar(struct uart_port *, char ch); | 
|  | static void mn10300_serial_stop_rx(struct uart_port *); | 
|  | static void mn10300_serial_enable_ms(struct uart_port *); | 
|  | static void mn10300_serial_break_ctl(struct uart_port *, int ctl); | 
|  | static int mn10300_serial_startup(struct uart_port *); | 
|  | static void mn10300_serial_shutdown(struct uart_port *); | 
|  | static void mn10300_serial_set_termios(struct uart_port *, | 
|  | struct ktermios *new, | 
|  | struct ktermios *old); | 
|  | static const char *mn10300_serial_type(struct uart_port *); | 
|  | static void mn10300_serial_release_port(struct uart_port *); | 
|  | static int mn10300_serial_request_port(struct uart_port *); | 
|  | static void mn10300_serial_config_port(struct uart_port *, int); | 
|  | static int mn10300_serial_verify_port(struct uart_port *, | 
|  | struct serial_struct *); | 
|  |  | 
|  | static const struct uart_ops mn10300_serial_ops = { | 
|  | .tx_empty	= mn10300_serial_tx_empty, | 
|  | .set_mctrl	= mn10300_serial_set_mctrl, | 
|  | .get_mctrl	= mn10300_serial_get_mctrl, | 
|  | .stop_tx	= mn10300_serial_stop_tx, | 
|  | .start_tx	= mn10300_serial_start_tx, | 
|  | .send_xchar	= mn10300_serial_send_xchar, | 
|  | .stop_rx	= mn10300_serial_stop_rx, | 
|  | .enable_ms	= mn10300_serial_enable_ms, | 
|  | .break_ctl	= mn10300_serial_break_ctl, | 
|  | .startup	= mn10300_serial_startup, | 
|  | .shutdown	= mn10300_serial_shutdown, | 
|  | .set_termios	= mn10300_serial_set_termios, | 
|  | .type		= mn10300_serial_type, | 
|  | .release_port	= mn10300_serial_release_port, | 
|  | .request_port	= mn10300_serial_request_port, | 
|  | .config_port	= mn10300_serial_config_port, | 
|  | .verify_port	= mn10300_serial_verify_port, | 
|  | }; | 
|  |  | 
|  | static irqreturn_t mn10300_serial_interrupt(int irq, void *dev_id); | 
|  |  | 
|  | /* | 
|  | * the first on-chip serial port: ttySM0 (aka SIF0) | 
|  | */ | 
|  | #ifdef CONFIG_MN10300_TTYSM0 | 
|  | struct mn10300_serial_port mn10300_serial_port_sif0 = { | 
|  | .uart.ops	= &mn10300_serial_ops, | 
|  | .uart.membase	= (void __iomem *) &SC0CTR, | 
|  | .uart.mapbase	= (unsigned long) &SC0CTR, | 
|  | .uart.iotype	= UPIO_MEM, | 
|  | .uart.irq	= 0, | 
|  | .uart.uartclk	= 0, /* MN10300_IOCLK, */ | 
|  | .uart.fifosize	= 1, | 
|  | .uart.flags	= UPF_BOOT_AUTOCONF, | 
|  | .uart.line	= 0, | 
|  | .uart.type	= PORT_MN10300, | 
|  | .uart.lock	= | 
|  | __SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif0.uart.lock), | 
|  | .name		= "ttySM0", | 
|  | ._iobase	= &SC0CTR, | 
|  | ._control	= &SC0CTR, | 
|  | ._status	= (volatile u8 *) &SC0STR, | 
|  | ._intr		= &SC0ICR, | 
|  | ._rxb		= &SC0RXB, | 
|  | ._txb		= &SC0TXB, | 
|  | .rx_name	= "ttySM0/Rx", | 
|  | .tx_name	= "ttySM0/Tx", | 
|  | #ifdef CONFIG_MN10300_TTYSM0_TIMER8 | 
|  | .tm_name	= "ttySM0/Timer8", | 
|  | ._tmxmd		= &TM8MD, | 
|  | ._tmxbr		= &TM8BR, | 
|  | ._tmicr		= &TM8ICR, | 
|  | .tm_irq		= TM8IRQ, | 
|  | .div_timer	= MNSCx_DIV_TIMER_16BIT, | 
|  | #else /* CONFIG_MN10300_TTYSM0_TIMER2 */ | 
|  | .tm_name	= "ttySM0/Timer2", | 
|  | ._tmxmd		= &TM2MD, | 
|  | ._tmxbr		= (volatile u16 *) &TM2BR, | 
|  | ._tmicr		= &TM2ICR, | 
|  | .tm_irq		= TM2IRQ, | 
|  | .div_timer	= MNSCx_DIV_TIMER_8BIT, | 
|  | #endif | 
|  | .rx_irq		= SC0RXIRQ, | 
|  | .tx_irq		= SC0TXIRQ, | 
|  | .rx_icr		= &GxICR(SC0RXIRQ), | 
|  | .tx_icr		= &GxICR(SC0TXIRQ), | 
|  | .clock_src	= MNSCx_CLOCK_SRC_IOCLK, | 
|  | .options	= 0, | 
|  | #ifdef CONFIG_GDBSTUB_ON_TTYSM0 | 
|  | .gdbstub	= 1, | 
|  | #endif | 
|  | }; | 
|  | #endif /* CONFIG_MN10300_TTYSM0 */ | 
|  |  | 
|  | /* | 
|  | * the second on-chip serial port: ttySM1 (aka SIF1) | 
|  | */ | 
|  | #ifdef CONFIG_MN10300_TTYSM1 | 
|  | struct mn10300_serial_port mn10300_serial_port_sif1 = { | 
|  | .uart.ops	= &mn10300_serial_ops, | 
|  | .uart.membase	= (void __iomem *) &SC1CTR, | 
|  | .uart.mapbase	= (unsigned long) &SC1CTR, | 
|  | .uart.iotype	= UPIO_MEM, | 
|  | .uart.irq	= 0, | 
|  | .uart.uartclk	= 0, /* MN10300_IOCLK, */ | 
|  | .uart.fifosize	= 1, | 
|  | .uart.flags	= UPF_BOOT_AUTOCONF, | 
|  | .uart.line	= 1, | 
|  | .uart.type	= PORT_MN10300, | 
|  | .uart.lock	= | 
|  | __SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif1.uart.lock), | 
|  | .name		= "ttySM1", | 
|  | ._iobase	= &SC1CTR, | 
|  | ._control	= &SC1CTR, | 
|  | ._status	= (volatile u8 *) &SC1STR, | 
|  | ._intr		= &SC1ICR, | 
|  | ._rxb		= &SC1RXB, | 
|  | ._txb		= &SC1TXB, | 
|  | .rx_name	= "ttySM1/Rx", | 
|  | .tx_name	= "ttySM1/Tx", | 
|  | #ifdef CONFIG_MN10300_TTYSM1_TIMER9 | 
|  | .tm_name	= "ttySM1/Timer9", | 
|  | ._tmxmd		= &TM9MD, | 
|  | ._tmxbr		= &TM9BR, | 
|  | ._tmicr		= &TM9ICR, | 
|  | .tm_irq		= TM9IRQ, | 
|  | .div_timer	= MNSCx_DIV_TIMER_16BIT, | 
|  | #else /* CONFIG_MN10300_TTYSM1_TIMER3 */ | 
|  | .tm_name	= "ttySM1/Timer3", | 
|  | ._tmxmd		= &TM3MD, | 
|  | ._tmxbr		= (volatile u16 *) &TM3BR, | 
|  | ._tmicr		= &TM3ICR, | 
|  | .tm_irq		= TM3IRQ, | 
|  | .div_timer	= MNSCx_DIV_TIMER_8BIT, | 
|  | #endif | 
|  | .rx_irq		= SC1RXIRQ, | 
|  | .tx_irq		= SC1TXIRQ, | 
|  | .rx_icr		= &GxICR(SC1RXIRQ), | 
|  | .tx_icr		= &GxICR(SC1TXIRQ), | 
|  | .clock_src	= MNSCx_CLOCK_SRC_IOCLK, | 
|  | .options	= 0, | 
|  | #ifdef CONFIG_GDBSTUB_ON_TTYSM1 | 
|  | .gdbstub	= 1, | 
|  | #endif | 
|  | }; | 
|  | #endif /* CONFIG_MN10300_TTYSM1 */ | 
|  |  | 
|  | /* | 
|  | * the third on-chip serial port: ttySM2 (aka SIF2) | 
|  | */ | 
|  | #ifdef CONFIG_MN10300_TTYSM2 | 
|  | struct mn10300_serial_port mn10300_serial_port_sif2 = { | 
|  | .uart.ops	= &mn10300_serial_ops, | 
|  | .uart.membase	= (void __iomem *) &SC2CTR, | 
|  | .uart.mapbase	= (unsigned long) &SC2CTR, | 
|  | .uart.iotype	= UPIO_MEM, | 
|  | .uart.irq	= 0, | 
|  | .uart.uartclk	= 0, /* MN10300_IOCLK, */ | 
|  | .uart.fifosize	= 1, | 
|  | .uart.flags	= UPF_BOOT_AUTOCONF, | 
|  | .uart.line	= 2, | 
|  | #ifdef CONFIG_MN10300_TTYSM2_CTS | 
|  | .uart.type	= PORT_MN10300_CTS, | 
|  | #else | 
|  | .uart.type	= PORT_MN10300, | 
|  | #endif | 
|  | .uart.lock	= | 
|  | __SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif2.uart.lock), | 
|  | .name		= "ttySM2", | 
|  | .rx_name	= "ttySM2/Rx", | 
|  | .tx_name	= "ttySM2/Tx", | 
|  | .tm_name	= "ttySM2/Timer10", | 
|  | ._iobase	= &SC2CTR, | 
|  | ._control	= &SC2CTR, | 
|  | ._status	= &SC2STR, | 
|  | ._intr		= &SC2ICR, | 
|  | ._rxb		= &SC2RXB, | 
|  | ._txb		= &SC2TXB, | 
|  | ._tmxmd		= &TM10MD, | 
|  | ._tmxbr		= &TM10BR, | 
|  | ._tmicr		= &TM10ICR, | 
|  | .tm_irq		= TM10IRQ, | 
|  | .div_timer	= MNSCx_DIV_TIMER_16BIT, | 
|  | .rx_irq		= SC2RXIRQ, | 
|  | .tx_irq		= SC2TXIRQ, | 
|  | .rx_icr		= &GxICR(SC2RXIRQ), | 
|  | .tx_icr		= &GxICR(SC2TXIRQ), | 
|  | .clock_src	= MNSCx_CLOCK_SRC_IOCLK, | 
|  | #ifdef CONFIG_MN10300_TTYSM2_CTS | 
|  | .options	= MNSCx_OPT_CTS, | 
|  | #else | 
|  | .options	= 0, | 
|  | #endif | 
|  | #ifdef CONFIG_GDBSTUB_ON_TTYSM2 | 
|  | .gdbstub	= 1, | 
|  | #endif | 
|  | }; | 
|  | #endif /* CONFIG_MN10300_TTYSM2 */ | 
|  |  | 
|  |  | 
|  | /* | 
|  | * list of available serial ports | 
|  | */ | 
|  | struct mn10300_serial_port *mn10300_serial_ports[NR_UARTS + 1] = { | 
|  | #ifdef CONFIG_MN10300_TTYSM0 | 
|  | [0]	= &mn10300_serial_port_sif0, | 
|  | #endif | 
|  | #ifdef CONFIG_MN10300_TTYSM1 | 
|  | [1]	= &mn10300_serial_port_sif1, | 
|  | #endif | 
|  | #ifdef CONFIG_MN10300_TTYSM2 | 
|  | [2]	= &mn10300_serial_port_sif2, | 
|  | #endif | 
|  | [NR_UARTS] = NULL, | 
|  | }; | 
|  |  | 
|  |  | 
|  | /* | 
|  | * we abuse the serial ports' baud timers' interrupt lines to get the ability | 
|  | * to deliver interrupts to userspace as we use the ports' interrupt lines to | 
|  | * do virtual DMA on account of the ports having no hardware FIFOs | 
|  | * | 
|  | * we can generate an interrupt manually in the assembly stubs by writing to | 
|  | * the enable and detect bits in the interrupt control register, so all we need | 
|  | * to do here is disable the interrupt line | 
|  | * | 
|  | * note that we can't just leave the line enabled as the baud rate timer *also* | 
|  | * generates interrupts | 
|  | */ | 
|  | static void mn10300_serial_mask_ack(unsigned int irq) | 
|  | { | 
|  | u16 tmp; | 
|  | GxICR(irq) = GxICR_LEVEL_6; | 
|  | tmp = GxICR(irq); /* flush write buffer */ | 
|  | } | 
|  |  | 
|  | static void mn10300_serial_nop(unsigned int irq) | 
|  | { | 
|  | } | 
|  |  | 
|  | static struct irq_chip mn10300_serial_pic = { | 
|  | .name		= "mnserial", | 
|  | .ack		= mn10300_serial_mask_ack, | 
|  | .mask		= mn10300_serial_mask_ack, | 
|  | .mask_ack	= mn10300_serial_mask_ack, | 
|  | .unmask		= mn10300_serial_nop, | 
|  | .end		= mn10300_serial_nop, | 
|  | }; | 
|  |  | 
|  |  | 
|  | /* | 
|  | * serial virtual DMA interrupt jump table | 
|  | */ | 
|  | struct mn10300_serial_int mn10300_serial_int_tbl[NR_IRQS]; | 
|  |  | 
|  | static void mn10300_serial_dis_tx_intr(struct mn10300_serial_port *port) | 
|  | { | 
|  | u16 x; | 
|  | *port->tx_icr = GxICR_LEVEL_1 | GxICR_DETECT; | 
|  | x = *port->tx_icr; | 
|  | } | 
|  |  | 
|  | static void mn10300_serial_en_tx_intr(struct mn10300_serial_port *port) | 
|  | { | 
|  | u16 x; | 
|  | *port->tx_icr = GxICR_LEVEL_1 | GxICR_ENABLE; | 
|  | x = *port->tx_icr; | 
|  | } | 
|  |  | 
|  | static void mn10300_serial_dis_rx_intr(struct mn10300_serial_port *port) | 
|  | { | 
|  | u16 x; | 
|  | *port->rx_icr = GxICR_LEVEL_1 | GxICR_DETECT; | 
|  | x = *port->rx_icr; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * multi-bit equivalent of test_and_clear_bit() | 
|  | */ | 
|  | static int mask_test_and_clear(volatile u8 *ptr, u8 mask) | 
|  | { | 
|  | u32 epsw; | 
|  | asm volatile("	bclr	%1,(%2)		\n" | 
|  | "	mov	epsw,%0		\n" | 
|  | : "=d"(epsw) : "d"(mask), "a"(ptr) | 
|  | : "cc", "memory"); | 
|  | return !(epsw & EPSW_FLAG_Z); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * receive chars from the ring buffer for this serial port | 
|  | * - must do break detection here (not done in the UART) | 
|  | */ | 
|  | static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port) | 
|  | { | 
|  | struct uart_icount *icount = &port->uart.icount; | 
|  | struct tty_struct *tty = port->uart.state->port.tty; | 
|  | unsigned ix; | 
|  | int count; | 
|  | u8 st, ch, push, status, overrun; | 
|  |  | 
|  | _enter("%s", port->name); | 
|  |  | 
|  | push = 0; | 
|  |  | 
|  | count = CIRC_CNT(port->rx_inp, port->rx_outp, MNSC_BUFFER_SIZE); | 
|  | count = tty_buffer_request_room(tty, count); | 
|  | if (count == 0) { | 
|  | if (!tty->low_latency) | 
|  | tty_flip_buffer_push(tty); | 
|  | return; | 
|  | } | 
|  |  | 
|  | try_again: | 
|  | /* pull chars out of the hat */ | 
|  | ix = port->rx_outp; | 
|  | if (ix == port->rx_inp) { | 
|  | if (push && !tty->low_latency) | 
|  | tty_flip_buffer_push(tty); | 
|  | return; | 
|  | } | 
|  |  | 
|  | ch = port->rx_buffer[ix++]; | 
|  | st = port->rx_buffer[ix++]; | 
|  | smp_rmb(); | 
|  | port->rx_outp = ix & (MNSC_BUFFER_SIZE - 1); | 
|  | port->uart.icount.rx++; | 
|  |  | 
|  | st &= SC01STR_FEF | SC01STR_PEF | SC01STR_OEF; | 
|  | status = 0; | 
|  | overrun = 0; | 
|  |  | 
|  | /* the UART doesn't detect BREAK, so we have to do that ourselves | 
|  | * - it starts as a framing error on a NUL character | 
|  | * - then we count another two NUL characters before issuing TTY_BREAK | 
|  | * - then we end on a normal char or one that has all the bottom bits | 
|  | *   zero and the top bits set | 
|  | */ | 
|  | switch (port->rx_brk) { | 
|  | case 0: | 
|  | /* not breaking at the moment */ | 
|  | break; | 
|  |  | 
|  | case 1: | 
|  | if (st & SC01STR_FEF && ch == 0) { | 
|  | port->rx_brk = 2; | 
|  | goto try_again; | 
|  | } | 
|  | goto not_break; | 
|  |  | 
|  | case 2: | 
|  | if (st & SC01STR_FEF && ch == 0) { | 
|  | port->rx_brk = 3; | 
|  | _proto("Rx Break Detected"); | 
|  | icount->brk++; | 
|  | if (uart_handle_break(&port->uart)) | 
|  | goto ignore_char; | 
|  | status |= 1 << TTY_BREAK; | 
|  | goto insert; | 
|  | } | 
|  | goto not_break; | 
|  |  | 
|  | default: | 
|  | if (st & (SC01STR_FEF | SC01STR_PEF | SC01STR_OEF)) | 
|  | goto try_again; /* still breaking */ | 
|  |  | 
|  | port->rx_brk = 0; /* end of the break */ | 
|  |  | 
|  | switch (ch) { | 
|  | case 0xFF: | 
|  | case 0xFE: | 
|  | case 0xFC: | 
|  | case 0xF8: | 
|  | case 0xF0: | 
|  | case 0xE0: | 
|  | case 0xC0: | 
|  | case 0x80: | 
|  | case 0x00: | 
|  | /* discard char at probable break end */ | 
|  | goto try_again; | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | process_errors: | 
|  | /* handle framing error */ | 
|  | if (st & SC01STR_FEF) { | 
|  | if (ch == 0) { | 
|  | /* framing error with NUL char is probably a BREAK */ | 
|  | port->rx_brk = 1; | 
|  | goto try_again; | 
|  | } | 
|  |  | 
|  | _proto("Rx Framing Error"); | 
|  | icount->frame++; | 
|  | status |= 1 << TTY_FRAME; | 
|  | } | 
|  |  | 
|  | /* handle parity error */ | 
|  | if (st & SC01STR_PEF) { | 
|  | _proto("Rx Parity Error"); | 
|  | icount->parity++; | 
|  | status = TTY_PARITY; | 
|  | } | 
|  |  | 
|  | /* handle normal char */ | 
|  | if (status == 0) { | 
|  | if (uart_handle_sysrq_char(&port->uart, ch)) | 
|  | goto ignore_char; | 
|  | status = (1 << TTY_NORMAL); | 
|  | } | 
|  |  | 
|  | /* handle overrun error */ | 
|  | if (st & SC01STR_OEF) { | 
|  | if (port->rx_brk) | 
|  | goto try_again; | 
|  |  | 
|  | _proto("Rx Overrun Error"); | 
|  | icount->overrun++; | 
|  | overrun = 1; | 
|  | } | 
|  |  | 
|  | insert: | 
|  | status &= port->uart.read_status_mask; | 
|  |  | 
|  | if (!overrun && !(status & port->uart.ignore_status_mask)) { | 
|  | int flag; | 
|  |  | 
|  | if (status & (1 << TTY_BREAK)) | 
|  | flag = TTY_BREAK; | 
|  | else if (status & (1 << TTY_PARITY)) | 
|  | flag = TTY_PARITY; | 
|  | else if (status & (1 << TTY_FRAME)) | 
|  | flag = TTY_FRAME; | 
|  | else | 
|  | flag = TTY_NORMAL; | 
|  |  | 
|  | tty_insert_flip_char(tty, ch, flag); | 
|  | } | 
|  |  | 
|  | /* overrun is special, since it's reported immediately, and doesn't | 
|  | * affect the current character | 
|  | */ | 
|  | if (overrun) | 
|  | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | 
|  |  | 
|  | count--; | 
|  | if (count <= 0) { | 
|  | if (!tty->low_latency) | 
|  | tty_flip_buffer_push(tty); | 
|  | return; | 
|  | } | 
|  |  | 
|  | ignore_char: | 
|  | push = 1; | 
|  | goto try_again; | 
|  |  | 
|  | not_break: | 
|  | port->rx_brk = 0; | 
|  | goto process_errors; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * handle an interrupt from the serial transmission "virtual DMA" driver | 
|  | * - note: the interrupt routine will disable its own interrupts when the Tx | 
|  | *   buffer is empty | 
|  | */ | 
|  | static void mn10300_serial_transmit_interrupt(struct mn10300_serial_port *port) | 
|  | { | 
|  | _enter("%s", port->name); | 
|  |  | 
|  | if (!port->uart.state || !port->uart.state->port.tty) { | 
|  | mn10300_serial_dis_tx_intr(port); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (uart_tx_stopped(&port->uart) || | 
|  | uart_circ_empty(&port->uart.state->xmit)) | 
|  | mn10300_serial_dis_tx_intr(port); | 
|  |  | 
|  | if (uart_circ_chars_pending(&port->uart.state->xmit) < WAKEUP_CHARS) | 
|  | uart_write_wakeup(&port->uart); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * deal with a change in the status of the CTS line | 
|  | */ | 
|  | static void mn10300_serial_cts_changed(struct mn10300_serial_port *port, u8 st) | 
|  | { | 
|  | u16 ctr; | 
|  |  | 
|  | port->tx_cts = st; | 
|  | port->uart.icount.cts++; | 
|  |  | 
|  | /* flip the CTS state selector flag to interrupt when it changes | 
|  | * back */ | 
|  | ctr = *port->_control; | 
|  | ctr ^= SC2CTR_TWS; | 
|  | *port->_control = ctr; | 
|  |  | 
|  | uart_handle_cts_change(&port->uart, st & SC2STR_CTS); | 
|  | wake_up_interruptible(&port->uart.state->port.delta_msr_wait); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * handle a virtual interrupt generated by the lower level "virtual DMA" | 
|  | * routines (irq is the baud timer interrupt) | 
|  | */ | 
|  | static irqreturn_t mn10300_serial_interrupt(int irq, void *dev_id) | 
|  | { | 
|  | struct mn10300_serial_port *port = dev_id; | 
|  | u8 st; | 
|  |  | 
|  | spin_lock(&port->uart.lock); | 
|  |  | 
|  | if (port->intr_flags) { | 
|  | _debug("INT %s: %x", port->name, port->intr_flags); | 
|  |  | 
|  | if (mask_test_and_clear(&port->intr_flags, MNSCx_RX_AVAIL)) | 
|  | mn10300_serial_receive_interrupt(port); | 
|  |  | 
|  | if (mask_test_and_clear(&port->intr_flags, | 
|  | MNSCx_TX_SPACE | MNSCx_TX_EMPTY)) | 
|  | mn10300_serial_transmit_interrupt(port); | 
|  | } | 
|  |  | 
|  | /* the only modem control line amongst the whole lot is CTS on | 
|  | * serial port 2 */ | 
|  | if (port->type == PORT_MN10300_CTS) { | 
|  | st = *port->_status; | 
|  | if ((port->tx_cts ^ st) & SC2STR_CTS) | 
|  | mn10300_serial_cts_changed(port, st); | 
|  | } | 
|  |  | 
|  | spin_unlock(&port->uart.lock); | 
|  |  | 
|  | return IRQ_HANDLED; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * return indication of whether the hardware transmit buffer is empty | 
|  | */ | 
|  | static unsigned int mn10300_serial_tx_empty(struct uart_port *_port) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | _enter("%s", port->name); | 
|  |  | 
|  | return (*port->_status & (SC01STR_TXF | SC01STR_TBF)) ? | 
|  | 0 : TIOCSER_TEMT; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * set the modem control lines (we don't have any) | 
|  | */ | 
|  | static void mn10300_serial_set_mctrl(struct uart_port *_port, | 
|  | unsigned int mctrl) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | _enter("%s,%x", port->name, mctrl); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * get the modem control line statuses | 
|  | */ | 
|  | static unsigned int mn10300_serial_get_mctrl(struct uart_port *_port) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | _enter("%s", port->name); | 
|  |  | 
|  | if (port->type == PORT_MN10300_CTS && !(*port->_status & SC2STR_CTS)) | 
|  | return TIOCM_CAR | TIOCM_DSR; | 
|  |  | 
|  | return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * stop transmitting characters | 
|  | */ | 
|  | static void mn10300_serial_stop_tx(struct uart_port *_port) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | _enter("%s", port->name); | 
|  |  | 
|  | /* disable the virtual DMA */ | 
|  | mn10300_serial_dis_tx_intr(port); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * start transmitting characters | 
|  | * - jump-start transmission if it has stalled | 
|  | *   - enable the serial Tx interrupt (used by the virtual DMA controller) | 
|  | *   - force an interrupt to happen if necessary | 
|  | */ | 
|  | static void mn10300_serial_start_tx(struct uart_port *_port) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | u16 x; | 
|  |  | 
|  | _enter("%s{%lu}", | 
|  | port->name, | 
|  | CIRC_CNT(&port->uart.state->xmit.head, | 
|  | &port->uart.state->xmit.tail, | 
|  | UART_XMIT_SIZE)); | 
|  |  | 
|  | /* kick the virtual DMA controller */ | 
|  | x = *port->tx_icr; | 
|  | x |= GxICR_ENABLE; | 
|  |  | 
|  | if (*port->_status & SC01STR_TBF) | 
|  | x &= ~(GxICR_REQUEST | GxICR_DETECT); | 
|  | else | 
|  | x |= GxICR_REQUEST | GxICR_DETECT; | 
|  |  | 
|  | _debug("CTR=%04hx ICR=%02hx STR=%04x TMD=%02hx TBR=%04hx ICR=%04hx", | 
|  | *port->_control, *port->_intr, *port->_status, | 
|  | *port->_tmxmd, *port->_tmxbr, *port->tx_icr); | 
|  |  | 
|  | *port->tx_icr = x; | 
|  | x = *port->tx_icr; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * transmit a high-priority XON/XOFF character | 
|  | */ | 
|  | static void mn10300_serial_send_xchar(struct uart_port *_port, char ch) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | _enter("%s,%02x", port->name, ch); | 
|  |  | 
|  | if (likely(port->gdbstub)) { | 
|  | port->tx_xchar = ch; | 
|  | if (ch) | 
|  | mn10300_serial_en_tx_intr(port); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * stop receiving characters | 
|  | * - called whilst the port is being closed | 
|  | */ | 
|  | static void mn10300_serial_stop_rx(struct uart_port *_port) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | u16 ctr; | 
|  |  | 
|  | _enter("%s", port->name); | 
|  |  | 
|  | ctr = *port->_control; | 
|  | ctr &= ~SC01CTR_RXE; | 
|  | *port->_control = ctr; | 
|  |  | 
|  | mn10300_serial_dis_rx_intr(port); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * enable modem status interrupts | 
|  | */ | 
|  | static void mn10300_serial_enable_ms(struct uart_port *_port) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | u16 ctr, cts; | 
|  |  | 
|  | _enter("%s", port->name); | 
|  |  | 
|  | if (port->type == PORT_MN10300_CTS) { | 
|  | /* want to interrupt when CTS goes low if CTS is now high and | 
|  | * vice versa | 
|  | */ | 
|  | port->tx_cts = *port->_status; | 
|  |  | 
|  | cts = (port->tx_cts & SC2STR_CTS) ? | 
|  | SC2CTR_TWE : SC2CTR_TWE | SC2CTR_TWS; | 
|  |  | 
|  | ctr = *port->_control; | 
|  | ctr &= ~SC2CTR_TWS; | 
|  | ctr |= cts; | 
|  | *port->_control = ctr; | 
|  |  | 
|  | mn10300_serial_en_tx_intr(port); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * transmit or cease transmitting a break signal | 
|  | */ | 
|  | static void mn10300_serial_break_ctl(struct uart_port *_port, int ctl) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | _enter("%s,%d", port->name, ctl); | 
|  |  | 
|  | if (ctl) { | 
|  | /* tell the virtual DMA handler to assert BREAK */ | 
|  | port->tx_break = 1; | 
|  | mn10300_serial_en_tx_intr(port); | 
|  | } else { | 
|  | port->tx_break = 0; | 
|  | *port->_control &= ~SC01CTR_BKE; | 
|  | mn10300_serial_en_tx_intr(port); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * grab the interrupts and enable the port for reception | 
|  | */ | 
|  | static int mn10300_serial_startup(struct uart_port *_port) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  | struct mn10300_serial_int *pint; | 
|  |  | 
|  | _enter("%s{%d}", port->name, port->gdbstub); | 
|  |  | 
|  | if (unlikely(port->gdbstub)) | 
|  | return -EBUSY; | 
|  |  | 
|  | /* allocate an Rx buffer for the virtual DMA handler */ | 
|  | port->rx_buffer = kmalloc(MNSC_BUFFER_SIZE, GFP_KERNEL); | 
|  | if (!port->rx_buffer) | 
|  | return -ENOMEM; | 
|  |  | 
|  | port->rx_inp = port->rx_outp = 0; | 
|  |  | 
|  | /* finally, enable the device */ | 
|  | *port->_intr = SC01ICR_TI; | 
|  | *port->_control |= SC01CTR_TXE | SC01CTR_RXE; | 
|  |  | 
|  | pint = &mn10300_serial_int_tbl[port->rx_irq]; | 
|  | pint->port = port; | 
|  | pint->vdma = mn10300_serial_vdma_rx_handler; | 
|  | pint = &mn10300_serial_int_tbl[port->tx_irq]; | 
|  | pint->port = port; | 
|  | pint->vdma = mn10300_serial_vdma_tx_handler; | 
|  |  | 
|  | set_intr_level(port->rx_irq, GxICR_LEVEL_1); | 
|  | set_intr_level(port->tx_irq, GxICR_LEVEL_1); | 
|  | set_irq_chip(port->tm_irq, &mn10300_serial_pic); | 
|  |  | 
|  | if (request_irq(port->rx_irq, mn10300_serial_interrupt, | 
|  | IRQF_DISABLED, port->rx_name, port) < 0) | 
|  | goto error; | 
|  |  | 
|  | if (request_irq(port->tx_irq, mn10300_serial_interrupt, | 
|  | IRQF_DISABLED, port->tx_name, port) < 0) | 
|  | goto error2; | 
|  |  | 
|  | if (request_irq(port->tm_irq, mn10300_serial_interrupt, | 
|  | IRQF_DISABLED, port->tm_name, port) < 0) | 
|  | goto error3; | 
|  | mn10300_serial_mask_ack(port->tm_irq); | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | error3: | 
|  | free_irq(port->tx_irq, port); | 
|  | error2: | 
|  | free_irq(port->rx_irq, port); | 
|  | error: | 
|  | kfree(port->rx_buffer); | 
|  | port->rx_buffer = NULL; | 
|  | return -EBUSY; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * shutdown the port and release interrupts | 
|  | */ | 
|  | static void mn10300_serial_shutdown(struct uart_port *_port) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | _enter("%s", port->name); | 
|  |  | 
|  | /* disable the serial port and its baud rate timer */ | 
|  | port->tx_break = 0; | 
|  | *port->_control &= ~(SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE); | 
|  | *port->_tmxmd = 0; | 
|  |  | 
|  | if (port->rx_buffer) { | 
|  | void *buf = port->rx_buffer; | 
|  | port->rx_buffer = NULL; | 
|  | kfree(buf); | 
|  | } | 
|  |  | 
|  | /* disable all intrs */ | 
|  | free_irq(port->tm_irq, port); | 
|  | free_irq(port->rx_irq, port); | 
|  | free_irq(port->tx_irq, port); | 
|  |  | 
|  | *port->rx_icr = GxICR_LEVEL_1; | 
|  | *port->tx_icr = GxICR_LEVEL_1; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * this routine is called to set the UART divisor registers to match the | 
|  | * specified baud rate for a serial port. | 
|  | */ | 
|  | static void mn10300_serial_change_speed(struct mn10300_serial_port *port, | 
|  | struct ktermios *new, | 
|  | struct ktermios *old) | 
|  | { | 
|  | unsigned long flags; | 
|  | unsigned long ioclk = port->ioclk; | 
|  | unsigned cflag; | 
|  | int baud, bits, xdiv, tmp; | 
|  | u16 tmxbr, scxctr; | 
|  | u8 tmxmd, battempt; | 
|  | u8 div_timer = port->div_timer; | 
|  |  | 
|  | _enter("%s{%lu}", port->name, ioclk); | 
|  |  | 
|  | /* byte size and parity */ | 
|  | cflag = new->c_cflag; | 
|  | switch (cflag & CSIZE) { | 
|  | case CS7: scxctr = SC01CTR_CLN_7BIT; bits = 9;  break; | 
|  | case CS8: scxctr = SC01CTR_CLN_8BIT; bits = 10; break; | 
|  | default:  scxctr = SC01CTR_CLN_8BIT; bits = 10; break; | 
|  | } | 
|  |  | 
|  | if (cflag & CSTOPB) { | 
|  | scxctr |= SC01CTR_STB_2BIT; | 
|  | bits++; | 
|  | } | 
|  |  | 
|  | if (cflag & PARENB) { | 
|  | bits++; | 
|  | if (cflag & PARODD) | 
|  | scxctr |= SC01CTR_PB_ODD; | 
|  | #ifdef CMSPAR | 
|  | else if (cflag & CMSPAR) | 
|  | scxctr |= SC01CTR_PB_FIXED0; | 
|  | #endif | 
|  | else | 
|  | scxctr |= SC01CTR_PB_EVEN; | 
|  | } | 
|  |  | 
|  | /* Determine divisor based on baud rate */ | 
|  | battempt = 0; | 
|  |  | 
|  | if (div_timer == MNSCx_DIV_TIMER_16BIT) | 
|  | scxctr |= SC0CTR_CK_TM8UFLOW_8; /* ( == SC1CTR_CK_TM9UFLOW_8 | 
|  | *   == SC2CTR_CK_TM10UFLOW) */ | 
|  | else if (div_timer == MNSCx_DIV_TIMER_8BIT) | 
|  | scxctr |= SC0CTR_CK_TM2UFLOW_8; | 
|  |  | 
|  | try_alternative: | 
|  | baud = uart_get_baud_rate(&port->uart, new, old, 0, | 
|  | port->ioclk / 8); | 
|  |  | 
|  | _debug("ALT %d [baud %d]", battempt, baud); | 
|  |  | 
|  | if (!baud) | 
|  | baud = 9600;	/* B0 transition handled in rs_set_termios */ | 
|  | xdiv = 1; | 
|  | if (baud == 134) { | 
|  | baud = 269;	/* 134 is really 134.5 */ | 
|  | xdiv = 2; | 
|  | } | 
|  |  | 
|  | if (baud == 38400 && | 
|  | (port->uart.flags & UPF_SPD_MASK) == UPF_SPD_CUST | 
|  | ) { | 
|  | _debug("CUSTOM %u", port->uart.custom_divisor); | 
|  |  | 
|  | if (div_timer == MNSCx_DIV_TIMER_16BIT) { | 
|  | if (port->uart.custom_divisor <= 65535) { | 
|  | tmxmd = TM8MD_SRC_IOCLK; | 
|  | tmxbr = port->uart.custom_divisor; | 
|  | port->uart.uartclk = ioclk; | 
|  | goto timer_okay; | 
|  | } | 
|  | if (port->uart.custom_divisor / 8 <= 65535) { | 
|  | tmxmd = TM8MD_SRC_IOCLK_8; | 
|  | tmxbr = port->uart.custom_divisor / 8; | 
|  | port->uart.custom_divisor = tmxbr * 8; | 
|  | port->uart.uartclk = ioclk / 8; | 
|  | goto timer_okay; | 
|  | } | 
|  | if (port->uart.custom_divisor / 32 <= 65535) { | 
|  | tmxmd = TM8MD_SRC_IOCLK_32; | 
|  | tmxbr = port->uart.custom_divisor / 32; | 
|  | port->uart.custom_divisor = tmxbr * 32; | 
|  | port->uart.uartclk = ioclk / 32; | 
|  | goto timer_okay; | 
|  | } | 
|  |  | 
|  | } else if (div_timer == MNSCx_DIV_TIMER_8BIT) { | 
|  | if (port->uart.custom_divisor <= 255) { | 
|  | tmxmd = TM2MD_SRC_IOCLK; | 
|  | tmxbr = port->uart.custom_divisor; | 
|  | port->uart.uartclk = ioclk; | 
|  | goto timer_okay; | 
|  | } | 
|  | if (port->uart.custom_divisor / 8 <= 255) { | 
|  | tmxmd = TM2MD_SRC_IOCLK_8; | 
|  | tmxbr = port->uart.custom_divisor / 8; | 
|  | port->uart.custom_divisor = tmxbr * 8; | 
|  | port->uart.uartclk = ioclk / 8; | 
|  | goto timer_okay; | 
|  | } | 
|  | if (port->uart.custom_divisor / 32 <= 255) { | 
|  | tmxmd = TM2MD_SRC_IOCLK_32; | 
|  | tmxbr = port->uart.custom_divisor / 32; | 
|  | port->uart.custom_divisor = tmxbr * 32; | 
|  | port->uart.uartclk = ioclk / 32; | 
|  | goto timer_okay; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | switch (div_timer) { | 
|  | case MNSCx_DIV_TIMER_16BIT: | 
|  | port->uart.uartclk = ioclk; | 
|  | tmxmd = TM8MD_SRC_IOCLK; | 
|  | tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1; | 
|  | if (tmp > 0 && tmp <= 65535) | 
|  | goto timer_okay; | 
|  |  | 
|  | port->uart.uartclk = ioclk / 8; | 
|  | tmxmd = TM8MD_SRC_IOCLK_8; | 
|  | tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1; | 
|  | if (tmp > 0 && tmp <= 65535) | 
|  | goto timer_okay; | 
|  |  | 
|  | port->uart.uartclk = ioclk / 32; | 
|  | tmxmd = TM8MD_SRC_IOCLK_32; | 
|  | tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1; | 
|  | if (tmp > 0 && tmp <= 65535) | 
|  | goto timer_okay; | 
|  | break; | 
|  |  | 
|  | case MNSCx_DIV_TIMER_8BIT: | 
|  | port->uart.uartclk = ioclk; | 
|  | tmxmd = TM2MD_SRC_IOCLK; | 
|  | tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1; | 
|  | if (tmp > 0 && tmp <= 255) | 
|  | goto timer_okay; | 
|  |  | 
|  | port->uart.uartclk = ioclk / 8; | 
|  | tmxmd = TM2MD_SRC_IOCLK_8; | 
|  | tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1; | 
|  | if (tmp > 0 && tmp <= 255) | 
|  | goto timer_okay; | 
|  |  | 
|  | port->uart.uartclk = ioclk / 32; | 
|  | tmxmd = TM2MD_SRC_IOCLK_32; | 
|  | tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1; | 
|  | if (tmp > 0 && tmp <= 255) | 
|  | goto timer_okay; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | BUG(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* refuse to change to a baud rate we can't support */ | 
|  | _debug("CAN'T SUPPORT"); | 
|  |  | 
|  | switch (battempt) { | 
|  | case 0: | 
|  | if (old) { | 
|  | new->c_cflag &= ~CBAUD; | 
|  | new->c_cflag |= (old->c_cflag & CBAUD); | 
|  | battempt = 1; | 
|  | goto try_alternative; | 
|  | } | 
|  |  | 
|  | case 1: | 
|  | /* as a last resort, if the quotient is zero, default to 9600 | 
|  | * bps */ | 
|  | new->c_cflag &= ~CBAUD; | 
|  | new->c_cflag |= B9600; | 
|  | battempt = 2; | 
|  | goto try_alternative; | 
|  |  | 
|  | default: | 
|  | /* hmmm... can't seem to support 9600 either | 
|  | * - we could try iterating through the speeds we know about to | 
|  | *   find the lowest | 
|  | */ | 
|  | new->c_cflag &= ~CBAUD; | 
|  | new->c_cflag |= B0; | 
|  |  | 
|  | if (div_timer == MNSCx_DIV_TIMER_16BIT) | 
|  | tmxmd = TM8MD_SRC_IOCLK_32; | 
|  | else if (div_timer == MNSCx_DIV_TIMER_8BIT) | 
|  | tmxmd = TM2MD_SRC_IOCLK_32; | 
|  | tmxbr = 1; | 
|  |  | 
|  | port->uart.uartclk = ioclk / 32; | 
|  | break; | 
|  | } | 
|  | timer_okay: | 
|  |  | 
|  | _debug("UARTCLK: %u / %hu", port->uart.uartclk, tmxbr); | 
|  |  | 
|  | /* make the changes */ | 
|  | spin_lock_irqsave(&port->uart.lock, flags); | 
|  |  | 
|  | uart_update_timeout(&port->uart, new->c_cflag, baud); | 
|  |  | 
|  | /* set the timer to produce the required baud rate */ | 
|  | switch (div_timer) { | 
|  | case MNSCx_DIV_TIMER_16BIT: | 
|  | *port->_tmxmd = 0; | 
|  | *port->_tmxbr = tmxbr; | 
|  | *port->_tmxmd = TM8MD_INIT_COUNTER; | 
|  | *port->_tmxmd = tmxmd | TM8MD_COUNT_ENABLE; | 
|  | break; | 
|  |  | 
|  | case MNSCx_DIV_TIMER_8BIT: | 
|  | *port->_tmxmd = 0; | 
|  | *(volatile u8 *) port->_tmxbr = (u8) tmxbr; | 
|  | *port->_tmxmd = TM2MD_INIT_COUNTER; | 
|  | *port->_tmxmd = tmxmd | TM2MD_COUNT_ENABLE; | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* CTS flow control flag and modem status interrupts */ | 
|  | scxctr &= ~(SC2CTR_TWE | SC2CTR_TWS); | 
|  |  | 
|  | if (port->type == PORT_MN10300_CTS && cflag & CRTSCTS) { | 
|  | /* want to interrupt when CTS goes low if CTS is now | 
|  | * high and vice versa | 
|  | */ | 
|  | port->tx_cts = *port->_status; | 
|  |  | 
|  | if (port->tx_cts & SC2STR_CTS) | 
|  | scxctr |= SC2CTR_TWE; | 
|  | else | 
|  | scxctr |= SC2CTR_TWE | SC2CTR_TWS; | 
|  | } | 
|  |  | 
|  | /* set up parity check flag */ | 
|  | port->uart.read_status_mask = (1 << TTY_NORMAL) | (1 << TTY_OVERRUN); | 
|  | if (new->c_iflag & INPCK) | 
|  | port->uart.read_status_mask |= | 
|  | (1 << TTY_PARITY) | (1 << TTY_FRAME); | 
|  | if (new->c_iflag & (BRKINT | PARMRK)) | 
|  | port->uart.read_status_mask |= (1 << TTY_BREAK); | 
|  |  | 
|  | /* characters to ignore */ | 
|  | port->uart.ignore_status_mask = 0; | 
|  | if (new->c_iflag & IGNPAR) | 
|  | port->uart.ignore_status_mask |= | 
|  | (1 << TTY_PARITY) | (1 << TTY_FRAME); | 
|  | if (new->c_iflag & IGNBRK) { | 
|  | port->uart.ignore_status_mask |= (1 << TTY_BREAK); | 
|  | /* | 
|  | * If we're ignoring parity and break indicators, | 
|  | * ignore overruns to (for real raw support). | 
|  | */ | 
|  | if (new->c_iflag & IGNPAR) | 
|  | port->uart.ignore_status_mask |= (1 << TTY_OVERRUN); | 
|  | } | 
|  |  | 
|  | /* Ignore all characters if CREAD is not set */ | 
|  | if ((new->c_cflag & CREAD) == 0) | 
|  | port->uart.ignore_status_mask |= (1 << TTY_NORMAL); | 
|  |  | 
|  | scxctr |= *port->_control & (SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE); | 
|  | *port->_control = scxctr; | 
|  |  | 
|  | spin_unlock_irqrestore(&port->uart.lock, flags); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * set the terminal I/O parameters | 
|  | */ | 
|  | static void mn10300_serial_set_termios(struct uart_port *_port, | 
|  | struct ktermios *new, | 
|  | struct ktermios *old) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | _enter("%s,%p,%p", port->name, new, old); | 
|  |  | 
|  | mn10300_serial_change_speed(port, new, old); | 
|  |  | 
|  | /* handle turning off CRTSCTS */ | 
|  | if (!(new->c_cflag & CRTSCTS)) { | 
|  | u16 ctr = *port->_control; | 
|  | ctr &= ~SC2CTR_TWE; | 
|  | *port->_control = ctr; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * return description of port type | 
|  | */ | 
|  | static const char *mn10300_serial_type(struct uart_port *_port) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | if (port->uart.type == PORT_MN10300_CTS) | 
|  | return "MN10300 SIF_CTS"; | 
|  |  | 
|  | return "MN10300 SIF"; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * release I/O and memory regions in use by port | 
|  | */ | 
|  | static void mn10300_serial_release_port(struct uart_port *_port) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | _enter("%s", port->name); | 
|  |  | 
|  | release_mem_region((unsigned long) port->_iobase, 16); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * request I/O and memory regions for port | 
|  | */ | 
|  | static int mn10300_serial_request_port(struct uart_port *_port) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | _enter("%s", port->name); | 
|  |  | 
|  | request_mem_region((unsigned long) port->_iobase, 16, port->name); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * configure the type and reserve the ports | 
|  | */ | 
|  | static void mn10300_serial_config_port(struct uart_port *_port, int type) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  |  | 
|  | _enter("%s", port->name); | 
|  |  | 
|  | port->uart.type = PORT_MN10300; | 
|  |  | 
|  | if (port->options & MNSCx_OPT_CTS) | 
|  | port->uart.type = PORT_MN10300_CTS; | 
|  |  | 
|  | mn10300_serial_request_port(_port); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * verify serial parameters are suitable for this port type | 
|  | */ | 
|  | static int mn10300_serial_verify_port(struct uart_port *_port, | 
|  | struct serial_struct *ss) | 
|  | { | 
|  | struct mn10300_serial_port *port = | 
|  | container_of(_port, struct mn10300_serial_port, uart); | 
|  | void *mapbase = (void *) (unsigned long) port->uart.mapbase; | 
|  |  | 
|  | _enter("%s", port->name); | 
|  |  | 
|  | /* these things may not be changed */ | 
|  | if (ss->irq		!= port->uart.irq	|| | 
|  | ss->port		!= port->uart.iobase	|| | 
|  | ss->io_type		!= port->uart.iotype	|| | 
|  | ss->iomem_base	!= mapbase || | 
|  | ss->iomem_reg_shift	!= port->uart.regshift	|| | 
|  | ss->hub6		!= port->uart.hub6	|| | 
|  | ss->xmit_fifo_size	!= port->uart.fifosize) | 
|  | return -EINVAL; | 
|  |  | 
|  | /* type may be changed on a port that supports CTS */ | 
|  | if (ss->type != port->uart.type) { | 
|  | if (!(port->options & MNSCx_OPT_CTS)) | 
|  | return -EINVAL; | 
|  |  | 
|  | if (ss->type != PORT_MN10300 && | 
|  | ss->type != PORT_MN10300_CTS) | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * initialise the MN10300 on-chip UARTs | 
|  | */ | 
|  | static int __init mn10300_serial_init(void) | 
|  | { | 
|  | struct mn10300_serial_port *port; | 
|  | int ret, i; | 
|  |  | 
|  | printk(KERN_INFO "%s version %s (%s)\n", | 
|  | serial_name, serial_version, serial_revdate); | 
|  |  | 
|  | #ifdef CONFIG_MN10300_TTYSM2 | 
|  | SC2TIM = 8; /* make the baud base of timer 2 IOCLK/8 */ | 
|  | #endif | 
|  |  | 
|  | set_intr_stub(EXCEP_IRQ_LEVEL1, mn10300_serial_vdma_interrupt); | 
|  |  | 
|  | ret = uart_register_driver(&mn10300_serial_driver); | 
|  | if (!ret) { | 
|  | for (i = 0 ; i < NR_PORTS ; i++) { | 
|  | port = mn10300_serial_ports[i]; | 
|  | if (!port || port->gdbstub) | 
|  | continue; | 
|  |  | 
|  | switch (port->clock_src) { | 
|  | case MNSCx_CLOCK_SRC_IOCLK: | 
|  | port->ioclk = MN10300_IOCLK; | 
|  | break; | 
|  |  | 
|  | #ifdef MN10300_IOBCLK | 
|  | case MNSCx_CLOCK_SRC_IOBCLK: | 
|  | port->ioclk = MN10300_IOBCLK; | 
|  | break; | 
|  | #endif | 
|  | default: | 
|  | BUG(); | 
|  | } | 
|  |  | 
|  | ret = uart_add_one_port(&mn10300_serial_driver, | 
|  | &port->uart); | 
|  |  | 
|  | if (ret < 0) { | 
|  | _debug("ERROR %d", -ret); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ret) | 
|  | uart_unregister_driver(&mn10300_serial_driver); | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | __initcall(mn10300_serial_init); | 
|  |  | 
|  |  | 
|  | #ifdef CONFIG_MN10300_TTYSM_CONSOLE | 
|  |  | 
|  | /* | 
|  | * print a string to the serial port without disturbing the real user of the | 
|  | * port too much | 
|  | * - the console must be locked by the caller | 
|  | */ | 
|  | static void mn10300_serial_console_write(struct console *co, | 
|  | const char *s, unsigned count) | 
|  | { | 
|  | struct mn10300_serial_port *port; | 
|  | unsigned i; | 
|  | u16 scxctr, txicr, tmp; | 
|  | u8 tmxmd; | 
|  |  | 
|  | port = mn10300_serial_ports[co->index]; | 
|  |  | 
|  | /* firstly hijack the serial port from the "virtual DMA" controller */ | 
|  | txicr = *port->tx_icr; | 
|  | *port->tx_icr = GxICR_LEVEL_1; | 
|  | tmp = *port->tx_icr; | 
|  |  | 
|  | /* the transmitter may be disabled */ | 
|  | scxctr = *port->_control; | 
|  | if (!(scxctr & SC01CTR_TXE)) { | 
|  | /* restart the UART clock */ | 
|  | tmxmd = *port->_tmxmd; | 
|  |  | 
|  | switch (port->div_timer) { | 
|  | case MNSCx_DIV_TIMER_16BIT: | 
|  | *port->_tmxmd = 0; | 
|  | *port->_tmxmd = TM8MD_INIT_COUNTER; | 
|  | *port->_tmxmd = tmxmd | TM8MD_COUNT_ENABLE; | 
|  | break; | 
|  |  | 
|  | case MNSCx_DIV_TIMER_8BIT: | 
|  | *port->_tmxmd = 0; | 
|  | *port->_tmxmd = TM2MD_INIT_COUNTER; | 
|  | *port->_tmxmd = tmxmd | TM2MD_COUNT_ENABLE; | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* enable the transmitter */ | 
|  | *port->_control = (scxctr & ~SC01CTR_BKE) | SC01CTR_TXE; | 
|  |  | 
|  | } else if (scxctr & SC01CTR_BKE) { | 
|  | /* stop transmitting BREAK */ | 
|  | *port->_control = (scxctr & ~SC01CTR_BKE); | 
|  | } | 
|  |  | 
|  | /* send the chars into the serial port (with LF -> LFCR conversion) */ | 
|  | for (i = 0; i < count; i++) { | 
|  | char ch = *s++; | 
|  |  | 
|  | while (*port->_status & SC01STR_TBF) | 
|  | continue; | 
|  | *(u8 *) port->_txb = ch; | 
|  |  | 
|  | if (ch == 0x0a) { | 
|  | while (*port->_status & SC01STR_TBF) | 
|  | continue; | 
|  | *(u8 *) port->_txb = 0xd; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* can't let the transmitter be turned off if it's actually | 
|  | * transmitting */ | 
|  | while (*port->_status & (SC01STR_TXF | SC01STR_TBF)) | 
|  | continue; | 
|  |  | 
|  | /* disable the transmitter if we re-enabled it */ | 
|  | if (!(scxctr & SC01CTR_TXE)) | 
|  | *port->_control = scxctr; | 
|  |  | 
|  | *port->tx_icr = txicr; | 
|  | tmp = *port->tx_icr; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * set up a serial port as a console | 
|  | * - construct a cflag setting for the first rs_open() | 
|  | * - initialize the serial port | 
|  | * - return non-zero if we didn't find a serial port. | 
|  | */ | 
|  | static int __init mn10300_serial_console_setup(struct console *co, | 
|  | char *options) | 
|  | { | 
|  | struct mn10300_serial_port *port; | 
|  | int i, parity = 'n', baud = 9600, bits = 8, flow = 0; | 
|  |  | 
|  | for (i = 0 ; i < NR_PORTS ; i++) { | 
|  | port = mn10300_serial_ports[i]; | 
|  | if (port && !port->gdbstub && port->uart.line == co->index) | 
|  | goto found_device; | 
|  | } | 
|  |  | 
|  | return -ENODEV; | 
|  |  | 
|  | found_device: | 
|  | switch (port->clock_src) { | 
|  | case MNSCx_CLOCK_SRC_IOCLK: | 
|  | port->ioclk = MN10300_IOCLK; | 
|  | break; | 
|  |  | 
|  | #ifdef MN10300_IOBCLK | 
|  | case MNSCx_CLOCK_SRC_IOBCLK: | 
|  | port->ioclk = MN10300_IOBCLK; | 
|  | break; | 
|  | #endif | 
|  | default: | 
|  | BUG(); | 
|  | } | 
|  |  | 
|  | if (options) | 
|  | uart_parse_options(options, &baud, &parity, &bits, &flow); | 
|  |  | 
|  | return uart_set_options(&port->uart, co, baud, parity, bits, flow); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * register console | 
|  | */ | 
|  | static int __init mn10300_serial_console_init(void) | 
|  | { | 
|  | register_console(&mn10300_serial_console); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | console_initcall(mn10300_serial_console_init); | 
|  | #endif |