在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驱动分析的更多相关文章

  1. Linux UART驱动分析

    1. 介绍 8250是IBM PC及兼容机使用的一种串口芯片; 16550是一种带先进先出(FIFO)功能的8250系列串口芯片; 16550A则是16550的升级版本, 修复了FIFO相关BUG, ...

  2. [tty与uart]3.tty驱动分析

    转自:http://www.wowotech.net/linux_kenrel/183.html 目录: 1 首先分析设备驱动的注册 1.1 uart_register_driver分析 1.2 tt ...

  3. [uart]3.tty驱动分析

    转自:http://www.wowotech.net/linux_kenrel/183.html 目录: 1 首先分析设备驱动的注册 1.1 uart_register_driver分析 1.2 tt ...

  4. uart驱动框架分析(二)uart_add_one_port

    作者:lizuobin (百问网论坛答疑助手) 原文: https://blog.csdn.net/lizuobin2/article/details/51801183 (所用开发板:mini2440 ...

  5. tty初探 — uart驱动框架分析

    写在前面: 我们没有讲UART驱动,不过我们认为,只要系统学习了第2期,应该具备分析UART驱动的能力,小编做答疑几年以来,陆陆续续有不少人问到UART驱动怎么写,所以今天就分享一篇深度长文(1700 ...

  6. linux的串口驱动分析

    1.串口驱动中的数据结构 • UART驱动程序结构:struct uart_driver  驱动 • UART端口结构: struct uart_port  串口 • UART相关操作函数结构: st ...

  7. ARM-Linux S5PV210 UART驱动(4)----串口驱动初始化过程

    对于S5PV210 UART驱动来说,主要关心的就是drivers/serial下的samsung.c和s5pv210.c连个文件. 由drivers/serial/Kconfig: config S ...

  8. linux串口驱动分析

    linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...

  9. linux内核SPI总线驱动分析(一)(转)

    linux内核SPI总线驱动分析(一)(转) 下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) ...

随机推荐

  1. 配置阿里云maven中央库

    <mirrors> <mirror> <id>nexus-aliyun</id> <mirrorOf>*</mirrorOf> ...

  2. gitlab 卸载

    gitlab 卸载 清理命令 sudo gitlab-ctl uninstall sudo gitlab-ctl cleanse sudo gitlab-ctl remove-accounts 停止g ...

  3. Pandas基本功能

    到目前为止,我们了解了三种Pandas数据结构以及如何创建它们.接下来将主要关注数据帧(DataFrame)对象,因为它在实时数据处理中非常重要,并且还讨论其他数据结构. 系列基本功能 编号 属性或方 ...

  4. MySQL主从配置实现

    //////////////////////MySQL主从配置//////////////////////////// 首先,两边都要安装MySQL,启动两边的MySQL 接着,配置主从,要保证主从数 ...

  5. 使用TypeScript拓展你自己的VSCode

    转自:http://www.iplaysoft.com/brackets.html使用TypeScript拓展你自己的VSCode! 0x00 前言在前几天的美国纽约,微软举行了Connect(); ...

  6. 找出此产品描述中包含N个关键字的长度最短的子串

    阿里巴巴笔试题:给定一段产品的英文描述,包含M个英文字母,每个英文单词以空格分隔,无其他标点符号:再给定N个英文关键词,请说明思路并变成实现方法. String extractSummary(Stri ...

  7. python----标准库概要

    操作系统接口 os模块提供了不少与操作系统相关联的函数. >>> import os >>> os.getcwd() # 返回当前的工作目录 'C:\\Python ...

  8. DGA GAN——GAN在安全中的应用

    DGA的模型:https://github.com/Yuren-Zhong/DeepDGA CNN.LSTM.双向LSTM 论文可以看https://openreview.net/pdf?id=BJL ...

  9. iOS自动化探索(一)WebDriverAgent安装

    WebDriverAgent FaceBook推出的一款iOS移动测试框架, 支持真机和模拟器, 同时支持USB, 官方是这样介绍的: https://github.com/facebook/WebD ...

  10. BZOJ3528: [Zjoi2014]星系调查

    唉,看到这题直接想起自己的Day1,还是挺难受的,挺傻一题考试的时候怎么就没弄出来呢…… 这两天CP让我给他写个题解,弄了不是很久就把这个题给弄出来了,真不知道考试的时候在干嘛. 明天就出发去北京了, ...