📄 serial.c
字号:
/* 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_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. *//* 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[] = { { DEF_BAUD, (unsigned char *)R_SERIAL0_CTRL, 1U << 12, /* uses DMA 6 and 7 */ R_DMA_CH6_CLR_INTR, R_DMA_CH6_FIRST, R_DMA_CH6_CMD, R_DMA_CH6_STATUS, R_DMA_CH6_HWSW, R_DMA_CH6_DESCR, R_DMA_CH7_CLR_INTR, R_DMA_CH7_FIRST, R_DMA_CH7_CMD, R_DMA_CH7_STATUS, R_DMA_CH7_HWSW, R_DMA_CH7_DESCR, STD_FLAGS, DEF_RX, DEF_TX, 2,#ifdef CONFIG_ETRAX_SERIAL_PORT0 1#else 0#endif}, /* ttyS0 */#ifndef CONFIG_SVINTO_SIM { DEF_BAUD, (unsigned char *)R_SERIAL1_CTRL, 1U << 16, /* uses DMA 8 and 9 */ R_DMA_CH8_CLR_INTR, R_DMA_CH8_FIRST, R_DMA_CH8_CMD, R_DMA_CH8_STATUS, R_DMA_CH8_HWSW, R_DMA_CH8_DESCR, R_DMA_CH9_CLR_INTR, R_DMA_CH9_FIRST, R_DMA_CH9_CMD, R_DMA_CH9_STATUS, R_DMA_CH9_HWSW, R_DMA_CH9_DESCR, STD_FLAGS, DEF_RX, DEF_TX, 3 ,#ifdef CONFIG_ETRAX_SERIAL_PORT1 1#else 0#endif}, /* ttyS1 */ { DEF_BAUD, (unsigned char *)R_SERIAL2_CTRL, 1U << 4, /* uses DMA 2 and 3 */ R_DMA_CH2_CLR_INTR, R_DMA_CH2_FIRST, R_DMA_CH2_CMD, R_DMA_CH2_STATUS, R_DMA_CH2_HWSW, R_DMA_CH2_DESCR, R_DMA_CH3_CLR_INTR, R_DMA_CH3_FIRST, R_DMA_CH3_CMD, R_DMA_CH3_STATUS, R_DMA_CH3_HWSW, R_DMA_CH3_DESCR, STD_FLAGS, DEF_RX, DEF_TX, 0,#ifdef CONFIG_ETRAX_SERIAL_PORT2 1#else 0#endif }, /* ttyS2 */ { DEF_BAUD, (unsigned char *)R_SERIAL3_CTRL, 1U << 8, /* uses DMA 4 and 5 */ R_DMA_CH4_CLR_INTR, R_DMA_CH4_FIRST, R_DMA_CH4_CMD, R_DMA_CH4_STATUS, R_DMA_CH4_HWSW, R_DMA_CH4_DESCR, R_DMA_CH5_CLR_INTR, R_DMA_CH5_FIRST, R_DMA_CH5_CMD, R_DMA_CH5_STATUS, R_DMA_CH5_HWSW, R_DMA_CH5_DESCR, STD_FLAGS, DEF_RX, DEF_TX, 1,#ifdef CONFIG_ETRAX_SERIAL_PORT3 1#else 0#endif } /* ttyS3 */#endif};#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) static struct tty_struct *serial_table[NR_PORTS]; 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 *//* RS-485 */#if defined(CONFIG_ETRAX_RS485)#ifdef CONFIG_ETRAX_FAST_TIMERstatic struct fast_timer fast_timers_rs485[NR_PORTS];#endif#if defined(CONFIG_ETRAX_RS485_ON_PA)static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;#endif#endif /* For now we assume that all bits are on the same port for each serial port *//* Dummy shadow variables */#if !defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)static unsigned char dummy_ser0 = 0x00;static unsigned char dummy_dir_ser0 = 0x00;#endif#if !defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)static unsigned char dummy_ser1 = 0x00;static unsigned char dummy_dir_ser1 = 0x00;#endif#if !defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)static unsigned char dummy_ser2 = 0x00;static unsigned char dummy_dir_ser2 = 0x00;#endifstatic unsigned char dummy_ser3 = 0x00;static unsigned char dummy_dir_ser3 = 0x00;/* Info needed for each ports extra control/status signals. We only supports that all pins uses same register for each port */struct control_pins{ volatile unsigned char *port; volatile unsigned char *shadow; volatile unsigned char *dir_shadow; unsigned char dtr_bit; unsigned char ri_bit; unsigned char dsr_bit; unsigned char cd_bit;};static const struct control_pins e100_modem_pins[NR_PORTS] = { /* Ser 0 */ {#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB) R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, CONFIG_ETRAX_SER0_DTR_ON_PB_BIT, CONFIG_ETRAX_SER0_RI_ON_PB_BIT, CONFIG_ETRAX_SER0_DSR_ON_PB_BIT, CONFIG_ETRAX_SER0_CD_ON_PB_BIT#else &dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3#endif }, /* Ser 1 */ {#if defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB) R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, CONFIG_ETRAX_SER1_DTR_ON_PB_BIT, CONFIG_ETRAX_SER1_RI_ON_PB_BIT, CONFIG_ETRAX_SER1_DSR_ON_PB_BIT, CONFIG_ETRAX_SER1_CD_ON_PB_BIT#else &dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3#endif }, /* Ser 2 */ {#if defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA) R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow, CONFIG_ETRAX_SER2_DTR_ON_PA_BIT, CONFIG_ETRAX_SER2_RI_ON_PA_BIT, CONFIG_ETRAX_SER2_DSR_ON_PA_BIT, CONFIG_ETRAX_SER2_CD_ON_PA_BIT#else &dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3#endif }, /* Ser 3 */ { &dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3 }};#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA)unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT;#endif#define E100_RTS_MASK 0x20#define E100_CTS_MASK 0x40/* All serial port signals are active low: * active = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level * inactive = 1 -> 0V to RS-232 driver -> +12V on RS-232 level * * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip *//* Output */#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK)/* Input */#define E100_CTS_GET(info) ((info)->port[REG_STATUS] & E100_CTS_MASK)/* These are typically PA or PB and 0 means 0V, 1 means 3.3V *//* Is an output */#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].shadow) & (1 << e100_modem_pins[(info)->line].dtr_bit))/* Normally inputs */#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].ri_bit))#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].cd_bit))/* Input */#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].dsr_bit))#ifndef MIN#define MIN(a,b) ((a) < (b) ? (a) : (b))#endif/* * tmp_buf is used as a temporary buffer by serial_write. We need to * lock it in case the memcpy_fromfs 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 unsigned char *tmp_buf;#ifdef DECLARE_MUTEXstatic DECLARE_MUTEX(tmp_buf_sem);#elsestatic struct semaphore tmp_buf_sem = MUTEX;#endif#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST/* clock select 10 for timer 1 gives 230400 Hz */#define FASTTIMER_SELECT (10)/* we use a source of 230400 Hz and a divider of 15 => 15360 Hz */#define FASTTIMER_DIV (15)/* fast flush timer stuff */static int fast_timer_started = 0;static unsigned long int fast_timer_ints = 0;static void _INLINE_ start_flush_timer(void){ if (fast_timer_started) return; *R_TIMER_CTRL = r_timer_ctrl_shadow = (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, timerdiv1) & ~IO_MASK(R_TIMER_CTRL, tm1) & ~IO_MASK(R_TIMER_CTRL, clksel1)) | IO_FIELD(R_TIMER_CTRL, timerdiv1, FASTTIMER_DIV) | IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | IO_FIELD(R_TIMER_CTRL, clksel1, FASTTIMER_SELECT); *R_TIMER_CTRL = r_timer_ctrl_shadow = (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) | IO_STATE(R_TIMER_CTRL, tm1, run); /* enable timer1 irq */ *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set); fast_timer_started = 1;}#endif /* CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST *//* Calculate the chartime depending on baudrate, numbor of bits etc. */static void update_char_time(struct e100_serial * info){ tcflag_t cflags = info->tty->termios->c_cflag; int bits; /* calc. number of bits / data byte */ /* databits + startbit and 1 stopbit */ if ((cflags & CSIZE) == CS7) bits = 9; else bits = 10; if (cflags & CSTOPB) /* 2 stopbits ? */ bits++; if (cflags & PARENB) /* parity bit ? */ bits++; /* calc timeout */ info->char_time_usec = ((bits * 1000000) / info->baud) + 1;}/* * This function maps from the Bxxxx defines in asm/termbits.h into real * baud rates. */static int cflag_to_baud(unsigned int cflag){ static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400 }; static int ext_baud_table[] = { 0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000, 0, 0, 0, 0, 0, 0, 0, 0 }; if (cflag & CBAUDEX) return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; else return baud_table[cflag & CBAUD];}/* and this maps to an etrax100 hardware baud constant */static unsigned char cflag_to_etrax_baud(unsigned int cflag){ char retval; static char baud_table[] = { -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 }; static char ext_baud_table[] = { -1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 }; if (cflag & CBAUDEX) retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; else retval = baud_table[cflag & CBAUD]; if (retval < 0) { printk("serdriver tried setting invalid baud rate, flags %x.\n", cflag); retval = 5; /* choose default 9600 instead */ } return retval | (retval << 4); /* choose same for both TX and RX */}/* Various static support functions *//* Functions to set or clear DTR/RTS on the requested line *//* It is complicated by the fact that RTS is a serial port register, while * DTR might not be implemented in the HW at all, and if it is, it can be on * any general port. */static inline void e100_dtr(struct e100_serial *info, int set){#ifndef CONFIG_SVINTO_SIM unsigned char mask = (1 << e100_modem_pins[info->line].dtr_bit);#ifdef SERIAL_DEBUG_IO printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask); printk("ser%i shadow before 0x%02X get: %i\n", info->line, *e100_modem_pins[info->line].shadow, E100_DTR_GET(info));#endif /* DTR is active low */ { unsigned long flags; save_flags(flags); cli(); *e100_modem_pins[info->line].shadow &= ~mask; *e100_modem_pins[info->line].shadow |= (set ? 0 : mask); *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow; restore_flags(flags); } #if 0 REG_SHADOW_SET(e100_modem_pins[info->line].port, *e100_modem_pins[info->line].shadow, e100_modem_pins[info->line].dtr_bit, !set);#endif#ifdef SERIAL_DEBUG_IO printk("ser%i shadow after 0x%02X get: %i\n", info->line, *e100_modem_pins[info->line].shadow, E100_DTR_GET(info));#endif#endif}/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive * 0=0V , 1=3.3V */static inline void e100_rts(struct e100_serial *info, int set){#ifndef CONFIG_SVINTO_SIM info->rx_ctrl &= ~E100_RTS_MASK; info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */ info->port[REG_REC_CTRL] = info->rx_ctrl;#ifdef SERIAL_DEBUG_IO printk("ser%i rts %i\n", info->line, set);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -