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

📄 serial_tx3912.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  drivers/char/serial_tx3912.c * *  Copyright (C) 1999 Harald Koerfgen *  Copyright (C) 2000 Jim Pick <jim@jimpick.com> *  Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) *  * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. *   *  Serial driver for TMPR3912/05 and PR31700 processors */#include <linux/init.h>#include <linux/config.h>#include <linux/tty.h>#include <linux/major.h>#include <linux/ptrace.h>#include <linux/init.h>#include <linux/console.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/pm.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/delay.h>#include <asm/wbflush.h>#include <asm/tx3912.h>#include "serial_tx3912.h"/* * Forward declarations for serial routines */static void rs_disable_tx_interrupts (void * ptr);static void rs_enable_tx_interrupts (void * ptr); static void rs_disable_rx_interrupts (void * ptr); static void rs_enable_rx_interrupts (void * ptr); static int rs_get_CD (void * ptr); static void rs_shutdown_port (void * ptr); static int rs_set_real_termios (void *ptr);static int rs_chars_in_buffer (void * ptr); static void rs_hungup (void *ptr);static void rs_close (void *ptr);/* * Used by generic serial driver to access hardware */static struct real_driver rs_real_driver = { 	disable_tx_interrupts: rs_disable_tx_interrupts, 	enable_tx_interrupts:  rs_enable_tx_interrupts, 	disable_rx_interrupts: rs_disable_rx_interrupts, 	enable_rx_interrupts:  rs_enable_rx_interrupts, 	get_CD:                rs_get_CD, 	shutdown_port:         rs_shutdown_port,  	set_real_termios:      rs_set_real_termios,  	chars_in_buffer:       rs_chars_in_buffer, 	close:                 rs_close, 	hungup:                rs_hungup,}; /* * Structures and such for TTY sessions and usage counts */static struct tty_driver rs_driver, rs_callout_driver;static struct tty_struct * rs_table[TX3912_UART_NPORTS] = { NULL, };static struct termios ** rs_termios;static struct termios ** rs_termios_locked;struct rs_port *rs_ports;int rs_refcount;int rs_initialized = 0;/* * ---------------------------------------------------------------------- * * 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 * ----------------------------------------------------------------------- */static inline void receive_char_pio(struct rs_port *port){	struct tty_struct *tty = port->gs.tty;	unsigned char ch;	int counter = 2048;	/* While there are characters, get them ... */	while (counter>0) {		if (!(inl(port->base + TX3912_UART_CTRL1) & UART_RX_HOLD_FULL))			break;		ch = inb(port->base + TX3912_UART_DATA);		if (tty->flip.count < TTY_FLIPBUF_SIZE) {			*tty->flip.char_buf_ptr++ = ch;			*tty->flip.flag_buf_ptr++ = 0;			tty->flip.count++;		}		udelay(1); /* Allow things to happen - it take a while */		counter--;	}	if (!counter)		printk( "Ugh, looped in receive_char_pio!\n" );	tty_flip_buffer_push(tty);#if 0	/* Now handle error conditions */	if (*status & (INTTYPE(UART_RXOVERRUN_INT) |			INTTYPE(UART_FRAMEERR_INT) |			INTTYPE(UART_PARITYERR_INT) |			INTTYPE(UART_BREAK_INT))) {		/*		 * Now check to see if character should be		 * ignored, and mask off conditions which		 * should be ignored.	       	 */		if (*status & port->ignore_status_mask) {			goto ignore_char;		}		*status &= port->read_status_mask;				if (*status & INTTYPE(UART_BREAK_INT)) {			rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "handling break....");			*tty->flip.flag_buf_ptr = TTY_BREAK;		}		else if (*status & INTTYPE(UART_PARITYERR_INT)) {			*tty->flip.flag_buf_ptr = TTY_PARITY;		}		else if (*status & INTTYPE(UART_FRAMEERR_INT)) {			*tty->flip.flag_buf_ptr = TTY_FRAME;		}		if (*status & INTTYPE(UART_RXOVERRUN_INT)) {			/*			 * Overrun is special, since it's			 * reported immediately, and doesn't			 * affect the current character			 */			if (tty->flip.count < TTY_FLIPBUF_SIZE) {				tty->flip.count++;				tty->flip.flag_buf_ptr++;				tty->flip.char_buf_ptr++;				*tty->flip.flag_buf_ptr = TTY_OVERRUN;			}		}	}	tty->flip.flag_buf_ptr++;	tty->flip.char_buf_ptr++;	tty->flip.count++;ignore_char:	tty_flip_buffer_push(tty);#endif}static inline void transmit_char_pio(struct rs_port *port){	/* While I'm able to transmit ... */	for (;;) {		if (!(inl(port->base + TX3912_UART_CTRL1) & UART_TX_EMPTY))			break;		else if (port->x_char) {			outb(port->x_char, port->base + TX3912_UART_DATA);			port->icount.tx++;			port->x_char = 0;		}		else if (port->gs.xmit_cnt <= 0 || port->gs.tty->stopped ||		    port->gs.tty->hw_stopped) {			break;		}		else {			outb(port->gs.xmit_buf[port->gs.xmit_tail++],				port->base + TX3912_UART_DATA);			port->icount.tx++;			port->gs.xmit_tail &= SERIAL_XMIT_SIZE-1;			if (--port->gs.xmit_cnt <= 0) {				break;			}		}		udelay(10); /* Allow things to happen - it take a while */	}	if (port->gs.xmit_cnt <= 0 || port->gs.tty->stopped ||	     port->gs.tty->hw_stopped) {		rs_disable_tx_interrupts(port);	}	        if (port->gs.xmit_cnt <= port->gs.wakeup_chars) {                if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&                    port->gs.tty->ldisc.write_wakeup)                        (port->gs.tty->ldisc.write_wakeup)(port->gs.tty);                rs_dprintk (TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",                            port->gs.wakeup_chars);                 wake_up_interruptible(&port->gs.tty->write_wait);       	}	}static inline void check_modem_status(struct rs_port *port){        /* We don't have a carrier detect line - but just respond           like we had one anyways so that open() becomes unblocked */	wake_up_interruptible(&port->gs.open_wait);}int count = 0;/* * This is the serial driver's interrupt routine (inlined, because * there are two different versions of this, one for each serial port, * differing only by the bits used in interrupt status 2 register) */static inline void rs_rx_interrupt(int irq, void *dev_id,				  struct pt_regs * regs, int intshift){	struct rs_port * port;	unsigned long int2status;	unsigned long flags;	unsigned long ints;	save_and_cli(flags);	port = (struct rs_port *)dev_id;	rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift);	/* Get the interrrupts we have enabled */	int2status = IntStatus2 & IntEnable2;	/* Get interrupts in easy to use form */	ints = int2status >> intshift;	/* Clear any interrupts we might be about to handle */	IntClear2 = int2status & (		(INTTYPE(UART_RXOVERRUN_INT) |		 INTTYPE(UART_FRAMEERR_INT) |		 INTTYPE(UART_BREAK_INT) |		 INTTYPE(UART_PARITYERR_INT) |		 INTTYPE(UART_RX_INT)) << intshift);	if (!port || !port->gs.tty) {		restore_flags(flags);		return;	}	/* RX Receiver Holding Register Overrun */	if (ints & INTTYPE(UART_RXOVERRUN_INT)) {		rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "overrun");		port->icount.overrun++;	}	/* RX Frame Error */	if (ints & INTTYPE(UART_FRAMEERR_INT)) {		rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "frame error");		port->icount.frame++;	}	/* Break signal received */	if (ints & INTTYPE(UART_BREAK_INT)) {		rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "break");		port->icount.brk++;      	}	/* RX Parity Error */	if (ints & INTTYPE(UART_PARITYERR_INT)) {		rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "parity error");		port->icount.parity++;	}	/* Receive byte (non-DMA) */	if (ints & INTTYPE(UART_RX_INT)) {		receive_char_pio(port);	}	restore_flags(flags);	rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "end.\n");}static inline void rs_tx_interrupt(int irq, void *dev_id,				  struct pt_regs * regs, int intshift){	struct rs_port * port;	unsigned long int2status;	unsigned long flags;	unsigned long ints;	save_and_cli(flags);	port = (struct rs_port *)dev_id;	rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift);	/* Get the interrrupts we have enabled */	int2status = IntStatus2 & IntEnable2;	if (!port || !port->gs.tty) {		restore_flags(flags);		return;	}	/* Get interrupts in easy to use form */	ints = int2status >> intshift;	/* Clear any interrupts we might be about to handle */	IntClear2 = int2status & (		(INTTYPE(UART_TX_INT) |		 INTTYPE(UART_EMPTY_INT) |		 INTTYPE(UART_TXOVERRUN_INT)) << intshift);	/* TX holding register empty, so transmit byte (non-DMA) */	if (ints & (INTTYPE(UART_TX_INT) | INTTYPE(UART_EMPTY_INT))) {		transmit_char_pio(port);	}	/* TX Transmit Holding Register Overrun (shouldn't happen) */	if (ints & INTTYPE(UART_TXOVERRUN_INT)) {		printk ( "rs: TX overrun\n");	}	/*	check_modem_status();	*/	restore_flags(flags);	rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "end.\n");}static void rs_rx_interrupt_uarta(int irq, void *dev_id,					 struct pt_regs * regs){	rs_rx_interrupt(irq, dev_id, regs, UARTA_SHIFT);}static void rs_tx_interrupt_uarta(int irq, void *dev_id,					 struct pt_regs * regs){	rs_tx_interrupt(irq, dev_id, regs, UARTA_SHIFT);}/* *********************************************************************** *                Here are the routines that actually                  * *              interface with the generic_serial driver               * *********************************************************************** */static void rs_disable_tx_interrupts (void * ptr) {	struct rs_port *port = ptr; 	unsigned long flags;	save_and_cli(flags);        port->gs.flags &= ~GS_TX_INTEN;	IntEnable2 &= ~((INTTYPE(UART_TX_INT) |			INTTYPE(UART_EMPTY_INT) |			INTTYPE(UART_TXOVERRUN_INT)) << port->intshift);	IntClear2 = (INTTYPE(UART_TX_INT) |			INTTYPE(UART_EMPTY_INT) |			INTTYPE(UART_TXOVERRUN_INT)) << port->intshift;	restore_flags(flags);}static void rs_enable_tx_interrupts (void * ptr) {	struct rs_port *port = ptr; 	unsigned long flags;	save_and_cli(flags);	IntClear2 = (INTTYPE(UART_TX_INT) |			INTTYPE(UART_EMPTY_INT) |			INTTYPE(UART_TXOVERRUN_INT)) << port->intshift;	IntEnable2 |= (INTTYPE(UART_TX_INT) |			INTTYPE(UART_EMPTY_INT) |			INTTYPE(UART_TXOVERRUN_INT)) << port->intshift;	/* Send a char to start TX interrupts happening */	transmit_char_pio(port);	restore_flags(flags);}static void rs_disable_rx_interrupts (void * ptr) {	struct rs_port *port = ptr;	unsigned long flags;	save_and_cli(flags);	IntEnable2 &= ~((INTTYPE(UART_RX_INT) |			 INTTYPE(UART_RXOVERRUN_INT) |			 INTTYPE(UART_FRAMEERR_INT) |			 INTTYPE(UART_BREAK_INT) |			 INTTYPE(UART_PARITYERR_INT)) << port->intshift);	IntClear2 = (INTTYPE(UART_RX_INT) |			 INTTYPE(UART_RXOVERRUN_INT) |			 INTTYPE(UART_FRAMEERR_INT) |			 INTTYPE(UART_BREAK_INT) |			 INTTYPE(UART_PARITYERR_INT)) << port->intshift;	restore_flags(flags);}static void rs_enable_rx_interrupts (void * ptr) {	struct rs_port *port = ptr;	unsigned long flags;	save_and_cli(flags);	IntEnable2 |= (INTTYPE(UART_RX_INT) |			 INTTYPE(UART_RXOVERRUN_INT) |			 INTTYPE(UART_FRAMEERR_INT) |			 INTTYPE(UART_BREAK_INT) |			 INTTYPE(UART_PARITYERR_INT)) << port->intshift;	/* Empty the input buffer - apparently this is *vital* */	while (inl(port->base + TX3912_UART_CTRL1) & UART_RX_HOLD_FULL) { 		inb(port->base + TX3912_UART_DATA);	}	IntClear2 = (INTTYPE(UART_RX_INT) |			 INTTYPE(UART_RXOVERRUN_INT) |			 INTTYPE(UART_FRAMEERR_INT) |			 INTTYPE(UART_BREAK_INT) |			 INTTYPE(UART_PARITYERR_INT)) << port->intshift;	restore_flags(flags);}static int rs_get_CD (void * ptr) {	/* No Carried Detect in Hardware - just return true */	func_exit();	return (1);}static void rs_shutdown_port (void * ptr) {	struct rs_port *port = ptr; 	func_enter();	port->gs.flags &= ~GS_ACTIVE;	func_exit();}static int rs_set_real_termios (void *ptr){	struct rs_port *port = ptr;	int t;	switch (port->gs.baud) {		/* Save some typing work... */#define e(x) case x:t= TX3912_UART_CTRL2_B ## x ; break		e(300);e(600);e(1200);e(2400);e(4800);e(9600);		e(19200);e(38400);e(57600);e(76800);e(115200);e(230400);	case 0      :t = -1;		break;	default:		/* Can I return "invalid"? */		t = TX3912_UART_CTRL2_B9600;		printk (KERN_INFO "rs: unsupported baud rate: %d.\n", port->gs.baud);		break;	}#undef e	if (t >= 0) {		/* Jim: Set Hardware Baud rate - there is some good		   code in drivers/char/serial.c */	  	/* Program hardware for parity, data bits, stop bits (note: these are hardcoded to 8N1 */		UartA_Ctrl1 &= 0xf000000f;		UartA_Ctrl1 &= ~(UART_DIS_TXD | SER_SEVEN_BIT | SER_EVEN_PARITY | SER_TWO_STOP);#define CFLAG port->gs.tty->termios->c_cflag		if (C_PARENB(port->gs.tty)) {			if (!C_PARODD(port->gs.tty))				UartA_Ctrl1 |= SER_EVEN_PARITY;			else				UartA_Ctrl1 |= SER_ODD_PARITY;		}		if ((CFLAG & CSIZE)==CS6)			printk(KERN_ERR "6 bits not supported\n");		if ((CFLAG & CSIZE)==CS5)			printk(KERN_ERR "5 bits not supported\n");		if ((CFLAG & CSIZE)==CS7)			UartA_Ctrl1 |= SER_SEVEN_BIT;		if (C_CSTOPB(port->gs.tty))			UartA_Ctrl1 |= SER_TWO_STOP;		outl(t, port->base + TX3912_UART_CTRL2);		outl(0, port->base + TX3912_UART_DMA_CTRL1);		outl(0, port->base + TX3912_UART_DMA_CTRL2);        	UartA_Ctrl1 |= TX3912_UART_CTRL1_UARTON;        /* wait until UARTA is stable */        while (~UartA_Ctrl1 & TX3912_UART_CTRL1_UARTON);	}	func_exit ();        return 0;}static int rs_chars_in_buffer (void * ptr) {	struct rs_port *port = ptr;	int scratch;	scratch = inl(port->base + TX3912_UART_CTRL1);	return ((scratch & UART_TX_EMPTY) ? 0 : 1);}/* ********************************************************************** * *                Here are the routines that actually                     * *               interface with the rest of the system                    * * ********************************************************************** */static int rs_open  (struct tty_struct * tty, struct file * filp)

⌨️ 快捷键说明

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