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

📄 trioserial.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* TRIO chip serial port driver * * Based on: * * drivers/char/68302serial.c */ #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/config.h>#include <linux/major.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/mm.h>#include <linux/kernel.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/arch-trio/irq.h>#include <asm/system.h>#include <asm/segment.h>#include <asm/bitops.h>#include <asm/delay.h>#if 0#include <asm/kdebug.h>#endif#include "trioserial.h"#define USE_INTS	1#define US_NB		2#define UART_CLOCK	(ARM_CLK/16)#define XMIT_SERIAL_SIZE	PAGE_SIZE#define RX_SERIAL_SIZE	PAGE_SIZEstatic struct uart_regs *uarts[US_NB] = {	(struct uart_regs*)USARTA_BASE, (struct uart_regs*)USARTB_BASE};static struct trio_serial trio_info[US_NB];struct tty_struct trio_ttys[US_NB];/* Console hooks... *//*static int m68k_cons_chanout = 0;static int m68k_cons_chanin = 0;*/struct trio_serial *trio_consinfo = 0;#if 0static unsigned char kgdb_regs[16] = {	0, 0, 0,                     /* write 0, 1, 2 */	(Rx8 | RxENABLE),            /* write 3 */	(X16CLK | SB1 | PAR_EVEN),   /* write 4 */	(Tx8 | TxENAB),              /* write 5 */	0, 0, 0,                     /* write 6, 7, 8 */	(NV),                        /* write 9 */	(NRZ),                       /* write 10 */	(TCBR | RCBR),               /* write 11 */	0, 0,                        /* BRG time constant, write 12 + 13 */	(BRSRC | BRENABL),           /* write 14 */	(DCDIE)                      /* write 15 */};#endifDECLARE_TASK_QUEUE(tq_serial);struct tq_struct serialpoll;struct tty_driver serial_driver, callout_driver;static int serial_refcount;/* serial subtype definitions */#define SERIAL_TYPE_NORMAL	1#define SERIAL_TYPE_CALLOUT	2  /* number of characters left in xmit buffer before we ask for more */#define WAKEUP_CHARS 256/* Debugging... DEBUG_INTR is bad to use when one of the zs * lines is your console ;( */#undef SERIAL_DEBUG_INTR#undef SERIAL_DEBUG_OPEN#undef SERIAL_DEBUG_FLOW#define RS_ISR_PASS_LIMIT 256#define _INLINE_static void serpoll(void *data);static void change_speed(struct trio_serial *info);static struct tty_struct *serial_table[US_NB];static struct termios *serial_termios[US_NB];static struct termios *serial_termios_locked[US_NB];#ifndef MIN#define MIN(a,b)	((a) < (b) ? (a) : (b))#endifstatic char prompt0;static void xmit_char(struct trio_serial* info, char ch);static void xmit_string(struct trio_serial *info, char *p, int len);static void start_rx(struct trio_serial *info);static void wait_EOT(struct uart_regs*);static void uart_init(struct trio_serial *info);static void uart_speed(struct trio_serial *info, unsigned cflag);static void tx_enable(struct uart_regs *uart);static void rx_enable(struct uart_regs *uart);static void tx_disable(struct uart_regs *uart);static void rx_disable(struct uart_regs *uart);static void tx_stop(struct uart_regs *uart);static void tx_start(struct uart_regs *uart, int ints);static void rx_stop(struct uart_regs *uart);static void rx_start(struct uart_regs *uart, int ints);static void set_ints_mode(int yes, struct trio_serial *info);static void rs_interrupt(struct trio_serial *info);extern void show_net_buffers(void);extern void hard_reset_now(void);static void _INLINE_ tx_enable(struct uart_regs *uart){	uart->ier	|= US_TXRDY;}static void _INLINE_ rx_enable(struct uart_regs *uart){	uart->ier	|= US_RXRDY;}static void _INLINE_ tx_disable(struct uart_regs *uart){	uart->idr	|= US_TXRDY;}static void _INLINE_ rx_disable(struct uart_regs *uart){	uart->idr	|= US_RXRDY;}static void _INLINE_ tx_stop(struct uart_regs *uart){	tx_disable(uart);	uart->cr	|= US_RXEN;}static void _INLINE_ tx_start(struct uart_regs *uart, int ints){	if(ints)		tx_enable(uart);	uart->cr	|= US_TXEN;}static void _INLINE_ rx_stop(struct uart_regs *uart){	rx_disable(uart);	uart->cr	|= US_RXDIS;}static void _INLINE_ rx_start(struct uart_regs *uart, int ints){	if(ints)		rx_enable(uart);	uart->cr	|= US_RXEN;}static void set_ints_mode(int yes, struct trio_serial *info){	info->use_ints = yes;	(yes)?unmask_irq(info->irq):mask_irq(info->irq);}/* * 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[XMIT_SERIAL_SIZE]; /* This is cheating */static struct semaphore tmp_buf_sem = MUTEX;static inline int serial_paranoia_check(struct trio_serial *info,					dev_t device, const char *routine){#ifdef SERIAL_PARANOIA_CHECK	static const char *badmagic =		"Warning: bad magic number for serial struct (%d, %d) in %s\n";	static const char *badinfo =		"Warning: null trio_serial for (%d, %d) in %s\n";	if (!info) {		printk(badinfo, MAJOR(device), MINOR(device), routine);		return 1;	}	if (info->magic != SERIAL_MAGIC) {		printk(badmagic, MAJOR(device), MINOR(device), routine);		return 1;	}#endif	return 0;}/* Sets or clears DTR/RTS on the requested line */static inline void trio_rtsdtr(struct trio_serial *ss, int set){	struct uart_regs *uart;	uart = ss->uart;	if(set) {		uart->mc |= US_DTR | US_RTS;	} else {		uart->mc &= ~(u_32)(US_DTR | US_RTS);	}	return;}static inline void kgdb_chaninit(struct trio_serial *ss, int intson, int bps){#if 0	int brg;	if(intson) {		kgdb_regs[R1] = INT_ALL_Rx;		kgdb_regs[R9] |= MIE;	} else {		kgdb_regs[R1] = 0;		kgdb_regs[R9] &= ~MIE;	}	brg = BPS_TO_BRG(bps, ZS_CLOCK/16);	kgdb_regs[R12] = (brg & 255);	kgdb_regs[R13] = ((brg >> 8) & 255);	load_zsregs(ss->trio_channel, kgdb_regs);#endif}/* * ------------------------------------------------------------ * rs_stop() and rs_start() * * This routines are called before setting or resetting tty->stopped. * They enable or disable transmitter interrupts, as necessary. * ------------------------------------------------------------ */static void rs_stop(struct tty_struct *tty){	struct trio_serial *info = (struct trio_serial *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "rs_stop"))		return;		save_flags(flags); cli();	tx_stop(info->uart);	rx_stop(info->uart);	restore_flags(flags);}static void rs_put_char(struct trio_serial *info, char ch){        int flags = 0;        save_flags(flags); cli();		wait_EOT(info->uart);		xmit_char(info,ch);		wait_EOT(info->uart);        restore_flags(flags);}static void rs_start(struct tty_struct *tty){	struct trio_serial *info = (struct trio_serial *)tty->driver_data;	unsigned long flags;		if (serial_paranoia_check(info, tty->device, "rs_start"))		return;		save_flags(flags); cli();	tx_start(info->uart, info->use_ints);	start_rx(info);	restore_flags(flags);}/* Drop into either the boot monitor or kadb upon receiving a break * from keyboard/console input. */static void batten_down_hatches(void){	/* If we are doing kadb, we call the debugger	 * else we just drop into the boot monitor.	 * Note that we must flush the user windows	 * first before giving up control.	 */#if 0	if((((unsigned long)linux_dbvec)>=DEBUG_FIRSTVADDR) &&	   (((unsigned long)linux_dbvec)<=DEBUG_LASTVADDR))		sp_enter_debugger();	else		panic("trio_serial: batten_down_hatches");	return;#endif}/* * ---------------------------------------------------------------------- * * 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 trio_serial *info,				    int event){	info->event |= 1 << event;	queue_task_irq_off(&info->tqueue, &tq_serial);	mark_bh(SERIAL_BH);}extern void breakpoint(void);  /* For the KGDB frame character */static _INLINE_ void receive_chars(struct trio_serial *info, u_32 status){	unsigned char ch;	int count;	struct uart_regs *uart = info->uart;	#if 0	// hack to receive chars by polling from anywhere	struct trio_serial * info1 = &trio_info;	struct tty_struct *tty = info1->tty;	if (!(info->flags & S_INITIALIZED))		return;#else	struct tty_struct *tty = info->tty;	if (!(info->flags & S_INITIALIZED))		return;#endif		count = uart->rcr;	// hack to receive chars by polling only BD fields	if (!(status & US_RXRDY)  || !count){		return;	}	ch = info->rx_buf[0];	if(info->is_cons) {		if(status & US_RXBRK) { /* whee, break received */			batten_down_hatches();			/*rs_recv_clear(info->trio_channel);*/			return;		} else if (ch == 0x10) { /* ^P */			show_state();			show_free_areas();			show_buffers();			show_net_buffers();			return;		} else if (ch == 0x12) { /* ^R */			hard_reset_now();			return;		}		/* It is a 'keyboard interrupt' ;-) */		wake_up(&keypress_wait);	}	/* Look for kgdb 'stop' character, consult the gdb documentation	 * for remote target debugging and arch/sparc/kernel/sparc-stub.c	 * to see how all this works.	 */	/*if((info->kgdb_channel) && (ch =='\003')) {		breakpoint();		goto clear_and_exit;	}*/	if(!tty)		goto clear_and_exit;	if (tty->flip.count >= TTY_FLIPBUF_SIZE)		queue_task_irq_off(&tty->flip.tqueue, &tq_timer);	tty->flip.count++;	if(status & US_PARE)		*tty->flip.flag_buf_ptr++ = TTY_PARITY;	else if(status & US_OVRE)		*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;	else if(status & US_FRAME)		*tty->flip.flag_buf_ptr++ = TTY_FRAME;	else		*tty->flip.flag_buf_ptr++ = 0; /* XXX */	*tty->flip.char_buf_ptr++ = ch;	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);clear_and_exit:	start_rx(info);	return;}static _INLINE_ void transmit_chars(struct trio_serial *info){	if (info->x_char) {		/* Send next char */		xmit_char(info, info->x_char);		info->x_char = 0;		goto clear_and_return;	}	if((info->xmit_cnt <= 0) || info->tty->stopped) {		/* That's peculiar... *///		tx_stop(0);		goto clear_and_return;	}	/* Send char */	xmit_char(info, info->xmit_buf[info->xmit_tail++]);	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);	info->xmit_cnt--;	if (info->xmit_cnt < WAKEUP_CHARS)		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);	if(info->xmit_cnt <= 0) {//		tx_stop(0);		goto clear_and_return;	}clear_and_return:	/* Clear interrupt (should be auto)*/	return;}static _INLINE_ void status_handle(struct trio_serial *info, u_32 status){#if 0	if(status & DCD) {		if((info->tty->termios->c_cflag & CRTSCTS) &&		   ((info->curregs[3] & AUTO_ENAB)==0)) {			info->curregs[3] |= AUTO_ENAB;			info->pendregs[3] |= AUTO_ENAB;			write_zsreg(info->trio_channel, 3, info->curregs[3]);		}	} else {		if((info->curregs[3] & AUTO_ENAB)) {			info->curregs[3] &= ~AUTO_ENAB;			info->pendregs[3] &= ~AUTO_ENAB;			write_zsreg(info->trio_channel, 3, info->curregs[3]);		}	}#endif	/* Whee, if this is console input and this is a	 * 'break asserted' status change interrupt, call	 * the boot prom.	 */	if((status & US_RXBRK) && info->break_abort)		batten_down_hatches();	/* XXX Whee, put in a buffer somewhere, the status information	 * XXX whee whee whee... Where does the information go...	 */	return;}

⌨️ 快捷键说明

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