一、UART 驱动程序概述

在嵌入式 Linux 系统中,串口被看成终端设备,终端设备(tty)的驱动程序分为三个部分:

tty_core

tty_disicipline

tty_driver

包括3个结构体:

uart_driver

uart_port

uart_ops( include/serial_core.h)

因此实现一个平台的 UART 驱动程序只需要实现这3个结构体即可。

二、uart_drvier 与 tty_driver 之间的关系

uart_driver 结构体:

uart_driver 结构体包含了串口设备名、串口驱动名、主次设备号、串口控制台(可选)等信息,还封装了 tty_driver(底层串口驱动,无需关心 tty_driver)。

struct uart_driver

{

struct module *owner; //拥有该uart_driver的模块,一般为THIS_MODULE

const char *driver_name; //串口驱动名,串口设备文件名以驱动名为基础

const char *dev_name; //串口设备名

int major; //主设备号

int minor; //次设备号

int nr; //该 uart_driver 支持的最大串口个数

struct console *cons; //其对应的console。若该uart_driver支持serial console,否则为NULL

...........................

struct uart_state *state;

struct tty_driver *tty_driver; //uart_driver 封装了 tty_driver,使底层uart驱动不用关心tty_driver。

};

一个 tty 驱动程序必须注册/注销 tty_driver;

一个 uart 驱动则变为注册/注销 uart_driver;

使用如下接口:

int uart_register_driver(struct uart_driver *drv);

void uart_unregister_driver(struct uart_drvier *drv);

int tty_register_driver(struct tty_driver *drv);

void tty_unregister_driver(struct tty_driver *drv);

实际上,uart_register_driver() 和 uart_unregister_drvier() 中分别包含了 tty_register_driver() 和 tty_unregister () 的操作,详情如下:

uart_port结构体:

uart_port 用于描述一个 UART 端口(直接对应于一个串口)的 I/O 端口或 I/O内存地址、FIFO大小、端口类型等信息。

struct uart_port

{

spinlock_t lock; //串口端口锁

unsigned int iobase; //IO 端口基地址

unsigned char __iomem *membase; //IO 内存基地址,经映射(如ioremap)后的IO内存虚拟基地址

unsigned int irq; //中断号

unsigend int uartlock; //串口时钟

unsigend int fifosize; //串口FIFO缓冲大小

unsigned char x_char; //xon/xoff 字符

unsigned char regshift; //寄存器位移

unsigned char iotype; //IO访问方式

unsigned char unused1;

#define UPIO_PORT (0) //IO端口

#deifne UPIO_HUB6 (1)

#define UPIO_MEM (2) //IO内存

#define UPIO_MEM32(3)

#define UPIO_AU (4) //Aulx00 type IO

#define UPIO_TSI (5) //Tsi108/109 type IO

#define UPIO_DWAPB (6) //DesignWare APB UART

#define UPIO_RM9000 (7) //RM9000 type IO

unsigned int read_status_mask; //关心的Rx error status

unsigned int ignore_status_mask; //忽略的Rx error status

struct uart_info *info; //重要,见下面

struct uart_icount icount; //计数器 uart_icount 为串口信息计数器,包含了发送字符计数、接收字符计数等。在串口的发送中断处理函数和接收处理函数中,我们需要管理这些计数。

struct console *cons; //console 结构体

#ifdef CONFIG_SERIAL_CORE_CONSOLE

unsigned long sysrq; //sysrq timeout

#endif

upf_t flags;

#define UPF_FOURPORT ((__forceupf_t)(1 << 1))

#define UPF_SAK ((__forceupf_t)(1 << 2))

#define UPF_SPD_MASK ((__forceupf_t)(0x1030))

#define UPF_SPD_HI ((__forceupf_t)(0x0010))

#define UPF_SPD_VHI ((__forceupf_t)(0x0020))

#define UPF_SPD_CUST ((__forceupf_t)(0x0030))

#define UPF_SPD_SHI ((__forceupf_t)(0x1000))

#define UPF_SPD_WARP ((__forceupf_t)(0x1010))

#define UPF_SKIP_TEST ((__forceupf_t)(1 << 6))

#define UPF_AUTO_IRQ ((__forceupf_t)(1 << 7))

#define UPF_HARDPPS_CD ((__forceupf_t)(1 << 11))

#define UPF_LOW_LATENCY ((__forceupf_t)(1 << 13))

#define UPF_BUGGY_UART ((__forceupf_t)(1 << 14))

#define UPF_MAGIC_MULTIPLIER((__force upf_t)(1 << 16))

#define UPF_CONS_FLOW ((__forceupf_t)(1 << 23))

#define UPF_SHARE_IRQ ((__forceupf_t)(1 << 24))

#define UPF_BOOT_AUTOCONF ((__forceupf_t)(1 << 28))

#define UPF_FIXED_PORT ((__forceupf_t)(1 << 29))

#define UPF_DEAD ((__forceupf_t)(1 << 30))

#define UPF_IOREMAP ((__forceupf_t)(1 << 31))

#define UPF_CHANGE_MASK((__forceupf_t)(0x17fff))

#define UPF_USR_MASK ((__forceupf_t)(UPF_SPD_MASK | UPF_LOW_LATENCY))

unsigned int mctrl; //当前的 moden 设置

unsigned int timeout; //character-based timeout

unsigned int type; //端口类型

const struct uart_ops *ops; //串口端口操作函数集

unsigned int custom_divisor;

unsigned int line; //端口索引

resource_size_t mapbase; //IO内存物理基地址,可用于ioremap

struct device *dev; //父设备

unsigned char hub6; //this should be in the 8250 driver

unsigned char suspended;

unsigend char unused[2];

void *private_data; //端口私有数据,一般为platform数据指针

};

