====本文系本站原创,欢迎转载! 转载请注明出处:http://blog.csdn.net/yyplc====
本文系itspy原创,复制/转载请尽量标明原出处http://blog.csdn.net/yyplc/article/details/7196290,谢谢!
软件篇(linux-2.6.30.4):
Linux系统的串口驱动与一般字符设备并一样,它采用层次化的架构,从而看做是一个串行系统来实现。
(1) 关注UART或其他底层串行硬件特征的底层驱动程序。
(2) 和底层驱动程序接口的TTY驱动程序。
(3) 加工用于和TTY驱动程序交换数据的线路规程。
下图描述了串行系统间的层次结构关系(s3c2440串口实现例),可以概括为:用户应用层 --> 线路规划层 --> TTY层 --> 底层驱动层 --> 物理硬件层
线路规程和TTY驱动程序是与硬件平台无关的,Linux源码中已经提供了实现,所以对于具体的平台,我们只需实现底层驱动程序即可,这也是我们最关心的。在s3c2440a中,主要由dirivers/serial/下的s3c2440.c和samsung.c实现。
Uart驱动程序主要围绕三个关键的数据结构展开(include/linux/serial_core.h中定义):
UART特定的驱动程序结构定义:struct uart_driver s3c24xx_uart_drv;
UART端口结构定义: struct uart_port s3c24xx_serial_ops;
UART相关操作函数结构定义: struct uart_ops s3c24xx_serial_ops;
基于以上三个结构体,来看看s3c2440是如何挂接到Linux中串口构架的:
S3c2440串口相关操作函数定义在s3c24xx_serial_ops中,这个是一个structuart_ops结构
static struct uart_ops s3c24xx_serial_ops ={
.pm =s3c24xx_serial_pm, //电源管理函数
.tx_empty = s3c24xx_serial_tx_empty, //检车发送FIFO缓冲区是否空
.get_mctrl = s3c24xx_serial_get_mctrl, //是否串口流控
.set_mctrl = s3c24xx_serial_set_mctrl, //是否设置串口流控cts
.stop_tx =s3c24xx_serial_stop_tx, //停止发送
.start_tx =s3c24xx_serial_start_tx, //启动发送
.stop_rx =s3c24xx_serial_stop_rx, //停止接收
.enable_ms = s3c24xx_serial_enable_ms, //空函数
.break_ctl = s3c24xx_serial_break_ctl, //发送break信号
.startup =s3c24xx_serial_startup, //串口发送/接收,以及中断申请初始配置函数
.shutdown = s3c24xx_serial_shutdown, //关闭串口
.set_termios = s3c24xx_serial_set_termios,//串口clk,波特率,数据位等参数设置
.type = s3c24xx_serial_type, // CPU类型关于串口
.release_port =s3c24xx_serial_release_port, //释放串口
.request_port =s3c24xx_serial_request_port, //申请串口
.config_port = s3c24xx_serial_config_port, //串口的一些配置信息info
.verify_port = s3c24xx_serial_verify_port, //串口检测
};
驱动程序结构定义:
static struct uart_driver s3c24xx_uart_drv= {
.owner =THIS_MODULE,
.dev_name = "s3c2440_serial", //具体设备名称
.nr =CONFIG_SERIAL_SAMSUNG_UARTS, //定义有几个端口
.cons = S3C24XX_SERIAL_CONSOLE, //console接口
.driver_name =S3C24XX_SERIAL_NAME, //串口名:ttySAC
.major =S3C24XX_SERIAL_MAJOR, //主设备号
.minor =S3C24XX_SERIAL_MINOR, //次设备号
};
端口配置结构定义,其中包括了一个structuart_ports结构:
struct s3c24xx_uart_port {
unsignedchar rx_claimed;
unsignedchar tx_claimed;
unsignedint pm_level;
unsignedlong baudclk_rate;
unsignedint rx_irq;
unsignedint tx_irq;
structs3c24xx_uart_info *info;
structs3c24xx_uart_clksrc *clksrc;
structclk *clk;
structclk *baudclk;
structuart_port port;
#ifdef CONFIG_CPU_FREQ
structnotifier_block freq_transition;
#endif
};
static structs3c24xx_uart_ports3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
[0]= { //串口0
.port= {
.lock =__SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
.iotype =UPIO_MEM, //
.irq =IRQ_S3CUART_RX0, //中断号
.uartclk = 0, //时钟值
.fifosize = 16, //定义FIFO缓存区大小
.ops = &s3c24xx_serial_ops, //串口相关操作函数
.flags = UPF_BOOT_AUTOCONF,
.line = 0, //线路1
}
},
[1]= {//串口1
.port= {
.lock =__SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX1,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = 1,
}
},
#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
[2]= {//串口2
.port= {
.lock =__SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX2,
.uartclk = 0,
.fifosize = 16,
.ops =&s3c24xx_serial_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = 2,
}
},
#endif
};
综上所述,s3c2440主要是实现这三个数据结构:
s3c24xx_serial_ops, s3c24xx_uart_drv, s3c24xx_uart_ports3c24xx_serial_ports
下篇将进一步结合源码探讨ARM-Linuxs3c2440 的实现。