在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. jenkins添加GIT repository报错

    添加了ssh互信,但一直提示如下错误. Failed to connect to repository : Command "git ls-remote -h git@git.xxx.cn: ...

  2. MySQL数据库表分区功能详解

    1.什么是表分区? mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件,一个是frm存放表 ...

  3. zabbix api

    #!/usr/bin/env python # -*-coding:utf-8 -*- import requests import json class AutoZabbix: def __init ...

  4. hadoop中mapreduce的默认设置

    MR任务默认配置: job.setMapperClass() Mapper Mapper将输入的<key,value>对原封不动地作为中间结果输出 job.setMapperOutputK ...

  5. React Native集成Redux框架讲解与应用

    学过React Native的都知道,RN的UI是根据相应组件的state进行render的,而页面又是由大大小小的组件构成,导致每个组件都必须维护自身的一套状态,因此当页面复杂化的时候,管理stat ...

  6. COS-4进程及进程管理

    操作系统是用户和计算机的接口,同时也是计算机硬件和其他软件的接口.操作系统的功能包括管理计算机系统的硬件.软件及数据资源,控制程序运行,改善人机界面,为其它应用软件提供支持,让计算机系统所有资源最大限 ...

  7. session的活化与钝化 (转)

    session的活化与钝化就是当用户访问时网站异常,不能丢掉session,所有也必须采用文件存储:和之前那个统计网站访问量一样的原理. class Person implements必须实现这两个接 ...

  8. struts2——上传文件

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  9. strcpy的实现

    // // Strcpy.c // libin // // Created by 李宾 on 15/8/20. // Copyright (c) 2015年 李宾. All rights reserv ...

  10. Spring中Bean的生命周期是怎样的

    1.Spring对Bean进行实例化(相当于程序中的new Xx()) 2.Spring将值和Bean的引用注入进Bean对应的属性中 3.如果Bean实现了BeanNameAware接口,Sprin ...