ARM-Linux S5PV210 UART驱动(2)---- 终端设备驱动
在Linux中,UART串口驱动完全遵循tty驱动的框架结构,但是进行了底层操作的再次封装,所以先介绍tty终端设备驱动。
一、终端设备
1.串行端口终端(/dev/ttySACn)
2.伪终端(/dev/pty/)
3.控制台终端(/dev/ttyn,/dev/console)
二、驱动结构
1.tty分层结构如下图所示:

包含tty核心、tty线路规程、tty驱动,其中tty规程的工作是以特殊的方式格式化从一个用户或者硬件接收到的数据,常采用一个协议转换的形式,如PPP、Bluetooth。
2.tty主要源文件关系及数据流向如下图:

特定的tty设备驱动的主体工作是填充tty_driver结构体中的成员,实现tty_operations结构体中的一系列成员函数
struct tty_driver {
int magic; /* magic number for this structure */
struct kref kref; /* Reference management */
struct cdev cdev;
struct module *owner;
const char *driver_name;//驱动名字
const char *name;//驱动设备结点名字
int name_base; /* offset of printed name */
int major; /* major device number */
int minor_start; /* start of minor device number */
int minor_num; /* number of *possible* devices */
int num; /* number of devices allocated */
short type; /* type of tty driver */
short subtype; /* subtype of tty driver */
struct ktermios init_termios; /* Initial termios */
int flags; /* tty driver flags */
struct proc_dir_entry *proc_entry; /* /proc fs entry */
struct tty_driver *other; /* only used for the PTY driver */
/*
* Pointer to the tty data structures
*/
struct tty_struct **ttys;
struct ktermios **termios;
struct ktermios **termios_locked;
void *driver_state;
/*
* Driver methods
*/
const struct tty_operations *ops;
struct list_head tty_drivers;
};
tty_operations中的成员函数需在特定设备tty驱动模块初始化函数中被赋值;
tty_struct结构体被tty核心用来保存当前tty端口的状态。
struct tty_operations {
struct tty_struct * (*lookup)(struct tty_driver *driver,
struct inode *inode, int idx);
int (*install)(struct tty_driver *driver, struct tty_struct *tty);
void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
int (*open)(struct tty_struct * tty, struct file * filp);
void (*close)(struct tty_struct * tty, struct file * filp);
void (*shutdown)(struct tty_struct *tty);
void (*cleanup)(struct tty_struct *tty);
int (*write)(struct tty_struct * tty,
const unsigned char *buf, int count);
int (*put_char)(struct tty_struct *tty, unsigned char ch);
void (*flush_chars)(struct tty_struct *tty);
int (*write_room)(struct tty_struct *tty);
int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
void (*stop)(struct tty_struct *tty);
void (*start)(struct tty_struct *tty);
void (*hangup)(struct tty_struct *tty);
int (*break_ctl)(struct tty_struct *tty, int state);
void (*flush_buffer)(struct tty_struct *tty);
void (*set_ldisc)(struct tty_struct *tty);
void (*wait_until_sent)(struct tty_struct *tty, int timeout);
void (*send_xchar)(struct tty_struct *tty, char ch);
int (*tiocmget)(struct tty_struct *tty, struct file *file);
int (*tiocmset)(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
int (*resize)(struct tty_struct *tty, struct winsize *ws);
int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
#ifdef CONFIG_CONSOLE_POLL
int (*poll_init)(struct tty_driver *driver, int line, char *options);
int (*poll_get_char)(struct tty_driver *driver, int line);
void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
#endif
const struct file_operations *proc_fops;
};
struct tty_operations
struct tty_struct {
int magic;
struct kref kref;
struct tty_driver *driver;
const struct tty_operations *ops;
int index;
/* Protects ldisc changes: Lock tty not pty */
struct mutex ldisc_mutex;
struct tty_ldisc *ldisc;
struct mutex termios_mutex;
spinlock_t ctrl_lock;
/* Termios values are protected by the termios mutex */
struct ktermios *termios, *termios_locked;
struct termiox *termiox; /* May be NULL for unsupported */
char name[];
struct pid *pgrp; /* Protected by ctrl lock */
struct pid *session;
unsigned long flags;
int count;
struct winsize winsize; /* termios mutex */
unsigned char stopped:, hw_stopped:, flow_stopped:, packet:;
unsigned char low_latency:, warned:;
unsigned char ctrl_status; /* ctrl_lock */
unsigned int receive_room; /* Bytes free for queue */
struct tty_struct *link;
struct fasync_struct *fasync;
struct tty_bufhead buf; /* Locked internally */
int alt_speed; /* For magic substitution of 38400 bps */
wait_queue_head_t write_wait;
wait_queue_head_t read_wait;
struct work_struct hangup_work;
void *disc_data;
void *driver_data;
struct list_head tty_files;
#define N_TTY_BUF_SIZE 4096
/*
* The following is data for the N_TTY line discipline. For
* historical reasons, this is included in the tty structure.
* Mostly locked by the BKL.
*/
unsigned int column;
unsigned char lnext:, erasing:, raw:, real_raw:, icanon:;
unsigned char closing:;
unsigned char echo_overrun:;
unsigned short minimum_to_wake;
unsigned long overrun_time;
int num_overrun;
unsigned long process_char_map[/(*sizeof(unsigned long))];
char *read_buf;
int read_head;
int read_tail;
int read_cnt;
unsigned long read_flags[N_TTY_BUF_SIZE/(*sizeof(unsigned long))];
unsigned char *echo_buf;
unsigned int echo_pos;
unsigned int echo_cnt;
int canon_data;
unsigned long canon_head;
unsigned int canon_column;
struct mutex atomic_read_lock;
struct mutex atomic_write_lock;
struct mutex output_lock;
struct mutex echo_lock;
unsigned char *write_buf;
int write_cnt;
spinlock_t read_lock;
/* If the tty has a pending do_SAK, queue it here - akpm */
struct work_struct SAK_work;
struct tty_port *port;
};
struct tty_struct
tty_io.c:
【1】定义了tty 设备通用的file_operations结构体:
static const struct file_operations tty_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
.unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
.fasync = tty_fasync,
};
【2】实现了接口函数alloc_tty_driver()用于分配tty驱动:
/*tty driver 的所有操作都包含在 tty_driver 中。内核即供了一个名叫 alloc_tty_driver()
来分配这个 tty_driver。当然我们也可以在自己的驱动中将它定义成一个静态的结构。对
tty_driver 进行一些必要的初始化之后,调用 tty_register_driver()将其注册. */
struct tty_driver *alloc_tty_driver(int lines)
{
struct tty_driver *driver; driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
if (driver) {
kref_init(&driver->kref);
driver->magic = TTY_DRIVER_MAGIC;
driver->num = lines;
/* later we'll move allocation of tables here */
}
return driver;
}
【3】实现了接口函数tty_set_operations()用于设置tty驱动操作:
/*将tty_operations结构体中的函数指针拷贝给tty_driver对应的函数指针*/
void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op)
{
driver->ops = op;
};
【4】实现了接口函数tty_register_driver()用于注册tty设备:
/*
* Called by a tty driver to register itself.
* 注册 tty 驱动成功时返回 0;参数为由 alloc_tty_driver()分配的 tty_driver 结构体指针。
*这个函数操作比较简单。就是为 tty_driver 创建字符设备。然后将字符设备的操作集指定
*为 tty_fops.并且将 tty_driver 挂载到 tty_drivers 链表中。以设备号为关键字找到对应
*的 driver.
*/
int tty_register_driver(struct tty_driver *driver)
{
int error;
int i;
dev_t dev;
void **p = NULL; /*TTY_DRIVER_DEVPTS_MEM:使用 devpts 进行动态内存映射*/
if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
p = kzalloc(driver->num * * sizeof(void *), GFP_KERNEL);
if (!p)
return -ENOMEM;
} if (!driver->major) {/*如果没有指定 driver->major,动态申请字符设备号 */
error = alloc_chrdev_region(&dev, driver->minor_start,
driver->num, driver->name);
if (!error) {
driver->major = MAJOR(dev);
driver->minor_start = MINOR(dev);
}
} else {/*否则根据主设备号申请字符设备号*/
dev = MKDEV(driver->major, driver->minor_start);
error = register_chrdev_region(dev, driver->num, driver->name);
}
if (error < ) {
kfree(p);/*如果失败则释放申请的内存空间*/
return error;
} if (p) {/*设置tty数据结构指针*/
driver->ttys = (struct tty_struct **)p;/*tty_struct结构体被tty核心用来保存当前端口的状态*/
driver->termios = (struct ktermios **)(p + driver->num);/*ktermios保存当前的线路设置*/
} else {
driver->ttys = NULL;
driver->termios = NULL;
} //注册字符设备
cdev_init(&driver->cdev, &tty_fops);
driver->cdev.owner = driver->owner;
error = cdev_add(&driver->cdev, dev, driver->num);
if (error) {
unregister_chrdev_region(dev, driver->num);
driver->ttys = NULL;
driver->termios = NULL;
kfree(p);
return error;
} mutex_lock(&tty_mutex);
list_add(&driver->tty_drivers, &tty_drivers);/*将 tty_driver 挂载到 tty_drivers 链表中*/
mutex_unlock(&tty_mutex); /*如果没有指定 TTY_DRIVER_DYNAMIC_DEV.即动态设备管理 */
if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
for (i = ; i < driver->num; i++)
tty_register_device(driver, i, NULL);/*注册tty设备*/
} /*
* This function is called by tty_register_driver() to handle
* registering the driver's /proc handler into /proc/tty/driver/<foo>
*/
proc_tty_register_driver(driver);
driver->flags |= TTY_DRIVER_INSTALLED;
return ;
}
ARM-Linux S5PV210 UART驱动(2)---- 终端设备驱动的更多相关文章
- 乾坤合一~Linux设备驱动之终端设备驱动
多想拥你在我的怀里 却无法超越那距离 美好回忆渐渐地远去 盼望今生出现奇迹 无尽的想念 荒了容颜 无助的爱恋 从未改变 这是今天的旋律,,,,今生今世,遥不可及~ 1 终端设备 终端是一种字符型设备, ...
- ARM-Linux S5PV210 UART驱动(4)----串口驱动初始化过程
对于S5PV210 UART驱动来说,主要关心的就是drivers/serial下的samsung.c和s5pv210.c连个文件. 由drivers/serial/Kconfig: config S ...
- ARM-Linux S5PV210 UART驱动(转)
ARM-Linux S5PV210 UART驱动(3)----串口核心层.关键结构体.接口关系 尽管一个特定的UART设备驱动完全可以按照tty驱动的设计方法来设计,即定义tty_driver并实现t ...
- arm linux利用alsa驱动并使用usb音频设备
一.背景: arm linux的内核版本是3.13.0 二.准备工作 添加alsa驱动到内核中,也就是在编译内核的时候加入以下选项: 接下来就重新编译内核即可 三.交叉编译alsa-lib和alsa- ...
- ARM Linux驱动篇 学习温度传感器ds18b20的驱动编写过程
ARM Linux驱动篇 学习温度传感器ds18b20的驱动编写过程 原文地址:http://www.cnblogs.com/NickQ/p/9026545.html 一.开发板与ds18b20的入门 ...
- [转]Linux芯片级移植与底层驱动(基于3.7.4内核)
1. SoC Linux底层驱动的组成和现状 为了让Linux在一个全新的ARM SoC上运行,需要提供大量的底层支撑,如定时器节拍.中断控制器.SMP启动.CPU hotplug以及底层的G ...
- 让天堂的归天堂,让尘土的归尘土——谈Linux的总线、设备、驱动模型
本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 公元1951年5月15日的国会听证上, ...
- Linux下smi/mdio总线驱动
Linux下smi/mdio总线驱动 韩大卫@吉林师范大学 MII(媒体独立接口), 是IEEE802.3定义的以太网行业标准接口, smi是mii中的标准管理接口, 有两跟管脚, mdio 和mdc ...
- 【Linux高级驱动】rtc驱动开发
[1.分层思想] 1.1 rtc-dev.c //设备接口层,功能:给用户提供接口 subsys_initcall(rtc_init); , RTC_DEV_MAX, "rtc&qu ...
随机推荐
- Android(java)学习笔记80:UDP协议发送数据
UDP协议发送数据:我们总是先运行接收端,再运行发送端发送端: 1 package cn.itcast_02; import java.io.IOException; import java.net. ...
- ZOJ 3122 Sudoku
Sudoku Time Limit:10000MS Memory Limit:32768KB 64bit IO Format:%lld & %llu Submit Status ...
- CF Exam (数学)
Exam time limit per test 1 second memory limit per test 256 megabytes input standard input output s ...
- 关于Hadoop之父Doug Cutting
生活中,可能所有人都间接用过他的作品,他是Lucene.Nutch .Hadoop等项目的发起人.是他,把高深莫测的搜索技术形成产品,贡献给普罗大众:还是他,打造了目前在云计算和大数据领域里如日中天的 ...
- discuze回放提示“抱歉,您的请求来路不正确或表单验证串不符,无法提交”
不知从哪里看到文章,但是实用: 背景:discuze就单纯的录制一个注册脚本,日志中没有报错,在报告中就提示"抱歉,您的请求来路不正确或表单验证串不符,无法提交"",以下 ...
- 模板引擎逻辑语句处理之对单层for循环的处理
先上代码 private function moldforExt(){//模板单层For循环处理 $SQL=$this->sql_obj; $URL=$this->url_obj; req ...
- Ajax具体使用
Ajax在注册页面经常使用,当注册用户是用户名必须唯一时,要使用ajax获取表单中你输入的内容, 然后将这个数据利用XMLHttpRequest对象请求一个php文件,这个php文件接收到信息,查询数 ...
- Linux 命令 - traceroute: 数据报传输路径追踪
traceroute 工具用于跟踪数据报的传输路径:当数据报从一台计算机传向另一台计算机时,会经过多重的网关,traceroute 命令能够找到数据报传输路径上的所有路由器.通过 traceroute ...
- ASP.NET二级域名站点共享Session状态
我的前面一篇文章提到了如何在使用了ASP.NET form authentication的二级站点之间共享登陆状态, http://www.cnblogs.com/jzywh/archive/2007 ...
- Android 分析工具 APKAnalyser
APKAnalyser 是 Android 静态,虚拟分析工具,用来测试和验证 Android 应用的开发工作.ApkAnalyser 是个完整的工具链,可以修改二进制应用.用户可以改装,安装,运行, ...