串口核心层提供如下函数来添加一个端口:

int uart_add_one_port(struct uart_driver *drv, struct uart_port *port);

对上述函数的调用应该发生在 uart_register_driver() 之后, uart_add_one_port() 的一个最重要的作用是封装了 tty_register_device()。

uart_add_one_port() 的“反函数”是 uart_remove_one_port(),其中会调用 tty_unregister_device(), 原型为:

int uart_remove_one_port(struct driver *drv, struct uart_port *port);

uart_info结构体:

uart_info 有两个成员在底层串口驱动会用到: xmit 和 tty。用户空间程序通过串口发送数据时,上层驱动将用户数据保存在xmit;而串口发送中断处理函数就是通过xmit获取到用户数据并将它们发送出去。串口接收中断处理函数需要通过tty将接收到的数据传递给行规则层。

在使用串口核心层这个通用串口tty驱动层的接口后,一个串口驱动要完成的主要工作将包括:

定义uart_drvier、uart_ops、uart_port等结构体的实例,并在适当的地方根据具体硬件和驱动的情况初始化它们。(当然具体设备xxx的驱动可以将这些结构套在新定义的 xxx_uart_driver、xxx_uart_ops、xxx_uart_port之内)。

在模块初始化时调用uart_register_driver() 和 uart_add_one_port()以注册UART驱动并添加端口,在模块卸载时调用uart_unregister_driver 和 uart_remove_one_port() 以注销UART驱动并移除端口。

根据具体硬件的datasheet实现uart_ops中的成员函数,这些函数的实现成为UART驱动的主体工作。

串口驱动之tty

概念介绍:

在Linux中,终端是一类字符设备,他包括多种类型,通常使用tty来简称各种中断设备串口终端(/dev/ttyS*):串口终端是使用串口连接的终端设备,Linux中将每一个串口设备都看作一个字符设备,这些串行端口对应的设备名称是/dev/ttySAC0 和 /dev/ttySAC1。

控制台终端(/dev/console):

