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

📄 amba.c

📁 hao dong xi a hao dong xi a
💻 C
📖 第 1 页 / 共 2 页
字号:

static void ambauart_break_ctl(struct uart_port *port, int break_state)
{
	unsigned int lcr_h;

	lcr_h = UART_GET_LCRH(port);
	if (break_state == -1)
		lcr_h |= AMBA_UARTLCR_H_BRK;
	else
		lcr_h &= ~AMBA_UARTLCR_H_BRK;
	UART_PUT_LCRH(port, lcr_h);
}

static int ambauart_startup(struct uart_port *port, struct uart_info *info)
{
	int retval;

	/*
	 * Allocate the IRQ
	 */
	retval = request_irq(port->irq, ambauart_int, 0, "amba", info);
	if (retval)
		return retval;

	/*
	 * initialise the old status of the modem signals
	 */
	info->drv_old_status = UART_GET_FR(port) & AMBA_UARTFR_MODEM_ANY;

	/*
	 * Finally, enable interrupts
	 */
	UART_PUT_CR(port, AMBA_UARTCR_UARTEN | AMBA_UARTCR_RIE |
			  AMBA_UARTCR_RTIE);

	return 0;
}

static void ambauart_shutdown(struct uart_port *port, struct uart_info *info)
{
	/*
	 * Free the interrupt
	 */
	free_irq(port->irq, info);

	/*
	 * disable all interrupts, disable the port
	 */
	UART_PUT_CR(port, 0);

	/* disable break condition and fifos */
	UART_PUT_LCRH(port, UART_GET_LCRH(port) &
		~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN));
}

static void ambauart_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot)
{
	u_int lcr_h, old_cr;
	unsigned long flags;

#if DEBUG
	printk("ambauart_set_cflag(0x%x) called\n", cflag);
#endif
	/* byte size and parity */
	switch (cflag & CSIZE) {
	case CS5: lcr_h = AMBA_UARTLCR_H_WLEN_5; break;
	case CS6: lcr_h = AMBA_UARTLCR_H_WLEN_6; break;
	case CS7: lcr_h = AMBA_UARTLCR_H_WLEN_7; break;
	default:  lcr_h = AMBA_UARTLCR_H_WLEN_8; break; // CS8
	}
	if (cflag & CSTOPB)
		lcr_h |= AMBA_UARTLCR_H_STP2;
	if (cflag & PARENB) {
		lcr_h |= AMBA_UARTLCR_H_PEN;
		if (!(cflag & PARODD))
			lcr_h |= AMBA_UARTLCR_H_EPS;
	}
	if (port->fifosize > 1)
		lcr_h |= AMBA_UARTLCR_H_FEN;

	port->read_status_mask = AMBA_UARTRSR_OE;
	if (iflag & INPCK)
		port->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;
	if (iflag & (BRKINT | PARMRK))
		port->read_status_mask |= AMBA_UARTRSR_BE;

	/*
	 * Characters to ignore
	 */
	port->ignore_status_mask = 0;
	if (iflag & IGNPAR)
		port->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;
	if (iflag & IGNBRK) {
		port->ignore_status_mask |= AMBA_UARTRSR_BE;
		/*
		 * If we're ignoring parity and break indicators,
		 * ignore overruns too (for real raw support).
		 */
		if (iflag & IGNPAR)
			port->ignore_status_mask |= AMBA_UARTRSR_OE;
	}

	/*
	 * Ignore all characters if CREAD is not set.
	 */
	if ((cflag & CREAD) == 0)
		port->ignore_status_mask |= UART_DUMMY_RSR_RX;

	/* first, disable everything */
	save_flags(flags); cli();
	old_cr = UART_GET_CR(port) & ~AMBA_UARTCR_MSIE;

	if ((port->flags & ASYNC_HARDPPS_CD) ||
	    (cflag & CRTSCTS) || !(cflag & CLOCAL))
		old_cr |= AMBA_UARTCR_MSIE;

	UART_PUT_CR(port, 0);

	/* Set baud rate */
	quot -= 1;
	UART_PUT_LCRM(port, ((quot & 0xf00) >> 8));
	UART_PUT_LCRL(port, (quot & 0xff));

	/*
	 * ----------v----------v----------v----------v-----
	 * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
	 * ----------^----------^----------^----------^-----
	 */
	UART_PUT_LCRH(port, lcr_h);
	UART_PUT_CR(port, old_cr);

	restore_flags(flags);
}

static const char *ambauart_type(struct uart_port *port)
{
	return port->type == PORT_AMBA ? "AMBA" : NULL;
}

/*
 * Release the memory region(s) being used by 'port'
 */
static void ambauart_release_port(struct uart_port *port)
{
	release_mem_region(port->mapbase, UART_PORT_SIZE);
}

/*
 * Request the memory region(s) being used by 'port'
 */
static int ambauart_request_port(struct uart_port *port)
{
	return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_amba")
			!= NULL ? 0 : -EBUSY;
}

/*
 * Configure/autoconfigure the port.
 */
static void ambauart_config_port(struct uart_port *port, int flags)
{
	if (flags & UART_CONFIG_TYPE) {
		port->type = PORT_AMBA;
		ambauart_request_port(port);
	}
}

/*
 * verify the new serial_struct (for TIOCSSERIAL).
 */
static int ambauart_verify_port(struct uart_port *port, struct serial_struct *ser)
{
	int ret = 0;
	if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
		ret = -EINVAL;
	if (ser->irq < 0 || ser->irq >= NR_IRQS)
		ret = -EINVAL;
	if (ser->baud_base < 9600)
		ret = -EINVAL;
	return ret;
}

