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

📄 serial.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 5 页
字号:
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 = e100_modem_pins[info->line].dtr_mask;#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].dtr_shadow,	       E100_DTR_GET(info));#endif	/* DTR is active low */	{		unsigned long flags;		save_flags(flags);		cli();		*e100_modem_pins[info->line].dtr_shadow &= ~mask;		*e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); 		*e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow;		restore_flags(flags);	}	#ifdef SERIAL_DEBUG_IO	printk("ser%i shadow after 0x%02X get: %i\n", 	       info->line, *e100_modem_pins[info->line].dtr_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);#endif#endif}/* If this behaves as a modem, RI and CD is an output */static inline void e100_ri_out(struct e100_serial *info, int set){#ifndef CONFIG_SVINTO_SIM	/* RI is active low */	{		unsigned char mask = e100_modem_pins[info->line].ri_mask;		unsigned long flags;		save_flags(flags);		cli();		*e100_modem_pins[info->line].ri_shadow &= ~mask;		*e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); 		*e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;		restore_flags(flags);	}#endif}static inline void e100_cd_out(struct e100_serial *info, int set){#ifndef CONFIG_SVINTO_SIM	/* CD is active low */	{		unsigned char mask = e100_modem_pins[info->line].cd_mask;		unsigned long flags;		save_flags(flags);		cli();		*e100_modem_pins[info->line].cd_shadow &= ~mask;		*e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); 		*e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;		restore_flags(flags);	}#endif}static inline voide100_disable_rx(struct e100_serial *info){#ifndef CONFIG_SVINTO_SIM	/* disable the receiver */	info->port[REG_REC_CTRL] =		(info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));#endif}static inline void e100_enable_rx(struct e100_serial *info){#ifndef CONFIG_SVINTO_SIM	/* enable the receiver */	info->port[REG_REC_CTRL] =		(info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));#endif}/* the rx DMA uses both the dma_descr and the dma_eop interrupts */static inline voide100_disable_rxdma_irq(struct e100_serial *info) {#ifdef SERIAL_DEBUG_INTR	printk("rxdma_irq(%d): 0\n",info->line);#endif	*R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3);}static inline voide100_enable_rxdma_irq(struct e100_serial *info) {#ifdef SERIAL_DEBUG_INTR	printk("rxdma_irq(%d): 1\n",info->line);#endif	*R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3);}/* the tx DMA uses only dma_descr interrupt */static inline voide100_disable_txdma_irq(struct e100_serial *info) {#ifdef SERIAL_DEBUG_INTR	printk("txdma_irq(%d): 0\n",info->line);#endif	*R_IRQ_MASK2_CLR = info->irq;}static inline voide100_enable_txdma_irq(struct e100_serial *info) {#ifdef SERIAL_DEBUG_INTR	printk("txdma_irq(%d): 1\n",info->line);#endif	*R_IRQ_MASK2_SET = info->irq;}#ifdef SERIAL_HANDLE_EARLY_ERRORS/* in order to detect and fix errors on the first byte   we have to use the serial interrupts as well. */static inline voide100_disable_serial_data_irq(struct e100_serial *info) {#ifdef SERIAL_DEBUG_INTR	printk("ser_irq(%d): 0\n",info->line);#endif	*R_IRQ_MASK1_CLR = (1U << (8+2*info->line));}static inline voide100_enable_serial_data_irq(struct e100_serial *info) {#ifdef SERIAL_DEBUG_INTR	printk("ser_irq(%d): 1\n",info->line);	printk("**** %d = %d\n",	       (8+2*info->line),	       (1U << (8+2*info->line)));#endif	*R_IRQ_MASK1_SET = (1U << (8+2*info->line));}#endif#if defined(CONFIG_ETRAX_RS485)/* Enable RS-485 mode on selected port. This is UGLY. */static inte100_enable_rs485(struct tty_struct *tty,struct rs485_control *r){	struct e100_serial * info = (struct e100_serial *)tty->driver_data;#if defined(CONFIG_ETRAX_RS485_ON_PA)		*R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);#endif	info->rs485.rts_on_send = 0x01 & r->rts_on_send;	info->rs485.rts_after_sent = 0x01 & r->rts_after_sent;	info->rs485.delay_rts_before_send = r->delay_rts_before_send;	info->rs485.enabled = r->enabled;/*	printk("rts: on send = %i, after = %i, enabled = %i",		    info->rs485.rts_on_send,		    info->rs485.rts_after_sent,		    info->rs485.enabled	);*/			return 0;}static inte100_write_rs485(struct tty_struct *tty, int from_user,                 const unsigned char *buf, int count){	struct e100_serial * info = (struct e100_serial *)tty->driver_data;	int old_enabled = info->rs485.enabled;	/* rs485 is always implicitly enabled if we're using the ioctl() 	 * but it doesn't have to be set in the rs485_control	 * (to be backward compatible with old apps)	 * So we store, set and restore it.	 */	info->rs485.enabled = 1;	/* rs_write now deals with RS485 if enabled */	count = rs_write(tty, from_user, buf, count);	info->rs485.enabled = old_enabled;	return count;}#ifdef CONFIG_ETRAX_FAST_TIMER/* Timer function to toggle RTS when using FAST_TIMER */static void rs485_toggle_rts_timer_function(unsigned long data){	struct e100_serial *info = (struct e100_serial *)data;	fast_timers_rs485[info->line].function = NULL;	e100_rts(info, info->rs485.rts_after_sent);#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)	e100_enable_rx(info);	e100_enable_rxdma_irq(info);#endif}#endif#endif /* CONFIG_ETRAX_RS485 *//* * ------------------------------------------------------------ * rs_stop() and rs_start() * * This routines are called before setting or resetting tty->stopped. * They enable or disable transmitter using the XOFF registers, as necessary. * ------------------------------------------------------------ */static void rs_stop(struct tty_struct *tty){	struct e100_serial *info = (struct e100_serial *)tty->driver_data;	if (info) {		unsigned long flags;		unsigned long xoff;				save_flags(flags); cli();		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);		if (tty->termios->c_iflag & IXON ) {			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);		}			*((unsigned long *)&info->port[REG_XOFF]) = xoff;		restore_flags(flags);	}}static void rs_start(struct tty_struct *tty){	struct e100_serial *info = (struct e100_serial *)tty->driver_data;	if (info) {		unsigned long flags;		unsigned long xoff;		save_flags(flags); cli();		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);		if (tty->termios->c_iflag & IXON ) {			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);		}			*((unsigned long *)&info->port[REG_XOFF]) = xoff;				restore_flags(flags);	}}/* * ---------------------------------------------------------------------- * * Here starts the interrupt handling routines.  All of the following * subroutines are declared as inline and are folded into * rs_interrupt().  They were separated out for readability's sake. * * Note: rs_interrupt() is a "fast" interrupt, which means that it * runs with interrupts turned off.  People who may want to modify * rs_interrupt() should try to keep the interrupt handler as fast as * possible.  After you are done making modifications, it is not a bad * idea to do: *  * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c * * and look at the resulting assemble code in serial.s. * * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93 * ----------------------------------------------------------------------- *//* * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. */static _INLINE_ void rs_sched_event(struct e100_serial *info,				    int event){	info->event |= 1 << event;

⌨️ 快捷键说明

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