• UART驱动程序结构:struct uart_driver 驱动
• UART端口结构: struct uart_port 串口
• UART相关操作函数结构: struct uart_ops 串口操作函数集
• UART状态结构: struct uart_state 串口状态
• UART信息结构: struct uart_info 串口信息
2、串口驱动程序-初始化

3、串口驱动分析-打开设备

static int s3c24xx_serial_startup(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
int ret;
dbg('s3c24xx_serial_startup: port=%p (%08lx,%p)n',
port->mapbase, port->membase);
rx_enabled(port) = 1;
ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
s3c24xx_serial_portname(port), ourport);
if (ret != 0) {
printk(KERN_ERR 'cannot get irq %dn', ourport->rx_irq);
return ret;
}
ourport->rx_claimed = 1;
dbg('requesting tx irq...n');
tx_enabled(port) = 1;
ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
s3c24xx_serial_portname(port), ourport);
if (ret) {
printk(KERN_ERR 'cannot get irq %dn', ourport->tx_irq);
goto err;
}
ourport->tx_claimed = 1;
dbg('s3c24xx_serial_startup okn');
/* the port reset code should have done the correct
* register setup for the port controls */
return ret;
err:
s3c24xx_serial_shutdown(port);
return ret;
}

3、串口驱动程序-数据发送

static void s3c24xx_serial_start_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
static int a =1;//temp
if (port->line == 3) {
// printk('485_start_txn');
if(a){
s3c_gpio_cfgpin(S3C64XX_GPK(5), S3C_GPIO_SFN(1));
a=0;
}
gpio_set_value(S3C64XX_GPK(5), 1);
}
if (!tx_enabled(port)) {
if (port->flags & UPF_CONS_FLOW)
s3c24xx_serial_rx_disable(port);
enable_irq(ourport->tx_irq);
tx_enabled(port) = 1;
}
}
static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
{
struct s3c24xx_uart_port *ourport = id;
struct uart_port *port = &ourport->port;
struct circ_buf *xmit = &port->state->xmit;
int count = 256;
if (port->x_char) {
wr_regb(port, S3C2410_UTXH, port->x_char);
port->icount.tx++;
port->x_char = 0;
goto out;
}
/* if there isn't anything more to transmit, or the uart is now
* stopped, disable the uart and exit
*/
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
s3c24xx_serial_stop_tx(port);
goto out;
}
/* try and drain the buffer... */
while (!uart_circ_empty(xmit) && count-- > 0) {
if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
break;
wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
s3c24xx_serial_stop_tx(port);
out:
return IRQ_HANDLED;
}
4、串口驱动程序-数据接收

s3c24xx_serial_rx_chars(int irq, void *dev_id)
{
struct s3c24xx_uart_port *ourport = dev_id;
struct uart_port *port = &ourport->port;
struct tty_struct *tty = port->state->port.tty;
unsigned int ufcon, ch, flag, ufstat, uerstat;
int max_count = 64;
while (max_count-- > 0) {
ufcon = rd_regl(port, S3C2410_UFCON);
ufstat = rd_regl(port, S3C2410_UFSTAT);
if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
break;
uerstat = rd_regl(port, S3C2410_UERSTAT);
ch = rd_regb(port, S3C2410_URXH);
if (port->flags & UPF_CONS_FLOW) {
int txe = s3c24xx_serial_txempty_nofifo(port);
if (rx_enabled(port)) {
if (!txe) {
rx_enabled(port) = 0;
continue;
}
} else {
if (txe) {
ufcon |= S3C2410_UFCON_RESETRX;
wr_regl(port, S3C2410_UFCON, ufcon);
rx_enabled(port) = 1;
goto out;
}
continue;
}
}
/* insert the character into the buffer */
flag = TTY_NORMAL;
port->icount.rx++;
if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
dbg('rxerr: port ch=0x%02x, rxs=0x%08xn',
ch, uerstat);
/* check for break */
if (uerstat & S3C2410_UERSTAT_BREAK) {
dbg('break!n');
port->icount.brk++;
if (uart_handle_break(port))
goto ignore_char;
}
if (uerstat & S3C2410_UERSTAT_FRAME)
port->icount.frame++;
if (uerstat & S3C2410_UERSTAT_OVERRUN)
port->icount.overrun++;
uerstat &= port->read_status_mask;
if (uerstat & S3C2410_UERSTAT_BREAK)
flag = TTY_BREAK;
else if (uerstat & S3C2410_UERSTAT_PARITY)
flag = TTY_PARITY;
else if (uerstat & (S3C2410_UERSTAT_FRAME |
S3C2410_UERSTAT_OVERRUN))
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(port, ch))
goto ignore_char;
uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
ch, flag);
ignore_char:
continue;
}
tty_flip_buffer_push(tty);
out:
return IRQ_HANDLED;
}

附:linux系统中一般的流控技术

上一篇:linux MTD系统解析,
下一篇:ok6410 3.0.1内核调用V4L接口出错解决方法
推荐阅读最新更新时间:2026-03-10 05:37
- 用于简单时钟振荡器的 NCP301LSN22T1 2.2V 电压检测器的典型应用
- 使用 LT3045EDD 超低 1/f 噪声基准缓冲器的典型应用
- 使用 ON Semiconductor 的 NCV7691 的参考设计
- AD8131,差分驱动器评估板
- TC78H651FNG 低压驱动有刷直流电机驱动器评估板
- 使用 Analog Devices 的 LT1117CM-2.85 的参考设计
- 基于 TD340 的低侧感应电机控制系统中的电流测量和限制
- R_149_V10基于IPS2电机换向传感器的设计
- AD584 大电流精密电源电压基准的典型应用
- TB67H400AHG 大电流驱动有刷直流电机驱动器评估板

Linux技术手册
【2025 DigiKey创意大赛】 学伴智盒 - 代码
智能机械臂
非常经典的关于LLC的杨波博士论文
1-292148-8






京公网安备 11010802033920号