在Linux中,计算中的输出设备通常被称为控制台终端(console)。这里特指printk()信息输出的。注意:/dev/console 是一个虚拟的设备,它需要映射到真正的tty上。比如通过内核启动参数“console=ttySAC0”就是把console映射到串口0,经常被内核所使用。

注意:这里的终端是一个虚拟设备,虚拟设备必须和实际的设备联系起来,console=ttySAC0系统启动的时候就关联起来了。

虚拟终端(/dev/tty*):

当用户登录的使用使用的是虚拟终端,使用快捷键组合:ctrl+alt+[F1-F6]组合键就可以切换到tty1,tty2,tty3等上面去。tty1-tty6等成为虚拟终端,而tty0是当前使用的终端的一个别名。主要是提供给应用程序使用。

tty架构

tty核心:

tty核心是对整个tty设备的抽象,并提供单一的接口。

tty线路规划:

tty线路规程是对数据的传输的格式化,比如需要实现某种协议,就需要将协议的实现代码放在该位置。

tty驱动:

是面向tty设备的硬件驱动

注意:Linux中的获取回溯信息使用函数dump_stack()用来显示各种函数的调用信息。

串口驱动程序的结构

分析:串口驱动程序需要提供给用户读数据的功能,写数据,打开串口和关闭串口的功能。打开之前需要对肯定需要对串口进行初始化的工作。

重要数据结构:

struct uart_driver :一个串口对应一个串口驱动,用于描述串口结构

struct uart_port:    有几个串口就对应几个port

struct uart_ops:  UART相关操作函数结构体,对应相关串口所支持的操作函数集

struct uart_state:UART状态结构

struct uart_info: UART信息结构

串口初始化:

定义并描述串口:struct uart_driver;

注册串口驱动程序:uart_register_driver;

取出相应的串口,并初始化该取出的串口。

串口驱动之打开驱动:

系统调用过程:用户使用open()函数打开设备文件

注意:

打开设备文件肯定有对应的设备驱动文件打开函数:file_operations;

在使用uart_register_driver()注册串口驱动的时候,该函数里面会调用函数tty_register_driver(),该函数会调用 cdev_init()函数和cdev_add()。

从这里可以看出tty设备是属于字符设备。

linux配置串口驱动程序,[Linux 驱动] -- Linux 驱动之串口(UART)相关推荐

  1. linux配置usb主从_基于Linux的USB主/从设备之间的三种通信方式

    随着简单易用的USB接口日益流行,在嵌入式系统中添加对USB接口的支持已成为大势所趋.本文通过介绍Linux中支持USB的各种模块和库,分析了在Linux上利用USB实现高速串口和以太网连接等通信方式 ...

  2. linux配置usb主从_基于Linux的USB 主/从设备之间通讯的三种方式

    转载:http://archive.eet-china.com/www.eet-china.com/ART_8800323770_617693_TA_eda530e7.HTM 随着简单易用的USB接口 ...

  3. linux配置iscsi无账号密码,linux配置ISCSI服务器的方法

    一.在linux下安装启动iscsi target 1.安装启动iscsi服务 [root@wjb10000 ~]# yum -y install targetcli.noarch 2.建立一个目录设 ...

  4. OEL / RedHat linux 配置无线网络连接(含驱动安装)

    本机环境:Thinkpad E440,Oracle Linux Server release 6.7(kernel 3.8.13-68.3.4.el6uek.x86_64) 本机无线网卡为RTL872 ...

  5. Linux字符设备驱动程序开发(4)-LED驱动程序设计

    这里编写一个LED内核驱动代码.流程大概如下: 1.实现一个内核模块. 2.添加字符设备驱动框架. 3.在字符设备驱动中实现open和ioctl函数. 4.编写应用程序. led.c #include ...

  6. linux中扫描仪驱动程序,VueScan For Linux通用扫描仪驱动下载_VueScan For Linux通用扫描仪驱动官方下载-太平洋下载中心...

    VueScan For Linux通用扫描仪驱动是一款提供 Linux 使用的图片扫描工具,它具有各种高级硬件能力使用非常广泛的的扫描仪软件,支持EPSon.HP.Nikon 和Canon 品牌的扫描 ...

  7. linux 移动硬盘 设备驱动程序,移动硬盘安装linux:如何在移动驱动器上安装Linux

    相关资源下载获得外置驱动器是一种为较老设备注入生机的极好方法,或者允许您在不能(或不想)改变内置硬盘驱动器的机器上运行Linux.假设您想在双引导系统中使用Linux,但计算机硬盘驱动器中没有任何可用 ...

  8. linux配置定时删除日志文件,Linux使用shell脚本定时删除历史日志文件

    Linux使用shell脚本定时删除历史日志文件,文件,小时,时间,目录,脚本 Linux使用shell脚本定时删除历史日志文件 易采站长站,站长之家为您整理了Linux使用shell脚本定时删除历史 ...

  9. Linux配置nginx打开报404,Linux下Nginx配置404页面的方法

    Linux下Nginx配置404页面很多设置后返回状态码是200,而不是404状态码,所以那样的404页面设置是不正确的,今天分享下Linux下Nginx配置404页面设置方法. 1.创建自己的404 ...

  10. Linux配置多网口IP地址,linux配置ip 多个网口

    SCC(超级计算集群)简介 SCC概述 超级计算集群(Super Computing Cluster,SCC)使用高速RDMA网络互联的CPU以及GPU等异构加速设备,面向高性能计算.人工智能/机器学 ...

