⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial_sicc.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  arch/ppc/4xx_io/serial_sicc.c * *  Driver for IBM STB3xxx SICC serial port * *  Based on drivers/char/serial_amba.c, by ARM Ltd. * *  Copyright 2001 IBM Crop. *  Author: IBM China Research Lab *            Yudong Yang <yangyud@cn.ibm.com> *            Yi Ge       <geyi@cn.ibm.com> * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * * This is a driver for SICC serial port on IBM Redwood 4 evaluation board. * The driver support both as a console device and normal serial device and * is compatible with normal ttyS* devices. */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/major.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/circ_buf.h>#include <linux/serial.h>#include <linux/console.h>#include <linux/sysrq.h>#include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/bitops.h>#include <asm/serial.h>#include <linux/serialP.h>/* ----------------------------------------------------------------------------- *  From STB03xxx SICC UART Specification * ----------------------------------------------------------------------------- *  UART Register Offsets. */#define BL_SICC_LSR   0x0000000      /* line status register read/clear */#define BL_SICC_LSRS  0x0000001      /* set line status register read/set */#define BL_SICC_HSR   0x0000002      /* handshake status register r/clear */#define BL_SICC_HSRS  0x0000003      /* set handshake status register r/set */#define BL_SICC_BRDH  0x0000004      /* baudrate divisor high reg r/w */#define BL_SICC_BRDL  0x0000005      /* baudrate divisor low reg r/w */#define BL_SICC_LCR   0x0000006      /* control register r/w */#define BL_SICC_RCR   0x0000007      /* receiver command register r/w */#define BL_SICC_TxCR  0x0000008      /* transmitter command register r/w */#define BL_SICC_RBR   0x0000009      /* receive buffer r */#define BL_SICC_TBR   0x0000009      /* transmit buffer w */#define BL_SICC_CTL2  0x000000A      /* added for Vesta */#define BL_SICC_IrCR  0x000000B      /* added for Vesta IR *//* masks and definitions for serial port control register */#define _LCR_LM_MASK  0xc0            /* loop back modes */#define _LCR_DTR_MASK 0x20            /* data terminal ready 0-inactive */#define _LCR_RTS_MASK 0x10            /* request to send 0-inactive */#define _LCR_DB_MASK  0x08            /* data bits mask */#define _LCR_PE_MASK  0x04            /* parity enable */#define _LCR_PTY_MASK 0x02            /* parity */#define _LCR_SB_MASK  0x01            /* stop bit mask */#define _LCR_LM_NORM  0x00            /* normal operation */#define _LCR_LM_LOOP  0x40            /* internal loopback mode */#define _LCR_LM_ECHO  0x80            /* automatic echo mode */#define _LCR_LM_RES   0xc0            /* reserved */#define _LCR_DTR_ACTIVE       _LCR_DTR_MASK /* DTR is active */#define _LCR_RTS_ACTIVE       _LCR_RTS_MASK /* RTS is active */#define _LCR_DB_8_BITS        _LCR_DB_MASK  /*  8 data bits */#define _LCR_DB_7_BITS        0x00          /*  7 data bits */#define _LCR_PE_ENABLE        _LCR_PE_MASK  /* parity enabled */#define _LCR_PE_DISABLE       0x00          /* parity disabled */#define _LCR_PTY_EVEN         0x00          /* even parity */#define _LCR_PTY_ODD          _LCR_PTY_MASK /* odd parity */#define _LCR_SB_1_BIT         0x00          /* one stop bit */#define _LCR_SB_2_BIT         _LCR_SB_MASK  /* two stop bit *//* serial port handshake register */#define _HSR_DIS_MASK  0x80            /* DSR input inactive error mask */#define _HSR_CS_MASK   0x40            /* CTS input inactive error mask */#define _HSR_DIS_ACT   0x00            /* dsr input is active */#define _HSR_DIS_INACT _HSR_DIS_MASK   /* dsr input is inactive */#define _HSR_CS_ACT    0x00            /* cts input is active */#define _HSR_CS_INACT  _HSR_CS_MASK    /* cts input is active *//* serial port line status register */#define _LSR_RBR_MASK  0x80            /* receive buffer ready mask */#define _LSR_FE_MASK   0x40            /* framing error */#define _LSR_OE_MASK   0x20            /* overrun error */#define _LSR_PE_MASK   0x10            /* parity error */#define _LSR_LB_MASK   0x08            /* line break */#define _LSR_TBR_MASK  0x04            /* transmit buffer ready */#define _LSR_TSR_MASK  0x02            /* transmit shift register ready */#define _LSR_RBR_FULL  _LSR_RBR_MASK  /* receive buffer is full */#define _LSR_FE_ERROR  _LSR_FE_MASK   /* framing error detected */#define _LSR_OE_ERROR  _LSR_OE_MASK   /* overrun error detected */#define _LSR_PE_ERROR  _LSR_PE_MASK   /* parity error detected */#define _LSR_LB_BREAK  _LSR_LB_MASK   /* line break detected */#define _LSR_TBR_EMPTY _LSR_TBR_MASK  /* transmit buffer is ready */#define _LSR_TSR_EMPTY _LSR_TSR_MASK  /* transmit shift register is empty */#define _LSR_TX_ALL    0x06           /* all physical transmit is done */#define _LSR_RX_ERR    (_LSR_LB_BREAK | _LSR_FE_MASK | _LSR_OE_MASK | \			 _LSR_PE_MASK )/* serial port receiver command register */#define _RCR_ER_MASK   0x80           /* enable receiver mask */#define _RCR_DME_MASK  0x60           /* dma mode */#define _RCR_EIE_MASK  0x10           /* error interrupt enable mask */#define _RCR_PME_MASK  0x08           /* pause mode mask */#define _RCR_ER_ENABLE _RCR_ER_MASK   /* receiver enabled */#define _RCR_DME_DISABLE 0x00         /* dma disabled */#define _RCR_DME_RXRDY 0x20           /* dma disabled, RxRDY interrupt enabled*/#define _RCR_DME_ENABLE2 0x40         /* dma enabled,receiver src channel 2 */#define _RCR_DME_ENABLE3 0x60         /* dma enabled,receiver src channel 3 */#define _RCR_PME_HARD  _RCR_PME_MASK  /* RTS controlled by hardware */#define _RCR_PME_SOFT  0x00           /* RTS controlled by software *//* serial port transmit command register */#define _TxCR_ET_MASK   0x80           /* transmiter enable mask */#define _TxCR_DME_MASK  0x60           /* dma mode mask */#define _TxCR_TIE_MASK  0x10           /* empty interrupt enable mask */#define _TxCR_EIE_MASK  0x08           /* error interrupt enable mask */#define _TxCR_SPE_MASK  0x04           /* stop/pause mask */#define _TxCR_TB_MASK   0x02           /* transmit break mask */#define _TxCR_ET_ENABLE _TxCR_ET_MASK  /* transmiter enabled */#define _TxCR_DME_DISABLE 0x00         /* transmiter disabled, TBR intr disabled */#define _TxCR_DME_TBR   0x20           /* transmiter disabled, TBR intr enabled */#define _TxCR_DME_CHAN_2 0x40          /* dma enabled, destination chann 2 */#define _TxCR_DME_CHAN_3 0x60          /* dma enabled, destination chann 3 *//* serial ctl reg 2 - added for Vesta */#define _CTL2_EXTERN  0x80            /*  */#define _CTL2_USEFIFO 0x40            /*  */#define _CTL2_RESETRF 0x08            /*  */#define _CTL2_RESETTF 0x04            /*  */#define SERIAL_SICC_NAME    "ttySICC"#define SERIAL_SICC_MAJOR   150#define SERIAL_SICC_MINOR   1#define SERIAL_SICC_NR      1#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE 0#endif/* * Things needed by tty driver */static struct tty_driver *siccnormal_driver;#if defined(CONFIG_SERIAL_SICC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)#define SUPPORT_SYSRQ#endif/* * Things needed internally to this driver *//* * tmp_buf is used as a temporary buffer by serial_write.  We need to * lock it in case the copy_from_user blocks while swapping in a page, * and some other program tries to do a serial write at the same time. * Since the lock will only come under contention when the system is * swapping and available memory is low, it makes sense to share one * buffer across all the serial ports, since it significantly saves * memory if large numbers of serial ports are open. */static u_char *tmp_buf;static DECLARE_MUTEX(tmp_buf_sem);#define HIGH_BITS_OFFSET    ((sizeof(long)-sizeof(int))*8)/* number of characters left in xmit buffer before we ask for more */#define WAKEUP_CHARS        256#define SICC_ISR_PASS_LIMIT 256#define EVT_WRITE_WAKEUP    0struct SICC_icount {    __u32   cts;    __u32   dsr;    __u32   rng;    __u32   dcd;    __u32   rx;    __u32   tx;    __u32   frame;    __u32   overrun;    __u32   parity;    __u32   brk;    __u32   buf_overrun;};/* * Static information about the port */struct SICC_port {    unsigned int        uart_base;    unsigned int        uart_base_phys;    unsigned int        irqrx;    unsigned int        irqtx;    unsigned int        uartclk;    unsigned int        fifosize;    unsigned int        tiocm_support;    void (*set_mctrl)(struct SICC_port *, u_int mctrl);};/* * This is the state information which is persistent across opens */struct SICC_state {    struct SICC_icount  icount;    unsigned int        line;    unsigned int        close_delay;    unsigned int        closing_wait;    unsigned int        custom_divisor;    unsigned int        flags;    int         count;    struct SICC_info    *info;};#define SICC_XMIT_SIZE 1024/* * This is the state information which is only valid when the port is open. */struct SICC_info {    struct SICC_port    *port;    struct SICC_state   *state;    struct tty_struct   *tty;    unsigned char       x_char;    unsigned char       old_status;    unsigned char       read_status_mask;    unsigned char       ignore_status_mask;    struct circ_buf     xmit;    unsigned int        flags;#ifdef SUPPORT_SYSRQ    unsigned long       sysrq;#endif    unsigned int        event;    unsigned int        timeout;    unsigned int        lcr_h;    unsigned int        mctrl;    int         blocked_open;    struct tasklet_struct   tlet;    wait_queue_head_t   open_wait;    wait_queue_head_t   close_wait;    wait_queue_head_t   delta_msr_wait;};#ifdef CONFIG_SERIAL_SICC_CONSOLEstatic struct console siccuart_cons;#endifstatic void siccuart_change_speed(struct SICC_info *info, struct termios *old_termios);static void siccuart_wait_until_sent(struct tty_struct *tty, int timeout);static void powerpcMtcic_cr(unsigned long value){    mtdcr(DCRN_CICCR, value);}static unsigned long powerpcMfcic_cr(void){    return mfdcr(DCRN_CICCR);}static unsigned long powerpcMfclkgpcr(void){    return mfdcr(DCRN_SCCR);}static void sicc_set_mctrl_null(struct SICC_port *port, u_int mctrl){}static struct SICC_port sicc_ports[SERIAL_SICC_NR] = {    {        .uart_base = 0,        .uart_base_phys = SICC0_IO_BASE,        .irqrx =    SICC0_INTRX,        .irqtx =    SICC0_INTTX,//      .uartclk =    0,        .fifosize = 1,        .set_mctrl = sicc_set_mctrl_null,    }};static struct SICC_state sicc_state[SERIAL_SICC_NR];static void siccuart_enable_rx_interrupt(struct SICC_info *info){    unsigned char cr;    cr = readb(info->port->uart_base+BL_SICC_RCR);    cr &= ~_RCR_DME_MASK;    cr |= _RCR_DME_RXRDY;    writeb(cr, info->port->uart_base+BL_SICC_RCR);}static void siccuart_disable_rx_interrupt(struct SICC_info *info){    unsigned char cr;    cr = readb(info->port->uart_base+BL_SICC_RCR);    cr &= ~_RCR_DME_MASK;    cr |=  _RCR_DME_DISABLE;    writeb(cr, info->port->uart_base+BL_SICC_RCR);}static void siccuart_enable_tx_interrupt(struct SICC_info *info){    unsigned char cr;    cr = readb(info->port->uart_base+BL_SICC_TxCR);    cr &= ~_TxCR_DME_MASK;    cr |= _TxCR_DME_TBR;    writeb(cr, info->port->uart_base+BL_SICC_TxCR);}static void siccuart_disable_tx_interrupt(struct SICC_info *info){    unsigned char cr;    cr = readb(info->port->uart_base+BL_SICC_TxCR);    cr &= ~_TxCR_DME_MASK;    cr |=  _TxCR_DME_DISABLE;    writeb(cr, info->port->uart_base+BL_SICC_TxCR);}static void siccuart_stop(struct tty_struct *tty){    struct SICC_info *info = tty->driver_data;    unsigned long flags;    save_flags(flags); cli();    siccuart_disable_tx_interrupt(info);    restore_flags(flags);}static void siccuart_start(struct tty_struct *tty){    struct SICC_info *info = tty->driver_data;    unsigned long flags;    save_flags(flags); cli();    if (info->xmit.head != info->xmit.tail        && info->xmit.buf)        siccuart_enable_tx_interrupt(info);    restore_flags(flags);}/* * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. */static void siccuart_event(struct SICC_info *info, int event){    info->event |= 1 << event;    tasklet_schedule(&info->tlet);}static voidsiccuart_rx_chars(struct SICC_info *info, struct pt_regs *regs){    struct tty_struct *tty = info->tty;    unsigned int status, ch, rsr, flg, ignored = 0;    struct SICC_icount *icount = &info->state->icount;    struct SICC_port *port = info->port;    status = readb(port->uart_base+BL_SICC_LSR );    while (status & _LSR_RBR_FULL) {        ch = readb(port->uart_base+BL_SICC_RBR);        if (tty->flip.count >= TTY_FLIPBUF_SIZE)            goto ignore_char;        icount->rx++;        flg = TTY_NORMAL;        /*         * Note that the error handling code is         * out of the main execution path         */        rsr = readb(port->uart_base+BL_SICC_LSR);        if (rsr & _LSR_RX_ERR)            goto handle_error;#ifdef SUPPORT_SYSRQ        if (info->sysrq) {            if (ch && time_before(jiffies, info->sysrq)) {                handle_sysrq(ch, regs, NULL);                info->sysrq = 0;                goto ignore_char;            }            info->sysrq = 0;        }#endif    error_return:        *tty->flip.flag_buf_ptr++ = flg;        *tty->flip.char_buf_ptr++ = ch;        tty->flip.count++;    ignore_char:        status = readb(port->uart_base+BL_SICC_LSR );    }out:    tty_flip_buffer_push(tty);    return;handle_error:    if (rsr & _LSR_LB_BREAK) {        rsr &= ~(_LSR_FE_MASK | _LSR_PE_MASK);        icount->brk++;#ifdef SUPPORT_SYSRQ        if (info->state->line == siccuart_cons.index) {            if (!info->sysrq) {                info->sysrq = jiffies + HZ*5;                goto ignore_char;            }        }#endif    } else if (rsr & _LSR_PE_MASK)        icount->parity++;    else if (rsr & _LSR_FE_MASK)        icount->frame++;    if (rsr & _LSR_OE_MASK)        icount->overrun++;    if (rsr & info->ignore_status_mask) {        if (++ignored > 100)            goto out;        goto ignore_char;    }    rsr &= info->read_status_mask;    if (rsr & _LSR_LB_BREAK)        flg = TTY_BREAK;    else if (rsr &  _LSR_PE_MASK)        flg = TTY_PARITY;    else if (rsr &  _LSR_FE_MASK)        flg = TTY_FRAME;    if (rsr &  _LSR_OE_MASK) {        /*         * CHECK: does overrun affect the current character?         * ASSUMPTION: it does not.         */        *tty->flip.flag_buf_ptr++ = flg;        *tty->flip.char_buf_ptr++ = ch;        tty->flip.count++;        if (tty->flip.count >= TTY_FLIPBUF_SIZE)            goto ignore_char;        ch = 0;        flg = TTY_OVERRUN;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -