diff options
Diffstat (limited to 'drivers/tty/serial')
56 files changed, 838 insertions, 3470 deletions
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index e0a77540b8ca..a88ef9782a4f 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -235,22 +235,6 @@ static void batten_down_hatches(void) static void status_handle(struct m68k_serial *info, unsigned short status) { -#if 0 - if(status & DCD) { - if((info->port.tty->termios->c_cflag & CRTSCTS) && - ((info->curregs[3] & AUTO_ENAB)==0)) { - info->curregs[3] |= AUTO_ENAB; - info->pendregs[3] |= AUTO_ENAB; - write_zsreg(info->m68k_channel, 3, info->curregs[3]); - } - } else { - if((info->curregs[3] & AUTO_ENAB)) { - info->curregs[3] &= ~AUTO_ENAB; - info->pendregs[3] &= ~AUTO_ENAB; - write_zsreg(info->m68k_channel, 3, info->curregs[3]); - } - } -#endif /* If this is console input and this is a * 'break asserted' status change interrupt * see if we can drop into the debugger @@ -340,9 +324,6 @@ static void transmit_chars(struct m68k_serial *info) info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->xmit_cnt--; - if (info->xmit_cnt < WAKEUP_CHARS) - schedule_work(&info->tqueue); - if(info->xmit_cnt <= 0) { /* All done for now... TX ints off */ uart->ustcnt &= ~USTCNT_TX_INTR_MASK; @@ -378,21 +359,6 @@ irqreturn_t rs_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void do_softint(struct work_struct *work) -{ - struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue); - struct tty_struct *tty; - - tty = info->tty; - if (!tty) - return; -#if 0 - if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - tty_wakeup(tty); - } -#endif -} - static int startup(struct m68k_serial * info) { m68328_uart *uart = &uart_addr[info->line]; @@ -1324,7 +1290,6 @@ rs68328_init(void) info->event = 0; info->count = 0; info->blocked_open = 0; - INIT_WORK(&info->tqueue, do_softint); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); info->line = i; @@ -1341,7 +1306,7 @@ rs68328_init(void) if (request_irq(uart_irqs[i], rs_interrupt, - IRQF_DISABLED, + 0, "M68328_UART", info)) panic("Unable to attach 68328 serial interrupt\n"); } diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h index 8c9c3c0745db..3d2faabd766f 100644 --- a/drivers/tty/serial/68328serial.h +++ b/drivers/tty/serial/68328serial.h @@ -158,7 +158,6 @@ struct m68k_serial { int xmit_head; int xmit_tail; int xmit_cnt; - struct work_struct tqueue; wait_queue_head_t open_wait; wait_queue_head_t close_wait; }; diff --git a/drivers/tty/serial/68360serial.c b/drivers/tty/serial/68360serial.c deleted file mode 100644 index 0a3e8787ed50..000000000000 --- a/drivers/tty/serial/68360serial.c +++ /dev/null @@ -1,2979 +0,0 @@ -/* - * UART driver for 68360 CPM SCC or SMC - * Copyright (c) 2000 D. Jeff Dionne <jeff@uclinux.org>, - * Copyright (c) 2000 Michael Leslie <mleslie@lineo.ca> - * Copyright (c) 1997 Dan Malek <dmalek@jlc.net> - * - * I used the serial.c driver as the framework for this driver. - * Give credit to those guys. - * The original code was written for the MBX860 board. I tried to make - * it generic, but there may be some assumptions in the structures that - * have to be fixed later. - * To save porting time, I did not bother to change any object names - * that are not accessed outside of this file. - * It still needs lots of work........When it was easy, I included code - * to support the SCCs, but this has never been tested, nor is it complete. - * Only the SCCs support modem control, so that is not complete either. - * - * This module exports the following rs232 io functions: - * - * int rs_360_init(void); - */ - -#include <linux/module.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/serial.h> -#include <linux/serialP.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/ptrace.h> -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <asm/irq.h> -#include <asm/m68360.h> -#include <asm/commproc.h> - - -#ifdef CONFIG_KGDB -extern void breakpoint(void); -extern void set_debug_traps(void); -extern int kgdb_output_string (const char* s, unsigned int count); -#endif - - -/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */ -#include <linux/console.h> -#include <linux/jiffies.h> - -/* this defines the index into rs_table for the port to use - */ -#ifndef CONFIG_SERIAL_CONSOLE_PORT -#define CONFIG_SERIAL_CONSOLE_PORT 1 /* ie SMC2 - note USE_SMC2 must be defined */ -#endif -/* #endif */ - -#if 0 -/* SCC2 for console - */ -#undef CONFIG_SERIAL_CONSOLE_PORT -#define CONFIG_SERIAL_CONSOLE_PORT 2 -#endif - - -#define TX_WAKEUP ASYNC_SHARE_IRQ - -static char *serial_name = "CPM UART driver"; -static char *serial_version = "0.03"; - -static struct tty_driver *serial_driver; -int serial_console_setup(struct console *co, char *options); - -/* - * Serial driver configuration section. Here are the various options: - */ -#define SERIAL_PARANOIA_CHECK -#define CONFIG_SERIAL_NOPAUSE_IO -#define SERIAL_DO_RESTART - -/* Set of debugging defines */ - -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW -#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - -#define _INLINE_ inline - -#define DBG_CNT(s) - -/* We overload some of the items in the data structure to meet our - * needs. For example, the port address is the CPM parameter ram - * offset for the SCC or SMC. The maximum number of ports is 4 SCCs and - * 2 SMCs. The "hub6" field is used to indicate the channel number, with - * a flag indicating SCC or SMC, and the number is used as an index into - * the CPM parameter area for this device. - * The "type" field is currently set to 0, for PORT_UNKNOWN. It is - * not currently used. I should probably use it to indicate the port - * type of SMC or SCC. - * The SMCs do not support any modem control signals. - */ -#define smc_scc_num hub6 -#define NUM_IS_SCC ((int)0x00010000) -#define PORT_NUM(P) ((P) & 0x0000ffff) - - -#if defined (CONFIG_UCQUICC) - -volatile extern void *_periph_base; -/* sipex transceiver - * mode bits for are on pins - * - * SCC2 d16..19 - * SCC3 d20..23 - * SCC4 d24..27 - */ -#define SIPEX_MODE(n,m) ((m & 0x0f)<<(16+4*(n-1))) - -static uint sipex_mode_bits = 0x00000000; - -#endif - -/* There is no `serial_state' defined back here in 2.0. - * Try to get by with serial_struct - */ -/* #define serial_state serial_struct */ - -/* 2.4 -> 2.0 portability problem: async_icount in 2.4 has a few - * extras: */ - -#if 0 -struct async_icount_24 { - __u32 cts, dsr, rng, dcd, tx, rx; - __u32 frame, parity, overrun, brk; - __u32 buf_overrun; -} icount; -#endif - -#if 0 - -struct serial_state { - int magic; - int baud_base; - unsigned long port; - int irq; - int flags; - int hub6; - int type; - int line; - int revision; /* Chip revision (950) */ - int xmit_fifo_size; - int custom_divisor; - int count; - u8 *iomem_base; - u16 iomem_reg_shift; - unsigned short close_delay; - unsigned short closing_wait; /* time to wait before closing */ - struct async_icount_24 icount; - int io_type; - struct async_struct *info; -}; -#endif - -#define SSTATE_MAGIC 0x5302 - - - -/* SMC2 is sometimes used for low performance TDM interfaces. Define - * this as 1 if you want SMC2 as a serial port UART managed by this driver. - * Define this as 0 if you wish to use SMC2 for something else. - */ -#define USE_SMC2 1 - -#if 0 -/* Define SCC to ttySx mapping. */ -#define SCC_NUM_BASE (USE_SMC2 + 1) /* SCC base tty "number" */ - -/* Define which SCC is the first one to use for a serial port. These - * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used - * for Ethernet, and the first available SCC for serial UART is SCC2. - * NOTE: IF YOU CHANGE THIS, you have to change the PROFF_xxx and - * interrupt vectors in the table below to match. - */ -#define SCC_IDX_BASE 1 /* table index */ -#endif - - -/* Processors other than the 860 only get SMCs configured by default. - * Either they don't have SCCs or they are allocated somewhere else. - * Of course, there are now 860s without some SCCs, so we will need to - * address that someday. - * The Embedded Planet Multimedia I/O cards use TDM interfaces to the - * stereo codec parts, and we use SMC2 to help support that. - */ -static struct serial_state rs_table[] = { -/* type line PORT IRQ FLAGS smc_scc_num (F.K.A. hub6) */ - { 0, 0, PRSLOT_SMC1, CPMVEC_SMC1, 0, 0 } /* SMC1 ttyS0 */ -#if USE_SMC2 - ,{ 0, 0, PRSLOT_SMC2, CPMVEC_SMC2, 0, 1 } /* SMC2 ttyS1 */ -#endif - -#if defined(CONFIG_SERIAL_68360_SCC) - ,{ 0, 0, PRSLOT_SCC2, CPMVEC_SCC2, 0, (NUM_IS_SCC | 1) } /* SCC2 ttyS2 */ - ,{ 0, 0, PRSLOT_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) } /* SCC3 ttyS3 */ - ,{ 0, 0, PRSLOT_SCC4, CPMVEC_SCC4, 0, (NUM_IS_SCC | 3) } /* SCC4 ttyS4 */ -#endif -}; - -#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) - -/* The number of buffer descriptors and their sizes. - */ -#define RX_NUM_FIFO 4 -#define RX_BUF_SIZE 32 -#define TX_NUM_FIFO 4 -#define TX_BUF_SIZE 32 - -#define CONSOLE_NUM_FIFO 2 -#define CONSOLE_BUF_SIZE 4 - -char *console_fifos[CONSOLE_NUM_FIFO * CONSOLE_BUF_SIZE]; - -/* The async_struct in serial.h does not really give us what we - * need, so define our own here. - */ -typedef struct serial_info { - int magic; - int flags; - - struct serial_state *state; - /* struct serial_struct *state; */ - /* struct async_struct *state; */ - - struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int timeout; - int line; - int x_char; /* xon/xoff character */ - int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; - unsigned long event; - unsigned long last_active; - int blocked_open; /* # of blocked opens */ - struct work_struct tqueue; - struct work_struct tqueue_hangup; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - - -/* CPM Buffer Descriptor pointers. - */ - QUICC_BD *rx_bd_base; - QUICC_BD *rx_cur; - QUICC_BD *tx_bd_base; - QUICC_BD *tx_cur; -} ser_info_t; - - -/* since kmalloc_init() does not get called until much after this initialization: */ -static ser_info_t quicc_ser_info[NR_PORTS]; -static char rx_buf_pool[NR_PORTS * RX_NUM_FIFO * RX_BUF_SIZE]; -static char tx_buf_pool[NR_PORTS * TX_NUM_FIFO * TX_BUF_SIZE]; - -static void change_speed(ser_info_t *info); -static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout); - -static inline int serial_paranoia_check(ser_info_t *info, - char *name, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for serial struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null async_struct for (%s) in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - if (info->magic != SERIAL_MAGIC) { - printk(badmagic, name, routine); - return 1; - } -#endif - return 0; -} - -/* - * This is used to figure out the divisor speeds and the timeouts, - * indexed by the termio value. The generic CPM functions are responsible - * for setting and assigning baud rate generators for us. - */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 }; - -/* This sucks. There is a better way: */ -#if defined(CONFIG_CONSOLE_9600) - #define CONSOLE_BAUDRATE 9600 -#elif defined(CONFIG_CONSOLE_19200) - #define CONSOLE_BAUDRATE 19200 -#elif defined(CONFIG_CONSOLE_115200) - #define CONSOLE_BAUDRATE 115200 -#else - #warning "console baud rate undefined" - #define CONSOLE_BAUDRATE 9600 -#endif - -/* - * ------------------------------------------------------------ - * rs_stop() and rs_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void rs_360_stop(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - int idx; - unsigned long flags; - volatile struct scc_regs *sccp; - volatile struct smc_regs *smcp; - - if (serial_paranoia_check(info, tty->name, "rs_stop")) - return; - - local_irq_save(flags); - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_sccm &= ~UART_SCCM_TX; - } else { - /* smcp = &cpmp->cp_smc[idx]; */ - smcp = &pquicc->smc_regs[idx]; - smcp->smc_smcm &= ~SMCM_TX; - } - local_irq_restore(flags); -} - - -static void rs_360_start(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - int idx; - unsigned long flags; - volatile struct scc_regs *sccp; - volatile struct smc_regs *smcp; - - if (serial_paranoia_check(info, tty->name, "rs_stop")) - return; - - local_irq_save(flags); - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_sccm |= UART_SCCM_TX; - } else { - smcp = &pquicc->smc_regs[idx]; - smcp->smc_smcm |= SMCM_TX; - } - local_irq_restore(flags); -} - -/* - * ---------------------------------------------------------------------- - * - * 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 (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- - */ - -static _INLINE_ void receive_chars(ser_info_t *info) -{ - struct tty_struct *tty = info->port.tty; - unsigned char ch, flag, *cp; - /*int ignored = 0;*/ - int i; - ushort status; - struct async_icount *icount; - /* struct async_icount_24 *icount; */ - volatile QUICC_BD *bdp; - - icount = &info->state->icount; - - /* Just loop through the closed BDs and copy the characters into - * the buffer. - */ - bdp = info->rx_cur; - for (;;) { - if (bdp->status & BD_SC_EMPTY) /* If this one is empty */ - break; /* we are all done */ - - /* The read status mask tell us what we should do with - * incoming characters, especially if errors occur. - * One special case is the use of BD_SC_EMPTY. If - * this is not set, we are supposed to be ignoring - * inputs. In this case, just mark the buffer empty and - * continue. - */ - if (!(info->read_status_mask & BD_SC_EMPTY)) { - bdp->status |= BD_SC_EMPTY; - bdp->status &= - ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); - - if (bdp->status & BD_SC_WRAP) - bdp = info->rx_bd_base; - else - bdp++; - continue; - } - - /* Get the number of characters and the buffer pointer. - */ - i = bdp->length; - /* cp = (unsigned char *)__va(bdp->buf); */ - cp = (char *)bdp->buf; - status = bdp->status; - - while (i-- > 0) { - ch = *cp++; - icount->rx++; - -#ifdef SERIAL_DEBUG_INTR - printk("DR%02x:%02x...", ch, status); -#endif - flag = TTY_NORMAL; - - if (status & (BD_SC_BR | BD_SC_FR | - BD_SC_PR | BD_SC_OV)) { - /* - * For statistics only - */ - if (status & BD_SC_BR) - icount->brk++; - else if (status & BD_SC_PR) - icount->parity++; - else if (status & BD_SC_FR) - icount->frame++; - if (status & BD_SC_OV) - icount->overrun++; - - /* - * Now check to see if character should be - * ignored, and mask off conditions which - * should be ignored. - if (status & info->ignore_status_mask) { - if (++ignored > 100) - break; - continue; - } - */ - status &= info->read_status_mask; - - if (status & (BD_SC_BR)) { -#ifdef SERIAL_DEBUG_INTR - printk("handling break...."); -#endif - *tty->flip.flag_buf_ptr = TTY_BREAK; - if (info->flags & ASYNC_SAK) - do_SAK(tty); - } else if (status & BD_SC_PR) - flag = TTY_PARITY; - else if (status & BD_SC_FR) - flag = TTY_FRAME; - } - tty_insert_flip_char(tty, ch, flag); - if (status & BD_SC_OV) - /* - * Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - - /* This BD is ready to be used again. Clear status. - * Get next BD. - */ - bdp->status |= BD_SC_EMPTY; - bdp->status &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); - - if (bdp->status & BD_SC_WRAP) - bdp = info->rx_bd_base; - else - bdp++; - } - - info->rx_cur = (QUICC_BD *)bdp; - - tty_schedule_flip(tty); -} - -static _INLINE_ void receive_break(ser_info_t *info) -{ - struct tty_struct *tty = info->port.tty; - - info->state->icount.brk++; - /* Check to see if there is room in the tty buffer for - * the break. If not, we exit now, losing the break. FIXME - */ - tty_insert_flip_char(tty, 0, TTY_BREAK); - tty_schedule_flip(tty); -} - -static _INLINE_ void transmit_chars(ser_info_t *info) -{ - - if ((info->flags & TX_WAKEUP) || - (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) { - schedule_work(&info->tqueue); - } - -#ifdef SERIAL_DEBUG_INTR - printk("THRE..."); -#endif -} - -#ifdef notdef - /* I need to do this for the SCCs, so it is left as a reminder. - */ -static _INLINE_ void check_modem_status(struct async_struct *info) -{ - int status; - /* struct async_icount *icount; */ - struct async_icount_24 *icount; - - status = serial_in(info, UART_MSR); - - if (status & UART_MSR_ANY_DELTA) { - icount = &info->state->icount; - /* update input line counters */ - if (status & UART_MSR_TERI) - icount->rng++; - if (status & UART_MSR_DDSR) - icount->dsr++; - if (status & UART_MSR_DDCD) { - icount->dcd++; -#ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && - (status & UART_MSR_DCD)) - hardpps(); -#endif - } - if (status & UART_MSR_DCTS) - icount->cts++; - wake_up_interruptible(&info->delta_msr_wait); - } - - if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { -#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) - printk("ttys%d CD now %s...", info->line, - (status & UART_MSR_DCD) ? "on" : "off"); -#endif - if (status & UART_MSR_DCD) - wake_up_interruptible(&info->open_wait); - else { -#ifdef SERIAL_DEBUG_OPEN - printk("scheduling hangup..."); -#endif - queue_task(&info->tqueue_hangup, - &tq_scheduler); - } - } - if (info->flags & ASYNC_CTS_FLOW) { - if (info->port.tty->hw_stopped) { - if (status & UART_MSR_CTS) { -#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) - printk("CTS tx start..."); -#endif - info->port.tty->hw_stopped = 0; - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); - return; - } - } else { - if (!(status & UART_MSR_CTS)) { -#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) - printk("CTS tx stop..."); -#endif - info->port.tty->hw_stopped = 1; - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } - } - } -} -#endif - -/* - * This is the serial driver's interrupt routine for a single port - */ -/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */ -static void rs_360_interrupt(int vec, void *dev_id) -{ - u_char events; - int idx; - ser_info_t *info; - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - - info = dev_id; - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - events = sccp->scc_scce; - if (events & SCCM_RX) - receive_chars(info); - if (events & SCCM_TX) - transmit_chars(info); - sccp->scc_scce = events; - } else { - smcp = &pquicc->smc_regs[idx]; - events = smcp->smc_smce; - if (events & SMCM_BRKE) - receive_break(info); - if (events & SMCM_RX) - receive_chars(info); - if (events & SMCM_TX) - transmit_chars(info); - smcp->smc_smce = events; - } - -#ifdef SERIAL_DEBUG_INTR - printk("rs_interrupt_single(%d, %x)...", - info->state->smc_scc_num, events); -#endif -#ifdef modem_control - check_modem_status(info); -#endif - info->last_active = jiffies; -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} - - -/* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- - */ - - -static void do_softint(void *private_) -{ - ser_info_t *info = (ser_info_t *) private_; - struct tty_struct *tty; - - tty = info->port.tty; - if (!tty) - return; - - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) - tty_wakeup(tty); -} - - -/* - * This routine is called from the scheduler tqueue when the interrupt - * routine has signalled that a hangup has occurred. The path of - * hangup processing is: - * - * serial interrupt routine -> (scheduler tqueue) -> - * do_serial_hangup() -> tty->hangup() -> rs_hangup() - * - */ -static void do_serial_hangup(void *private_) -{ - struct async_struct *info = (struct async_struct *) private_; - struct tty_struct *tty; - - tty = info->port.tty; - if (!tty) - return; - - tty_hangup(tty); -} - - -static int startup(ser_info_t *info) -{ - unsigned long flags; - int retval=0; - int idx; - /*struct serial_state *state = info->state;*/ - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - volatile struct smc_uart_pram *up; - volatile struct uart_pram *scup; - - - local_irq_save(flags); - - if (info->flags & ASYNC_INITIALIZED) { - goto errout; - } - -#ifdef maybe - if (!state->port || !state->type) { - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - goto errout; - } -#endif - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up ttys%d (irq %d)...", info->line, state->irq); -#endif - - -#ifdef modem_control - info->MCR = 0; - if (info->port.tty->termios->c_cflag & CBAUD) - info->MCR = UART_MCR_DTR | UART_MCR_RTS; -#endif - - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - - /* - * and set the speed of the serial port - */ - change_speed(info); - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - scup = &pquicc->pram[info->state->port].scc.pscc.u; - - scup->mrblr = RX_BUF_SIZE; - scup->max_idl = RX_BUF_SIZE; - - sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX); - sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - } else { - smcp = &pquicc->smc_regs[idx]; - - /* Enable interrupts and I/O. - */ - smcp->smc_smcm |= (SMCM_RX | SMCM_TX); - smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); - - /* We can tune the buffer length and idle characters - * to take advantage of the entire incoming buffer size. - * If mrblr is something other than 1, maxidl has to be - * non-zero or we never get an interrupt. The maxidl - * is the number of character times we wait after reception - * of the last character before we decide no more characters - * are coming. - */ - /* up = (smc_uart_t *)&pquicc->cp_dparam[state->port]; */ - /* holy unionized structures, Batman: */ - up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; - - up->mrblr = RX_BUF_SIZE; - up->max_idl = RX_BUF_SIZE; - - up->brkcr = 1; /* number of break chars */ - } - - info->flags |= ASYNC_INITIALIZED; - local_irq_restore(flags); - return 0; - -errout: - local_irq_restore(flags); - return retval; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void shutdown(ser_info_t *info) -{ - unsigned long flags; - struct serial_state *state; - int idx; - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - - if (!(info->flags & ASYNC_INITIALIZED)) - return; - - state = info->state; - -#ifdef SERIAL_DEBUG_OPEN - printk("Shutting down serial port %d (irq %d)....", info->line, - state->irq); -#endif - - local_irq_save(flags); - - idx = PORT_NUM(state->smc_scc_num); - if (state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#ifdef CONFIG_SERIAL_CONSOLE - /* We can't disable the transmitter if this is the - * system console. - */ - if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT) -#endif - sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); - } else { - smcp = &pquicc->smc_regs[idx]; - - /* Disable interrupts and I/O. - */ - smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); -#ifdef CONFIG_SERIAL_CONSOLE - /* We can't disable the transmitter if this is the - * system console. - */ - if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT) -#endif - smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - } - - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - - info->flags &= ~ASYNC_INITIALIZED; - local_irq_restore(flags); -} - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void change_speed(ser_info_t *info) -{ - int baud_rate; - unsigned cflag, cval, scval, prev_mode; - int i, bits, sbits, idx; - unsigned long flags; - struct serial_state *state; - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - - if (!info->port.tty || !info->port.tty->termios) - return; - cflag = info->port.tty->termios->c_cflag; - - state = info->state; - - /* Character length programmed into the mode register is the - * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, - * 1 or 2 stop bits, minus 1. - * The value 'bits' counts this for us. - */ - cval = 0; - scval = 0; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: bits = 5; break; - case CS6: bits = 6; break; - case CS7: bits = 7; break; - case CS8: bits = 8; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: bits = 8; break; - } - sbits = bits - 5; - - if (cflag & CSTOPB) { - cval |= SMCMR_SL; /* Two stops */ - scval |= SCU_PMSR_SL; - bits++; - } - if (cflag & PARENB) { - cval |= SMCMR_PEN; - scval |= SCU_PMSR_PEN; - bits++; - } - if (!(cflag & PARODD)) { - cval |= SMCMR_PM_EVEN; - scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP); - } - - /* Determine divisor based on baud rate */ - i = cflag & CBAUD; - if (i >= (sizeof(baud_table)/sizeof(int))) - baud_rate = 9600; - else - baud_rate = baud_table[i]; - - info->timeout = (TX_BUF_SIZE*HZ*bits); - info->timeout += HZ/50; /* Add .02 seconds of slop */ - -#ifdef modem_control - /* CTS flow control flag and modem status interrupts */ - info->IER &= ~UART_IER_MSI; - if (info->flags & ASYNC_HARDPPS_CD) - info->IER |= UART_IER_MSI; - if (cflag & CRTSCTS) { - info->flags |= ASYNC_CTS_FLOW; - info->IER |= UART_IER_MSI; - } else - info->flags &= ~ASYNC_CTS_FLOW; - if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; - else { - info->flags |= ASYNC_CHECK_CD; - info->IER |= UART_IER_MSI; - } - serial_out(info, UART_IER, info->IER); -#endif - - /* - * Set up parity check flag - */ - info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); - if (I_INPCK(info->port.tty)) - info->read_status_mask |= BD_SC_FR | BD_SC_PR; - if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) - info->read_status_mask |= BD_SC_BR; - - /* - * Characters to ignore - */ - info->ignore_status_mask = 0; - if (I_IGNPAR(info->port.tty)) - info->ignore_status_mask |= BD_SC_PR | BD_SC_FR; - if (I_IGNBRK(info->port.tty)) { - info->ignore_status_mask |= BD_SC_BR; - /* - * If we're ignore parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (I_IGNPAR(info->port.tty)) - info->ignore_status_mask |= BD_SC_OV; - } - /* - * !!! ignore all characters if CREAD is not set - */ - if ((cflag & CREAD) == 0) - info->read_status_mask &= ~BD_SC_EMPTY; - local_irq_save(flags); - - /* Start bit has not been added (so don't, because we would just - * subtract it later), and we need to add one for the number of - * stops bits (there is always at least one). - */ - bits++; - idx = PORT_NUM(state->smc_scc_num); - if (state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_psmr = (sbits << 12) | scval; - } else { - smcp = &pquicc->smc_regs[idx]; - - /* Set the mode register. We want to keep a copy of the - * enables, because we want to put them back if they were - * present. - */ - prev_mode = smcp->smc_smcmr; - smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART; - smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN)); - } - - m360_cpm_setbrg((state - rs_table), baud_rate); - - local_irq_restore(flags); -} - -static void rs_360_put_char(struct tty_struct *tty, unsigned char ch) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - volatile QUICC_BD *bdp; - - if (serial_paranoia_check(info, tty->name, "rs_put_char")) - return 0; - - if (!tty) - return 0; - - bdp = info->tx_cur; - while (bdp->status & BD_SC_READY); - - /* *((char *)__va(bdp->buf)) = ch; */ - *((char *)bdp->buf) = ch; - bdp->length = 1; - bdp->status |= BD_SC_READY; - - /* Get next BD. - */ - if (bdp->status & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - - info->tx_cur = (QUICC_BD *)bdp; - return 1; - -} - -static int rs_360_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - int c, ret = 0; - ser_info_t *info = (ser_info_t *)tty->driver_data; - volatile QUICC_BD *bdp; - -#ifdef CONFIG_KGDB - /* Try to let stub handle output. Returns true if it did. */ - if (kgdb_output_string(buf, count)) - return ret; -#endif - - if (serial_paranoia_check(info, tty->name, "rs_write")) - return 0; - - if (!tty) - return 0; - - bdp = info->tx_cur; - - while (1) { - c = min(count, TX_BUF_SIZE); - - if (c <= 0) - break; - - if (bdp->status & BD_SC_READY) { - info->flags |= TX_WAKEUP; - break; - } - - /* memcpy(__va(bdp->buf), buf, c); */ - memcpy((void *)bdp->buf, buf, c); - - bdp->length = c; - bdp->status |= BD_SC_READY; - - buf += c; - count -= c; - ret += c; - - /* Get next BD. - */ - if (bdp->status & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - info->tx_cur = (QUICC_BD *)bdp; - } - return ret; -} - -static int rs_360_write_room(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - int ret; - - if (serial_paranoia_check(info, tty->name, "rs_write_room")) - return 0; - - if ((info->tx_cur->status & BD_SC_READY) == 0) { - info->flags &= ~TX_WAKEUP; - ret = TX_BUF_SIZE; - } - else { - info->flags |= TX_WAKEUP; - ret = 0; - } - return ret; -} - -/* I could track this with transmit counters....maybe later. -*/ -static int rs_360_chars_in_buffer(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) - return 0; - return 0; -} - -static void rs_360_flush_buffer(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) - return; - - /* There is nothing to "flush", whatever we gave the CPM - * is on its way out. - */ - tty_wakeup(tty); - info->flags &= ~TX_WAKEUP; -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ -static void rs_360_send_xchar(struct tty_struct *tty, char ch) -{ - volatile QUICC_BD *bdp; - - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "rs_send_char")) - return; - - bdp = info->tx_cur; - while (bdp->status & BD_SC_READY); - - /* *((char *)__va(bdp->buf)) = ch; */ - *((char *)bdp->buf) = ch; - bdp->length = 1; - bdp->status |= BD_SC_READY; - - /* Get next BD. - */ - if (bdp->status & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - - info->tx_cur = (QUICC_BD *)bdp; -} - -/* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void rs_360_throttle(struct tty_struct * tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->name, "rs_throttle")) - return; - - if (I_IXOFF(tty)) - rs_360_send_xchar(tty, STOP_CHAR(tty)); - -#ifdef modem_control - if (tty->termios->c_cflag & CRTSCTS) - info->MCR &= ~UART_MCR_RTS; - - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); -#endif -} - -static void rs_360_unthrottle(struct tty_struct * tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - rs_360_send_xchar(tty, START_CHAR(tty)); - } -#ifdef modem_control - if (tty->termios->c_cflag & CRTSCTS) - info->MCR |= UART_MCR_RTS; - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); -#endif -} - -/* - * ------------------------------------------------------------ - * rs_ioctl() and friends - * ------------------------------------------------------------ - */ - -#ifdef maybe -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct async_struct * info, unsigned int *value) -{ - unsigned char status; - unsigned int result; - - local_irq_disable(); - status = serial_in(info, UART_LSR); - local_irq_enable(); - result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - return put_user(result,value); -} -#endif - -static int rs_360_tiocmget(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - unsigned int result = 0; -#ifdef modem_control - unsigned char control, status; - - if (serial_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - - control = info->MCR; - local_irq_disable(); - status = serial_in(info, UART_MSR); - local_irq_enable(); - result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) - | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) -#ifdef TIOCM_OUT1 - | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0) - | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0) -#endif - | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) - | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) - | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) - | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); -#endif - return result; -} - -static int rs_360_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ -#ifdef modem_control - ser_info_t *info = (ser_info_t *)tty->driver_data; - unsigned int arg; - - if (serial_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - /* FIXME: locking on info->mcr */ - if (set & TIOCM_RTS) - info->mcr |= UART_MCR_RTS; - if (set & TIOCM_DTR) - info->mcr |= UART_MCR_DTR; - if (clear & TIOCM_RTS) - info->MCR &= ~UART_MCR_RTS; - if (clear & TIOCM_DTR) - info->MCR &= ~UART_MCR_DTR; - -#ifdef TIOCM_OUT1 - if (set & TIOCM_OUT1) - info->MCR |= UART_MCR_OUT1; - if (set & TIOCM_OUT2) - info->MCR |= UART_MCR_OUT2; - if (clear & TIOCM_OUT1) - info->MCR &= ~UART_MCR_OUT1; - if (clear & TIOCM_OUT2) - info->MCR &= ~UART_MCR_OUT2; -#endif - - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); -#endif - return 0; -} - -/* Sending a break is a two step process on the SMC/SCC. It is accomplished - * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT - * command. We take advantage of the begin/end functions to make this - * happen. - */ -static ushort smc_chan_map[] = { - CPM_CR_CH_SMC1, - CPM_CR_CH_SMC2 -}; - -static ushort scc_chan_map[] = { - CPM_CR_CH_SCC1, - CPM_CR_CH_SCC2, - CPM_CR_CH_SCC3, - CPM_CR_CH_SCC4 -}; - -static void begin_break(ser_info_t *info) -{ - volatile QUICC *cp; - ushort chan; - int idx; - - cp = pquicc; - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) - chan = scc_chan_map[idx]; - else - chan = smc_chan_map[idx]; - - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); -} - -static void end_break(ser_info_t *info) -{ - volatile QUICC *cp; - ushort chan; - int idx; - - cp = pquicc; - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) - chan = scc_chan_map[idx]; - else - chan = smc_chan_map[idx]; - - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); -} - -/* - * This routine sends a break character out the serial port. - */ -static void send_break(ser_info_t *info, unsigned int duration) -{ -#ifdef SERIAL_DEBUG_SEND_BREAK - printk("rs_send_break(%d) jiff=%lu...", duration, jiffies); -#endif - begin_break(info); - msleep_interruptible(duration); - end_break(info); -#ifdef SERIAL_DEBUG_SEND_BREAK - printk("done jiffies=%lu\n", jiffies); -#endif -} - - -/* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ -static int rs_360_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - struct async_icount cnow; - - local_irq_disable(); - cnow = info->state->icount; - local_irq_enable(); - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - - return 0; -} - -static int rs_360_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - int error; - ser_info_t *info = (ser_info_t *)tty->driver_data; - int retval; - struct async_icount cnow; - /* struct async_icount_24 cnow;*/ /* kernel counter temps */ - struct serial_icounter_struct *p_cuser; /* user space */ - - if (serial_paranoia_check(info, tty->name, "rs_ioctl")) - return -ENODEV; - - if (cmd != TIOCMIWAIT) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - if (!arg) { - send_break(info, 250); /* 1/4 second */ - if (signal_pending(current)) - return -EINTR; - } - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - send_break(info, arg ? arg*100 : 250); - if (signal_pending(current)) - return -EINTR; - return 0; - case TIOCSBRK: - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - begin_break(info); - return 0; - case TIOCCBRK: - retval = tty_check_change(tty); - if (retval) - return retval; - end_break(info); - return 0; -#ifdef maybe - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info(info, (unsigned int *) arg); -#endif - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: -#ifdef modem_control - local_irq_disable(); - /* note the counters on entry */ - cprev = info->state->icount; - local_irq_enable(); - while (1) { - interruptible_sleep_on(&info->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - local_irq_disable(); - cnow = info->state->icount; /* atomic copy */ - local_irq_enable(); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ -#else - return 0; -#endif - - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -/* FIX UP modem control here someday...... -*/ -static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - - change_speed(info); - -#ifdef modem_control - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && - !(tty->termios->c_cflag & CBAUD)) { - info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - (tty->termios->c_cflag & CBAUD)) { - info->MCR |= UART_MCR_DTR; - if (!tty->hw_stopped || - !(tty->termios->c_cflag & CRTSCTS)) { - info->MCR |= UART_MCR_RTS; - } - local_irq_disable(); - serial_out(info, UART_MCR, info->MCR); - local_irq_enable(); - } - - /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - rs_360_start(tty); - } -#endif - -#if 0 - /* - * No need to wake up processes in open wait, since they - * sample the CLOCAL flag once, and don't recheck it. - * XXX It's not clear whether the current behavior is correct - * or not. Hence, this may change..... - */ - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); -#endif -} - -/* - * ------------------------------------------------------------ - * rs_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * async structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ -static void rs_360_close(struct tty_struct *tty, struct file * filp) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - /* struct async_state *state; */ - struct serial_state *state; - unsigned long flags; - int idx; - volatile struct smc_regs *smcp; - volatile struct scc_regs *sccp; - - if (!info || serial_paranoia_check(info, tty->name, "rs_close")) - return; - - state = info->state; - - local_irq_save(flags); - - if (tty_hung_up_p(filp)) { - DBG_CNT("before DEC-hung"); - local_irq_restore(flags); - return; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttys%d, count = %d\n", info->line, state->count); -#endif - if ((tty->count == 1) && (state->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. state->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("rs_close: bad serial port count; tty->count is 1, " - "state->count is %d\n", state->count); - state->count = 1; - } - if (--state->count < 0) { - printk("rs_close: bad serial port count for ttys%d: %d\n", - info->line, state->count); - state->count = 0; - } - if (state->count) { - DBG_CNT("before DEC-2"); - local_irq_restore(flags); - return; - } - info->flags |= ASYNC_CLOSING; - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - info->read_status_mask &= ~BD_SC_EMPTY; - if (info->flags & ASYNC_INITIALIZED) { - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - sccp = &pquicc->scc_regs[idx]; - sccp->scc_sccm &= ~UART_SCCM_RX; - sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR; - } else { - smcp = &pquicc->smc_regs[idx]; - smcp->smc_smcm &= ~SMCM_RX; - smcp->smc_smcmr &= ~SMCMR_REN; - } - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - rs_360_wait_until_sent(tty, info->timeout); - } - shutdown(info); - rs_360_flush_buffer(tty); - tty_ldisc_flush(tty); - tty->closing = 0; - info->event = 0; - info->port.tty = NULL; - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); - } - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - local_irq_restore(flags); -} - -/* - * rs_wait_until_sent() --- wait until the transmitter is empty - */ -static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - unsigned long orig_jiffies, char_time; - /*int lsr;*/ - volatile QUICC_BD *bdp; - - if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) - return; - -#ifdef maybe - if (info->state->type == PORT_UNKNOWN) - return; -#endif - - orig_jiffies = jiffies; - /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - char_time = 1; - if (timeout) - char_time = min(char_time, (unsigned long)timeout); -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); - printk("jiff=%lu...", jiffies); -#endif - - /* We go through the loop at least once because we can't tell - * exactly when the last character exits the shifter. There can - * be at least two characters waiting to be sent after the buffers - * are empty. - */ - do { -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...", lsr, jiffies); -#endif -/* current->counter = 0; make us low-priority */ - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && (time_after(jiffies, orig_jiffies + timeout))) - break; - /* The 'tx_cur' is really the next buffer to send. We - * have to back up to the previous BD and wait for it - * to go. This isn't perfect, because all this indicates - * is the buffer is available. There are still characters - * in the CPM FIFO. - */ - bdp = info->tx_cur; - if (bdp == info->tx_bd_base) - bdp += (TX_NUM_FIFO-1); - else - bdp--; - } while (bdp->status & BD_SC_READY); - current->state = TASK_RUNNING; -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); -#endif -} - -/* - * rs_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void rs_360_hangup(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - struct serial_state *state = info->state; - - if (serial_paranoia_check(info, tty->name, "rs_hangup")) - return; - - state = info->state; - - rs_360_flush_buffer(tty); - shutdown(info); - info->event = 0; - state->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->port.tty = NULL; - wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - ser_info_t *info) -{ -#ifdef DO_THIS_LATER - DECLARE_WAITQUEUE(wait, current); -#endif - struct serial_state *state = info->state; - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - * If this is an SMC port, we don't have modem control to wait - * for, so just get out here. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR)) || - !(info->state->smc_scc_num & NUM_IS_SCC)) { - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, state->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; -#ifdef DO_THIS_LATER - add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttys%d, count = %d\n", - state->line, state->count); -#endif - local_irq_disable(); - if (!tty_hung_up_p(filp)) - state->count--; - local_irq_enable(); - info->blocked_open++; - while (1) { - local_irq_disable(); - if (tty->termios->c_cflag & CBAUD) - serial_out(info, UART_MCR, - serial_inp(info, UART_MCR) | - (UART_MCR_DTR | UART_MCR_RTS)); - local_irq_enable(); - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & ASYNC_CLOSING) && - (do_clocal || (serial_in(info, UART_MSR) & - UART_MSR_DCD))) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttys%d, count = %d\n", - info->line, state->count); -#endif - tty_unlock(); - schedule(); - tty_lock(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - state->count++; - info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttys%d, count = %d\n", - info->line, state->count); -#endif -#endif /* DO_THIS_LATER */ - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -static int get_async_struct(int line, ser_info_t **ret_info) -{ - struct serial_state *sstate; - - sstate = rs_table + line; - if (sstate->info) { - sstate->count++; - *ret_info = (ser_info_t *)sstate->info; - return 0; - } - else { - return -ENOMEM; - } -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its async structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -static int rs_360_open(struct tty_struct *tty, struct file * filp) -{ - ser_info_t *info; - int retval, line; - - line = tty->index; - if ((line < 0) || (line >= NR_PORTS)) - return -ENODEV; - retval = get_async_struct(line, &info); - if (retval) - return retval; - if (serial_paranoia_check(info, tty->name, "rs_open")) - return -ENODEV; - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s, count = %d\n", tty->name, info->state->count); -#endif - tty->driver_data = info; - info->port.tty = tty; - - /* - * Start up serial port - */ - retval = startup(info); - if (retval) - return retval; - - retval = block_til_ready(tty, filp, info); - if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open returning after block_til_ready with %d\n", - retval); -#endif - return retval; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s successful...", tty->name); -#endif - return 0; -} - -/* - * /proc fs routines.... - */ - -static inline int line_info(char *buf, struct serial_state *state) -{ -#ifdef notdef - struct async_struct *info = state->info, scr_info; - char stat_buf[30], control, status; -#endif - int ret; - - ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", - state->line, - (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC", - (unsigned int)(state->port), state->irq); - - if (!state->port || (state->type == PORT_UNKNOWN)) { - ret += sprintf(buf+ret, "\n"); - return ret; - } - -#ifdef notdef - /* - * Figure out the current RS-232 lines - */ - if (!info) { - info = &scr_info; /* This is just for serial_{in,out} */ - - info->magic = SERIAL_MAGIC; - info->port = state->port; - info->flags = state->flags; - info->quot = 0; - info->port.tty = NULL; - } - local_irq_disable(); - status = serial_in(info, UART_MSR); - control = info ? info->MCR : serial_in(info, UART_MCR); - local_irq_enable(); - - stat_buf[0] = 0; - stat_buf[1] = 0; - if (control & UART_MCR_RTS) - strcat(stat_buf, "|RTS"); - if (status & UART_MSR_CTS) - strcat(stat_buf, "|CTS"); - if (control & UART_MCR_DTR) - strcat(stat_buf, "|DTR"); - if (status & UART_MSR_DSR) - strcat(stat_buf, "|DSR"); - if (status & UART_MSR_DCD) - strcat(stat_buf, "|CD"); - if (status & UART_MSR_RI) - strcat(stat_buf, "|RI"); - - if (info->quot) { - ret += sprintf(buf+ret, " baud:%d", - state->baud_base / info->quot); - } - - ret += sprintf(buf+ret, " tx:%d rx:%d", - state->icount.tx, state->icount.rx); - - if (state->icount.frame) - ret += sprintf(buf+ret, " fe:%d", state->icount.frame); - - if (state->icount.parity) - ret += sprintf(buf+ret, " pe:%d", state->icount.parity); - - if (state->icount.brk) - ret += sprintf(buf+ret, " brk:%d", state->icount.brk); - - if (state->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); - - /* - * Last thing is the RS-232 status lines - */ - ret += sprintf(buf+ret, " %s\n", stat_buf+1); -#endif - return ret; -} - -int rs_360_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - int i, len = 0; - off_t begin = 0; - - len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); - for (i = 0; i < NR_PORTS && len < 4000; i++) { - len += line_info(page + len, &rs_table[i]); - if (len+begin > off+count) - goto done; - if (len+begin < off) { - begin += len; - len = 0; - } - } - *eof = 1; -done: - if (off >= len+begin) - return 0; - *start = page + (begin-off); - return ((count < begin+len-off) ? count : begin+len-off); -} - -/* - * --------------------------------------------------------------------- - * rs_init() and friends - * - * rs_init() is called at boot-time to initialize the serial driver. - * --------------------------------------------------------------------- - */ - -/* - * This routine prints out the appropriate serial driver version - * number, and identifies which options were configured into this - * driver. - */ -static _INLINE_ void show_serial_version(void) -{ - printk(KERN_INFO "%s version %s\n", serial_name, serial_version); -} - - -/* - * The serial console driver used during boot. Note that these names - * clash with those found in "serial.c", so we currently can't support - * the 16xxx uarts and these at the same time. I will fix this to become - * an indirect function call from tty_io.c (or something). - */ - -#ifdef CONFIG_SERIAL_CONSOLE - -/* - * Print a string to the serial port trying not to disturb any possible - * real use of the port... - */ -static void my_console_write(int idx, const char *s, - unsigned count) -{ - struct serial_state *ser; - ser_info_t *info; - unsigned i; - QUICC_BD *bdp, *bdbase; - volatile struct smc_uart_pram *up; - volatile u_char *cp; - - ser = rs_table + idx; - - - /* If the port has been initialized for general use, we have - * to use the buffer descriptors allocated there. Otherwise, - * we simply use the single buffer allocated. - */ - if ((info = (ser_info_t *)ser->info) != NULL) { - bdp = info->tx_cur; - bdbase = info->tx_bd_base; - } - else { - /* Pointer to UART in parameter ram. - */ - /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */ - up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u; - - /* Get the address of the host memory buffer. - */ - bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->tbase); - } - - /* - * We need to gracefully shut down the transmitter, disable - * interrupts, then send our bytes out. - */ - - /* - * Now, do each character. This is not as bad as it looks - * since this is a holding FIFO and not a transmitting FIFO. - * We could add the complexity of filling the entire transmit - * buffer, but we would just wait longer between accesses...... - */ - for (i = 0; i < count; i++, s++) { - /* Wait for transmitter fifo to empty. - * Ready indicates output is ready, and xmt is doing - * that, not that it is ready for us to send. - */ - while (bdp->status & BD_SC_READY); - - /* Send the character out. - */ - cp = bdp->buf; - *cp = *s; - - bdp->length = 1; - bdp->status |= BD_SC_READY; - - if (bdp->status & BD_SC_WRAP) - bdp = bdbase; - else - bdp++; - - /* if a LF, also do CR... */ - if (*s == 10) { - while (bdp->status & BD_SC_READY); - /* cp = __va(bdp->buf); */ - cp = bdp->buf; - *cp = 13; - bdp->length = 1; - bdp->status |= BD_SC_READY; - - if (bdp->status & BD_SC_WRAP) { - bdp = bdbase; - } - else { - bdp++; - } - } - } - - /* - * Finally, Wait for transmitter & holding register to empty - * and restore the IER - */ - while (bdp->status & BD_SC_READY); - - if (info) - info->tx_cur = (QUICC_BD *)bdp; -} - -static void serial_console_write(struct console *c, const char *s, - unsigned count) -{ -#ifdef CONFIG_KGDB - /* Try to let stub handle output. Returns true if it did. */ - if (kgdb_output_string(s, count)) - return; -#endif - my_console_write(c->index, s, count); -} - - - -/*void console_print_68360(const char *p) -{ - const char *cp = p; - int i; - - for (i=0;cp[i]!=0;i++); - - serial_console_write (p, i); - - //Comment this if you want to have a strict interrupt-driven output - //rs_fair_output(); - - return; -}*/ - - - - - - -#ifdef CONFIG_XMON -int -xmon_360_write(const char *s, unsigned count) -{ - my_console_write(0, s, count); - return(count); -} -#endif - -#ifdef CONFIG_KGDB -void -putDebugChar(char ch) -{ - my_console_write(0, &ch, 1); -} -#endif - -/* - * Receive character from the serial port. This only works well - * before the port is initialized for real use. - */ -static int my_console_wait_key(int idx, int xmon, char *obuf) -{ - struct serial_state *ser; - u_char c, *cp; - ser_info_t *info; - QUICC_BD *bdp; - volatile struct smc_uart_pram *up; - int i; - - ser = rs_table + idx; - - /* Get the address of the host memory buffer. - * If the port has been initialized for general use, we must - * use information from the port structure. - */ - if ((info = (ser_info_t *)ser->info)) - bdp = info->rx_cur; - else - /* bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */ - bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase); - - /* Pointer to UART in parameter ram. - */ - /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */ - up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; - - /* - * We need to gracefully shut down the receiver, disable - * interrupts, then read the input. - * XMON just wants a poll. If no character, return -1, else - * return the character. - */ - if (!xmon) { - while (bdp->status & BD_SC_EMPTY); - } - else { - if (bdp->status & BD_SC_EMPTY) - return -1; - } - - cp = (char *)bdp->buf; - - if (obuf) { - i = c = bdp->length; - while (i-- > 0) - *obuf++ = *cp++; - } - else { - c = *cp; - } - bdp->status |= BD_SC_EMPTY; - - if (info) { - if (bdp->status & BD_SC_WRAP) { - bdp = info->rx_bd_base; - } - else { - bdp++; - } - info->rx_cur = (QUICC_BD *)bdp; - } - - return((int)c); -} - -static int serial_console_wait_key(struct console *co) -{ - return(my_console_wait_key(co->index, 0, NULL)); -} - -#ifdef CONFIG_XMON -int -xmon_360_read_poll(void) -{ - return(my_console_wait_key(0, 1, NULL)); -} - -int -xmon_360_read_char(void) -{ - return(my_console_wait_key(0, 0, NULL)); -} -#endif - -#ifdef CONFIG_KGDB -static char kgdb_buf[RX_BUF_SIZE], *kgdp; -static int kgdb_chars; - -unsigned char -getDebugChar(void) -{ - if (kgdb_chars <= 0) { - kgdb_chars = my_console_wait_key(0, 0, kgdb_buf); - kgdp = kgdb_buf; - } - kgdb_chars--; - - return(*kgdp++); -} - -void kgdb_interruptible(int state) -{ -} -void kgdb_map_scc(void) -{ - struct serial_state *ser; - uint mem_addr; - volatile QUICC_BD *bdp; - volatile smc_uart_t *up; - - cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); - - /* To avoid data cache CPM DMA coherency problems, allocate a - * buffer in the CPM DPRAM. This will work until the CPM and - * serial ports are initialized. At that time a memory buffer - * will be allocated. - * The port is already initialized from the boot procedure, all - * we do here is give it a different buffer and make it a FIFO. - */ - - ser = rs_table; - - /* Right now, assume we are using SMCs. - */ - up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; - - /* Allocate space for an input FIFO, plus a few bytes for output. - * Allocate bytes to maintain word alignment. - */ - mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]); - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; - bdp->buf = mem_addr; - - bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase]; - bdp->buf = mem_addr+RX_BUF_SIZE; - - up->smc_mrblr = RX_BUF_SIZE; /* receive buffer length */ - up->smc_maxidl = RX_BUF_SIZE; -} -#endif - -static struct tty_struct *serial_console_device(struct console *c, int *index) -{ - *index = c->index; - return serial_driver; -} - - -struct console sercons = { - .name = "ttyS", - .write = serial_console_write, - .device = serial_console_device, - .wait_key = serial_console_wait_key, - .setup = serial_console_setup, - .flags = CON_PRINTBUFFER, - .index = CONFIG_SERIAL_CONSOLE_PORT, -}; - - - -/* - * Register console. - */ -long console_360_init(long kmem_start, long kmem_end) -{ - register_console(&sercons); - /*register_console (console_print_68360); - 2.0.38 only required a write - function pointer. */ - return kmem_start; -} - -#endif - -/* Index in baud rate table of the default console baud rate. -*/ -static int baud_idx; - -static const struct tty_operations rs_360_ops = { - .owner = THIS_MODULE, - .open = rs_360_open, - .close = rs_360_close, - .write = rs_360_write, - .put_char = rs_360_put_char, - .write_room = rs_360_write_room, - .chars_in_buffer = rs_360_chars_in_buffer, - .flush_buffer = rs_360_flush_buffer, - .ioctl = rs_360_ioctl, - .throttle = rs_360_throttle, - .unthrottle = rs_360_unthrottle, - /* .send_xchar = rs_360_send_xchar, */ - .set_termios = rs_360_set_termios, - .stop = rs_360_stop, - .start = rs_360_start, - .hangup = rs_360_hangup, - /* .wait_until_sent = rs_360_wait_until_sent, */ - /* .read_proc = rs_360_read_proc, */ - .tiocmget = rs_360_tiocmget, - .tiocmset = rs_360_tiocmset, - .get_icount = rs_360_get_icount, -}; - -static int __init rs_360_init(void) -{ - struct serial_state * state; - ser_info_t *info; - void *mem_addr; - uint dp_addr, iobits; - int i, j, idx; - ushort chan; - QUICC_BD *bdp; - volatile QUICC *cp; - volatile struct smc_regs *sp; - volatile struct smc_uart_pram *up; - volatile struct scc_regs *scp; - volatile struct uart_pram *sup; - /* volatile immap_t *immap; */ - - serial_driver = alloc_tty_driver(NR_PORTS); - if (!serial_driver) - return -1; - - show_serial_version(); - - serial_driver->name = "ttyS"; - serial_driver->major = TTY_MAJOR; - serial_driver->minor_start = 64; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = - baud_idx | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(serial_driver, &rs_360_ops); - - if (tty_register_driver(serial_driver)) - panic("Couldn't register serial driver\n"); - - cp = pquicc; /* Get pointer to Communication Processor */ - /* immap = (immap_t *)IMAP_ADDR; */ /* and to internal registers */ - - - /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O. - */ - /* The "standard" configuration through the 860. - */ -/* immap->im_ioport.iop_papar |= 0x00fc; */ -/* immap->im_ioport.iop_padir &= ~0x00fc; */ -/* immap->im_ioport.iop_paodr &= ~0x00fc; */ - cp->pio_papar |= 0x00fc; - cp->pio_padir &= ~0x00fc; - /* cp->pio_paodr &= ~0x00fc; */ - - - /* Since we don't yet do modem control, connect the port C pins - * as general purpose I/O. This will assert CTS and CD for the - * SCC ports. - */ - /* FIXME: see 360um p.7-365 and 860um p.34-12 - * I can't make sense of these bits - mleslie*/ -/* immap->im_ioport.iop_pcdir |= 0x03c6; */ -/* immap->im_ioport.iop_pcpar &= ~0x03c6; */ - -/* cp->pio_pcdir |= 0x03c6; */ -/* cp->pio_pcpar &= ~0x03c6; */ - - - - /* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and - * BRG4 to SCC3. - */ - cp->si_sicr &= ~0x00ffff00; - cp->si_sicr |= 0x001b1200; - -#ifdef CONFIG_PP04 - /* Frequentis PP04 forced to RS-232 until we know better. - * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4. - */ - immap->im_ioport.iop_pcdir |= 0x000c; - immap->im_ioport.iop_pcpar &= ~0x000c; - immap->im_ioport.iop_pcdat &= ~0x000c; - - /* This enables the TX driver. - */ - cp->cp_pbpar &= ~0x6000; - cp->cp_pbdat &= ~0x6000; -#endif - - for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { - state->magic = SSTATE_MAGIC; - state->line = i; - state->type = PORT_UNKNOWN; - state->custom_divisor = 0; - state->close_delay = 5*HZ/10; - state->closing_wait = 30*HZ; - state->icount.cts = state->icount.dsr = - state->icount.rng = state->icount.dcd = 0; - state->icount.rx = state->icount.tx = 0; - state->icount.frame = state->icount.parity = 0; - state->icount.overrun = state->icount.brk = 0; - printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n", - i, (unsigned int)(state->irq), - (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC"); - -#ifdef CONFIG_SERIAL_CONSOLE - /* If we just printed the message on the console port, and - * we are about to initialize it for general use, we have - * to wait a couple of character times for the CR/NL to - * make it out of the transmit buffer. - */ - if (i == CONFIG_SERIAL_CONSOLE_PORT) - mdelay(8); - - -/* idx = PORT_NUM(info->state->smc_scc_num); */ -/* if (info->state->smc_scc_num & NUM_IS_SCC) */ -/* chan = scc_chan_map[idx]; */ -/* else */ -/* chan = smc_chan_map[idx]; */ - -/* cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; */ -/* while (cp->cp_cr & CPM_CR_FLG); */ - -#endif - /* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */ - info = &quicc_ser_info[i]; - if (info) { - memset (info, 0, sizeof(ser_info_t)); - info->magic = SERIAL_MAGIC; - info->line = i; - info->flags = state->flags; - INIT_WORK(&info->tqueue, do_softint, info); - INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - info->state = state; - state->info = (struct async_struct *)info; - - /* We need to allocate a transmit and receive buffer - * descriptors from dual port ram, and a character - * buffer area from host mem. - */ - dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO); - - /* Allocate space for FIFOs in the host memory. - * (for now this is from a static array of buffers :( - */ - /* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); */ - /* mem_addr = kmalloc (RX_NUM_FIFO * RX_BUF_SIZE, GFP_BUFFER); */ - mem_addr = &rx_buf_pool[i * RX_NUM_FIFO * RX_BUF_SIZE]; - - /* Set the physical address of the host memory - * buffers in the buffer descriptors, and the - * virtual address for us to work with. - */ - bdp = (QUICC_BD *)((uint)pquicc + dp_addr); - info->rx_cur = info->rx_bd_base = bdp; - - /* initialize rx buffer descriptors */ - for (j=0; j<(RX_NUM_FIFO-1); j++) { - bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE]; - bdp->status = BD_SC_EMPTY | BD_SC_INTRPT; - mem_addr += RX_BUF_SIZE; - bdp++; - } - bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE]; - bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; - - - idx = PORT_NUM(info->state->smc_scc_num); - if (info->state->smc_scc_num & NUM_IS_SCC) { - -#if defined (CONFIG_UCQUICC) && 1 - /* set the transceiver mode to RS232 */ - sipex_mode_bits &= ~(uint)SIPEX_MODE(idx,0x0f); /* clear current mode */ - sipex_mode_bits |= (uint)SIPEX_MODE(idx,0x02); - *(uint *)_periph_base = sipex_mode_bits; - /* printk ("sipex bits = 0x%08x\n", sipex_mode_bits); */ -#endif - } - - dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_NUM_FIFO); - - /* Allocate space for FIFOs in the host memory. - */ - /* mem_addr = m360_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); */ - /* mem_addr = kmalloc (TX_NUM_FIFO * TX_BUF_SIZE, GFP_BUFFER); */ - mem_addr = &tx_buf_pool[i * TX_NUM_FIFO * TX_BUF_SIZE]; - - /* Set the physical address of the host memory - * buffers in the buffer descriptors, and the - * virtual address for us to work with. - */ - /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */ - bdp = (QUICC_BD *)((uint)pquicc + dp_addr); - info->tx_cur = info->tx_bd_base = (QUICC_BD *)bdp; - - /* initialize tx buffer descriptors */ - for (j=0; j<(TX_NUM_FIFO-1); j++) { - bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE]; - bdp->status = BD_SC_INTRPT; - mem_addr += TX_BUF_SIZE; - bdp++; - } - bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE]; - bdp->status = (BD_SC_WRAP | BD_SC_INTRPT); - - if (info->state->smc_scc_num & NUM_IS_SCC) { - scp = &pquicc->scc_regs[idx]; - sup = &pquicc->pram[info->state->port].scc.pscc.u; - sup->rbase = dp_addr; - sup->tbase = dp_addr; - - /* Set up the uart parameters in the - * parameter ram. - */ - sup->rfcr = SMC_EB; - sup->tfcr = SMC_EB; - - /* Set this to 1 for now, so we get single - * character interrupts. Using idle character - * time requires some additional tuning. - */ - sup->mrblr = 1; - sup->max_idl = 0; - sup->brkcr = 1; - sup->parec = 0; - sup->frmer = 0; - sup->nosec = 0; - sup->brkec = 0; - sup->uaddr1 = 0; - sup->uaddr2 = 0; - sup->toseq = 0; - { - int i; - for (i=0;i<8;i++) - sup->cc[i] = 0x8000; - } - sup->rccm = 0xc0ff; - - /* Send the CPM an initialize command. - */ - chan = scc_chan_map[idx]; - - /* execute the INIT RX & TX PARAMS command for this channel. */ - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - scp->scc_gsmr.w.high = 0; - scp->scc_gsmr.w.low = - (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); - - /* Disable all interrupts and clear all pending - * events. - */ - scp->scc_sccm = 0; - scp->scc_scce = 0xffff; - scp->scc_dsr = 0x7e7e; - scp->scc_psmr = 0x3000; - - /* If the port is the console, enable Rx and Tx. - */ -#ifdef CONFIG_SERIAL_CONSOLE - if (i == CONFIG_SERIAL_CONSOLE_PORT) - scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#endif - } - else { - /* Configure SMCs Tx/Rx instead of port B - * parallel I/O. - */ - up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u; - up->rbase = dp_addr; - - iobits = 0xc0 << (idx * 4); - cp->pip_pbpar |= iobits; - cp->pip_pbdir &= ~iobits; - cp->pip_pbodr &= ~iobits; - - - /* Connect the baud rate generator to the - * SMC based upon index in rs_table. Also - * make sure it is connected to NMSI. - */ - cp->si_simode &= ~(0xffff << (idx * 16)); - cp->si_simode |= (i << ((idx * 16) + 12)); - - up->tbase = dp_addr; - - /* Set up the uart parameters in the - * parameter ram. - */ - up->rfcr = SMC_EB; - up->tfcr = SMC_EB; - - /* Set this to 1 for now, so we get single - * character interrupts. Using idle character - * time requires some additional tuning. - */ - up->mrblr = 1; - up->max_idl = 0; - up->brkcr = 1; - - /* Send the CPM an initialize command. - */ - chan = smc_chan_map[idx]; - - cp->cp_cr = mk_cr_cmd(chan, - CPM_CR_INIT_TRX) | CPM_CR_FLG; -#ifdef CONFIG_SERIAL_CONSOLE - if (i == CONFIG_SERIAL_CONSOLE_PORT) - printk(""); -#endif - while (cp->cp_cr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp = &cp->smc_regs[idx]; - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Disable all interrupts and clear all pending - * events. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - - /* If the port is the console, enable Rx and Tx. - */ -#ifdef CONFIG_SERIAL_CONSOLE - if (i == CONFIG_SERIAL_CONSOLE_PORT) - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; -#endif - } - - /* Install interrupt handler. - */ - /* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info); */ - /*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */ - request_irq(state->irq, rs_360_interrupt, - IRQ_FLG_LOCK, "ttyS", (void *)info); - - /* Set up the baud rate generator. - */ - m360_cpm_setbrg(i, baud_table[baud_idx]); - - } - } - - return 0; -} -module_init(rs_360_init); - -/* This must always be called before the rs_360_init() function, otherwise - * it blows away the port control information. - */ -//static int __init serial_console_setup( struct console *co, char *options) -int serial_console_setup( struct console *co, char *options) -{ - struct serial_state *ser; - uint mem_addr, dp_addr, bidx, idx, iobits; - ushort chan; - QUICC_BD *bdp; - volatile QUICC *cp; - volatile struct smc_regs *sp; - volatile struct scc_regs *scp; - volatile struct smc_uart_pram *up; - volatile struct uart_pram *sup; - -/* mleslie TODO: - * add something to the 68k bootloader to store a desired initial console baud rate */ - -/* bd_t *bd; */ /* a board info struct used by EPPC-bug */ -/* bd = (bd_t *)__res; */ - - for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++) - /* if (bd->bi_baudrate == baud_table[bidx]) */ - if (CONSOLE_BAUDRATE == baud_table[bidx]) - break; - - /* co->cflag = CREAD|CLOCAL|bidx|CS8; */ - baud_idx = bidx; - - ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT; - - cp = pquicc; /* Get pointer to Communication Processor */ - - idx = PORT_NUM(ser->smc_scc_num); - if (ser->smc_scc_num & NUM_IS_SCC) { - - /* TODO: need to set up SCC pin assignment etc. here */ - - } - else { - iobits = 0xc0 << (idx * 4); - cp->pip_pbpar |= iobits; - cp->pip_pbdir &= ~iobits; - cp->pip_pbodr &= ~iobits; - - /* Connect the baud rate generator to the - * SMC based upon index in rs_table. Also - * make sure it is connected to NMSI. - */ - cp->si_simode &= ~(0xffff << (idx * 16)); - cp->si_simode |= (idx << ((idx * 16) + 12)); - } - - /* When we get here, the CPM has been reset, so we need - * to configure the port. - * We need to allocate a transmit and receive buffer descriptor - * from dual port ram, and a character buffer area from host mem. - */ - - /* Allocate space for two buffer descriptors in the DP ram. - */ - dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * CONSOLE_NUM_FIFO); - - /* Allocate space for two 2 byte FIFOs in the host memory. - */ - /* mem_addr = m360_cpm_hostalloc(8); */ - mem_addr = (uint)console_fifos; - - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */ - bdp = (QUICC_BD *)((uint)pquicc + dp_addr); - bdp->buf = (char *)mem_addr; - (bdp+1)->buf = (char *)(mem_addr+4); - - /* For the receive, set empty and wrap. - * For transmit, set wrap. - */ - bdp->status = BD_SC_EMPTY | BD_SC_WRAP; - (bdp+1)->status = BD_SC_WRAP; - - /* Set up the uart parameters in the parameter ram. - */ - if (ser->smc_scc_num & NUM_IS_SCC) { - scp = &cp->scc_regs[idx]; - /* sup = (scc_uart_t *)&cp->cp_dparam[ser->port]; */ - sup = &pquicc->pram[ser->port].scc.pscc.u; - - sup->rbase = dp_addr; - sup->tbase = dp_addr + sizeof(QUICC_BD); - - /* Set up the uart parameters in the - * parameter ram. - */ - sup->rfcr = SMC_EB; - sup->tfcr = SMC_EB; - - /* Set this to 1 for now, so we get single - * character interrupts. Using idle character - * time requires some additional tuning. - */ - sup->mrblr = 1; - sup->max_idl = 0; - sup->brkcr = 1; - sup->parec = 0; - sup->frmer = 0; - sup->nosec = 0; - sup->brkec = 0; - sup->uaddr1 = 0; - sup->uaddr2 = 0; - sup->toseq = 0; - { - int i; - for (i=0;i<8;i++) - sup->cc[i] = 0x8000; - } - sup->rccm = 0xc0ff; - - /* Send the CPM an initialize command. - */ - chan = scc_chan_map[idx]; - - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - scp->scc_gsmr.w.high = 0; - scp->scc_gsmr.w.low = - (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); - - /* Disable all interrupts and clear all pending - * events. - */ - scp->scc_sccm = 0; - scp->scc_scce = 0xffff; - scp->scc_dsr = 0x7e7e; - scp->scc_psmr = 0x3000; - - scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - } - else { - /* up = (smc_uart_t *)&cp->cp_dparam[ser->port]; */ - up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u; - - up->rbase = dp_addr; /* Base of receive buffer desc. */ - up->tbase = dp_addr+sizeof(QUICC_BD); /* Base of xmt buffer desc. */ - up->rfcr = SMC_EB; - up->tfcr = SMC_EB; - - /* Set this to 1 for now, so we get single character interrupts. - */ - up->mrblr = 1; /* receive buffer length */ - up->max_idl = 0; /* wait forever for next char */ - - /* Send the CPM an initialize command. - */ - chan = smc_chan_map[idx]; - cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp = &cp->smc_regs[idx]; - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* And finally, enable Rx and Tx. - */ - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; - } - - /* Set up the baud rate generator. - */ - /* m360_cpm_setbrg((ser - rs_table), bd->bi_baudrate); */ - m360_cpm_setbrg((ser - rs_table), CONSOLE_BAUDRATE); - - return 0; -} - -/* - * Local variables: - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c index 7f50999eebc2..a87a56cb5417 100644 --- a/drivers/tty/serial/8250.c +++ b/drivers/tty/serial/8250.c @@ -309,6 +309,13 @@ static const struct serial8250_config uart_config[] = { UART_FCR_T_TRIG_01, .flags = UART_CAP_FIFO | UART_CAP_RTOIE, }, + [PORT_XR17D15X] = { + .name = "XR17D15X", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR, + }, }; #if defined(CONFIG_MIPS_ALCHEMY) @@ -461,42 +468,6 @@ static void tsi_serial_out(struct uart_port *p, int offset, int value) writeb(value, p->membase + offset); } -/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */ -static inline void dwapb_save_out_value(struct uart_port *p, int offset, - int value) -{ - struct uart_8250_port *up = - container_of(p, struct uart_8250_port, port); - - if (offset == UART_LCR) - up->lcr = value; -} - -/* Read the IER to ensure any interrupt is cleared before returning from ISR. */ -static inline void dwapb_check_clear_ier(struct uart_port *p, int offset) -{ - if (offset == UART_TX || offset == UART_IER) - p->serial_in(p, UART_IER); -} - -static void dwapb_serial_out(struct uart_port *p, int offset, int value) -{ - int save_offset = offset; - offset = map_8250_out_reg(p, offset) << p->regshift; - dwapb_save_out_value(p, save_offset, value); - writeb(value, p->membase + offset); - dwapb_check_clear_ier(p, save_offset); -} - -static void dwapb32_serial_out(struct uart_port *p, int offset, int value) -{ - int save_offset = offset; - offset = map_8250_out_reg(p, offset) << p->regshift; - dwapb_save_out_value(p, save_offset, value); - writel(value, p->membase + offset); - dwapb_check_clear_ier(p, save_offset); -} - static unsigned int io_serial_in(struct uart_port *p, int offset) { offset = map_8250_in_reg(p, offset) << p->regshift; @@ -509,6 +480,8 @@ static void io_serial_out(struct uart_port *p, int offset, int value) outb(value, p->iobase + offset); } +static int serial8250_default_handle_irq(struct uart_port *port); + static void set_io_from_upio(struct uart_port *p) { struct uart_8250_port *up = @@ -540,16 +513,6 @@ static void set_io_from_upio(struct uart_port *p) p->serial_out = tsi_serial_out; break; - case UPIO_DWAPB: - p->serial_in = mem_serial_in; - p->serial_out = dwapb_serial_out; - break; - - case UPIO_DWAPB32: - p->serial_in = mem32_serial_in; - p->serial_out = dwapb32_serial_out; - break; - default: p->serial_in = io_serial_in; p->serial_out = io_serial_out; @@ -557,6 +520,7 @@ static void set_io_from_upio(struct uart_port *p) } /* Remember loaded iotype */ up->cur_iotype = p->iotype; + p->handle_irq = serial8250_default_handle_irq; } static void @@ -567,8 +531,6 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value) case UPIO_MEM: case UPIO_MEM32: case UPIO_AU: - case UPIO_DWAPB: - case UPIO_DWAPB32: p->serial_out(p, offset, value); p->serial_in(p, UART_LCR); /* safe, no side-effects */ break; @@ -1120,6 +1082,14 @@ static void autoconfig_16550a(struct uart_8250_port *up) serial_outp(up, UART_IER, iersave); /* + * Exar uarts have EFR in a weird location + */ + if (up->port.flags & UPF_EXAR_EFR) { + up->port.type = PORT_XR17D15X; + up->capabilities |= UART_CAP_AFE | UART_CAP_EFR; + } + + /* * We distinguish between 16550A and U6 16550A by counting * how many bytes are in the FIFO. */ @@ -1621,6 +1591,29 @@ static void serial8250_handle_port(struct uart_8250_port *up) spin_unlock_irqrestore(&up->port.lock, flags); } +int serial8250_handle_irq(struct uart_port *port, unsigned int iir) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + if (!(iir & UART_IIR_NO_INT)) { + serial8250_handle_port(up); + return 1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(serial8250_handle_irq); + +static int serial8250_default_handle_irq(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + unsigned int iir = serial_in(up, UART_IIR); + + return serial8250_handle_irq(port, iir); +} + /* * This is the serial driver's interrupt routine. * @@ -1648,30 +1641,13 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) l = i->head; do { struct uart_8250_port *up; - unsigned int iir; + struct uart_port *port; up = list_entry(l, struct uart_8250_port, list); + port = &up->port; - iir = serial_in(up, UART_IIR); - if (!(iir & UART_IIR_NO_INT)) { - serial8250_handle_port(up); - + if (port->handle_irq(port)) { handled = 1; - - end = NULL; - } else if ((up->port.iotype == UPIO_DWAPB || - up->port.iotype == UPIO_DWAPB32) && - (iir & UART_IIR_BUSY) == UART_IIR_BUSY) { - /* The DesignWare APB UART has an Busy Detect (0x07) - * interrupt meaning an LCR write attempt occurred while the - * UART was busy. The interrupt must be cleared by reading - * the UART status register (USR) and the LCR re-written. */ - unsigned int status; - status = *(volatile u32 *)up->port.private_data; - serial_out(up, UART_LCR, up->lcr); - - handled = 1; - end = NULL; } else if (end == NULL) end = l; @@ -2081,8 +2057,8 @@ static int serial8250_startup(struct uart_port *port) */ if (!(up->port.flags & UPF_BUGGY_UART) && (serial_inp(up, UART_LSR) == 0xff)) { - printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n", - serial_index(&up->port)); + printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", + serial_index(&up->port)); return -ENODEV; } @@ -2458,7 +2434,10 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, efr |= UART_EFR_CTS; serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_outp(up, UART_EFR, efr); + if (up->port.flags & UPF_EXAR_EFR) + serial_outp(up, UART_XR_EFR, efr); + else + serial_outp(up, UART_EFR, efr); } #ifdef CONFIG_ARCH_OMAP @@ -2570,8 +2549,6 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) case UPIO_TSI: case UPIO_MEM32: case UPIO_MEM: - case UPIO_DWAPB: - case UPIO_DWAPB32: if (!up->port.mapbase) break; @@ -2608,8 +2585,6 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) case UPIO_TSI: case UPIO_MEM32: case UPIO_MEM: - case UPIO_DWAPB: - case UPIO_DWAPB32: if (!up->port.mapbase) break; @@ -3050,6 +3025,10 @@ int __init early_serial_setup(struct uart_port *port) p->serial_in = port->serial_in; if (port->serial_out) p->serial_out = port->serial_out; + if (port->handle_irq) + p->handle_irq = port->handle_irq; + else + p->handle_irq = serial8250_default_handle_irq; return 0; } @@ -3118,6 +3097,7 @@ static int __devinit serial8250_probe(struct platform_device *dev) port.type = p->type; port.serial_in = p->serial_in; port.serial_out = p->serial_out; + port.handle_irq = p->handle_irq; port.set_termios = p->set_termios; port.pm = p->pm; port.dev = &dev->dev; @@ -3283,6 +3263,8 @@ int serial8250_register_port(struct uart_port *port) uart->port.serial_in = port->serial_in; if (port->serial_out) uart->port.serial_out = port->serial_out; + if (port->handle_irq) + uart->port.handle_irq = port->handle_irq; /* Possibly override set_termios call */ if (port->set_termios) uart->port.set_termios = port->set_termios; diff --git a/drivers/tty/serial/8250_dw.c b/drivers/tty/serial/8250_dw.c new file mode 100644 index 000000000000..bf1fba640c2d --- /dev/null +++ b/drivers/tty/serial/8250_dw.c @@ -0,0 +1,194 @@ +/* + * Synopsys DesignWare 8250 driver. + * + * Copyright 2011 Picochip, Jamie Iles. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The Synopsys DesignWare 8250 has an extra feature whereby it detects if the + * LCR is written whilst busy. If it is, then a busy detect interrupt is + * raised, the LCR needs to be rewritten and the uart status register read. + */ +#include <linux/device.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/serial_8250.h> +#include <linux/serial_core.h> +#include <linux/serial_reg.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +struct dw8250_data { + int last_lcr; + int line; +}; + +static void dw8250_serial_out(struct uart_port *p, int offset, int value) +{ + struct dw8250_data *d = p->private_data; + + if (offset == UART_LCR) + d->last_lcr = value; + + offset <<= p->regshift; + writeb(value, p->membase + offset); +} + +static unsigned int dw8250_serial_in(struct uart_port *p, int offset) +{ + offset <<= p->regshift; + + return readb(p->membase + offset); +} + +static void dw8250_serial_out32(struct uart_port *p, int offset, int value) +{ + struct dw8250_data *d = p->private_data; + + if (offset == UART_LCR) + d->last_lcr = value; + + offset <<= p->regshift; + writel(value, p->membase + offset); +} + +static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) +{ + offset <<= p->regshift; + + return readl(p->membase + offset); +} + +/* Offset for the DesignWare's UART Status Register. */ +#define UART_USR 0x1f + +static int dw8250_handle_irq(struct uart_port *p) +{ + struct dw8250_data *d = p->private_data; + unsigned int iir = p->serial_in(p, UART_IIR); + + if (serial8250_handle_irq(p, iir)) { + return 1; + } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { + /* Clear the USR and write the LCR again. */ + (void)p->serial_in(p, UART_USR); + p->serial_out(p, d->last_lcr, UART_LCR); + + return 1; + } + + return 0; +} + +static int __devinit dw8250_probe(struct platform_device *pdev) +{ + struct uart_port port = {}; + struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + struct device_node *np = pdev->dev.of_node; + u32 val; + struct dw8250_data *data; + + if (!regs || !irq) { + dev_err(&pdev->dev, "no registers/irq defined\n"); + return -EINVAL; + } + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + port.private_data = data; + + spin_lock_init(&port.lock); + port.mapbase = regs->start; + port.irq = irq->start; + port.handle_irq = dw8250_handle_irq; + port.type = PORT_8250; + port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | + UPF_FIXED_PORT | UPF_FIXED_TYPE; + port.dev = &pdev->dev; + + port.iotype = UPIO_MEM; + port.serial_in = dw8250_serial_in; + port.serial_out = dw8250_serial_out; + if (!of_property_read_u32(np, "reg-io-width", &val)) { + switch (val) { + case 1: + break; + case 4: + port.iotype = UPIO_MEM32; + port.serial_in = dw8250_serial_in32; + port.serial_out = dw8250_serial_out32; + break; + default: + dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n", + val); + return -EINVAL; + } + } + + if (!of_property_read_u32(np, "reg-shift", &val)) + port.regshift = val; + + if (of_property_read_u32(np, "clock-frequency", &val)) { + dev_err(&pdev->dev, "no clock-frequency property set\n"); + return -EINVAL; + } + port.uartclk = val; + + data->line = serial8250_register_port(&port); + if (data->line < 0) + return data->line; + + platform_set_drvdata(pdev, data); + + return 0; +} + +static int __devexit dw8250_remove(struct platform_device *pdev) +{ + struct dw8250_data *data = platform_get_drvdata(pdev); + + serial8250_unregister_port(data->line); + + return 0; +} + +static const struct of_device_id dw8250_match[] = { + { .compatible = "snps,dw-apb-uart" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dw8250_match); + +static struct platform_driver dw8250_platform_driver = { + .driver = { + .name = "dw-apb-uart", + .owner = THIS_MODULE, + .of_match_table = dw8250_match, + }, + .probe = dw8250_probe, + .remove = __devexit_p(dw8250_remove), +}; + +static int __init dw8250_init(void) +{ + return platform_driver_register(&dw8250_platform_driver); +} +module_init(dw8250_init); + +static void __exit dw8250_exit(void) +{ + platform_driver_unregister(&dw8250_platform_driver); +} +module_exit(dw8250_exit); + +MODULE_AUTHOR("Jamie Iles"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver"); diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c index 3abeca2a2a1b..825937a5f210 100644 --- a/drivers/tty/serial/8250_pci.c +++ b/drivers/tty/serial/8250_pci.c @@ -1101,6 +1101,15 @@ static int pci_eg20t_init(struct pci_dev *dev) #endif } +static int +pci_xr17c154_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_port *port, int idx) +{ + port->flags |= UPF_EXAR_EFR; + return pci_default_setup(priv, board, port, idx); +} + /* This should be in linux/pci_ids.h */ #define PCI_VENDOR_ID_SBSMODULARIO 0x124B #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B @@ -1506,6 +1515,30 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_timedia_setup, }, /* + * Exar cards + */ + { + .vendor = PCI_VENDOR_ID_EXAR, + .device = PCI_DEVICE_ID_EXAR_XR17C152, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17c154_setup, + }, + { + .vendor = PCI_VENDOR_ID_EXAR, + .device = PCI_DEVICE_ID_EXAR_XR17C154, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17c154_setup, + }, + { + .vendor = PCI_VENDOR_ID_EXAR, + .device = PCI_DEVICE_ID_EXAR_XR17C158, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17c154_setup, + }, + /* * Xircom cards */ { @@ -1558,46 +1591,55 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x8811, .init = pci_eg20t_init, + .setup = pci_default_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x8812, .init = pci_eg20t_init, + .setup = pci_default_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x8813, .init = pci_eg20t_init, + .setup = pci_default_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x8814, .init = pci_eg20t_init, + .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x8027, .init = pci_eg20t_init, + .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x8028, .init = pci_eg20t_init, + .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x8029, .init = pci_eg20t_init, + .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x800C, .init = pci_eg20t_init, + .setup = pci_default_setup, }, { .vendor = 0x10DB, .device = 0x800D, .init = pci_eg20t_init, + .setup = pci_default_setup, }, /* * Cronyx Omega PCI (PLX-chip based) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 4dcb37bbdf92..5f479dada6f2 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -267,6 +267,13 @@ config SERIAL_8250_RM9K port hardware found on MIPS RM9122 and similar processors. If unsure, say N. +config SERIAL_8250_DW + tristate "Support for Synopsys DesignWare 8250 quirks" + depends on SERIAL_8250 && OF + help + Selecting this option will enable handling of the extra features + present in the Synopsys DesignWare APB UART. + comment "Non-8250 serial port support" config SERIAL_AMBA_PL010 @@ -522,8 +529,8 @@ config SERIAL_S3C6400 config SERIAL_S5PV210 tristate "Samsung S5PV210 Serial port support" - depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_EXYNOS4210) - select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_EXYNOS4210) + depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_EXYNOS4210 || SOC_EXYNOS4212) + select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_EXYNOS4210 || SOC_EXYNOS4212) default y help Serial port support for Samsung's S5P Family of SoC's @@ -722,7 +729,7 @@ config SERIAL_BFIN Add support for the built-in UARTs on the Blackfin. To compile this driver as a module, choose M here: the - module will be called bfin_5xx. + module is named bfin_uart.ko. config SERIAL_BFIN_CONSOLE bool "Console on Blackfin serial port" @@ -1035,23 +1042,6 @@ config SERIAL_MCF_CONSOLE help Enable a ColdFire internal serial port to be the system console. -config SERIAL_68360_SMC - bool "68360 SMC uart support" - depends on M68360 - help - This driver supports the SMC serial ports of the Motorola 68360 CPU. - -config SERIAL_68360_SCC - bool "68360 SCC uart support" - depends on M68360 - help - This driver supports the SCC serial ports of the Motorola 68360 CPU. - -config SERIAL_68360 - bool - depends on SERIAL_68360_SMC || SERIAL_68360_SCC - default y - config SERIAL_PMACZILOG tristate "Mac or PowerMac z85c30 ESCC support" depends on (M68K && MAC) || (PPC_OF && PPC_PMAC) diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 83b4da6a1062..e10cf5b54b6d 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o +obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o @@ -35,7 +36,7 @@ obj-$(CONFIG_SERIAL_PXA) += pxa.o obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o -obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o +obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o @@ -49,7 +50,6 @@ obj-$(CONFIG_SERIAL_MAX3107_AAVA) += max3107-aava.o obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o obj-$(CONFIG_SERIAL_MUX) += mux.o obj-$(CONFIG_SERIAL_68328) += 68328serial.o -obj-$(CONFIG_SERIAL_68360) += 68360serial.o obj-$(CONFIG_SERIAL_MCF) += mcf.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o obj-$(CONFIG_SERIAL_DZ) += dz.o diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index 60e049b041a7..530181e49f6b 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -18,6 +18,7 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/console.h> +#include <linux/of.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial.h> @@ -218,7 +219,7 @@ static int altera_jtaguart_startup(struct uart_port *port) unsigned long flags; int ret; - ret = request_irq(port->irq, altera_jtaguart_interrupt, IRQF_DISABLED, + ret = request_irq(port->irq, altera_jtaguart_interrupt, 0, DRV_NAME, port); if (ret) { pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d " @@ -472,8 +473,6 @@ static struct of_device_id altera_jtaguart_match[] = { {}, }; MODULE_DEVICE_TABLE(of, altera_jtaguart_match); -#else -#define altera_jtaguart_match NULL #endif /* CONFIG_OF */ static struct platform_driver altera_jtaguart_platform_driver = { @@ -482,7 +481,7 @@ static struct platform_driver altera_jtaguart_platform_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, - .of_match_table = altera_jtaguart_match, + .of_match_table = of_match_ptr(altera_jtaguart_match), }, }; diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 50bc5a5ac653..1d04c5037f25 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -315,7 +315,7 @@ static int altera_uart_startup(struct uart_port *port) return 0; } - ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED, + ret = request_irq(port->irq, altera_uart_interrupt, 0, DRV_NAME, port); if (ret) { pr_err(DRV_NAME ": unable to attach Altera UART %d " @@ -616,8 +616,6 @@ static struct of_device_id altera_uart_match[] = { {}, }; MODULE_DEVICE_TABLE(of, altera_uart_match); -#else -#define altera_uart_match NULL #endif /* CONFIG_OF */ static struct platform_driver altera_uart_platform_driver = { @@ -626,7 +624,7 @@ static struct platform_driver altera_uart_platform_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, - .of_match_table = altera_uart_match, + .of_match_table = of_match_ptr(altera_uart_match), }, }; diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index c0d10c4ddb73..efdf92c3a352 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -312,12 +312,16 @@ static int pl010_startup(struct uart_port *port) struct uart_amba_port *uap = (struct uart_amba_port *)port; int retval; + retval = clk_prepare(uap->clk); + if (retval) + goto out; + /* * Try to enable the clock producer. */ retval = clk_enable(uap->clk); if (retval) - goto out; + goto clk_unprep; uap->port.uartclk = clk_get_rate(uap->clk); @@ -343,6 +347,8 @@ static int pl010_startup(struct uart_port *port) clk_dis: clk_disable(uap->clk); + clk_unprep: + clk_unprepare(uap->clk); out: return retval; } @@ -370,6 +376,7 @@ static void pl010_shutdown(struct uart_port *port) * Shut down the clock producer */ clk_disable(uap->clk); + clk_unprepare(uap->clk); } static void @@ -626,6 +633,7 @@ static int __init pl010_console_setup(struct console *co, char *options) int bits = 8; int parity = 'n'; int flow = 'n'; + int ret; /* * Check whether an invalid uart number has been specified, and @@ -638,6 +646,10 @@ static int __init pl010_console_setup(struct console *co, char *options) if (!uap) return -ENODEV; + ret = clk_prepare(uap->clk); + if (ret) + return ret; + uap->port.uartclk = clk_get_rate(uap->clk); if (options) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index f5f6831b0a64..00233af1acc4 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1367,12 +1367,16 @@ static int pl011_startup(struct uart_port *port) unsigned int cr; int retval; + retval = clk_prepare(uap->clk); + if (retval) + goto out; + /* * Try to enable the clock producer. */ retval = clk_enable(uap->clk); if (retval) - goto out; + goto clk_unprep; uap->port.uartclk = clk_get_rate(uap->clk); @@ -1446,6 +1450,8 @@ static int pl011_startup(struct uart_port *port) clk_dis: clk_disable(uap->clk); + clk_unprep: + clk_unprepare(uap->clk); out: return retval; } @@ -1497,6 +1503,7 @@ static void pl011_shutdown(struct uart_port *port) * Shut down the clock producer */ clk_disable(uap->clk); + clk_unprepare(uap->clk); if (uap->port.dev->platform_data) { struct amba_pl011_data *plat; @@ -1800,6 +1807,7 @@ static int __init pl011_console_setup(struct console *co, char *options) int bits = 8; int parity = 'n'; int flow = 'n'; + int ret; /* * Check whether an invalid uart number has been specified, and @@ -1812,6 +1820,10 @@ static int __init pl011_console_setup(struct console *co, char *options) if (!uap) return -ENODEV; + ret = clk_prepare(uap->clk); + if (ret) + return ret; + if (uap->port.dev->platform_data) { struct amba_pl011_data *plat; diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 19a943693e4c..77554fd68d1f 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/serial.h> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index b922f5d2e61e..4a0f86fa1e90 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -33,6 +33,8 @@ #include <linux/sysrq.h> #include <linux/tty_flip.h> #include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/dma-mapping.h> #include <linux/atmel_pdc.h> #include <linux/atmel_serial.h> @@ -46,7 +48,7 @@ #ifdef CONFIG_ARM #include <mach/cpu.h> -#include <mach/gpio.h> +#include <asm/gpio.h> #endif #define PDC_BUFFER_SIZE 512 @@ -157,11 +159,22 @@ struct atmel_uart_port { }; static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; +static unsigned long atmel_ports_in_use; #ifdef SUPPORT_SYSRQ static struct console atmel_console; #endif +#if defined(CONFIG_OF) +static const struct of_device_id atmel_serial_dt_ids[] = { + { .compatible = "atmel,at91rm9200-usart" }, + { .compatible = "atmel,at91sam9260-usart" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, atmel_serial_dt_ids); +#endif + static inline struct atmel_uart_port * to_atmel_uart_port(struct uart_port *uart) { @@ -339,7 +352,8 @@ static void atmel_stop_tx(struct uart_port *port) /* Disable interrupts */ UART_PUT_IDR(port, atmel_port->tx_done_mask); - if (atmel_port->rs485.flags & SER_RS485_ENABLED) + if ((atmel_port->rs485.flags & SER_RS485_ENABLED) && + !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX)) atmel_start_rx(port); } @@ -356,7 +370,8 @@ static void atmel_start_tx(struct uart_port *port) really need this.*/ return; - if (atmel_port->rs485.flags & SER_RS485_ENABLED) + if ((atmel_port->rs485.flags & SER_RS485_ENABLED) && + !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX)) atmel_stop_rx(port); /* re-enable PDC transmit */ @@ -680,7 +695,8 @@ static void atmel_tx_dma(struct uart_port *port) /* Enable interrupts */ UART_PUT_IER(port, atmel_port->tx_done_mask); } else { - if (atmel_port->rs485.flags & SER_RS485_ENABLED) { + if ((atmel_port->rs485.flags & SER_RS485_ENABLED) && + !(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX)) { /* DMA done, stop TX, start RX for RS485 */ atmel_start_rx(port); } @@ -1407,6 +1423,48 @@ static struct uart_ops atmel_pops = { #endif }; +static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port, + struct device_node *np) +{ + u32 rs485_delay[2]; + + /* DMA/PDC usage specification */ + if (of_get_property(np, "atmel,use-dma-rx", NULL)) + atmel_port->use_dma_rx = 1; + else + atmel_port->use_dma_rx = 0; + if (of_get_property(np, "atmel,use-dma-tx", NULL)) + atmel_port->use_dma_tx = 1; + else + atmel_port->use_dma_tx = 0; + + /* rs485 properties */ + if (of_property_read_u32_array(np, "rs485-rts-delay", + rs485_delay, 2) == 0) { + struct serial_rs485 *rs485conf = &atmel_port->rs485; + + rs485conf->delay_rts_before_send = rs485_delay[0]; + rs485conf->delay_rts_after_send = rs485_delay[1]; + rs485conf->flags = 0; + + if (rs485conf->delay_rts_before_send == 0 && + rs485conf->delay_rts_after_send == 0) { + rs485conf->flags |= SER_RS485_RTS_ON_SEND; + } else { + if (rs485conf->delay_rts_before_send) + rs485conf->flags |= SER_RS485_RTS_BEFORE_SEND; + if (rs485conf->delay_rts_after_send) + rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; + } + + if (of_get_property(np, "rs485-rx-during-tx", NULL)) + rs485conf->flags |= SER_RS485_RX_DURING_TX; + + if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL)) + rs485conf->flags |= SER_RS485_ENABLED; + } +} + /* * Configure the port from the platform device resource info. */ @@ -1414,13 +1472,20 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev) { struct uart_port *port = &atmel_port->uart; - struct atmel_uart_data *data = pdev->dev.platform_data; + struct atmel_uart_data *pdata = pdev->dev.platform_data; + + if (pdev->dev.of_node) { + atmel_of_init_port(atmel_port, pdev->dev.of_node); + } else { + atmel_port->use_dma_rx = pdata->use_dma_rx; + atmel_port->use_dma_tx = pdata->use_dma_tx; + atmel_port->rs485 = pdata->rs485; + } port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF; port->ops = &atmel_pops; port->fifosize = 1; - port->line = data->num; port->dev = &pdev->dev; port->mapbase = pdev->resource[0].start; port->irq = pdev->resource[1].start; @@ -1430,10 +1495,10 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); - if (data->regs) + if (pdata && pdata->regs) { /* Already mapped by setup code */ - port->membase = data->regs; - else { + port->membase = pdata->regs; + } else { port->flags |= UPF_IOREMAP; port->membase = NULL; } @@ -1447,9 +1512,6 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, /* only enable clock when USART is in use */ } - atmel_port->use_dma_rx = data->use_dma_rx; - atmel_port->use_dma_tx = data->use_dma_tx; - atmel_port->rs485 = data->rs485; /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */ if (atmel_port->rs485.flags & SER_RS485_ENABLED) atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; @@ -1611,10 +1673,14 @@ static int __init atmel_console_init(void) if (atmel_default_console_device) { struct atmel_uart_data *pdata = atmel_default_console_device->dev.platform_data; + int id = pdata->num; + struct atmel_uart_port *port = &atmel_ports[id]; + + port->backup_imr = 0; + port->uart.line = id; - add_preferred_console(ATMEL_DEVICENAME, pdata->num, NULL); - atmel_init_port(&atmel_ports[pdata->num], - atmel_default_console_device); + add_preferred_console(ATMEL_DEVICENAME, id, NULL); + atmel_init_port(port, atmel_default_console_device); register_console(&atmel_console); } @@ -1711,14 +1777,39 @@ static int atmel_serial_resume(struct platform_device *pdev) static int __devinit atmel_serial_probe(struct platform_device *pdev) { struct atmel_uart_port *port; + struct device_node *np = pdev->dev.of_node; struct atmel_uart_data *pdata = pdev->dev.platform_data; void *data; - int ret; + int ret = -ENODEV; BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); - port = &atmel_ports[pdata->num]; + if (np) + ret = of_alias_get_id(np, "serial"); + else + if (pdata) + ret = pdata->num; + + if (ret < 0) + /* port id not found in platform data nor device-tree aliases: + * auto-enumerate it */ + ret = find_first_zero_bit(&atmel_ports_in_use, + sizeof(atmel_ports_in_use)); + + if (ret > ATMEL_MAX_UART) { + ret = -ENODEV; + goto err; + } + + if (test_and_set_bit(ret, &atmel_ports_in_use)) { + /* port already in use */ + ret = -EBUSY; + goto err; + } + + port = &atmel_ports[ret]; port->backup_imr = 0; + port->uart.line = ret; atmel_init_port(port, pdev); @@ -1764,7 +1855,7 @@ err_alloc_ring: clk_put(port->clk); port->clk = NULL; } - +err: return ret; } @@ -1784,6 +1875,8 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev) /* "port" is allocated statically, so we shouldn't free it */ + clear_bit(port->line, &atmel_ports_in_use); + clk_put(atmel_port->clk); return ret; @@ -1797,6 +1890,7 @@ static struct platform_driver atmel_serial_driver = { .driver = { .name = "atmel_usart", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(atmel_serial_dt_ids), }, }; diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c index 891d194ae754..ee101c0d358f 100644 --- a/drivers/tty/serial/bfin_sport_uart.c +++ b/drivers/tty/serial/bfin_sport_uart.c @@ -294,7 +294,7 @@ static int sport_startup(struct uart_port *port) if (request_irq(gpio_to_irq(up->cts_pin), sport_mctrl_cts_int, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | - IRQF_DISABLED, "BFIN_SPORT_UART_CTS", up)) { + 0, "BFIN_SPORT_UART_CTS", up)) { up->cts_pin = -1; dev_info(port->dev, "Unable to attach BlackFin UART over SPORT CTS interrupt. So, disable it.\n"); } diff --git a/drivers/tty/serial/bfin_5xx.c b/drivers/tty/serial/bfin_uart.c index ff6979181ac5..66afb98b77b5 100644 --- a/drivers/tty/serial/bfin_5xx.c +++ b/drivers/tty/serial/bfin_uart.c @@ -234,8 +234,8 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart) status = UART_GET_LSR(uart); UART_CLEAR_LSR(uart); - ch = UART_GET_CHAR(uart); - uart->port.icount.rx++; + ch = UART_GET_CHAR(uart); + uart->port.icount.rx++; #if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE) @@ -667,17 +667,17 @@ static int bfin_serial_startup(struct uart_port *port) kgdboc_break_enabled = 0; else { # endif - if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, + if (request_irq(uart->rx_irq, bfin_serial_rx_int, 0, "BFIN_UART_RX", uart)) { printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); return -EBUSY; } if (request_irq - (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED, + (uart->tx_irq, bfin_serial_tx_int, 0, "BFIN_UART_TX", uart)) { printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n"); - free_irq(uart->port.irq, uart); + free_irq(uart->rx_irq, uart); return -EBUSY; } @@ -692,7 +692,7 @@ static int bfin_serial_startup(struct uart_port *port) */ unsigned uart_dma_ch_rx, uart_dma_ch_tx; - switch (uart->port.irq) { + switch (uart->rx_irq) { case IRQ_UART3_RX: uart_dma_ch_rx = CH_UART3_RX; uart_dma_ch_tx = CH_UART3_TX; @@ -709,16 +709,16 @@ static int bfin_serial_startup(struct uart_port *port) if (uart_dma_ch_rx && request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) { printk(KERN_NOTICE"Fail to attach UART interrupt\n"); - free_irq(uart->port.irq, uart); - free_irq(uart->port.irq + 1, uart); + free_irq(uart->rx_irq, uart); + free_irq(uart->tx_irq, uart); return -EBUSY; } if (uart_dma_ch_tx && request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) { printk(KERN_NOTICE "Fail to attach UART interrupt\n"); free_dma(uart_dma_ch_rx); - free_irq(uart->port.irq, uart); - free_irq(uart->port.irq + 1, uart); + free_irq(uart->rx_irq, uart); + free_irq(uart->tx_irq, uart); return -EBUSY; } } @@ -734,19 +734,18 @@ static int bfin_serial_startup(struct uart_port *port) if (request_irq(gpio_to_irq(uart->cts_pin), bfin_serial_mctrl_cts_int, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | - IRQF_DISABLED, "BFIN_UART_CTS", uart)) { + 0, "BFIN_UART_CTS", uart)) { uart->cts_pin = -1; pr_info("Unable to attach BlackFin UART CTS interrupt. So, disable it.\n"); } } - if (uart->rts_pin >= 0) { + if (uart->rts_pin >= 0) gpio_direction_output(uart->rts_pin, 0); - } #endif #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS if (uart->cts_pin >= 0 && request_irq(uart->status_irq, bfin_serial_mctrl_cts_int, - IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) { + 0, "BFIN_UART_MODEM_STATUS", uart)) { uart->cts_pin = -1; pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n"); } @@ -786,8 +785,8 @@ static void bfin_serial_shutdown(struct uart_port *port) break; }; #endif - free_irq(uart->port.irq, uart); - free_irq(uart->port.irq+1, uart); + free_irq(uart->rx_irq, uart); + free_irq(uart->tx_irq, uart); #endif #ifdef CONFIG_SERIAL_BFIN_CTSRTS @@ -1091,10 +1090,18 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, *parity = 'o'; } switch (lcr & 0x03) { - case 0: *bits = 5; break; - case 1: *bits = 6; break; - case 2: *bits = 7; break; - case 3: *bits = 8; break; + case 0: + *bits = 5; + break; + case 1: + *bits = 6; + break; + case 2: + *bits = 7; + break; + case 3: + *bits = 8; + break; } /* Set DLAB in LCR to Access DLL and DLH */ UART_SET_DLAB(uart); @@ -1183,7 +1190,7 @@ static struct console bfin_serial_console = { .index = -1, .data = &bfin_serial_reg, }; -#define BFIN_SERIAL_CONSOLE &bfin_serial_console +#define BFIN_SERIAL_CONSOLE (&bfin_serial_console) #else #define BFIN_SERIAL_CONSOLE NULL #endif /* CONFIG_SERIAL_BFIN_CONSOLE */ @@ -1312,14 +1319,22 @@ static int bfin_serial_probe(struct platform_device *pdev) } uart->port.mapbase = res->start; - uart->port.irq = platform_get_irq(pdev, 0); - if (uart->port.irq < 0) { - dev_err(&pdev->dev, "No uart RX/TX IRQ specified\n"); + uart->tx_irq = platform_get_irq(pdev, 0); + if (uart->tx_irq < 0) { + dev_err(&pdev->dev, "No uart TX IRQ specified\n"); + ret = -ENOENT; + goto out_error_unmap; + } + + uart->rx_irq = platform_get_irq(pdev, 1); + if (uart->rx_irq < 0) { + dev_err(&pdev->dev, "No uart RX IRQ specified\n"); ret = -ENOENT; goto out_error_unmap; } + uart->port.irq = uart->rx_irq; - uart->status_irq = platform_get_irq(pdev, 1); + uart->status_irq = platform_get_irq(pdev, 2); if (uart->status_irq < 0) { dev_err(&pdev->dev, "No uart status IRQ specified\n"); ret = -ENOENT; diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 9488da74d4f7..b418947b7107 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -31,6 +31,7 @@ #include <linux/module.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/serial.h> diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 58be715913cd..b7435043f2fe 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -258,7 +258,7 @@ static struct e100_serial rs_table[] = { .dma_out_enabled = 1, .dma_out_nbr = SER0_TX_DMA_NBR, .dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR, - .dma_out_irq_flags = IRQF_DISABLED, + .dma_out_irq_flags = 0, .dma_out_irq_description = "serial 0 dma tr", #else .dma_out_enabled = 0, @@ -271,7 +271,7 @@ static struct e100_serial rs_table[] = { .dma_in_enabled = 1, .dma_in_nbr = SER0_RX_DMA_NBR, .dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR, - .dma_in_irq_flags = IRQF_DISABLED, + .dma_in_irq_flags = 0, .dma_in_irq_description = "serial 0 dma rec", #else .dma_in_enabled = 0, @@ -313,7 +313,7 @@ static struct e100_serial rs_table[] = { .dma_out_enabled = 1, .dma_out_nbr = SER1_TX_DMA_NBR, .dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR, - .dma_out_irq_flags = IRQF_DISABLED, + .dma_out_irq_flags = 0, .dma_out_irq_description = "serial 1 dma tr", #else .dma_out_enabled = 0, @@ -326,7 +326,7 @@ static struct e100_serial rs_table[] = { .dma_in_enabled = 1, .dma_in_nbr = SER1_RX_DMA_NBR, .dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR, - .dma_in_irq_flags = IRQF_DISABLED, + .dma_in_irq_flags = 0, .dma_in_irq_description = "serial 1 dma rec", #else .dma_in_enabled = 0, @@ -369,7 +369,7 @@ static struct e100_serial rs_table[] = { .dma_out_enabled = 1, .dma_out_nbr = SER2_TX_DMA_NBR, .dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR, - .dma_out_irq_flags = IRQF_DISABLED, + .dma_out_irq_flags = 0, .dma_out_irq_description = "serial 2 dma tr", #else .dma_out_enabled = 0, @@ -382,7 +382,7 @@ static struct e100_serial rs_table[] = { .dma_in_enabled = 1, .dma_in_nbr = SER2_RX_DMA_NBR, .dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR, - .dma_in_irq_flags = IRQF_DISABLED, + .dma_in_irq_flags = 0, .dma_in_irq_description = "serial 2 dma rec", #else .dma_in_enabled = 0, @@ -423,7 +423,7 @@ static struct e100_serial rs_table[] = { .dma_out_enabled = 1, .dma_out_nbr = SER3_TX_DMA_NBR, .dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR, - .dma_out_irq_flags = IRQF_DISABLED, + .dma_out_irq_flags = 0, .dma_out_irq_description = "serial 3 dma tr", #else .dma_out_enabled = 0, @@ -436,7 +436,7 @@ static struct e100_serial rs_table[] = { .dma_in_enabled = 1, .dma_in_nbr = SER3_RX_DMA_NBR, .dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR, - .dma_in_irq_flags = IRQF_DISABLED, + .dma_in_irq_flags = 0, .dma_in_irq_description = "serial 3 dma rec", #else .dma_in_enabled = 0, @@ -1788,7 +1788,7 @@ static unsigned int handle_descr_data(struct e100_serial *info, struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer; if (info->recv_cnt + recvl > 65536) { - printk(KERN_CRIT + printk(KERN_WARNING "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl); return 0; } @@ -3813,13 +3813,13 @@ rs_close(struct tty_struct *tty, struct file * filp) * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk(KERN_CRIT + printk(KERN_ERR "rs_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { - printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n", + printk(KERN_ERR "rs_close: bad serial port count for ttyS%d: %d\n", info->line, info->count); info->count = 0; } @@ -4452,7 +4452,7 @@ static int __init rs_init(void) #if defined(CONFIG_ETRAX_RS485_ON_PA) if (cris_io_interface_allocate_pins(if_serial_0, 'a', rs485_pa_bit, rs485_pa_bit)) { - printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " + printk(KERN_ERR "ETRAX100LX serial: Could not allocate " "RS485 pin\n"); put_tty_driver(driver); return -EBUSY; @@ -4461,7 +4461,7 @@ static int __init rs_init(void) #if defined(CONFIG_ETRAX_RS485_ON_PORT_G) if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit, rs485_port_g_bit)) { - printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " + printk(KERN_ERR "ETRAX100LX serial: Could not allocate " "RS485 pin\n"); put_tty_driver(driver); return -EBUSY; @@ -4494,7 +4494,7 @@ static int __init rs_init(void) if (info->enabled) { if (cris_request_io_interface(info->io_if, info->io_if_description)) { - printk(KERN_CRIT "ETRAX100LX async serial: " + printk(KERN_ERR "ETRAX100LX async serial: " "Could not allocate IO pins for " "%s, port %d\n", info->io_if_description, i); @@ -4558,7 +4558,7 @@ static int __init rs_init(void) /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, - IRQF_SHARED | IRQF_DISABLED, "serial ", driver)) + IRQF_SHARED, "serial ", driver)) panic("%s: Failed to request irq8", __func__); #endif diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c index ddc487a2d42f..e3699a84049f 100644 --- a/drivers/tty/serial/dz.c +++ b/drivers/tty/serial/dz.c @@ -47,6 +47,7 @@ #include <linux/serial_core.h> #include <linux/sysrq.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/atomic.h> #include <asm/bootinfo.h> diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index 8a869e58f6d7..d55709a7a75a 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -1554,7 +1554,7 @@ static int __devinit icom_probe(struct pci_dev *dev, /* save off irq and request irq line */ if ( (retval = request_irq(dev->irq, icom_interrupt, - IRQF_DISABLED | IRQF_SHARED, ICOM_DRIVER_NAME, + IRQF_SHARED, ICOM_DRIVER_NAME, (void *) icom_adapter))) { goto probe_exit2; } diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 7e91b3d368cd..163fc9021f5a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -508,8 +508,10 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) continue; - if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { - if (rx & URXD_PRERR) + if (unlikely(rx & URXD_ERR)) { + if (rx & URXD_BRK) + sport->port.icount.brk++; + else if (rx & URXD_PRERR) sport->port.icount.parity++; else if (rx & URXD_FRMERR) sport->port.icount.frame++; @@ -524,7 +526,9 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) rx &= sport->port.read_status_mask; - if (rx & URXD_PRERR) + if (rx & URXD_BRK) + flg = TTY_BREAK; + else if (rx & URXD_PRERR) flg = TTY_PARITY; else if (rx & URXD_FRMERR) flg = TTY_FRAME; @@ -1286,17 +1290,20 @@ static int serial_imx_resume(struct platform_device *dev) static int serial_imx_probe_dt(struct imx_port *sport, struct platform_device *pdev) { - static int portnum = 0; struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(imx_uart_dt_ids, &pdev->dev); + int ret; if (!np) return -ENODEV; - sport->port.line = portnum++; - if (sport->port.line >= UART_NR) - return -EINVAL; + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); + return -ENODEV; + } + sport->port.line = ret; if (of_get_property(np, "fsl,uart-has-rtscts", NULL)) sport->have_rtscts = 1; diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c index ee43efc7bdcc..758ff310f7f8 100644 --- a/drivers/tty/serial/ioc3_serial.c +++ b/drivers/tty/serial/ioc3_serial.c @@ -13,6 +13,7 @@ */ #include <linux/errno.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/serial.h> #include <linux/circ_buf.h> #include <linux/serial_reg.h> diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c index fcfe82653ac8..6b36c1554d7e 100644 --- a/drivers/tty/serial/ioc4_serial.c +++ b/drivers/tty/serial/ioc4_serial.c @@ -14,6 +14,7 @@ */ #include <linux/errno.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/serial.h> #include <linux/serialP.h> #include <linux/circ_buf.h> diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h index b704c8ce0d71..529bec6edaf8 100644 --- a/drivers/tty/serial/jsm/jsm.h +++ b/drivers/tty/serial/jsm/jsm.h @@ -88,7 +88,6 @@ enum { /* 4 extra for alignment play space */ #define WRITEBUFLEN ((4096) + 4) -#define MYFLIPLEN N_TTY_BUF_SIZE #define JSM_VERSION "jsm: 1.2-1-INKERNEL" #define JSM_PARTNUM "40002438_A-INKERNEL" @@ -150,7 +149,6 @@ struct jsm_board u32 bd_uart_offset; /* Space between each UART */ struct jsm_channel *channels[MAXPORTS]; /* array of pointers to our channels. */ - char *flipbuf; /* Our flip buffer, alloced if board is found */ u32 bd_dividend; /* Board/UARTs specific dividend */ @@ -177,16 +175,13 @@ struct jsm_board #define CH_TX_FIFO_LWM 0x0800 /* TX Fifo is below Low Water */ #define CH_BREAK_SENDING 0x1000 /* Break is being sent */ #define CH_LOOPBACK 0x2000 /* Channel is in lookback mode */ -#define CH_FLIPBUF_IN_USE 0x4000 /* Channel's flipbuf is in use */ #define CH_BAUD0 0x08000 /* Used for checking B0 transitions */ /* Our Read/Error/Write queue sizes */ #define RQUEUEMASK 0x1FFF /* 8 K - 1 */ #define EQUEUEMASK 0x1FFF /* 8 K - 1 */ -#define WQUEUEMASK 0x0FFF /* 4 K - 1 */ #define RQUEUESIZE (RQUEUEMASK + 1) #define EQUEUESIZE RQUEUESIZE -#define WQUEUESIZE (WQUEUEMASK + 1) /************************************************************************ @@ -226,10 +221,6 @@ struct jsm_channel { u16 ch_e_head; /* Head location of the error queue */ u16 ch_e_tail; /* Tail location of the error queue */ - u8 *ch_wqueue; /* Our write queue buffer - malloc'ed */ - u16 ch_w_head; /* Head location of the write queue */ - u16 ch_w_tail; /* Tail location of the write queue */ - u64 ch_rxcount; /* total of data received so far */ u64 ch_txcount; /* total of data transmitted so far */ @@ -378,7 +369,6 @@ extern int jsm_debug; * Prototypes for non-static functions used in more than one module * *************************************************************************/ -int jsm_tty_write(struct uart_port *port); int jsm_tty_init(struct jsm_board *); int jsm_uart_port_init(struct jsm_board *); int jsm_remove_uart_port(struct jsm_board *); diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index 96da17868cf3..648b6a3efa32 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c @@ -160,27 +160,10 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device dev_info(&pdev->dev, "board %d: Digi Neo (rev %d), irq %d\n", adapter_count, brd->rev, brd->irq); - /* - * allocate flip buffer for board. - * - * Okay to malloc with GFP_KERNEL, we are not at interrupt - * context, and there are no locks held. - */ - brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL); - if (!brd->flipbuf) { - /* XXX: leaking all resources from jsm_tty_init and - jsm_uart_port_init here! */ - dev_err(&pdev->dev, "memory allocation for flipbuf failed\n"); - rc = -ENOMEM; - goto out_free_uart; - } - pci_set_drvdata(pdev, brd); pci_save_state(pdev); return 0; - out_free_uart: - jsm_remove_uart_port(brd); out_free_irq: jsm_remove_uart_port(brd); free_irq(brd->irq, brd); @@ -211,14 +194,12 @@ static void __devexit jsm_remove_one(struct pci_dev *pdev) if (brd->channels[i]) { kfree(brd->channels[i]->ch_rqueue); kfree(brd->channels[i]->ch_equeue); - kfree(brd->channels[i]->ch_wqueue); kfree(brd->channels[i]); } } pci_release_regions(pdev); pci_disable_device(pdev); - kfree(brd->flipbuf); kfree(brd); } diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index 4538c3e3646e..81dfafa11b0b 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -496,12 +496,15 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) int s; int qlen; u32 len_written = 0; + struct circ_buf *circ; if (!ch) return; + circ = &ch->uart_port.state->xmit; + /* No data to write to the UART */ - if (ch->ch_w_tail == ch->ch_w_head) + if (uart_circ_empty(circ)) return; /* If port is "stopped", don't send any data to the UART */ @@ -517,11 +520,10 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) if (ch->ch_cached_lsr & UART_LSR_THRE) { ch->ch_cached_lsr &= ~(UART_LSR_THRE); - writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx); + writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx); jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev, - "Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]); - ch->ch_w_tail++; - ch->ch_w_tail &= WQUEUEMASK; + "Tx data: %x\n", circ->buf[circ->tail]); + circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1); ch->ch_txcount++; } return; @@ -536,36 +538,36 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel; /* cache head and tail of queue */ - head = ch->ch_w_head & WQUEUEMASK; - tail = ch->ch_w_tail & WQUEUEMASK; - qlen = (head - tail) & WQUEUEMASK; + head = circ->head & (UART_XMIT_SIZE - 1); + tail = circ->tail & (UART_XMIT_SIZE - 1); + qlen = uart_circ_chars_pending(circ); /* Find minimum of the FIFO space, versus queue length */ n = min(n, qlen); while (n > 0) { - s = ((head >= tail) ? head : WQUEUESIZE) - tail; + s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail; s = min(s, n); if (s <= 0) break; - memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s); + memcpy_toio(&ch->ch_neo_uart->txrxburst, circ->buf + tail, s); /* Add and flip queue if needed */ - tail = (tail + s) & WQUEUEMASK; + tail = (tail + s) & (UART_XMIT_SIZE - 1); n -= s; ch->ch_txcount += s; len_written += s; } /* Update the final tail */ - ch->ch_w_tail = tail & WQUEUEMASK; + circ->tail = tail & (UART_XMIT_SIZE - 1); if (len_written >= ch->ch_t_tlevel) ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - if (!jsm_tty_write(&ch->uart_port)) + if (uart_circ_empty(circ)) uart_write_wakeup(&ch->uart_port); } @@ -946,7 +948,6 @@ static void neo_param(struct jsm_channel *ch) if ((ch->ch_c_cflag & (CBAUD)) == 0) { ch->ch_r_head = ch->ch_r_tail = 0; ch->ch_e_head = ch->ch_e_tail = 0; - ch->ch_w_head = ch->ch_w_tail = 0; neo_flush_uart_write(ch); neo_flush_uart_read(ch); diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 7a4a914ecff0..434bd881fcae 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -118,6 +118,19 @@ static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl) udelay(10); } +/* + * jsm_tty_write() + * + * Take data from the user or kernel and send it out to the FEP. + * In here exists all the Transparent Print magic as well. + */ +static void jsm_tty_write(struct uart_port *port) +{ + struct jsm_channel *channel; + channel = container_of(port, struct jsm_channel, uart_port); + channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel); +} + static void jsm_tty_start_tx(struct uart_port *port) { struct jsm_channel *channel = (struct jsm_channel *)port; @@ -216,14 +229,6 @@ static int jsm_tty_open(struct uart_port *port) return -ENOMEM; } } - if (!channel->ch_wqueue) { - channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL); - if (!channel->ch_wqueue) { - jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, - "unable to allocate write queue buf"); - return -ENOMEM; - } - } channel->ch_flags &= ~(CH_OPENING); /* @@ -237,7 +242,6 @@ static int jsm_tty_open(struct uart_port *port) */ channel->ch_r_head = channel->ch_r_tail = 0; channel->ch_e_head = channel->ch_e_tail = 0; - channel->ch_w_head = channel->ch_w_tail = 0; brd->bd_ops->flush_uart_write(channel); brd->bd_ops->flush_uart_read(channel); @@ -836,75 +840,3 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch) } } } - -/* - * jsm_tty_write() - * - * Take data from the user or kernel and send it out to the FEP. - * In here exists all the Transparent Print magic as well. - */ -int jsm_tty_write(struct uart_port *port) -{ - int bufcount; - int data_count = 0,data_count1 =0; - u16 head; - u16 tail; - u16 tmask; - u32 remain; - int temp_tail = port->state->xmit.tail; - struct jsm_channel *channel = (struct jsm_channel *)port; - - tmask = WQUEUEMASK; - head = (channel->ch_w_head) & tmask; - tail = (channel->ch_w_tail) & tmask; - - if ((bufcount = tail - head - 1) < 0) - bufcount += WQUEUESIZE; - - bufcount = min(bufcount, 56); - remain = WQUEUESIZE - head; - - data_count = 0; - if (bufcount >= remain) { - bufcount -= remain; - while ((port->state->xmit.head != temp_tail) && - (data_count < remain)) { - channel->ch_wqueue[head++] = - port->state->xmit.buf[temp_tail]; - - temp_tail++; - temp_tail &= (UART_XMIT_SIZE - 1); - data_count++; - } - if (data_count == remain) head = 0; - } - - data_count1 = 0; - if (bufcount > 0) { - remain = bufcount; - while ((port->state->xmit.head != temp_tail) && - (data_count1 < remain)) { - channel->ch_wqueue[head++] = - port->state->xmit.buf[temp_tail]; - - temp_tail++; - temp_tail &= (UART_XMIT_SIZE - 1); - data_count1++; - - } - } - - port->state->xmit.tail = temp_tail; - - data_count += data_count1; - if (data_count) { - head &= tmask; - channel->ch_w_head = head; - } - - if (data_count) { - channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel); - } - - return data_count; -} diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index 58cf279ed879..96c1cacc7360 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -338,21 +338,21 @@ lqasc_startup(struct uart_port *port) ASCCON_ROEN, port->membase + LTQ_ASC_CON); retval = request_irq(ltq_port->tx_irq, lqasc_tx_int, - IRQF_DISABLED, "asc_tx", port); + 0, "asc_tx", port); if (retval) { pr_err("failed to request lqasc_tx_int\n"); return retval; } retval = request_irq(ltq_port->rx_irq, lqasc_rx_int, - IRQF_DISABLED, "asc_rx", port); + 0, "asc_rx", port); if (retval) { pr_err("failed to request lqasc_rx_int\n"); goto err1; } retval = request_irq(ltq_port->err_irq, lqasc_err_int, - IRQF_DISABLED, "asc_err", port); + 0, "asc_err", port); if (retval) { pr_err("failed to request lqasc_err_int\n"); goto err2; @@ -478,8 +478,10 @@ lqasc_set_termios(struct uart_port *port, spin_unlock_irqrestore(<q_asc_lock, flags); /* Don't rewrite B0 */ - if (tty_termios_baud_rate(new)) + if (tty_termios_baud_rate(new)) tty_termios_encode_baud_rate(new, baud, baud); + + uart_update_timeout(port, cflag, baud); } static const char* diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 8e07517f8acd..08018934e013 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -32,6 +32,7 @@ #include <linux/module.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/console.h> diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 7b951adac54b..2af5aa5f3a80 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -47,6 +47,8 @@ #include <linux/serial.h> #include <linux/spi/spi.h> #include <linux/freezer.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/serial_max3100.h> diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c index a8164601c0ea..db00b595cab0 100644 --- a/drivers/tty/serial/max3107.c +++ b/drivers/tty/serial/max3107.c @@ -31,6 +31,8 @@ #include <linux/device.h> #include <linux/serial_core.h> #include <linux/serial.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/gpio.h> #include <linux/spi/spi.h> #include <linux/freezer.h> diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 3394b7cc1722..9afca093d6ec 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -380,7 +380,7 @@ static void mcf_config_port(struct uart_port *port, int flags) /* Clear mask, so no surprise interrupts. */ writeb(0, port->membase + MCFUART_UIMR); - if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port)) + if (request_irq(port->irq, mcf_interrupt, 0, "UART", port)) printk(KERN_ERR "MCF: unable to attach ColdFire UART %d " "interrupt vector=%d\n", port->line, port->irq); } diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index cab52f4a88b0..286c386d9c46 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c @@ -38,6 +38,7 @@ #include <linux/pci.h> #include <linux/io.h> #include <linux/debugfs.h> +#include <linux/pm_runtime.h> #define HSU_DMA_BUF_SIZE 2048 @@ -764,6 +765,8 @@ static int serial_hsu_startup(struct uart_port *port) container_of(port, struct uart_hsu_port, port); unsigned long flags; + pm_runtime_get_sync(up->dev); + /* * Clear the FIFO buffers and disable them. * (they will be reenabled in set_termios()) @@ -871,6 +874,8 @@ static void serial_hsu_shutdown(struct uart_port *port) UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); serial_out(up, UART_FCR, 0); + + pm_runtime_put(up->dev); } static void @@ -1249,6 +1254,39 @@ static int serial_hsu_resume(struct pci_dev *pdev) #define serial_hsu_resume NULL #endif +#ifdef CONFIG_PM_RUNTIME +static int serial_hsu_runtime_idle(struct device *dev) +{ + int err; + + err = pm_schedule_suspend(dev, 500); + if (err) + return -EBUSY; + + return 0; +} + +static int serial_hsu_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int serial_hsu_runtime_resume(struct device *dev) +{ + return 0; +} +#else +#define serial_hsu_runtime_idle NULL +#define serial_hsu_runtime_suspend NULL +#define serial_hsu_runtime_resume NULL +#endif + +static const struct dev_pm_ops serial_hsu_pm_ops = { + .runtime_suspend = serial_hsu_runtime_suspend, + .runtime_resume = serial_hsu_runtime_resume, + .runtime_idle = serial_hsu_runtime_idle, +}; + /* temp global pointer before we settle down on using one or four PCI dev */ static struct hsu_port *phsu; @@ -1315,6 +1353,9 @@ static int serial_hsu_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, uport); } + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_allow(&pdev->dev); + return 0; err_disable: @@ -1411,6 +1452,9 @@ static void serial_hsu_remove(struct pci_dev *pdev) if (!priv) return; + pm_runtime_forbid(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + /* For port 0/1/2, priv is the address of uart_hsu_port */ if (pdev->device != 0x081E) { up = priv; @@ -1423,7 +1467,7 @@ static void serial_hsu_remove(struct pci_dev *pdev) } /* First 3 are UART ports, and the 4th is the DMA */ -static const struct pci_device_id pci_ids[] __devinitdata = { +static const struct pci_device_id pci_ids[] __devinitconst = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) }, @@ -1438,6 +1482,9 @@ static struct pci_driver hsu_pci_driver = { .remove = __devexit_p(serial_hsu_remove), .suspend = serial_hsu_suspend, .resume = serial_hsu_resume, + .driver = { + .pm = &serial_hsu_pm_ops, + }, }; static int __init hsu_pci_init(void) diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index a0bcd8a3758d..1093a88a1fe3 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -34,6 +34,7 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/serial.h> #include <linux/sysrq.h> #include <linux/console.h> @@ -273,7 +274,7 @@ static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port, static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np) { - port->irqflags = IRQF_DISABLED; + port->irqflags = 0; port->irq = irq_of_parse_and_map(np, 0); } diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c index 23bc743f2a22..4c309e869903 100644 --- a/drivers/tty/serial/mrst_max3110.c +++ b/drivers/tty/serial/mrst_max3110.c @@ -23,10 +23,14 @@ * 1 word. If SPI master controller doesn't support sclk frequency change, * then the char need be sent out one by one with some delay * - * 2. Currently only RX available interrrupt is used, no need for waiting TXE + * 2. Currently only RX available interrupt is used, no need for waiting TXE * interrupt for a low speed UART device */ +#ifdef CONFIG_MAGIC_SYSRQ +#define SUPPORT_SYSRQ +#endif + #include <linux/module.h> #include <linux/ioport.h> #include <linux/irq.h> @@ -73,9 +77,9 @@ struct uart_max3110 { /* global data structure, may need be removed */ static struct uart_max3110 *pmax; -static void receive_chars(struct uart_max3110 *max, - unsigned char *str, int len); -static int max3110_read_multi(struct uart_max3110 *max, u8 *buf); +static int receive_chars(struct uart_max3110 *max, + unsigned short *str, int len); +static int max3110_read_multi(struct uart_max3110 *max); static void max3110_con_receive(struct uart_max3110 *max); static int max3110_write_then_read(struct uart_max3110 *max, @@ -108,7 +112,6 @@ static int max3110_out(struct uart_max3110 *max, const u16 out) { void *buf; u16 *obuf, *ibuf; - u8 ch; int ret; buf = kzalloc(8, GFP_KERNEL | GFP_DMA); @@ -125,11 +128,7 @@ static int max3110_out(struct uart_max3110 *max, const u16 out) goto exit; } - /* If some valid data is read back */ - if (*ibuf & MAX3110_READ_DATA_AVAILABLE) { - ch = *ibuf & 0xff; - receive_chars(max, &ch, 1); - } + receive_chars(max, ibuf, 1); exit: kfree(buf); @@ -142,12 +141,11 @@ exit: * * Return how many valide bytes are read back */ -static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf) +static int max3110_read_multi(struct uart_max3110 *max) { void *buf; u16 *obuf, *ibuf; - u8 *pbuf, valid_str[M3110_RX_FIFO_DEPTH]; - int i, j, blen; + int ret, blen; blen = M3110_RX_FIFO_DEPTH * sizeof(u16); buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA); @@ -165,19 +163,10 @@ static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf) return 0; } - /* If caller doesn't provide a buffer, then handle received char */ - pbuf = rxbuf ? rxbuf : valid_str; - - for (i = 0, j = 0; i < M3110_RX_FIFO_DEPTH; i++) { - if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE) - pbuf[j++] = ibuf[i] & 0xff; - } - - if (j && (pbuf == valid_str)) - receive_chars(max, valid_str, j); + ret = receive_chars(max, ibuf, M3110_RX_FIFO_DEPTH); kfree(buf); - return j; + return ret; } static void serial_m3110_con_putchar(struct uart_port *port, int ch) @@ -207,7 +196,7 @@ static void serial_m3110_con_write(struct console *co, uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar); if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags)) - wake_up_process(pmax->main_thread); + wake_up(&pmax->wq); } static int __init @@ -276,8 +265,7 @@ static void send_circ_buf(struct uart_max3110 *max, { void *buf; u16 *obuf, *ibuf; - u8 valid_str[WORDS_PER_XFER]; - int i, j, len, blen, dma_size, left, ret = 0; + int i, len, blen, dma_size, left, ret = 0; dma_size = WORDS_PER_XFER * sizeof(u16) * 2; @@ -301,18 +289,13 @@ static void send_circ_buf(struct uart_max3110 *max, } /* Fail to send msg to console is not very critical */ + ret = max3110_write_then_read(max, obuf, ibuf, blen, 0); if (ret) pr_warning(PR_FMT "%s(): get err msg %d\n", __func__, ret); - for (i = 0, j = 0; i < len; i++) { - if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE) - valid_str[j++] = ibuf[i] & 0xff; - } - - if (j) - receive_chars(max, valid_str, j); + receive_chars(max, ibuf, len); max->port.icount.tx += len; left -= len; @@ -349,33 +332,54 @@ static void serial_m3110_start_tx(struct uart_port *port) container_of(port, struct uart_max3110, port); if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags)) - wake_up_process(max->main_thread); + wake_up(&max->wq); } -static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len) +static int +receive_chars(struct uart_max3110 *max, unsigned short *str, int len) { struct uart_port *port = &max->port; struct tty_struct *tty; - int usable; + char buf[M3110_RX_FIFO_DEPTH]; + int r, w, usable; /* If uart is not opened, just return */ if (!port->state) - return; + return 0; - tty = port->state->port.tty; + tty = tty_port_tty_get(&port->state->port); if (!tty) - return; + return 0; + + for (r = 0, w = 0; r < len; r++) { + if (str[r] & MAX3110_BREAK && + uart_handle_break(port)) + continue; + + if (str[r] & MAX3110_READ_DATA_AVAILABLE) { + if (uart_handle_sysrq_char(port, str[r] & 0xff)) + continue; + + buf[w++] = str[r] & 0xff; + } + } + + if (!w) { + tty_kref_put(tty); + return 0; + } - while (len) { - usable = tty_buffer_request_room(tty, len); + for (r = 0; w; r += usable, w -= usable) { + usable = tty_buffer_request_room(tty, w); if (usable) { - tty_insert_flip_string(tty, str, usable); - str += usable; + tty_insert_flip_string(tty, buf + r, usable); port->icount.rx += usable; } - len -= usable; } tty_flip_buffer_push(tty); + tty_kref_put(tty); + + return r; } /* @@ -390,28 +394,15 @@ static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len) */ static void max3110_con_receive(struct uart_max3110 *max) { - int loop = 1, num, total = 0; - u8 recv_buf[512], *pbuf; + int loop = 1, num; - pbuf = recv_buf; do { - num = max3110_read_multi(max, pbuf); + num = max3110_read_multi(max); if (num) { loop = 5; - pbuf += num; - total += num; - - if (total >= 504) { - receive_chars(max, recv_buf, total); - pbuf = recv_buf; - total = 0; - } } } while (--loop); - - if (total) - receive_chars(max, recv_buf, total); } static int max3110_main_thread(void *_max) @@ -424,7 +415,8 @@ static int max3110_main_thread(void *_max) pr_info(PR_FMT "start main thread\n"); do { - wait_event_interruptible(*wq, max->uart_flags || kthread_should_stop()); + wait_event_interruptible(*wq, + max->uart_flags || kthread_should_stop()); mutex_lock(&max->thread_mutex); @@ -452,8 +444,9 @@ static irqreturn_t serial_m3110_irq(int irq, void *dev_id) /* max3110's irq is a falling edge, not level triggered, * so no need to disable the irq */ + if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags)) - wake_up_process(max->main_thread); + wake_up(&max->wq); return IRQ_HANDLED; } diff --git a/drivers/tty/serial/mrst_max3110.h b/drivers/tty/serial/mrst_max3110.h index c37ea48c825a..35af0739513b 100644 --- a/drivers/tty/serial/mrst_max3110.h +++ b/drivers/tty/serial/mrst_max3110.h @@ -7,6 +7,7 @@ /* status bits for all 4 MAX3110 operate modes */ #define MAX3110_READ_DATA_AVAILABLE (1 << 15) #define MAX3110_WRITE_BUF_EMPTY (1 << 14) +#define MAX3110_BREAK (1 << 10) #define WC_TAG (3 << 14) #define RC_TAG (1 << 14) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index e6ba83876508..29cbfd8c4e7c 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -804,8 +804,6 @@ static int __init msm_console_setup(struct console *co, char *options) if (unlikely(!port->membase)) return -ENXIO; - port->cons = co; - msm_init_clock(port); if (options) diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index 624701f8138a..60c6eb850265 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -30,6 +30,8 @@ #include <linux/serial.h> #include <linux/serial_core.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/interrupt.h> diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 9711e06a8374..06f6aefd5ba6 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -21,6 +21,8 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/serial.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/console.h> #include <linux/delay.h> /* for udelay */ #include <linux/device.h> diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c index de173671e3d0..9beaff1cec24 100644 --- a/drivers/tty/serial/nwpserial.c +++ b/drivers/tty/serial/nwpserial.c @@ -15,6 +15,7 @@ #include <linux/serial_reg.h> #include <linux/serial_core.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/irqreturn.h> #include <linux/mutex.h> #include <linux/of_platform.h> diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index e58cece6f443..e8c9cee07d00 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -200,17 +200,7 @@ static struct platform_driver of_platform_serial_driver = { .remove = of_platform_serial_remove, }; -static int __init of_platform_serial_init(void) -{ - return platform_driver_register(&of_platform_serial_driver); -} -module_init(of_platform_serial_init); - -static void __exit of_platform_serial_exit(void) -{ - return platform_driver_unregister(&of_platform_serial_driver); -}; -module_exit(of_platform_serial_exit); +module_platform_driver(of_platform_serial_driver); MODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>"); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index b46218d679e2..21febef926aa 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -20,6 +20,8 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/serial_core.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/dmi.h> diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 531931c1b250..5c8e3bba6c84 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -100,6 +100,16 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) int max_count = 256; do { + /* work around Errata #20 according to + * Intel(R) PXA27x Processor Family + * Specification Update (May 2005) + * + * Step 2 + * Disable the Reciever Time Out Interrupt via IER[RTOEI] + */ + up->ier &= ~UART_IER_RTOIE; + serial_out(up, UART_IER, up->ier); + ch = serial_in(up, UART_RX); flag = TTY_NORMAL; up->port.icount.rx++; @@ -156,6 +166,16 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) *status = serial_in(up, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); tty_flip_buffer_push(tty); + + /* work around Errata #20 according to + * Intel(R) PXA27x Processor Family + * Specification Update (May 2005) + * + * Step 6: + * No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE] + */ + up->ier |= UART_IER_RTOIE; + serial_out(up, UART_IER, up->ier); } static void transmit_chars(struct uart_pxa_port *up) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 6edafb5ace18..b31f1c3a2c4c 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -83,6 +83,16 @@ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port) return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE); } +/* + * s3c64xx and later SoC's include the interrupt mask and status registers in + * the controller itself, unlike the s3c24xx SoC's which have these registers + * in the interrupt controller. Check if the port type is s3c64xx or higher. + */ +static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port) +{ + return to_ourport(port)->info->type == PORT_S3C6400; +} + static void s3c24xx_serial_rx_enable(struct uart_port *port) { unsigned long flags; @@ -126,7 +136,11 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port) struct s3c24xx_uart_port *ourport = to_ourport(port); if (tx_enabled(port)) { - disable_irq_nosync(ourport->tx_irq); + if (s3c24xx_serial_has_interrupt_mask(port)) + __set_bit(S3C64XX_UINTM_TXD, + portaddrl(port, S3C64XX_UINTM)); + else + disable_irq_nosync(ourport->tx_irq); tx_enabled(port) = 0; if (port->flags & UPF_CONS_FLOW) s3c24xx_serial_rx_enable(port); @@ -141,19 +155,26 @@ static void s3c24xx_serial_start_tx(struct uart_port *port) if (port->flags & UPF_CONS_FLOW) s3c24xx_serial_rx_disable(port); - enable_irq(ourport->tx_irq); + if (s3c24xx_serial_has_interrupt_mask(port)) + __clear_bit(S3C64XX_UINTM_TXD, + portaddrl(port, S3C64XX_UINTM)); + else + enable_irq(ourport->tx_irq); tx_enabled(port) = 1; } } - static void s3c24xx_serial_stop_rx(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); if (rx_enabled(port)) { dbg("s3c24xx_serial_stop_rx: port=%p\n", port); - disable_irq_nosync(ourport->rx_irq); + if (s3c24xx_serial_has_interrupt_mask(port)) + __set_bit(S3C64XX_UINTM_RXD, + portaddrl(port, S3C64XX_UINTM)); + else + disable_irq_nosync(ourport->rx_irq); rx_enabled(port) = 0; } } @@ -320,6 +341,28 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) return IRQ_HANDLED; } +/* interrupt handler for s3c64xx and later SoC's.*/ +static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id) +{ + struct s3c24xx_uart_port *ourport = id; + struct uart_port *port = &ourport->port; + unsigned int pend = rd_regl(port, S3C64XX_UINTP); + unsigned long flags; + irqreturn_t ret = IRQ_HANDLED; + + spin_lock_irqsave(&port->lock, flags); + if (pend & S3C64XX_UINTM_RXD_MSK) { + ret = s3c24xx_serial_rx_chars(irq, id); + wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK); + } + if (pend & S3C64XX_UINTM_TXD_MSK) { + ret = s3c24xx_serial_tx_chars(irq, id); + wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK); + } + spin_unlock_irqrestore(&port->lock, flags); + return ret; +} + static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) { struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port); @@ -377,18 +420,25 @@ static void s3c24xx_serial_shutdown(struct uart_port *port) struct s3c24xx_uart_port *ourport = to_ourport(port); if (ourport->tx_claimed) { - free_irq(ourport->tx_irq, ourport); + if (!s3c24xx_serial_has_interrupt_mask(port)) + free_irq(ourport->tx_irq, ourport); tx_enabled(port) = 0; ourport->tx_claimed = 0; } if (ourport->rx_claimed) { - free_irq(ourport->rx_irq, ourport); + if (!s3c24xx_serial_has_interrupt_mask(port)) + free_irq(ourport->rx_irq, ourport); ourport->rx_claimed = 0; rx_enabled(port) = 0; } -} + /* Clear pending interrupts and mask all interrupts */ + if (s3c24xx_serial_has_interrupt_mask(port)) { + wr_regl(port, S3C64XX_UINTP, 0xf); + wr_regl(port, S3C64XX_UINTM, 0xf); + } +} static int s3c24xx_serial_startup(struct uart_port *port) { @@ -436,6 +486,33 @@ static int s3c24xx_serial_startup(struct uart_port *port) return ret; } +static int s3c64xx_serial_startup(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + int ret; + + dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n", + port->mapbase, port->membase); + + ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED, + s3c24xx_serial_portname(port), ourport); + if (ret) { + printk(KERN_ERR "cannot get irq %d\n", port->irq); + return ret; + } + + /* For compatibility with s3c24xx Soc's */ + rx_enabled(port) = 1; + ourport->rx_claimed = 1; + tx_enabled(port) = 0; + ourport->tx_claimed = 1; + + /* Enable Rx Interrupt */ + __clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM)); + dbg("s3c64xx_serial_startup ok\n"); + return ret; +} + /* power power management control */ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, @@ -879,7 +956,6 @@ static struct uart_ops s3c24xx_serial_ops = { .verify_port = s3c24xx_serial_verify_port, }; - static struct uart_driver s3c24xx_uart_drv = { .owner = THIS_MODULE, .driver_name = "s3c2410_serial", @@ -895,7 +971,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS .port = { .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock), .iotype = UPIO_MEM, - .irq = IRQ_S3CUART_RX0, .uartclk = 0, .fifosize = 16, .ops = &s3c24xx_serial_ops, @@ -907,7 +982,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS .port = { .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock), .iotype = UPIO_MEM, - .irq = IRQ_S3CUART_RX1, .uartclk = 0, .fifosize = 16, .ops = &s3c24xx_serial_ops, @@ -921,7 +995,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS .port = { .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock), .iotype = UPIO_MEM, - .irq = IRQ_S3CUART_RX2, .uartclk = 0, .fifosize = 16, .ops = &s3c24xx_serial_ops, @@ -935,7 +1008,6 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS .port = { .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock), .iotype = UPIO_MEM, - .irq = IRQ_S3CUART_RX3, .uartclk = 0, .fifosize = 16, .ops = &s3c24xx_serial_ops, @@ -1077,6 +1149,10 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, port->dev = &platdev->dev; ourport->info = info; + /* Startup sequence is different for s3c64xx and higher SoC's */ + if (s3c24xx_serial_has_interrupt_mask(port)) + s3c24xx_serial_ops.startup = s3c64xx_serial_startup; + /* copy the info in from provided structure */ ourport->port.fifosize = info->fifosize; @@ -1116,6 +1192,13 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, ourport->clk = clk_get(&platdev->dev, "uart"); + /* Keep all interrupts masked and cleared */ + if (s3c24xx_serial_has_interrupt_mask(port)) { + wr_regl(port, S3C64XX_UINTM, 0xf); + wr_regl(port, S3C64XX_UINTP, 0xf); + wr_regl(port, S3C64XX_UINTSP, 0xf); + } + dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n", port->mapbase, port->membase, port->irq, ourport->rx_irq, ourport->tx_irq, port->uartclk); diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h index a69d9a54be94..8e87b788e5c6 100644 --- a/drivers/tty/serial/samsung.h +++ b/drivers/tty/serial/samsung.h @@ -61,6 +61,7 @@ struct s3c24xx_uart_port { /* register access controls */ #define portaddr(port, reg) ((port)->membase + (reg)) +#define portaddrl(port, reg) ((unsigned long *)((port)->membase + (reg))) #define rd_regb(port, reg) (__raw_readb(portaddr(port, reg))) #define rd_regl(port, reg) (__raw_readl(portaddr(port, reg))) diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index 6bc2e3f876f4..0be8a2f00d0b 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -37,6 +37,7 @@ #include <linux/spinlock.h> #include <linux/sysrq.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/types.h> #include <linux/atomic.h> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index a3efbea5dbba..0406d7ff505e 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -57,7 +57,7 @@ static struct lock_class_key port_lock_key; static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios); -static void __uart_wait_until_sent(struct uart_port *port, int timeout); +static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_change_pm(struct uart_state *state, int pm_state); /* @@ -72,7 +72,7 @@ void uart_write_wakeup(struct uart_port *port) * closed. No cookie for you. */ BUG_ON(!state); - tasklet_schedule(&state->tlet); + tty_wakeup(state->port.tty); } static void uart_stop(struct tty_struct *tty) @@ -107,12 +107,6 @@ static void uart_start(struct tty_struct *tty) spin_unlock_irqrestore(&port->lock, flags); } -static void uart_tasklet_action(unsigned long data) -{ - struct uart_state *state = (struct uart_state *)data; - tty_wakeup(state->port.tty); -} - static inline void uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) { @@ -255,9 +249,11 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) } /* - * kill off our tasklet + * It's possible for shutdown to be called after suspend if we get + * a DCD drop (hangup) at just the right time. Clear suspended bit so + * we don't try to resume a port that has been shutdown. */ - tasklet_kill(&state->tlet); + clear_bit(ASYNCB_SUSPENDED, &port->flags); /* * Free the transmit buffer page. @@ -1261,8 +1257,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp) struct uart_port *uport; unsigned long flags; - BUG_ON(!tty_locked()); - if (!state) return; @@ -1271,12 +1265,11 @@ static void uart_close(struct tty_struct *tty, struct file *filp) pr_debug("uart_close(%d) called\n", uport->line); - mutex_lock(&port->mutex); spin_lock_irqsave(&port->lock, flags); if (tty_hung_up_p(filp)) { spin_unlock_irqrestore(&port->lock, flags); - goto done; + return; } if ((tty->count == 1) && (port->count != 1)) { @@ -1298,7 +1291,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) } if (port->count) { spin_unlock_irqrestore(&port->lock, flags); - goto done; + return; } /* @@ -1306,19 +1299,13 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * the line discipline to only process XON/XOFF characters by * setting tty->closing. */ + set_bit(ASYNCB_CLOSING, &port->flags); tty->closing = 1; spin_unlock_irqrestore(&port->lock, flags); - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) { - /* - * hack: open-coded tty_wait_until_sent to avoid - * recursive tty_lock - */ - long timeout = msecs_to_jiffies(port->closing_wait); - if (wait_event_interruptible_timeout(tty->write_wait, - !tty_chars_in_buffer(tty), timeout) >= 0) - __uart_wait_until_sent(uport, timeout); - } + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent_from_close(tty, + msecs_to_jiffies(port->closing_wait)); /* * At this point, we stop accepting input. To do this, we @@ -1334,9 +1321,10 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * has completely drained; this is especially * important if there is a transmit FIFO! */ - __uart_wait_until_sent(uport, uport->timeout); + uart_wait_until_sent(tty, uport->timeout); } + mutex_lock(&port->mutex); uart_shutdown(tty, state); uart_flush_buffer(tty); @@ -1361,15 +1349,18 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * Wake up anyone trying to open this port. */ clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); + clear_bit(ASYNCB_CLOSING, &port->flags); spin_unlock_irqrestore(&port->lock, flags); wake_up_interruptible(&port->open_wait); + wake_up_interruptible(&port->close_wait); -done: mutex_unlock(&port->mutex); } -static void __uart_wait_until_sent(struct uart_port *port, int timeout) +static void uart_wait_until_sent(struct tty_struct *tty, int timeout) { + struct uart_state *state = tty->driver_data; + struct uart_port *port = state->uart_port; unsigned long char_time, expire; if (port->type == PORT_UNKNOWN || port->fifosize == 0) @@ -1421,16 +1412,6 @@ static void __uart_wait_until_sent(struct uart_port *port, int timeout) } } -static void uart_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct uart_state *state = tty->driver_data; - struct uart_port *port = state->uart_port; - - tty_lock(); - __uart_wait_until_sent(port, timeout); - tty_unlock(); -} - /* * This is called with the BKL held in * linux/drivers/char/tty_io.c:do_tty_hangup() @@ -1443,7 +1424,6 @@ static void uart_hangup(struct tty_struct *tty) struct tty_port *port = &state->port; unsigned long flags; - BUG_ON(!tty_locked()); pr_debug("uart_hangup(%d)\n", state->uart_port->line); mutex_lock(&port->mutex); @@ -1530,7 +1510,6 @@ static int uart_open(struct tty_struct *tty, struct file *filp) struct tty_port *port; int retval, line = tty->index; - BUG_ON(!tty_locked()); pr_debug("uart_open(%d) called\n", line); /* @@ -2008,6 +1987,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) if (port->tty && port->tty->termios && termios.c_cflag == 0) termios = *(port->tty->termios); + if (console_suspend_enabled) + uart_change_pm(state, 0); uport->ops->set_termios(uport, &termios, NULL); if (console_suspend_enabled) console_start(uport->cons); @@ -2068,8 +2049,6 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) case UPIO_MEM32: case UPIO_AU: case UPIO_TSI: - case UPIO_DWAPB: - case UPIO_DWAPB32: snprintf(address, sizeof(address), "MMIO 0x%llx", (unsigned long long)port->mapbase); break; @@ -2298,8 +2277,6 @@ int uart_register_driver(struct uart_driver *drv) port->ops = &uart_port_ops; port->close_delay = 500; /* .5 seconds */ port->closing_wait = 30000; /* 30 seconds */ - tasklet_init(&state->tlet, uart_tasklet_action, - (unsigned long)state); } retval = tty_register_driver(normal); @@ -2460,11 +2437,6 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) */ uport->type = PORT_UNKNOWN; - /* - * Kill the tasklet, and free resources. - */ - tasklet_kill(&state->tlet); - state->uart_port = NULL; mutex_unlock(&port_mutex); @@ -2489,8 +2461,6 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2) case UPIO_MEM32: case UPIO_AU: case UPIO_TSI: - case UPIO_DWAPB: - case UPIO_DWAPB32: return (port1->mapbase == port2->mapbase); } return 0; diff --git a/drivers/tty/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c index 2430319f2f52..7c13639c597e 100644 --- a/drivers/tty/serial/serial_ks8695.c +++ b/drivers/tty/serial/serial_ks8695.c @@ -13,6 +13,7 @@ */ #include <linux/module.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/serial.h> @@ -336,19 +337,19 @@ static int ks8695uart_startup(struct uart_port *port) /* * Allocate the IRQ */ - retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, IRQF_DISABLED, "UART TX", port); + retval = request_irq(KS8695_IRQ_UART_TX, ks8695uart_tx_chars, 0, "UART TX", port); if (retval) goto err_tx; - retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, IRQF_DISABLED, "UART RX", port); + retval = request_irq(KS8695_IRQ_UART_RX, ks8695uart_rx_chars, 0, "UART RX", port); if (retval) goto err_rx; - retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, IRQF_DISABLED, "UART LineStatus", port); + retval = request_irq(KS8695_IRQ_UART_LINE_STATUS, ks8695uart_rx_chars, 0, "UART LineStatus", port); if (retval) goto err_ls; - retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, IRQF_DISABLED, "UART ModemStatus", port); + retval = request_irq(KS8695_IRQ_UART_MODEM_STATUS, ks8695uart_modem_status, 0, "UART ModemStatus", port); if (retval) goto err_ms; diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 8e3fc1944e6d..34bd345da775 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -28,6 +28,8 @@ #include <linux/pci.h> #include <linux/serial_core.h> #include <linux/serial.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #include <asm/io.h> diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 5ea6ec3442e6..9871c57b348e 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1976,7 +1976,7 @@ static int __devinit sci_init_single(struct platform_device *dev, * For the muxed case there's nothing more to do. */ port->irq = p->irqs[SCIx_RXI_IRQ]; - port->irqflags = IRQF_DISABLED; + port->irqflags = 0; port->serial_in = sci_serial_in; port->serial_out = sci_serial_out; diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c index 377ae74e7154..238c7df73ef5 100644 --- a/drivers/tty/serial/sn_console.c +++ b/drivers/tty/serial/sn_console.c @@ -39,6 +39,7 @@ #include <linux/interrupt.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/serial.h> #include <linux/console.h> #include <linux/module.h> @@ -737,7 +738,7 @@ static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port) DPRINTF("sn_console: switching to interrupt driven console\n"); if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt, - IRQF_DISABLED | IRQF_SHARED, + IRQF_SHARED, "SAL console driver", port) >= 0) { spin_lock_irqsave(&port->sc_port.lock, flags); port->sc_port.irq = SGI_UART_VECTOR; diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index 1f36b7eb7351..a4b63bfeaa2f 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -23,6 +23,8 @@ #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/serial_core.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/ioport.h> diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 8af1ed83a4c0..6cd414341d5e 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -15,6 +15,7 @@ #include <linux/serial.h> #include <linux/serial_core.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -568,8 +569,6 @@ static struct of_device_id ulite_of_match[] __devinitdata = { {} }; MODULE_DEVICE_TABLE(of, ulite_of_match); -#else /* CONFIG_OF */ -#define ulite_of_match NULL #endif /* CONFIG_OF */ static int __devinit ulite_probe(struct platform_device *pdev) @@ -609,7 +608,7 @@ static struct platform_driver ulite_platform_driver = { .driver = { .owner = THIS_MODULE, .name = "uartlite", - .of_match_table = ulite_of_match, + .of_match_table = of_match_ptr(ulite_of_match), }, }; diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 9af9f0879a24..cea8918b8233 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -20,8 +20,10 @@ #include <linux/module.h> #include <linux/serial.h> -#include <linux/slab.h> #include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/io.h> #include <linux/of_platform.h> #include <linux/dma-mapping.h> diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 19cc1e8149dd..8c03b127fd03 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -12,9 +12,11 @@ */ #include <linux/platform_device.h> +#include <linux/serial.h> #include <linux/serial_core.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/console.h> -#include <linux/serial.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/of.h> diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c index 0aebd7121b56..b7455b526080 100644 --- a/drivers/tty/serial/zs.c +++ b/drivers/tty/serial/zs.c @@ -63,6 +63,7 @@ #include <linux/spinlock.h> #include <linux/sysrq.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/types.h> #include <linux/atomic.h> |