UART驱动分析
在linux用户层上要操作底层串口需要对/dev/ttySxxx操作,这里的ttySx指实际的终端串口。
以下以全志A64为实例,分析UART驱动以及浅谈TTY架构。
linux-3.10/drivers/tty/serial/sunxi-uart.c:
static const struct of_device_id sunxi_uart_match[] = {
{ .compatible = "allwinner,sun8i-uart", },
{ .compatible = "allwinner,sun50i-uart", },
{},
};
MODULE_DEVICE_TABLE(of, sunxi_uart_match); //设备树查找device并注册
static struct uart_driver sw_uart_driver = {
.owner = THIS_MODULE,
.driver_name = SUNXI_UART_DEV_NAME, //"uart"
.dev_name = "ttyS",
.nr = SUNXI_UART_NUM, //
.cons = SW_CONSOLE,
};
static int __init sunxi_uart_init(void)
{
int ret;
ret = uart_register_driver(&sw_uart_driver); //注册tty_driver
if (unlikely(ret)) {
SERIAL_MSG("driver initializied\n");
return ret;
}
return platform_driver_register(&sw_uport_platform_driver); //硬件平台相关相关进入probe
}
先看看注册tty_driver里面做了什么操作,删减部分代码linux-3.10/drivers/tty/serial/serial_core.c:
static const struct tty_operations uart_ops = {
.open = uart_open,
.close = uart_close,
.write = uart_write,
.put_char = uart_put_char,
.flush_chars = uart_flush_chars,
.write_room = uart_write_room,
.chars_in_buffer = uart_chars_in_buffer,
.flush_buffer = uart_flush_buffer,
.ioctl = uart_ioctl,
.throttle = uart_throttle,
.unthrottle = uart_unthrottle,
.send_xchar = uart_send_xchar,
.set_termios = uart_set_termios,
.set_ldisc = uart_set_ldisc,
.stop = uart_stop,
.start = uart_start,
.hangup = uart_hangup,
.break_ctl = uart_break_ctl,
.wait_until_sent = uart_wait_until_sent,
#ifdef CONFIG_PROC_FS
.proc_fops = &uart_proc_fops,
#endif
.tiocmget = uart_tiocmget,
.tiocmset = uart_tiocmset,
.get_icount = uart_get_icount,
#ifdef CONFIG_CONSOLE_POLL
.poll_init = uart_poll_init,
.poll_get_char = uart_poll_get_char,
.poll_put_char = uart_poll_put_char,
#endif
};
int uart_register_driver(struct uart_driver *drv)
{
struct tty_driver *normal;
int i, retval;
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
normal = alloc_tty_driver(drv->nr);
drv->tty_driver = normal;
normal->driver_name = drv->driver_name;
normal->name = drv->dev_name;
normal->major = drv->major;
normal->minor_start = drv->minor;
normal->type = TTY_DRIVER_TYPE_SERIAL;
normal->subtype = SERIAL_TYPE_NORMAL;
normal->init_termios = tty_std_termios;
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = ;
normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
//TTY_DRIVER_DYNAMIC_DEV不立刻注册设备,只初始化
normal->driver_state = drv;
tty_set_operations(normal, &uart_ops); //normal->ops = uart_ops
/*
* Initialise the UART state(s).
*/
for (i = ; i < drv->nr; i++) {
struct uart_state *state = drv->state + i;
struct tty_port *port = &state->port;
//初始化tty_port的等待队列open_wait,close_wait,delta_msr_wait和buffer工作队列flush_to_ldisc
tty_port_init(port);
port->ops = &uart_port_ops; //tty_port->ops = uart_port_ops
port->close_delay = HZ / ; /* .5 seconds */
port->closing_wait = * HZ;/* 30 seconds */
}
retval = tty_register_driver(normal); //初始化tty字符设备但不注册
return retval;
以上完成tty的初始化,从以上代码可以知道tty_driver->ops = uart_ops,uart_ops是串口底层操作。
回到硬件平台的probe函数,部分删减代码linux-3.10/drivers/tty/serial/sunxi-uart.c:
static int sw_uart_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct uart_port *port;
struct sw_uart_port *sw_uport;
struct sw_uart_pdata *pdata;
struct resource *res;
char uart_para[] = {};
int ret = -; pdev->id = of_alias_get_id(np, "serial"); //通过别名获取UART的ID port = &sw_uart_ports[pdev->id].port;
port->dev = &pdev->dev;
pdata = &sw_uport_pdata[pdev->id];
sw_uport = UART_TO_SPORT(port);
sw_uport->pdata = pdata;
sw_uport->id = pdev->id;
sw_uport->ier = ;
sw_uport->lcr = ;
sw_uport->mcr = ;
sw_uport->fcr = ;
sw_uport->dll = ;
sw_uport->dlh = ;
snprintf(sw_uport->name, , SUNXI_UART_DEV_NAME"%d", pdev->id);
pdev->dev.init_name = sw_uport->name;
pdev->dev.platform_data = sw_uport->pdata; sw_uport->mclk = of_clk_get(np, ); port->uartclk = clk_get_rate(sw_uport->mclk); res = platform_get_resource(pdev, IORESOURCE_MEM, ); port->mapbase = res->start; port->irq = platform_get_irq(pdev, ); snprintf(uart_para, sizeof(uart_para), "uart%d_port", pdev->id);
ret = of_property_read_u32(np, uart_para, &port->line); //设备树uartx_port定义第几路 snprintf(uart_para, sizeof(uart_para), "uart%d_type", pdev->id);
ret = of_property_read_u32(np, uart_para, &pdata->io_num); //设备树uartx_type是2线还是4线 pdata->used = ;
port->iotype = UPIO_MEM;
port->type = PORT_SUNXI;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &sw_uart_ops;
port->fifosize = ;
platform_set_drvdata(pdev, port); sunxi_uart_sysfs(pdev); return uart_add_one_port(&sw_uart_driver, port); //把串口底层代码向上映射
}
以上代码基本是从设备树获取硬件相关的初始化代码,最后的uart_add_one_port把driver和uart_port参数作为形参向上映射。
删减部分代码linux-3.10/drivers/tty/serial/serial_core.c:
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
{
struct uart_state *state;
struct tty_port *port;
int ret = ;
struct device *tty_dev; state = drv->state + uport->line;
port = &state->port; state->uart_port = uport;
state->pm_state = UART_PM_STATE_UNDEFINED; uport->cons = drv->cons;
uport->state = state; //通过port->ops->config_port =sw_uart_config_port通过设备树申请复用io口资源
uart_configure_port(drv, state, uport); /*
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this ports parameters.
*/
tty_dev = tty_port_register_device_attr(port, drv->tty_driver, //注册ttySx字符设备
uport->line, uport->dev, port, tty_dev_attr_groups); device_set_wakeup_capable(tty_dev, );
/*
* Ensure UPF_DEAD is not set.
*/
uport->flags &= ~UPF_DEAD;
return ret;
}
现在可以在用户层看到/dev多了ttySx字符设备,可以像普通的字符设备进行读写操作了。但事实并不是tty->uart这样,在tty_driver->ops里面并不是直接调用uart_port->ops,其中又用映射线路规程(Line discipline)。
在kernel初始化终端的时候会调用:
void tty_ldisc_begin(void)
{
/* Setup the default TTY line discipline. */
(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); //串口都是tty_ldisc_N_TTY
}
串口都会用默认线路N_TTY进行规程。
对/dev/ttySxxx字符设备操作的时候,通过N_TTY---->TTY_DRIVER---->UART_PORT---->硬件平台相关。
对N_TTY分析后续补上,未完!
UART驱动分析的更多相关文章
- Linux UART驱动分析
1. 介绍 8250是IBM PC及兼容机使用的一种串口芯片; 16550是一种带先进先出(FIFO)功能的8250系列串口芯片; 16550A则是16550的升级版本, 修复了FIFO相关BUG, ...
- [tty与uart]3.tty驱动分析
转自:http://www.wowotech.net/linux_kenrel/183.html 目录: 1 首先分析设备驱动的注册 1.1 uart_register_driver分析 1.2 tt ...
- [uart]3.tty驱动分析
转自:http://www.wowotech.net/linux_kenrel/183.html 目录: 1 首先分析设备驱动的注册 1.1 uart_register_driver分析 1.2 tt ...
- uart驱动框架分析(二)uart_add_one_port
作者:lizuobin (百问网论坛答疑助手) 原文: https://blog.csdn.net/lizuobin2/article/details/51801183 (所用开发板:mini2440 ...
- tty初探 — uart驱动框架分析
写在前面: 我们没有讲UART驱动,不过我们认为,只要系统学习了第2期,应该具备分析UART驱动的能力,小编做答疑几年以来,陆陆续续有不少人问到UART驱动怎么写,所以今天就分享一篇深度长文(1700 ...
- linux的串口驱动分析
1.串口驱动中的数据结构 • UART驱动程序结构:struct uart_driver 驱动 • UART端口结构: struct uart_port 串口 • UART相关操作函数结构: st ...
- ARM-Linux S5PV210 UART驱动(4)----串口驱动初始化过程
对于S5PV210 UART驱动来说,主要关心的就是drivers/serial下的samsung.c和s5pv210.c连个文件. 由drivers/serial/Kconfig: config S ...
- linux串口驱动分析
linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...
- linux内核SPI总线驱动分析(一)(转)
linux内核SPI总线驱动分析(一)(转) 下面有两个大的模块: 一个是SPI总线驱动的分析 (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) ...
随机推荐
- InterruptedException异常
本文总结自:https://blog.csdn.net/asdfsadfasdfsa/article/details/78808131 什么样的方法会抛出InterruptedException异常? ...
- setState详解
我们都知道,React通过this.state来访问state,通过this.setState()方法来更新state.当this.setState()方法被调用的时候,React会重新调用rende ...
- Jave基础之选择排序
选择排序(Selection sort) 基本介绍 选择排序: 每一次从未排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余未排序的元素中选出最小(或最大的)放在已排序序 ...
- 定制kali linux
Kali Linux Ps: Kali发布撸~ 写了个如此装13的标题.这是一个Guide… 都是些基本操作撸.定制为王实推 ArchLinux. 各位看官继续………………………………………号外.L ...
- maven 项目转 gradle
打开maven 项目的根目录,CMD 执行命令:gradle init --type pom maven项目就变成了gradle项目
- C++ dll的隐式与显式调用
应用程序使用DLL可以采用两种方式:一种是隐式链接,另一种是显式链接.在使用DLL之前首先要知道DLL中函数的结构信息.Visual C++6.0(或者更先进的版本)在VC\bin目录下提供了一个名为 ...
- Spring -- 如何为applicationContext.xml 添加 util 的 *.xsd文件
- Linux 增加对外开放的端口
查看端口是否对外开放 /etc/init.d/iptables status # /etc/init.d/iptables status 表格:filter Chain INPUT (policy A ...
- css 中的background:transparent到底是什么意思有什么作用
有时我在看css时,看到有的css属性定义为background:transparent.意思就是背景透明.实际上background默认的颜色就是透明的属性.所以写和不写都是一样的 有段时间没写文章 ...
- VMware 虚拟镜像转 Hyper-V(Win10/2016)
VMware 虚拟镜像转 Hyper-V(Win10/2016) 参考:http://www.askme4tech.com/how-convert-vmware-virtual-machine-hyp ...