最新文章

  1. AjaxPro组件的应用(实现Ajax)
  2. 【Flutter】侧拉导航栏实现 ( Drawer 组件 | PageView 组件 )
  3. 二分法(三种基本模版)
  4. fastjson list转json字符串_程序员:JSON、JSONObject 与 JSONArray 简单讲解
  5. 新闻发布系统类图_如何熟悉一个系统?(内含知识大图)
  6. ListView执行notifyDatasetChanged无数据显示,getView未执行
  7. ES6/05/正则表达式简介,正则表达式如何使用,正则表达式中的特殊字符(边界符,量词符),预定义类,正则表达式中的替换
  8. Python 爬虫6——Scrapy的安装和使用
  9. opencv 处理黑夜_基于 opencv图像去噪
  10. 多行文字或者单行文字的垂直居中解决方案
  11. [转帖]从 2G 到 5G,手机上网话语权的三次改变
  12. python打包exe反编译源码_python的exe反编译
  13. 桌面超简单小代码 bat形式
  14. 完全小白级DataX安装配置过程详解
  15. 365天深度学习训练营-第P3周:天气识别
  16. Excel 按照某一列不同内容插入分页符号
  17. amCharts 5.2.2 Crack
  18. 对话周鸿袆:从程序员创业谈起
  19. DistilBERT, a distilled version of BERT: smaller, faster, cheaper and lighter学习
  20. 如何给Vue v-for循环渲染出的元素(导航栏) 批量添加点击事件 及 点击后添加css类样式 及 点击后路由跳转切换

热门文章

  1. 08.存储Cinder→5.场景学习→02.Create Volume→1.cinder-api处理过程
  2. WinRAR5.60 64位 官方无广告正式版注册破解
  3. 计算机运行命令定时关机,电脑定时关机命令 使用系统命令定时关机 - 云骑士一键重装系统...
  4. KETTLE、spoon使用
  5. ovito在linux下安装教程,linux下超详细教程安装phonopy
  6. 机器学习中的训练集、验证集、测试集;交叉验证方法
  7. 贝叶斯网络是神经网络吗,贝叶斯网络和神经网络
  8. 计算机图形学 全局光照及方法,实时全局光照渲染研究
  9. 杨辉三角 java版
  10. 以太网交换机芯片概述