📄 mx21_16c2552.c
字号:
lcr = UART16C2552_GET_LCR(p);
UART16C2552_PUT_LCR(p,lcr|0x80); // enable divisor latch access
rv = UART16C2552_GET_DLL(p);
UART16C2552_PUT_LCR(p,lcr); // restore original LCR
return rv;
}
// #define UART_PUT_LCRL(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_L, (c))
void UART_PUT_LCRL(struct amba_port *p, unsigned char c)
{
unsigned char lcr;
lcr = UART16C2552_GET_LCR(p);
UART16C2552_PUT_LCR(p,lcr|0x80); // enable divisor latch access
UART16C2552_PUT_DLL(p,c);
UART16C2552_PUT_LCR(p,lcr); // restore original LCR
}
// #define UART_GET_LCRM(p) IO_READ((p)->uart_base + AMBA_UARTLCR_M)
unsigned char UART_GET_LCRM(struct amba_port *p)
{
unsigned char lcr, rv;
lcr = UART16C2552_GET_LCR(p);
UART16C2552_PUT_LCR(p,lcr|0x80); // enable divisor latch access
rv = UART16C2552_GET_DLM(p);
UART16C2552_PUT_LCR(p,lcr); // restore original LCR
return rv;
}
// #define UART_PUT_LCRM(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_M, (c))
void UART_PUT_LCRM(struct amba_port *p, unsigned char c)
{
unsigned char lcr;
lcr = UART16C2552_GET_LCR(p);
UART16C2552_PUT_LCR(p,lcr|0x80); // enable divisor latch access
UART16C2552_PUT_DLM(p,c);
UART16C2552_PUT_LCR(p,lcr); // restore original LCR
}
// #define UART_GET_LCRH(p) IO_READ((p)->uart_base + AMBA_UARTLCR_H)
// LCRH (Line Control Register High) bits:
// 7 - reserved
// 6:5 - word length (11=8, 10=7, 01=6, 00=5)
// 4 - FEN (FIFO enable), not supported (always read as 1)
// 3 - STP2 (Two Stop Bits Select)
// 2 - EPS (Even Parity Select)
// 1 - PEN (Parity Enable)
// 0 - BRK (Send Break)
unsigned char UART_GET_LCRH(struct amba_port *p)
{
unsigned char rv, lcr;
lcr = UART16C2552_GET_LCR(p);
rv = ((lcr & 3) << 5) | 0x10; // WLEN (FEN always 1)
rv |= ((lcr & 4) << 1); // stop bit
rv |= ((lcr & 0x10) >> 2); // even parity
rv |= ((lcr & 8) >> 2); // parity enable
rv |= ((lcr & 0x40) >> 6); // set break
return rv;
}
// #define UART_PUT_LCRH(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_H, (c))
// LCRH (Line Control Register High) bits:
// 7 - reserved
// 6:5 - word length (11=8, 10=7, 01=6, 00=5)
// 4 - FEN (FIFO enable), not supported
// 3 - STP2 (Two Stop Bits Select)
// 2 - EPS (Even Parity Select)
// 1 - PEN (Parity Enable)
// 0 - BRK (Send Break)
void UART_PUT_LCRH(struct amba_port *p, unsigned char c)
{
unsigned char lcr;
lcr = UART16C2552_GET_LCR(p) & 0xA0;
lcr |= ((c & 0x60) >> 5); // WLEN
lcr |= ((c & 8) >> 1); // STP2
lcr |= ((c & 4) << 2); // EPS
lcr |= ((c & 2) << 2); // PEN
lcr |= ((c & 1) << 6); // BRK
UART16C2552_PUT_LCR(p,lcr);
}
#define UART_RX_DATA(s) (((s) & AMBA_UARTFR_RXFE) == 0)
#define UART_TX_READY(s) (((s) & AMBA_UARTFR_TXFF) == 0)
#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & AMBA_UARTFR_TMSK) == 0)
static void ambauart_enable_rx_interrupt(struct amba_info *info)
{
unsigned int cr;
cr = UART_GET_CR(info->port);
cr |= AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE;
UART_PUT_CR(info->port, cr);
}
static void ambauart_disable_rx_interrupt(struct amba_info *info)
{
unsigned int cr;
cr = UART_GET_CR(info->port);
cr &= ~(AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE);
UART_PUT_CR(info->port, cr);
}
static void ambauart_enable_tx_interrupt(struct amba_info *info)
{
unsigned int cr;
cr = UART_GET_CR(info->port);
cr |= AMBA_UARTCR_TIE;
UART_PUT_CR(info->port, cr);
}
static void ambauart_disable_tx_interrupt(struct amba_info *info)
{
unsigned int cr;
cr = UART_GET_CR(info->port);
cr &= ~AMBA_UARTCR_TIE;
UART_PUT_CR(info->port, cr);
}
static void ambauart_stop(struct tty_struct *tty)
{
struct amba_info *info = tty->driver_data;
unsigned long flags;
save_flags(flags); cli();
ambauart_disable_tx_interrupt(info);
restore_flags(flags);
}
static void ambauart_start(struct tty_struct *tty)
{
struct amba_info *info = tty->driver_data;
unsigned long flags;
save_flags(flags); cli();
if (info->xmit.head != info->xmit.tail
&& info->xmit.buf)
ambauart_enable_tx_interrupt(info);
restore_flags(flags);
}
/*
* This routine is used by the interrupt handler to schedule
* processing in the software interrupt portion of the driver.
*/
static void ambauart_event(struct amba_info *info, int event)
{
info->event |= 1 << event;
tasklet_schedule(&info->tlet);
}
static void
#ifdef SUPPORT_SYSRQ
ambauart_rx_chars(struct amba_info *info, struct pt_regs *regs)
#else
ambauart_rx_chars(struct amba_info *info)
#endif
{
struct tty_struct *tty = info->tty;
unsigned int status, ch, rsr, flg, ignored = 0;
struct amba_icount *icount = &info->state->icount;
struct amba_port *port = info->port;
//int i;
status = UART_GET_FR(port);
while (UART_RX_DATA(status)) {
ch = UART_GET_CHAR(port);
//MX1ADS
//printk("[%c]",ch);
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
{ // MX1ADS
//printk("-Ignore-");
goto ignore_char;
}
icount->rx++;
flg = TTY_NORMAL;
/*
* Note that the error handling code is
* out of the main execution path
*/
rsr = UART_GET_RSR(port);
if (rsr & AMBA_UARTRSR_ANY)
{ // MX1ADS
//printk("-error-");
goto handle_error;
}
#ifdef SUPPORT_SYSRQ
if (info->sysrq) {
if (ch && time_before(jiffies, info->sysrq)) {
handle_sysrq(ch, regs, NULL, NULL);
info->sysrq = 0;
goto ignore_char;
}
info->sysrq = 0;
}
#endif
error_return:
*tty->flip.flag_buf_ptr++ = flg;
*tty->flip.char_buf_ptr++ = ch;
tty->flip.count++;
ignore_char:
status = UART_GET_FR(port);
}
out:
tty_flip_buffer_push(tty);
return;
handle_error:
if (rsr & AMBA_UARTRSR_BE) {
rsr &= ~(AMBA_UARTRSR_FE | AMBA_UARTRSR_PE);
icount->brk++;
#ifdef SUPPORT_SYSRQ
if (info->state->line == ambauart_cons.index) {
if (!info->sysrq) {
info->sysrq = jiffies + HZ*5;
goto ignore_char;
}
}
#endif
} else if (rsr & AMBA_UARTRSR_PE)
icount->parity++;
else if (rsr & AMBA_UARTRSR_FE)
icount->frame++;
if (rsr & AMBA_UARTRSR_OE)
icount->overrun++;
if (rsr & info->ignore_status_mask) {
if (++ignored > 100)
goto out;
goto ignore_char;
}
rsr &= info->read_status_mask;
if (rsr & AMBA_UARTRSR_BE)
flg = TTY_BREAK;
else if (rsr & AMBA_UARTRSR_PE)
flg = TTY_PARITY;
else if (rsr & AMBA_UARTRSR_FE)
flg = TTY_FRAME;
if (rsr & AMBA_UARTRSR_OE) {
/*
* CHECK: does overrun affect the current character?
* ASSUMPTION: it does not.
*/
*tty->flip.flag_buf_ptr++ = flg;
*tty->flip.char_buf_ptr++ = ch;
tty->flip.count++;
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
goto ignore_char;
ch = 0;
flg = TTY_OVERRUN;
}
#ifdef SUPPORT_SYSRQ
info->sysrq = 0;
#endif
goto error_return;
}
static void ambauart_tx_chars(struct amba_info *info)
{
struct amba_port *port = info->port;
int count,i;
unsigned char ch;
if (info->x_char) {
UART_PUT_CHAR(port, info->x_char);
info->state->icount.tx++;
info->x_char = 0;
return;
}
if (info->xmit.head == info->xmit.tail
|| info->tty->stopped
|| info->tty->hw_stopped) {
ambauart_disable_tx_interrupt(info);
return;
}
count = port->fifosize;
//printk("head-tail=%d\n",(info->xmit.head - info->xmit.tail));
//printk("xmitbuf=%s\n",&info->xmit.buf[info->xmit.tail]);
do {
ch = info->xmit.buf[info->xmit.tail];
UART_PUT_CHAR(port, ch);
//for(i=0;i<1000;i++);
printk("send char %c\n",ch);
info->xmit.tail = (info->xmit.tail + 1) & (AMBA_XMIT_SIZE - 1);
info->state->icount.tx++;
if (info->xmit.head == info->xmit.tail)
break;
} while (--count > 0);
if (CIRC_CNT(info->xmit.head,
info->xmit.tail,
AMBA_XMIT_SIZE) < WAKEUP_CHARS)
ambauart_event(info, EVT_WRITE_WAKEUP);
if (info->xmit.head == info->xmit.tail) {
ambauart_disable_tx_interrupt(info);
}
}
static void ambauart_modem_status(struct amba_info *info)
{
unsigned int status, delta;
struct amba_icount *icount = &info->state->icount;
UART_PUT_ICR(info->port, 0);
status = UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY;
delta = status ^ info->old_status;
info->old_status = status;
if (!delta)
return;
if (delta & AMBA_UARTFR_DCD) {
icount->dcd++;
#ifdef CONFIG_HARD_PPS
if ((info->flags & ASYNC_HARDPPS_CD) &&
(status & AMBA_UARTFR_DCD))
hardpps();
#endif
if (info->flags & ASYNC_CHECK_CD) {
if (status & AMBA_UARTFR_DCD)
wake_up_interruptible(&info->open_wait);
else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
(info->flags & ASYNC_CALLOUT_NOHUP))) {
if (info->tty)
tty_hangup(info->tty);
}
}
}
if (delta & AMBA_UARTFR_DSR)
icount->dsr++;
if (delta & AMBA_UARTFR_CTS) {
icount->cts++;
if (info->flags & ASYNC_CTS_FLOW) {
status &= AMBA_UARTFR_CTS;
if (info->tty->hw_stopped) {
if (status) {
info->tty->hw_stopped = 0;
ambauart_enable_tx_interrupt(info);
ambauart_event(info, EVT_WRITE_WAKEUP);
}
} else {
if (!status) {
info->tty->hw_stopped = 1;
ambauart_disable_tx_interrupt(info);
}
}
}
}
wake_up_interruptible(&info->delta_msr_wait);
}
static void ambauart_int(int irq, void *dev_id, struct pt_regs *regs)
{
struct amba_info *info = dev_id;
unsigned int status, pass_counter = 0;
// we need to clear port C interrupt here
if(((_reg_GPIO_ISR(GPIOC) & _reg_GPIO_IMR(GPIOC))&0x00040000)!=0)
_reg_GPIO_ISR(GPIOC) = 0x00040000;
else
return;
//printk("uart interupt\n");
//st16c2552_gpio_disable_inter();
status = UART_GET_INT_STATUS(info->port);
do {
/*
* FIXME: what about clearing the interrupts?
*/
if (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS))
{ // MX1ADS
//printk("<Rx>");
#ifdef SUPPORT_SYSRQ
ambauart_rx_chars(info, regs);
#else
ambauart_rx_chars(info);
#endif
}
// if (status & AMBA_UARTIIR_TIS)
ambauart_tx_chars(info);
if (status & AMBA_UARTIIR_MIS)
ambauart_modem_status(info);
if (pass_counter++ > AMBA_ISR_PASS_LIMIT)
break;
status = UART_GET_INT_STATUS(info->port);
} while (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS | AMBA_UARTIIR_TIS));
//st16c2552_gpio_enable_inter();
}
static void ambauart_tasklet_action(unsigned long data)
{
struct amba_info *info = (struct amba_info *)data;
struct tty_struct *tty;
tty = info->tty;
if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event))
return;
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
wake_up_interruptible(&tty->write_wait);
}
static int ambauart_startup(struct amba_info *info)
{
unsigned long flags;
unsigned long page;
int retval = 0;
page = get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
save_flags(flags); cli();
if (info->flags & ASYNC_INITIALIZED) {
free_page(page);
goto errout;
}
if (info->xmit.buf)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -