📄 amba.c
字号:
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 + -