在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. 分布式集群Session原理及实现共享

    1.什么是Session/Cookie? 用户使用网站的服务,基本上需要浏览器与Web服务器的多次交互.HTTP协议本身是无状态的,当用户的第一次访问请求结束后,后端服务器就无法知道下一次来访问的还是 ...

  2. Linux下捕捉信号

    关于 信号signal的知识铺垫 点这里 信号由三种处理方式: 忽略 执行该信号的默认处理动作 捕捉信号 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个自定义函数,这称为捕捉信号. 进程收 ...

  3. 回溯算法 DFS深度优先搜索 (递归与非递归实现)

    回溯法是一种选优搜索法(试探法),被称为通用的解题方法,这种方法适用于解一些组合数相当大的问题.通过剪枝(约束+限界)可以大幅减少解决问题的计算量(搜索量). 基本思想 将n元问题P的状态空间E表示成 ...

  4. 电脑 HOST 文件

    路径: C:\Windows\System32\drivers\etc\HOSTS

  5. javascript页面打印

    打印本身比较简单,但要考虑到具体的需求.比如 1. 多浏览器: if (isIE()) { //打印预览 WebBrowser1.execWB(7, 1); } else { window.print ...

  6. ssm框架搭建流程及原理分析

    这几天自己想搭建个ssm框架玩一下,有些东西长时间不玩都给忘了,所以自己把整个流程整理了一下,只要跟着步骤,就能顺利完成ssm框架的搭建. 一.搭建步骤: 1.整理jar包     2.对于一个web ...

  7. activity状态的保存和恢复

    activity状态的保存和恢复 一.简介 1.保存activity状态 * 保存activity状态,onSaveInstanceState这个方法会自动保存有ID的组件的状态 * 没有ID的组件或 ...

  8. mysql 分区优缺点

    分区不一定能够提高查询速度: 原因:分区是按字段分区,如果查询条件不是分区字段会很慢.

  9. Installing Forms Developer 10g and Reports 32-bit on 64-bit Windows versions(win7 or win10)

    E-Business Suite 12.1 and 12.2 require Forms Developer 10g and Reports Designer 10g.  Forms Develope ...

  10. 亲测安装nginx1.8.1 日期2016年3月16日

    1.安装nginx tar zxvf nginx-1.8.1.tar.gz cd nginx-1.8.1 ./configure make make install /usr/local/nginx/ ...