📄 vme_scc.c
字号:
} SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);}static void scc_stat_int(int irq, void *data, struct pt_regs *fp){ struct scc_port *port = data; unsigned channel = port->channel; unsigned char last_sr, sr, changed; SCC_ACCESS_INIT(port); last_sr = scc_last_status_reg[channel]; sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG); changed = last_sr ^ sr; if (changed & SR_DCD) { port->c_dcd = !!(sr & SR_DCD); if (!(port->gs.flags & ASYNC_CHECK_CD)) ; /* Don't report DCD changes */ else if (port->c_dcd) { if (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) { /* Are we blocking in open?*/ wake_up_interruptible(&port->gs.open_wait); } } else { if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) && (port->gs.flags & ASYNC_CALLOUT_NOHUP))) { if (port->gs.tty) tty_hangup (port->gs.tty); } } } SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET); SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);}/*--------------------------------------------------------------------------- * generic_serial.c callback funtions *--------------------------------------------------------------------------*/static void scc_disable_tx_interrupts(void *ptr){ struct scc_port *port = ptr; unsigned long flags; SCC_ACCESS_INIT(port); save_flags(flags); cli(); SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); port->gs.flags &= ~GS_TX_INTEN; restore_flags(flags);}static void scc_enable_tx_interrupts(void *ptr){ struct scc_port *port = ptr; unsigned long flags; SCC_ACCESS_INIT(port); save_flags(flags); cli(); SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB); /* restart the transmitter */ scc_tx_int (0, port, 0); restore_flags(flags);}static void scc_disable_rx_interrupts(void *ptr){ struct scc_port *port = ptr; unsigned long flags; SCC_ACCESS_INIT(port); save_flags(flags); cli(); SCCmod(INT_AND_DMA_REG, ~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0); restore_flags(flags);}static void scc_enable_rx_interrupts(void *ptr){ struct scc_port *port = ptr; unsigned long flags; SCC_ACCESS_INIT(port); save_flags(flags); cli(); SCCmod(INT_AND_DMA_REG, 0xff, IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL); restore_flags(flags);}static int scc_get_CD(void *ptr){ struct scc_port *port = ptr; unsigned channel = port->channel; return !!(scc_last_status_reg[channel] & SR_DCD);}static void scc_shutdown_port(void *ptr){ struct scc_port *port = ptr; port->gs.flags &= ~ GS_ACTIVE; if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) { scc_setsignals (port, 0, 0); }}static int scc_set_real_termios (void *ptr){ /* the SCC has char sizes 5,7,6,8 in that order! */ static int chsize_map[4] = { 0, 2, 1, 3 }; unsigned cflag, baud, chsize, channel, brgval = 0; unsigned long flags; struct scc_port *port = ptr; SCC_ACCESS_INIT(port); if (!port->gs.tty || !port->gs.tty->termios) return 0; channel = port->channel; if (channel == CHANNEL_A) return 0; /* Settings controlled by boot PROM */ cflag = port->gs.tty->termios->c_cflag; baud = port->gs.baud; chsize = (cflag & CSIZE) >> 4; if (baud == 0) { /* speed == 0 -> drop DTR */ save_flags(flags); cli(); SCCmod(TX_CTRL_REG, ~TCR_DTR, 0); restore_flags(flags); return 0; } else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) || (MACH_IS_MVME147 && (baud < 50 || baud > 19200)) || (MACH_IS_BVME6000 &&(baud < 50 || baud > 76800))) { printk("SCC: Bad speed requested, %d\n", baud); return 0; } if (cflag & CLOCAL) port->gs.flags &= ~ASYNC_CHECK_CD; else port->gs.flags |= ASYNC_CHECK_CD;#ifdef CONFIG_MVME147_SCC if (MACH_IS_MVME147) brgval = (M147_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2; else#endif#ifdef CONFIG_MVME162_SCC if (MACH_IS_MVME16x) brgval = (MVME_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2; else#endif#ifdef CONFIG_BVME6000_SCC if (MACH_IS_BVME6000) brgval = (BVME_SCC_RTxC + baud/2) / (16 * 2 * baud) - 2;#endif /* Now we have all parameters and can go to set them: */ save_flags(flags); cli(); /* receiver's character size and auto-enables */ SCCmod(RX_CTRL_REG, ~(RCR_CHSIZE_MASK|RCR_AUTO_ENAB_MODE), (chsize_map[chsize] << 6) | ((cflag & CRTSCTS) ? RCR_AUTO_ENAB_MODE : 0)); /* parity and stop bits (both, Tx and Rx), clock mode never changes */ SCCmod (AUX1_CTRL_REG, ~(A1CR_PARITY_MASK | A1CR_MODE_MASK), ((cflag & PARENB ? (cflag & PARODD ? A1CR_PARITY_ODD : A1CR_PARITY_EVEN) : A1CR_PARITY_NONE) | (cflag & CSTOPB ? A1CR_MODE_ASYNC_2 : A1CR_MODE_ASYNC_1))); /* sender's character size, set DTR for valid baud rate */ SCCmod(TX_CTRL_REG, ~TCR_CHSIZE_MASK, chsize_map[chsize] << 5 | TCR_DTR); /* clock sources never change */ /* disable BRG before changing the value */ SCCmod(DPLL_CTRL_REG, ~DCR_BRG_ENAB, 0); /* BRG value */ SCCwrite(TIMER_LOW_REG, brgval & 0xff); SCCwrite(TIMER_HIGH_REG, (brgval >> 8) & 0xff); /* BRG enable, and clock source never changes */ SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB); restore_flags(flags); return 0;}static int scc_chars_in_buffer (void *ptr){ struct scc_port *port = ptr; SCC_ACCESS_INIT(port); return (SCCread (SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0 : 1;}static void scc_hungup(void *ptr){ scc_disable_tx_interrupts(ptr); scc_disable_rx_interrupts(ptr); MOD_DEC_USE_COUNT;}static void scc_close(void *ptr){ scc_disable_tx_interrupts(ptr); scc_disable_rx_interrupts(ptr);}/*--------------------------------------------------------------------------- * Internal support functions *--------------------------------------------------------------------------*/static void scc_setsignals(struct scc_port *port, int dtr, int rts){ unsigned long flags; unsigned char t; SCC_ACCESS_INIT(port); save_flags(flags); t = SCCread(TX_CTRL_REG); if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR); if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS); SCCwrite(TX_CTRL_REG, t); restore_flags(flags);}static void scc_send_xchar(struct tty_struct *tty, char ch){ struct scc_port *port = (struct scc_port *)tty->driver_data; port->x_char = ch; if (ch) scc_enable_tx_interrupts(port);}/*--------------------------------------------------------------------------- * Driver entrypoints referenced from above *--------------------------------------------------------------------------*/static int scc_open (struct tty_struct * tty, struct file * filp){ int line = MINOR(tty->device) - SCC_MINOR_BASE; int retval; struct scc_port *port = &scc_ports[line]; int i, channel = port->channel; unsigned long flags; SCC_ACCESS_INIT(port);#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_MVME147_SCC) static const struct { unsigned reg, val; } mvme_init_tab[] = { /* Values for MVME162 and MVME147 */ /* no parity, 1 stop bit, async, 1:16 */ { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 }, /* parity error is special cond, ints disabled, no DMA */ { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, /* Rx 8 bits/char, no auto enable, Rx off */ { RX_CTRL_REG, RCR_CHSIZE_8 }, /* DTR off, Tx 8 bits/char, RTS off, Tx off */ { TX_CTRL_REG, TCR_CHSIZE_8 }, /* special features off */ { AUX2_CTRL_REG, 0 }, { CLK_CTRL_REG, CCR_RXCLK_BRG | CCR_TXCLK_BRG }, { DPLL_CTRL_REG, DCR_BRG_ENAB | DCR_BRG_USE_PCLK }, /* Start Rx */ { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, /* Start Tx */ { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, /* Ext/Stat ints: DCD only */ { INT_CTRL_REG, ICR_ENAB_DCD_INT }, /* Reset Ext/Stat ints */ { COMMAND_REG, CR_EXTSTAT_RESET }, /* ...again */ { COMMAND_REG, CR_EXTSTAT_RESET }, };#endif#if defined(CONFIG_BVME6000_SCC) static const struct { unsigned reg, val; } bvme_init_tab[] = { /* Values for BVME6000 */ /* no parity, 1 stop bit, async, 1:16 */ { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 }, /* parity error is special cond, ints disabled, no DMA */ { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, /* Rx 8 bits/char, no auto enable, Rx off */ { RX_CTRL_REG, RCR_CHSIZE_8 }, /* DTR off, Tx 8 bits/char, RTS off, Tx off */ { TX_CTRL_REG, TCR_CHSIZE_8 }, /* special features off */ { AUX2_CTRL_REG, 0 }, { CLK_CTRL_REG, CCR_RTxC_XTAL | CCR_RXCLK_BRG | CCR_TXCLK_BRG }, { DPLL_CTRL_REG, DCR_BRG_ENAB }, /* Start Rx */ { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, /* Start Tx */ { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, /* Ext/Stat ints: DCD only */ { INT_CTRL_REG, ICR_ENAB_DCD_INT }, /* Reset Ext/Stat ints */ { COMMAND_REG, CR_EXTSTAT_RESET }, /* ...again */ { COMMAND_REG, CR_EXTSTAT_RESET }, };#endif if (!(port->gs.flags & ASYNC_INITIALIZED)) { save_flags(flags); cli();#if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC) if (MACH_IS_MVME147 || MACH_IS_MVME16x) { for (i=0; i<sizeof(mvme_init_tab)/sizeof(*mvme_init_tab); ++i) SCCwrite(mvme_init_tab[i].reg, mvme_init_tab[i].val); }#endif#if defined(CONFIG_BVME6000_SCC) if (MACH_IS_BVME6000) { for (i=0; i<sizeof(bvme_init_tab)/sizeof(*bvme_init_tab); ++i) SCCwrite(bvme_init_tab[i].reg, bvme_init_tab[i].val); }#endif /* remember status register for detection of DCD and CTS changes */ scc_last_status_reg[channel] = SCCread(STATUS_REG); port->c_dcd = 0; /* Prevent initial 1->0 interrupt */ scc_setsignals (port, 1,1); restore_flags(flags); } tty->driver_data = port; port->gs.tty = tty; port->gs.count++; retval = gs_init_port(&port->gs); if (retval) { port->gs.count--; return retval; } port->gs.flags |= GS_ACTIVE; if (port->gs.count == 1) { MOD_INC_USE_COUNT; } retval = block_til_ready(port, filp); if (retval) { MOD_DEC_USE_COUNT; port->gs.count--; return retval; } if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = port->gs.normal_termios; else *tty->termios = port->gs.callout_termios; scc_set_real_termios (port); } port->gs.session = current->session; port->gs.pgrp = current->pgrp; port->c_dcd = scc_get_CD (port); scc_enable_rx_interrupts(port); return 0;}static void scc_throttle (struct tty_struct * tty){ struct scc_port *port = (struct scc_port *)tty->driver_data; unsigned long flags; SCC_ACCESS_INIT(port); if (tty->termios->c_cflag & CRTSCTS) { save_flags(flags); cli(); SCCmod(TX_CTRL_REG, ~TCR_RTS, 0); restore_flags(flags); } if (I_IXOFF(tty)) scc_send_xchar(tty, STOP_CHAR(tty));}static void scc_unthrottle (struct tty_struct * tty){ struct scc_port *port = (struct scc_port *)tty->driver_data; unsigned long flags; SCC_ACCESS_INIT(port); if (tty->termios->c_cflag & CRTSCTS) { save_flags(flags); cli(); SCCmod(TX_CTRL_REG, 0xff, TCR_RTS); restore_flags(flags); } if (I_IXOFF(tty)) scc_send_xchar(tty, START_CHAR(tty));}static int scc_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ return -ENOIOCTLCMD;}static void scc_break_ctl(struct tty_struct *tty, int break_state){ struct scc_port *port = (struct scc_port *)tty->driver_data; unsigned long flags; SCC_ACCESS_INIT(port); save_flags(flags); cli(); SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, break_state ? TCR_SEND_BREAK : 0); restore_flags(flags);}/*--------------------------------------------------------------------------- * Serial console stuff... *--------------------------------------------------------------------------*/#define scc_delay() do { __asm__ __volatile__ (" nop; nop"); } while (0)static void scc_ch_write (char ch){ volatile char *p = NULL; #ifdef CONFIG_MVME147_SCC if (MACH_IS_MVME147) p = (volatile char *)M147_SCC_A_ADDR;#endif#ifdef CONFIG_MVME162_SCC if (MACH_IS_MVME16x) p = (volatile char *)MVME_SCC_A_ADDR;#endif#ifdef CONFIG_BVME6000_SCC if (MACH_IS_BVME6000) p = (volatile char *)BVME_SCC_A_ADDR;#endif do { scc_delay(); } while (!(*p & 4)); scc_delay(); *p = 8; scc_delay(); *p = ch;}/* The console_lock must be held when we get here. */static void scc_console_write (struct console *co, const char *str, unsigned count){ unsigned long flags; save_flags(flags); cli(); while (count--) { if (*str == '\n') scc_ch_write ('\r'); scc_ch_write (*str++); } restore_flags(flags);}static int scc_console_wait_key(struct console *co){ unsigned long flags; volatile char *p = NULL; int c; #ifdef CONFIG_MVME147_SCC if (MACH_IS_MVME147) p = (volatile char *)M147_SCC_A_ADDR;#endif#ifdef CONFIG_MVME162_SCC if (MACH_IS_MVME16x) p = (volatile char *)MVME_SCC_A_ADDR;#endif#ifdef CONFIG_BVME6000_SCC if (MACH_IS_BVME6000) p = (volatile char *)BVME_SCC_A_ADDR;#endif save_flags(flags); cli(); /* wait for rx buf filled */ while ((*p & 0x01) == 0) ; *p = 8; scc_delay(); c = *p; restore_flags(flags); return c;}static kdev_t scc_console_device(struct console *c){ return MKDEV(TTY_MAJOR, SCC_MINOR_BASE + c->index);}static int __init scc_console_setup(struct console *co, char *options){ return 0;}static struct console sercons = { name: "ttyS", write: scc_console_write, device: scc_console_device, wait_key: scc_console_wait_key, setup: scc_console_setup, flags: CON_PRINTBUFFER, index: -1,};void __init vme_scc_console_init(void){ if (vme_brdtype == VME_TYPE_MVME147 || vme_brdtype == VME_TYPE_MVME162 || vme_brdtype == VME_TYPE_MVME172 || vme_brdtype == VME_TYPE_BVME4000 || vme_brdtype == VME_TYPE_BVME6000) register_console(&sercons);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -