📄 sh-sci.c
字号:
mark_bh(IMMEDIATE_BH);}static void sci_transmit_chars(struct sci_port *port){ int count, i; int txroom; unsigned long flags; unsigned short status; unsigned short ctrl; unsigned char c; status = sci_in(port, SCxSR); if (!(status & SCxSR_TDxE(port))) { save_and_cli(flags); ctrl = sci_in(port, SCSCR); if (port->gs.xmit_cnt == 0) { ctrl &= ~SCI_CTRL_FLAGS_TIE; port->gs.flags &= ~GS_TX_INTEN; } else ctrl |= SCI_CTRL_FLAGS_TIE; sci_out(port, SCSCR, ctrl); restore_flags(flags); return; } while (1) { count = port->gs.xmit_cnt; if (port->type == PORT_SCIF) { txroom = 16 - (sci_in(port, SCFDR)>>8); } else { txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0; } if (count > txroom) count = txroom; /* Don't copy pas the end of the source buffer */ if (count > SERIAL_XMIT_SIZE - port->gs.xmit_tail) count = SERIAL_XMIT_SIZE - port->gs.xmit_tail; /* If for one reason or another, we can't copy more data, we're done! */ if (count == 0) break; for (i=0; i<count; i++) { c = port->gs.xmit_buf[port->gs.xmit_tail + i]; sci_out(port, SCxTDR, c); } sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); port->icount.tx += count; /* Update the kernel buffer end */ port->gs.xmit_tail = (port->gs.xmit_tail + count) & (SERIAL_XMIT_SIZE-1); /* This one last. (this is essential) It would allow others to start putting more data into the buffer! */ port->gs.xmit_cnt -= count; } if (port->gs.xmit_cnt <= port->gs.wakeup_chars) sci_sched_event(port, SCI_EVENT_WRITE_WAKEUP); save_and_cli(flags); ctrl = sci_in(port, SCSCR); if (port->gs.xmit_cnt == 0) { ctrl &= ~SCI_CTRL_FLAGS_TIE; port->gs.flags &= ~GS_TX_INTEN; } else { if (port->type == PORT_SCIF) { sci_in(port, SCxSR); /* Dummy read */ sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); } ctrl |= SCI_CTRL_FLAGS_TIE; } sci_out(port, SCSCR, ctrl); restore_flags(flags);}static inline void sci_receive_chars(struct sci_port *port){ int i, count; struct tty_struct *tty; int copied=0; unsigned short status; status = sci_in(port, SCxSR); if (!(status & SCxSR_RDxF(port))) return; tty = port->gs.tty; while (1) { if (port->type == PORT_SCIF) { count = sci_in(port, SCFDR)&0x001f; } else { count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0; } /* Don't copy more bytes than there is room for in the buffer */ if (tty->flip.count + count > TTY_FLIPBUF_SIZE) count = TTY_FLIPBUF_SIZE - tty->flip.count; /* If for one reason or another, we can't copy more data, we're done! */ if (count == 0) break; if (port->type == PORT_SCI) { tty->flip.char_buf_ptr[0] = sci_in(port, SCxRDR); tty->flip.flag_buf_ptr[0] = TTY_NORMAL; } else { for (i=0; i<count; i++) { tty->flip.char_buf_ptr[i] = sci_in(port, SCxRDR); status = sci_in(port, SCxSR); if (status&SCxSR_FER(port)) { tty->flip.flag_buf_ptr[i] = TTY_FRAME; dprintk("sci: frame error\n"); } else if (status&SCxSR_PER(port)) { tty->flip.flag_buf_ptr[i] = TTY_PARITY; dprintk("sci: parity error\n"); } else { tty->flip.flag_buf_ptr[i] = TTY_NORMAL; } } } sci_in(port, SCxSR); /* dummy read */ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); /* Update the kernel buffer end */ tty->flip.count += count; tty->flip.char_buf_ptr += count; tty->flip.flag_buf_ptr += count; copied += count; port->icount.rx += count; } if (copied) /* Tell the rest of the system the news. New characters! */ tty_flip_buffer_push(tty);}static inline int sci_handle_errors(struct sci_port *port){ int copied = 0; unsigned short status = sci_in(port, SCxSR); struct tty_struct *tty = port->gs.tty; if (status&SCxSR_ORER(port) && tty->flip.count<TTY_FLIPBUF_SIZE) { /* overrun error */ copied++; *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; dprintk("sci: overrun error\n"); } if (status&SCxSR_FER(port) && tty->flip.count<TTY_FLIPBUF_SIZE) { if (sci_rxd_in(port) == 0) { /* Notify of BREAK */ copied++; *tty->flip.flag_buf_ptr++ = TTY_BREAK; dprintk("sci: BREAK detected\n"); } else { /* frame error */ copied++; *tty->flip.flag_buf_ptr++ = TTY_FRAME; dprintk("sci: frame error\n"); } } if (status&SCxSR_PER(port) && tty->flip.count<TTY_FLIPBUF_SIZE) { /* parity error */ copied++; *tty->flip.flag_buf_ptr++ = TTY_PARITY; dprintk("sci: parity error\n"); } if (copied) { tty->flip.count += copied; tty_flip_buffer_push(tty); } return copied;}static inline int sci_handle_breaks(struct sci_port *port){ int copied = 0; unsigned short status = sci_in(port, SCxSR); struct tty_struct *tty = port->gs.tty; if (status&SCxSR_BRK(port) && tty->flip.count<TTY_FLIPBUF_SIZE) { /* Notify of BREAK */ copied++; *tty->flip.flag_buf_ptr++ = TTY_BREAK; dprintk("sci: BREAK detected\n"); }#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1) /* XXX: Handle SCIF overrun error */ if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) { sci_out(port, SCLSR, 0); if(tty->flip.count<TTY_FLIPBUF_SIZE) { copied++; *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; dprintk("sci: overrun error\n"); } }#endif if (copied) { tty->flip.count += copied; tty_flip_buffer_push(tty); } return copied;}static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs){ struct sci_port *port = ptr; if (port->gs.flags & GS_ACTIVE) if (!(port->gs.flags & SCI_RX_THROTTLE)) { sci_receive_chars(port); return; } sci_disable_rx_interrupts(port);}static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs){ struct sci_port *port = ptr; if (port->gs.flags & GS_ACTIVE) sci_transmit_chars(port); else { sci_disable_tx_interrupts(port); }}static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs){ struct sci_port *port = ptr; /* Handle errors */ if (port->type == PORT_SCI) { if(sci_handle_errors(port)) { /* discard character in rx buffer */ sci_in(port, SCxSR); sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); } } else sci_rx_interrupt(irq, ptr, regs); sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ sci_tx_interrupt(irq, ptr, regs);}static void sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs){ struct sci_port *port = ptr; /* Handle BREAKs */ sci_handle_breaks(port); sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));}static void do_softint(void *private_){ struct sci_port *port = (struct sci_port *) private_; struct tty_struct *tty; tty = port->gs.tty; if (!tty) return; if (test_and_clear_bit(SCI_EVENT_WRITE_WAKEUP, &port->event)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); }}/* ********************************************************************** * * Here are the routines that actually * * interface with the generic_serial driver * * ********************************************************************** */static void sci_disable_tx_interrupts(void *ptr){ struct sci_port *port = ptr; unsigned long flags; unsigned short ctrl; /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ save_and_cli(flags); ctrl = sci_in(port, SCSCR); ctrl &= ~SCI_CTRL_FLAGS_TIE; sci_out(port, SCSCR, ctrl); restore_flags(flags);}static void sci_enable_tx_interrupts(void *ptr){ struct sci_port *port = ptr; disable_irq(port->irqs[SCIx_TXI_IRQ]); sci_transmit_chars(port); enable_irq(port->irqs[SCIx_TXI_IRQ]);}static void sci_disable_rx_interrupts(void * ptr){ struct sci_port *port = ptr; unsigned long flags; unsigned short ctrl; /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ save_and_cli(flags); ctrl = sci_in(port, SCSCR); ctrl &= ~SCI_CTRL_FLAGS_RIE; sci_out(port, SCSCR, ctrl); restore_flags(flags);}static void sci_enable_rx_interrupts(void * ptr){ struct sci_port *port = ptr; unsigned long flags; unsigned short ctrl; /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ save_and_cli(flags); ctrl = sci_in(port, SCSCR); ctrl |= SCI_CTRL_FLAGS_RIE; sci_out(port, SCSCR, ctrl); restore_flags(flags);}static int sci_get_CD(void * ptr){ /* If you have signal for CD (Carrier Detect), please change here. */ return 1;}static int sci_chars_in_buffer(void * ptr){ struct sci_port *port = ptr; if (port->type == PORT_SCIF) { return (sci_in(port, SCFDR) >> 8) + ((sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1); } else { return (sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1; }}static void sci_shutdown_port(void * ptr){ struct sci_port *port = ptr; port->gs.flags &= ~ GS_ACTIVE; if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) sci_setsignals(port, 0, 0); sci_free_irq(port);}/* ********************************************************************** * * Here are the routines that actually * * interface with the rest of the system * * ********************************************************************** */static int sci_open(struct tty_struct * tty, struct file * filp){ struct sci_port *port; int retval, line; line = MINOR(tty->device) - SCI_MINOR_START; if ((line < 0) || (line >= SCI_NPORTS)) return -ENODEV; port = &sci_ports[line]; tty->driver_data = port; port->gs.tty = tty; port->gs.count++; port->event = 0; port->tqueue.routine = do_softint; port->tqueue.data = port; /* * Start up serial port */ retval = gs_init_port(&port->gs); if (retval) { goto failed_1; } port->gs.flags |= GS_ACTIVE; sci_setsignals(port, 1,1); if (port->gs.count == 1) { MOD_INC_USE_COUNT; retval = sci_request_irq(port); if (retval) { goto failed_2; } } retval = gs_block_til_ready(port, filp); if (retval) { goto failed_3; } 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; sci_set_real_termios(port); }#ifdef CONFIG_SERIAL_CONSOLE if (sercons.cflag && sercons.index == line) { tty->termios->c_cflag = sercons.cflag; port->gs.baud = sercons_baud;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -