微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux下的串口总线驱动(一)

Linux下的串口总线驱动(一)

时间:11-22 来源:互联网 点击:
一.系统理论

PC机南桥的LPC总线(Low Pin Count并行总线,代替以前的ISA总线)上挂接了一个超级I/O模块,而UART是这个超级模块芯片组的一部分,这个UART通过RS232线程转换与串行端口相连。与RS232不同,RS485并不是标准的PC接口,但在嵌入式领域,会为了可靠通信而使用RS485,RS485使用差分信号,因此其传输距离可以达到数百米,而RS232传输距离仅数几米,在处理器一端,RS485接口是半双工的UART操作。

Linux包含如下几种终端设备:串行端口终端(/dev/ttySn)、伪终端(/dev/pty)、控制终端(/dev/tty)、控制台终端(/dev/ttyn,/dev/conslole)。串行端口终端使用的设备名为/dev/ttyS0,/dev/ttyS1等,对应的设备号为(4,0),(4,1)。通过查看/proc/tty/drivers文件可以知道什么类型的tty设备存在以及什么驱动被加载到内核,这个文件包括一个当前存在的不同tty驱动的列表,包括驱动名,缺省的节点名,驱动的主编号,驱动的次编号范围,以及tty驱动的类型。

I/O系统调用是从带有线路规程的TTY I/O核心开始,然后通过TTY层,最后到达UART驱动层。主要涉及串口内核配置、UART层内核代码、TTY层内核代码、线路规程内核代码、串口测试代码五个部分。

二.串口内核配置

对于Mini2440串口驱动,我想从配置开始讲起。在内核中Kconfig必须完成一层层调用,如果没有在上一个Kconfig中调用该层Kconfig,那么该层Kconfig中的内容不会在此出现。这种情况下,只有当该层的Kconfig被其他层调用,该层Kconfig中的内容才会被显示。所以我们找找drivers/serial/Kconfig在哪里被调用的呢?

在/drivers/char/kconfig中可以看到一行代码source "drivers/serial/Kconfig",那我们就到drivers/serial/Kconfig下看看

Samsung SoC serial support对应于samsung.o serial_core.o

config SERIAL_SAMSUNG

tristate "Samsung SoC serial support"

depends on ARM && PLAT_S3C

select SERIAL_CORE

Support for console on Samsung SoC serial port对应于控制台驱动

Samsung S3C2440/S3C2442 Serial port support对应于s3c2440.o

在/drivers/char/Makefile中可以看到

obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o

我们知道tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o已编入内核

自此,我们知道关于串口驱动,我们内核中被编译了s3c2440.o samsung.o serial_core.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o

我们对此进行分类,属于UART层的是s3c2440.o samsung.o;属于TTY层的是serial_core.o;属于线路规程的是tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o 。

好了,对于串口的地图我们已经分析好了,那我们就按照UART层,TTY层,线路规程一个个的逛逛吧。

三.UART层内核代码

我们先看看samsung.o的init代码吧,这里面完成了uart_driver的注册

static int __init s3c24xx_serial_modinit(void)

{

int ret;

ret = uart_register_driver(&s3c24xx_uart_drv); //注册uart_driver

if (ret < 0) {

printk(KERN_ERR "failed to register UART driver\n");

return -1;

}

return 0;

}

static struct uart_driver s3c24xx_uart_drv = {

.owner = THIS_MODULE,

.dev_name = "s3c2410_serial", //设备名

.nr = CONFIG_SERIAL_SAMSUNG_UARTS, //UART端口个数

.cons = S3C24XX_SERIAL_CONSOLE, //指向控制台结构

.driver_name = S3C24XX_SERIAL_NAME, //驱动的名字

.major = S3C24XX_SERIAL_MAJOR, //串口主设备号

.minor = S3C24XX_SERIAL_MINOR, //串口次设备号

};

我们关注下上面这个结构体中一个成员S3C24XX_SERIAL_CONSOLE

#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console

static struct console s3c24xx_serial_console = {

.name = S3C24XX_SERIAL_NAME,

.device = uart_console_device,

.flags = CON_PRINTBUFFER,

.index = -1,

.write = s3c24xx_serial_console_write,

.setup = s3c24xx_serial_console_setup

};

上面是控制台的结构体成员。

对于UART驱动,我们除了需要注册uart_driver外,还需要注册端口,我们看看s3c2440.o。

这个文件里面注册了一个平台设备,其中平台设备的探测函数最终调用了samsung.o中的s3c24xx_serial_probe函数。

int s3c24xx_serial_probe(struct platform_device *dev,

struct s3c24xx_uart_info *info)

{

struct s3c24xx_uart_port *ourport;

int ret;

dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top