static struct uart_ops amba_pops = {
	tx_empty:	ambauart_tx_empty,
	set_mctrl:	ambauart_set_mctrl,
	get_mctrl:	ambauart_get_mctrl,
	stop_tx:	ambauart_stop_tx,
	start_tx:	ambauart_start_tx,
	stop_rx:	ambauart_stop_rx,
	enable_ms:	ambauart_enable_ms,
	break_ctl:	ambauart_break_ctl,
	startup:	ambauart_startup,
	shutdown:	ambauart_shutdown,
	change_speed:	ambauart_change_speed,
	type:		ambauart_type,
	release_port:	ambauart_release_port,
	request_port:	ambauart_request_port,
	config_port:	ambauart_config_port,
	verify_port:	ambauart_verify_port,
};

static struct uart_port amba_ports[UART_NR] = {
	{
		membase:	(void *)IO_ADDRESS(INTEGRATOR_UART0_BASE),
		mapbase:	INTEGRATOR_UART0_BASE,
		iotype:		SERIAL_IO_MEM,
		irq:		IRQ_UARTINT0,
		uartclk:	14745600,
		fifosize:	16,
		unused:		{ 4, 5 }, /*driver_priv:	PORT_CTRLS(5, 4), */
		ops:		&amba_pops,
		flags:		ASYNC_BOOT_AUTOCONF,
	},
	{
		membase:	(void *)IO_ADDRESS(INTEGRATOR_UART1_BASE),
		mapbase:	INTEGRATOR_UART1_BASE,
		iotype:		SERIAL_IO_MEM,
		irq:		IRQ_UARTINT1,
		uartclk:	14745600,
		fifosize:	16,
		unused:		{ 6, 7 }, /*driver_priv:	PORT_CTRLS(7, 6), */
		ops:		&amba_pops,
		flags:		ASYNC_BOOT_AUTOCONF,
	}
};

#ifdef CONFIG_SERIAL_AMBA_CONSOLE

static void ambauart_console_write(struct console *co, const char *s, u_int count)
{
	struct uart_port *port = amba_ports + co->index;
	unsigned int status, old_cr;
	int i;

	/*
	 *	First save the CR then disable the interrupts
	 */
	old_cr = UART_GET_CR(port);
	UART_PUT_CR(port, AMBA_UARTCR_UARTEN);

	/*
	 *	Now, do each character
	 */
	for (i = 0; i < count; i++) {
		do {
			status = UART_GET_FR(port);
		} while (!UART_TX_READY(status));
		UART_PUT_CHAR(port, s[i]);
		if (s[i] == '\n') {
			do {
				status = UART_GET_FR(port);
			} while (!UART_TX_READY(status));
			UART_PUT_CHAR(port, '\r');
		}
	}

	/*
	 *	Finally, wait for transmitter to become empty
	 *	and restore the TCR
	 */
	do {
		status = UART_GET_FR(port);
	} while (status & AMBA_UARTFR_BUSY);
	UART_PUT_CR(port, old_cr);
}

static kdev_t ambauart_console_device(struct console *co)
{
	return MKDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + co->index);
}

static void __init
ambauart_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
{
	if (UART_GET_CR(port) & AMBA_UARTCR_UARTEN) {
		u_int lcr_h, quot;
		lcr_h = UART_GET_LCRH(port);

		*parity = 'n';
		if (lcr_h & AMBA_UARTLCR_H_PEN) {
			if (lcr_h & AMBA_UARTLCR_H_EPS)
				*parity = 'e';
			else
				*parity = 'o';
		}

		if ((lcr_h & 0x60) == AMBA_UARTLCR_H_WLEN_7)
			*bits = 7;
		else
			*bits = 8;

		quot = UART_GET_LCRL(port) | UART_GET_LCRM(port) << 8;
		*baud = port->uartclk / (16 * (quot + 1));
	}
}

static int __init ambauart_console_setup(struct console *co, char *options)
{
	struct uart_port *port;
	int baud = 38400;
	int bits = 8;
	int parity = 'n';
	int flow = '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(amba_ports, UART_NR, co);

	if (options)
		uart_parse_options(options, &baud, &parity, &bits, &flow);
	else
		ambauart_console_get_options(port, &baud, &parity, &bits);

	return uart_set_options(port, co, baud, parity, bits, flow);
}

static struct console amba_console = {
	name:		"ttyAM",
	write:		ambauart_console_write,
	device:		ambauart_console_device,
	setup:		ambauart_console_setup,
	flags:		CON_PRINTBUFFER,
	index:		-1,
};

void __init ambauart_console_init(void)
{
	register_console(&amba_console);
}

#define AMBA_CONSOLE	&amba_console
#else
#define AMBA_CONSOLE	NULL
#endif

static struct uart_driver amba_reg = {
	owner:			THIS_MODULE,
	normal_major:		SERIAL_AMBA_MAJOR,
#ifdef CONFIG_DEVFS_FS
	normal_name:		"ttyAM%d",
	callout_name:		"cuaam%d",
#else
	normal_name:		"ttyAM",
	callout_name:		"cuaam",
#endif
	normal_driver:		&normal,
	callout_major:		CALLOUT_AMBA_MAJOR,
	callout_driver:		&callout,
	table:			amba_table,
	termios:		amba_termios,
	termios_locked:		amba_termios_locked,
	minor:			SERIAL_AMBA_MINOR,
	nr:			UART_NR,
	port:			amba_ports,
	cons:			AMBA_CONSOLE,
};

static int __init ambauart_init(void)
{
	return uart_register_driver(&amba_reg);
}

static void __exit ambauart_exit(void)
{
	uart_unregister_driver(&amba_reg);
}

module_init(ambauart_init);
module_exit(ambauart_exit);

EXPORT_NO_SYMBOLS;

MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
MODULE_DESCRIPTION("ARM AMBA serial port driver");
MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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