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

📄 anakin.c

📁 IXP425 平台下嵌入式LINUX的串口的驱动程序
💻 C
字号:
/* *  linux/drivers/char/serial_anakin.c * *  Based on driver for AMBA serial ports, by ARM Limited, *  Deep Blue Solutions Ltd., Linus Torvalds and Theodore Ts'o. * *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V. * *  Copyright (C) 2001 Blue Mug, Inc. for Acunia N.V. * * 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. * *  Changelog: *   20-Apr-2001 TTC	Created *   05-May-2001 W/TTC	Updated for serial_core.c *   27-Jun-2001 jonm	Minor changes; add mctrl support, switch to  *   			SA_INTERRUPT. Works reliably now. No longer requires *   			changes to the serial_core API. * *  $Id: anakin.c,v 1.5.2.2 2002/10/24 09:53:25 rmk Exp $ */#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.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/ptrace.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/circ_buf.h>#include <linux/serial.h>#include <linux/console.h>#include <linux/sysrq.h>#include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/bitops.h>#include <linux/serial_core.h>#include <asm/arch/serial_reg.h>#define UART_NR			5#define SERIAL_ANAKIN_NAME	"ttyAN"#define SERIAL_ANAKIN_MAJOR	204#define SERIAL_ANAKIN_MINOR	32#define CALLOUT_ANAKIN_NAME	"cuaan"#define CALLOUT_ANAKIN_MAJOR	205#define CALLOUT_ANAKIN_MINOR	32static struct tty_driver normal, callout;static struct tty_struct *anakin_table[UART_NR];static struct termios *anakin_termios[UART_NR], *anakin_termios_locked[UART_NR];static struct uart_state anakin_state[UART_NR];static u_int txenable[NR_IRQS];		/* Software interrupt register */static inline unsigned intanakin_in(struct uart_port *port, u_int offset){	return __raw_readl(port->base + offset);}static inline voidanakin_out(struct uart_port *port, u_int offset, unsigned int value){	__raw_writel(value, port->base + offset);}static voidanakin_stop_tx(struct uart_port *port, u_int from_tty){	txenable[port->irq] = 0;}static inline voidanakin_transmit_buffer(struct uart_info *info){	struct uart_port *port = info->port;	while (!(anakin_in(port, 0x10) & TXEMPTY));	anakin_out(port, 0x14, info->xmit.buf[info->xmit.tail]);	anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);	info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE-1);        info->state->icount.tx++;	if (info->xmit.head == info->xmit.tail)		anakin_stop_tx(port, 0); }static inline voidanakin_transmit_x_char(struct uart_info *info){	struct uart_port *port = info->port;	anakin_out(port, 0x14, info->x_char);	anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);	info->state->icount.tx++;	info->x_char = 0;}static voidanakin_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty){	unsigned int flags;	save_flags_cli(flags);	// is it this... or below: if (nonempty	if (!txenable[port->irq]) {		txenable[port->irq] = TXENABLE;		if ((anakin_in(port, 0x10) & TXEMPTY) && nonempty) {		    anakin_transmit_buffer((struct uart_info*)port->unused);		}	}	restore_flags(flags);}static voidanakin_stop_rx(struct uart_port *port){	unsigned long flags;	save_flags_cli(flags);	while (anakin_in(port, 0x10) & RXRELEASE) 	    anakin_in(port, 0x14);	anakin_out(port, 0x18, anakin_in(port, 0x18) | BLOCKRX);	restore_flags(flags);}static voidanakin_enable_ms(struct uart_port *port){}static inline voidanakin_rx_chars(struct uart_info *info){	unsigned int ch;	struct tty_struct *tty = info->tty;	if (!(anakin_in(info->port, 0x10) & RXRELEASE))		return;	ch = anakin_in(info->port, 0x14) & 0xff;	if (tty->flip.count < TTY_FLIPBUF_SIZE) {		*tty->flip.char_buf_ptr++ = ch;		*tty->flip.flag_buf_ptr++ = TTY_NORMAL;		info->state->icount.rx++;		tty->flip.count++;	} 	tty_flip_buffer_push(tty);}static inline voidanakin_overrun_chars(struct uart_info *info){	unsigned int ch;	ch = anakin_in(info->port, 0x14);	info->state->icount.overrun++;}static inline voidanakin_tx_chars(struct uart_info *info){	if (info->x_char) {		anakin_transmit_x_char(info);		return; 	}	if (info->xmit.head == info->xmit.tail	    || info->tty->stopped	    || info->tty->hw_stopped) {		anakin_stop_tx(info->port, 0);		return;	}	anakin_transmit_buffer(info);	if (CIRC_CNT(info->xmit.head,		     info->xmit.tail,		     UART_XMIT_SIZE) < WAKEUP_CHARS)		uart_event(info, EVT_WRITE_WAKEUP);}static voidanakin_int(int irq, void *dev_id, struct pt_regs *regs){	unsigned int status;	struct uart_info *info = dev_id;	status = anakin_in(info->port, 0x1c);	if (status & RX) 		anakin_rx_chars(info);	if (status & OVERRUN) 		anakin_overrun_chars(info);	if (txenable[info->port->irq] && (status & TX)) 		anakin_tx_chars(info);}static u_intanakin_tx_empty(struct uart_port *port){	return anakin_in(port, 0x10) & TXEMPTY ? TIOCSER_TEMT : 0;}static u_intanakin_get_mctrl(struct uart_port *port){	unsigned int status = 0;	status |= (anakin_in(port, 0x10) & CTS ? TIOCM_CTS : 0);	status |= (anakin_in(port, 0x18) & DCD ? TIOCM_CAR : 0);	status |= (anakin_in(port, 0x18) & DTR ? TIOCM_DTR : 0);	status |= (anakin_in(port, 0x18) & RTS ? TIOCM_RTS : 0);		return status;}static voidanakin_set_mctrl(struct uart_port *port, u_int mctrl){	unsigned int status;	status = anakin_in(port, 0x18);	if (mctrl & TIOCM_RTS) 		status |= RTS;	else 		status &= ~RTS;	if (mctrl & TIOCM_CAR)		status |= DCD;	else 		status &= ~DCD;	anakin_out(port, 0x18, status);}static voidanakin_break_ctl(struct uart_port *port, int break_state){	unsigned int status;	status = anakin_in(port, 0x20);	if (break_state == -1)		status |= SETBREAK;	else		status &= ~SETBREAK;	anakin_out(port, 0x20, status);}static intanakin_startup(struct uart_port *port, struct uart_info *info){	int retval;	unsigned int read,write;	/*	 * Allocate the IRQ	 */	retval = request_irq(port->irq, anakin_int, SA_INTERRUPT, "serial_anakin", info);	if (retval)		return retval;	port->ops->set_mctrl(port, info->mctrl);	/*	 * initialise the old status of the modem signals	 */	port->old_status = 0;	/*	 * Finally, disable IRQ and softIRQs for first byte)	 */	txenable[port->irq] = 0;	read = anakin_in(port, 0x18);	write = (read & ~(RTS | DTR | BLOCKRX)) | IRQENABLE;	anakin_out(port, 0x18, write);	/* Store the uart_info pointer so we can reference it in 	 * anakin_start_tx() */	port->unused = (u_int)info;		return 0;}static voidanakin_shutdown(struct uart_port *port, struct uart_info *info){	/*	 * Free the interrupt	 */	free_irq(port->irq, info);	/*	 * disable all interrupts, disable the port	 */	anakin_out(port, 0x18, anakin_in(port, 0x18) & ~IRQENABLE);}static voidanakin_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot){	unsigned int flags;	save_flags_cli(flags);	while (!(anakin_in(port, 0x10) & TXEMPTY));	anakin_out(port, 0x10, (anakin_in(port, 0x10) & ~PRESCALER)			| (quot << 3));	//parity always set to none	anakin_out(port, 0x18, anakin_in(port, 0x18) & ~PARITY);	restore_flags(flags);}static const char *anakin_type(struct port *port){	return port->type == PORT_ANAKIN ? "ANAKIN" : NULL;}static struct uart_ops anakin_pops = {	tx_empty:	anakin_tx_empty,	set_mctrl:	anakin_set_mctrl,	get_mctrl:	anakin_get_mctrl,	stop_tx:	anakin_stop_tx,	start_tx:	anakin_start_tx,	stop_rx:	anakin_stop_rx,	enable_ms:	anakin_enable_ms,	break_ctl:	anakin_break_ctl,	startup:	anakin_startup,	shutdown:	anakin_shutdown,	change_speed:	anakin_change_speed,	type:		anakin_type,};static struct uart_port anakin_ports[UART_NR] = {	{		base:		IO_BASE + UART0,		irq:		IRQ_UART0,		uartclk:	3686400,		fifosize:	0,		ops:		&anakin_pops,	},	{		base:		IO_BASE + UART1,		irq:		IRQ_UART1,		uartclk:	3686400,		fifosize:	0,		ops:		&anakin_pops,	},	{		base:		IO_BASE + UART2,		irq:		IRQ_UART2,		uartclk:	3686400,		fifosize:	0,		ops:		&anakin_pops,	},	{		base:		IO_BASE + UART3,		irq:		IRQ_UART3,		uartclk:	3686400,		fifosize:	0,		ops:		&anakin_pops,	},	{		base:		IO_BASE + UART4,		irq:		IRQ_UART4,		uartclk:	3686400,		fifosize:	0,		ops:		&anakin_pops,	},};#ifdef CONFIG_SERIAL_ANAKIN_CONSOLEstatic voidanakin_console_write(struct console *co, const char *s, u_int count){	struct uart_port *port = anakin_ports + co->index;	unsigned int flags, status, i;	/*	 *	First save the status then disable the interrupts	 */	save_flags_cli(flags);	status = anakin_in(port, 0x18);	anakin_out(port, 0x18, status & ~IRQENABLE);	restore_flags(flags);	/*	 *	Now, do each character	 */	for (i = 0; i < count; i++, s++) {		while (!(anakin_in(port, 0x10) & TXEMPTY));		/*		 *	Send the character out.		 *	If a LF, also do CR...		 */		anakin_out(port, 0x14, *s);		anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);		if (*s == 10) {			while (!(anakin_in(port, 0x10) & TXEMPTY));			anakin_out(port, 0x14, 13);			anakin_out(port, 0x18, anakin_in(port, 0x18)					| SENDREQUEST);		}	}	/*	 *	Finally, wait for transmitter to become empty	 *	and restore the interrupts	 */	while (!(anakin_in(port, 0x10) & TXEMPTY));	if (status & IRQENABLE)		save_flags_cli(flags); 		anakin_out(port, 0x18, anakin_in(port, 0x18) | IRQENABLE);		restore_flags(flags);}static kdev_tanakin_console_device(struct console *co){	return MKDEV(SERIAL_ANAKIN_MAJOR, SERIAL_ANAKIN_MINOR + co->index);}/* * Read the current UART setup. */static void __initanakin_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits){	int paritycode;	*baud = GETBAUD (anakin_in(port, 0x10) & PRESCALER);	paritycode = GETPARITY(anakin_in(port, 0x18) & PARITY);	switch (paritycode) {	  case NONEPARITY: *parity = 'n'; break;	  case ODDPARITY: *parity = 'o'; break;	  case EVENPARITY: *parity = 'e'; break;	}	*bits = 8;}static int __initanakin_console_setup(struct console *co, char *options){	struct uart_port *port;	int baud = CONFIG_ANAKIN_DEFAULT_BAUDRATE;	int bits = 8;	int parity = 'n';	/*	 * Check whether an invalid uart number has been specified, and	 * if so, search for the first available port that does have	 * console support.	 */	port = uart_get_console(anakin_ports, UART_NR, co);	if (options)		uart_parse_options(options, &baud, &parity, &bits);	else		anakin_console_get_options(port, &baud, &parity, &bits);	return uart_set_options(port, co, baud, parity, bits);}static struct console anakin_console = {	name:		SERIAL_ANAKIN_NAME,	write:		anakin_console_write,	device:		anakin_console_device,	setup:		anakin_console_setup,	flags:		CON_PRINTBUFFER,	index:		-1,};void __initanakin_console_init(void){	register_console(&anakin_console);}#define ANAKIN_CONSOLE		&anakin_console#else#define ANAKIN_CONSOLE		NULL#endifstatic struct uart_register anakin_reg = {	normal_major:		SERIAL_ANAKIN_MAJOR,	normal_name:		SERIAL_ANAKIN_NAME,	normal_driver:		&normal,	callout_major:		CALLOUT_ANAKIN_MAJOR,	callout_name:		CALLOUT_ANAKIN_NAME,	callout_driver:		&callout,	table:			anakin_table,	termios:		anakin_termios,	termios_locked:		anakin_termios_locked,	minor:			SERIAL_ANAKIN_MINOR,	nr:			UART_NR,	state:			anakin_state,	port:			anakin_ports,	cons:			ANAKIN_CONSOLE,};static int __initanakin_init(void){	return uart_register_port(&anakin_reg);}__initcall(anakin_init);MODULE_DESCRIPTION("Anakin serial driver");MODULE_AUTHOR("Tak-Shing Chan <chan@aleph1.co.uk>");MODULE_SUPPORTED_DEVICE("ttyAN");MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;

⌨️ 快捷键说明

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