📄 serial.c
字号:
#include <linux/version.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/major.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/init.h>#include <asm/uaccess.h>#include <linux/kernel.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/segment.h>#include <asm/bitops.h>#include <linux/delay.h>#include <asm/arch/svinto.h>/* non-arch dependent serial structures are in linux/serial.h */#include <linux/serial.h>/* while we keep our own stuff (struct e100_serial) in a local .h file */#include "serial.h"#include <asm/fasttimer.h>#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER#ifndef CONFIG_ETRAX_FAST_TIMER#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER"#endif#endif#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \ (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0)#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1"#endif#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G)#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G"#endif/* * All of the compatibilty code so we can compile serial.c against * older kernels is hidden in serial_compat.h */#if defined(LOCAL_HEADERS)#include "serial_compat.h"#endif#define _INLINE_ inlinestruct tty_driver *serial_driver;/* serial subtype definitions */#ifndef SERIAL_TYPE_NORMAL#define SERIAL_TYPE_NORMAL 1#endif/* number of characters left in xmit buffer before we ask for more */#define WAKEUP_CHARS 256//#define SERIAL_DEBUG_INTR//#define SERIAL_DEBUG_OPEN //#define SERIAL_DEBUG_FLOW//#define SERIAL_DEBUG_DATA//#define SERIAL_DEBUG_THROTTLE//#define SERIAL_DEBUG_IO /* Debug for Extra control and status pins *///#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug *//* Enable this to use serial interrupts to handle when you expect the first received event on the serial port to be an error, break or similar. Used to be able to flash IRMA from eLinux */#define SERIAL_HANDLE_EARLY_ERRORS/* Defined and used in n_tty.c, but we need it here as well */#define TTY_THRESHOLD_THROTTLE 128/* Due to buffersizes and threshold values, our SERIAL_DESCR_BUF_SIZE * must not be to high or flow control won't work if we leave it to the tty * layer so we have our own throttling in flush_to_flip * TTY_FLIPBUF_SIZE=512, * TTY_THRESHOLD_THROTTLE/UNTHROTTLE=128 * BUF_SIZE can't be > 128 *//* Currently 16 descriptors x 128 bytes = 2048 bytes */#define SERIAL_DESCR_BUF_SIZE 256#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE/* We don't want to load the system with massive fast timer interrupt * on high baudrates so limit it to 250 us (4kHz) */#define MIN_FLUSH_TIME_USEC 250/* Add an x here to log a lot of timer stuff */#define TIMERD(x)/* Debug details of interrupt handling */#define DINTR1(x) /* irq on/off, errors */#define DINTR2(x) /* tx and rx *//* Debug flip buffer stuff */#define DFLIP(x)/* Debug flow control and overview of data flow */#define DFLOW(x)#define DBAUD(x)#define DLOG_INT_TRIG(x)//#define DEBUG_LOG_INCLUDED#ifndef DEBUG_LOG_INCLUDED#define DEBUG_LOG(line, string, value)#elsestruct debug_log_info{ unsigned long time; unsigned long timer_data;// int line; const char *string; int value;};#define DEBUG_LOG_SIZE 4096struct debug_log_info debug_log[DEBUG_LOG_SIZE];int debug_log_pos = 0;#define DEBUG_LOG(_line, _string, _value) do { \ if ((_line) == SERIAL_DEBUG_LINE) {\ debug_log_func(_line, _string, _value); \ }\}while(0)void debug_log_func(int line, const char *string, int value){ if (debug_log_pos < DEBUG_LOG_SIZE) { debug_log[debug_log_pos].time = jiffies; debug_log[debug_log_pos].timer_data = *R_TIMER_DATA;// debug_log[debug_log_pos].line = line; debug_log[debug_log_pos].string = string; debug_log[debug_log_pos].value = value; debug_log_pos++; } /*printk(string, value);*/}#endif#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/* Default number of timer ticks before flushing rx fifo * When using "little data, low latency applications: use 0 * When using "much data applications (PPP)" use ~5 */#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 #endifunsigned long timer_data_to_ns(unsigned long timer_data);static void change_speed(struct e100_serial *info);static void rs_throttle(struct tty_struct * tty);static void rs_wait_until_sent(struct tty_struct *tty, int timeout);static int rs_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count);extern _INLINE_ int rs_raw_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count);#ifdef CONFIG_ETRAX_RS485static int e100_write_rs485(struct tty_struct * tty, int from_user, const unsigned char *buf, int count);#endifstatic int get_lsr_info(struct e100_serial * info, unsigned int *value);#define DEF_BAUD 115200 /* 115.2 kbit/s */#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)#define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 *//* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */#define DEF_TX 0x80 /* or SERIAL_CTRL_B *//* offsets from R_SERIALx_CTRL */#define REG_DATA 0#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */#define REG_TR_DATA 0#define REG_STATUS 1#define REG_TR_CTRL 1#define REG_REC_CTRL 2#define REG_BAUD 3#define REG_XOFF 4 /* this is a 32 bit register *//* The bitfields are the same for all serial ports */#define SER_RXD_MASK IO_MASK(R_SERIAL0_STATUS, rxd)#define SER_DATA_AVAIL_MASK IO_MASK(R_SERIAL0_STATUS, data_avail)#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err)#define SER_PAR_ERR_MASK IO_MASK(R_SERIAL0_STATUS, par_err)#define SER_OVERRUN_MASK IO_MASK(R_SERIAL0_STATUS, overrun)#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK)/* Values for info->errorcode */#define ERRCODE_SET_BREAK (TTY_BREAK)#define ERRCODE_INSERT 0x100#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK)#define FORCE_EOP(info) *R_SET_EOP = 1U << info->iseteop;/* * General note regarding the use of IO_* macros in this file: * * We will use the bits defined for DMA channel 6 when using various * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are * the same for all channels (which of course they are). * * We will also use the bits defined for serial port 0 when writing commands * to the different ports, as these bits too are the same for all ports. *//* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */static const unsigned long e100_ser_int_mask = 0#ifdef CONFIG_ETRAX_SERIAL_PORT0| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready)#endif#ifdef CONFIG_ETRAX_SERIAL_PORT1| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready)#endif#ifdef CONFIG_ETRAX_SERIAL_PORT2| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready)#endif#ifdef CONFIG_ETRAX_SERIAL_PORT3| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready)#endif;unsigned long r_alt_ser_baudrate_shadow = 0;/* this is the data for the four serial ports in the etrax100 *//* DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) *//* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */static struct e100_serial rs_table[] = { { .baud = DEF_BAUD, .port = (unsigned char *)R_SERIAL0_CTRL, .irq = 1U << 12, /* uses DMA 6 and 7 */ .oclrintradr = R_DMA_CH6_CLR_INTR, .ofirstadr = R_DMA_CH6_FIRST, .ocmdadr = R_DMA_CH6_CMD, .ostatusadr = R_DMA_CH6_STATUS, .iclrintradr = R_DMA_CH7_CLR_INTR, .ifirstadr = R_DMA_CH7_FIRST, .icmdadr = R_DMA_CH7_CMD, .idescradr = R_DMA_CH7_DESCR, .flags = STD_FLAGS, .rx_ctrl = DEF_RX, .tx_ctrl = DEF_TX, .iseteop = 2,#ifdef CONFIG_ETRAX_SERIAL_PORT0 .enabled = 1,#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT .dma_out_enabled = 1,#else .dma_out_enabled = 0,#endif#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN .dma_in_enabled = 1,#else .dma_in_enabled = 0#endif#else .enabled = 0, .dma_out_enabled = 0, .dma_in_enabled = 0#endif}, /* ttyS0 */#ifndef CONFIG_SVINTO_SIM { .baud = DEF_BAUD, .port = (unsigned char *)R_SERIAL1_CTRL, .irq = 1U << 16, /* uses DMA 8 and 9 */ .oclrintradr = R_DMA_CH8_CLR_INTR, .ofirstadr = R_DMA_CH8_FIRST, .ocmdadr = R_DMA_CH8_CMD, .ostatusadr = R_DMA_CH8_STATUS, .iclrintradr = R_DMA_CH9_CLR_INTR, .ifirstadr = R_DMA_CH9_FIRST, .icmdadr = R_DMA_CH9_CMD, .idescradr = R_DMA_CH9_DESCR, .flags = STD_FLAGS, .rx_ctrl = DEF_RX, .tx_ctrl = DEF_TX, .iseteop = 3,#ifdef CONFIG_ETRAX_SERIAL_PORT1 .enabled = 1,#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT .dma_out_enabled = 1,#else .dma_out_enabled = 0,#endif#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN .dma_in_enabled = 1,#else .dma_in_enabled = 0#endif#else .enabled = 0, .dma_out_enabled = 0, .dma_in_enabled = 0#endif}, /* ttyS1 */ { .baud = DEF_BAUD, .port = (unsigned char *)R_SERIAL2_CTRL, .irq = 1U << 4, /* uses DMA 2 and 3 */ .oclrintradr = R_DMA_CH2_CLR_INTR, .ofirstadr = R_DMA_CH2_FIRST, .ocmdadr = R_DMA_CH2_CMD, .ostatusadr = R_DMA_CH2_STATUS, .iclrintradr = R_DMA_CH3_CLR_INTR, .ifirstadr = R_DMA_CH3_FIRST, .icmdadr = R_DMA_CH3_CMD, .idescradr = R_DMA_CH3_DESCR, .flags = STD_FLAGS, .rx_ctrl = DEF_RX, .tx_ctrl = DEF_TX, .iseteop = 0,#ifdef CONFIG_ETRAX_SERIAL_PORT2 .enabled = 1,#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT .dma_out_enabled = 1,#else .dma_out_enabled = 0,#endif#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN .dma_in_enabled = 1,#else .dma_in_enabled = 0#endif#else .enabled = 0, .dma_out_enabled = 0, .dma_in_enabled = 0#endif }, /* ttyS2 */ { .baud = DEF_BAUD, .port = (unsigned char *)R_SERIAL3_CTRL, .irq = 1U << 8, /* uses DMA 4 and 5 */ .oclrintradr = R_DMA_CH4_CLR_INTR, .ofirstadr = R_DMA_CH4_FIRST, .ocmdadr = R_DMA_CH4_CMD, .ostatusadr = R_DMA_CH4_STATUS, .iclrintradr = R_DMA_CH5_CLR_INTR, .ifirstadr = R_DMA_CH5_FIRST, .icmdadr = R_DMA_CH5_CMD, .idescradr = R_DMA_CH5_DESCR, .flags = STD_FLAGS, .rx_ctrl = DEF_RX, .tx_ctrl = DEF_TX, .iseteop = 1,#ifdef CONFIG_ETRAX_SERIAL_PORT3 .enabled = 1,#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT .dma_out_enabled = 1,#else .dma_out_enabled = 0,#endif#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN .dma_in_enabled = 1,#else .dma_in_enabled = 0#endif#else .enabled = 0, .dma_out_enabled = 0, .dma_in_enabled = 0#endif } /* ttyS3 */#endif};#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))static struct termios *serial_termios[NR_PORTS];static struct termios *serial_termios_locked[NR_PORTS];#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMERstatic struct fast_timer fast_timers[NR_PORTS];#endif#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY#define PROCSTAT(x) xstruct ser_statistics_type { int overrun_cnt; int early_errors_cnt; int ser_ints_ok_cnt; int errors_cnt; unsigned long int processing_flip; unsigned long processing_flip_still_room; unsigned long int timeout_flush_cnt; int rx_dma_ints; int tx_dma_ints; int rx_tot; int tx_tot;};static struct ser_statistics_type ser_stat[NR_PORTS];#else#define PROCSTAT(x)#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -