static void pl011_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); unsigned int lcr_h, old_cr; unsigned long flags; unsigned int baud, quot, clkdiv; if (uap->vendor->oversampling) clkdiv = 8; else clkdiv = 16; baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / clkdiv); if (baud > port->uartclk/16) quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); else quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud); switch (termios->c_cflag & CSIZE) { case CS5: lcr_h = UART01x_LCRH_WLEN_5; break; case CS6: lcr_h = UART01x_LCRH_WLEN_6; break; case CS7: lcr_h = UART01x_LCRH_WLEN_7; break; default: // CS8 lcr_h = UART01x_LCRH_WLEN_8; break; } if (termios->c_cflag & CSTOPB) lcr_h |= UART01x_LCRH_STP2; if (termios->c_cflag & PARENB) { lcr_h |= UART01x_LCRH_PEN; if (!(termios->c_cflag & PARODD)) lcr_h |= UART01x_LCRH_EPS; if (termios->c_cflag & CMSPAR) lcr_h |= UART011_LCRH_SPS; } if (uap->fifosize > 1) lcr_h |= UART01x_LCRH_FEN; spin_lock_irqsave(&port->lock, flags); uart_update_timeout(port, termios->c_cflag, baud); pl011_setup_status_masks(port, termios); if (UART_ENABLE_MS(port, termios->c_cflag)) pl011_enable_ms(port); old_cr = pl011_read(uap, REG_CR); pl011_write(0, uap, REG_CR); if (termios->c_cflag & CRTSCTS) { if (old_cr & UART011_CR_RTS) old_cr |= UART011_CR_RTSEN; old_cr |= UART011_CR_CTSEN; port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; } else { old_cr &= ~(UART011_CR_CTSEN | UART011_CR_RTSEN); port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); } if (uap->vendor->oversampling) { if (baud > port->uartclk / 16) old_cr |= ST_UART011_CR_OVSFACT; else old_cr &= ~ST_UART011_CR_OVSFACT; } if (uap->vendor->oversampling) { if ((baud >= 3000000) && (baud < 3250000) && (quot > 1)) quot -= 1; else if ((baud > 3250000) && (quot > 2)) quot -= 2; } pl011_write(quot & 0x3f, uap, REG_FBRD); pl011_write(quot >> 6, uap, REG_IBRD); pl011_write_lcr_h(uap, lcr_h); pl011_write(old_cr, uap, REG_CR); spin_unlock_irqrestore(&port->lock, flags); 详细分析这段代码中哪些部分是设置波特率,哪些是设置校验位,哪些是设置停止位,哪些是设置数据位宽,细致拆分出来
时间: 2023-09-01 19:10:52 浏览: 111
uart_test.rar_linux uart_linux 串口_uart收发测试_串口UART_串口收发
这段代码中设置波特率的部分包括以下几行:
```
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / clkdiv);
if (baud > port->uartclk/16)
quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
else
quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
pl011_write(quot & 0x3f, uap, REG_FBRD);
pl011_write(quot >> 6, uap, REG_IBRD);
```
其中,第一行通过调用 `uart_get_baud_rate` 函数获取波特率,第二行根据波特率计算出 `quot` 值,然后通过 `pl011_write` 函数分别将 `quot` 的低6位和高位写入寄存器 `REG_FBRD` 和 `REG_IBRD` 中,从而设置波特率。
设置校验位的部分包括以下几行:
```
if (termios->c_cflag & PARENB) {
lcr_h |= UART01x_LCRH_PEN;
if (!(termios->c_cflag & PARODD))
lcr_h |= UART01x_LCRH_EPS;
if (termios->c_cflag & CMSPAR)
lcr_h |= UART011_LCRH_SPS;
}
```
其中,第一行判断是否启用校验位,如果是,则将 `lcr_h` 的 `UART01x_LCRH_PEN` 位置1,表示启用校验位。第二行判断校验位类型是否为偶校验,如果不是,则将 `lcr_h` 的 `UART01x_LCRH_EPS` 位置1,表示启用偶校验。第三行判断是否启用奇偶校验位,如果是,则将 `lcr_h` 的 `UART011_LCRH_SPS` 位置1,表示启用奇偶校验位。
设置停止位的部分包括以下一行:
```
if (termios->c_cflag & CSTOPB)
lcr_h |= UART01x_LCRH_STP2;
```
其中,判断是否启用两个停止位,如果是,则将 `lcr_h` 的 `UART01x_LCRH_STP2` 位置1,表示启用两个停止位。
设置数据位宽的部分包括以下几行:
```
switch (termios->c_cflag & CSIZE) {
case CS5:
lcr_h = UART01x_LCRH_WLEN_5;
break;
case CS6:
lcr_h = UART01x_LCRH_WLEN_6;
break;
case CS7:
lcr_h = UART01x_LCRH_WLEN_7;
break;
default: // CS8
lcr_h = UART01x_LCRH_WLEN_8;
break;
}
```
其中,根据 `termios->c_cflag` 中的 `CSIZE` 值(表示数据位宽)选择相应的 `lcr_h` 值,从而设置数据位宽。如果 `CSIZE` 为 5、6、7 中的任意一个,就将 `lcr_h` 的相应位设置为对应值,否则默认为 8 位数据位宽。
阅读全文