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 ...
随机推荐
- QTP自学攻略
QTP自学攻略 自学总是很痛苦的,看大量的书籍,可是学到的东西却不是那么实用,下面整理了一些在QTP中经常需要的函数,以及方法很实用! QTP常用函数 1, 获取对话框相应的文字: GetVisi ...
- Number Game poj1143
Description Christine and Matt are playing an exciting game they just invented: the Number Game. The ...
- BeanDefinitionRegistry extends AliasRegistry
// 用该Registry注册一个新定义的bean,但是新的bean必须支持父的定义和子的定义void registerBeanDefinition(String beanName, BeanDefi ...
- Android(java)学习笔记82:我们到底该如何处理异常?
我们到底该如何处理异常? 原则: 如果该功能内部可以将问题处理,用try,自己能解决就自己解决问题. 如果处理不了,交由调用者处理,这是用throws,自己不能解决的问题,我们就抛出去交个调用者解决这 ...
- [转]Install Windows Server 2012 in VMware Workstation
本文转自:http://kb4you.wordpress.com/2012/06/28/install-windows-server-2012-in-vmware-workstation-2/ Thi ...
- mysql导入数据load data infile用法
mysql导入数据load data infile用法 基本语法: load data [low_priority] [local] infile 'file_name txt' [replace | ...
- 关于Linux系统和Windows系统中文件夹的命名规范
Windows系统中. 1.在创建文件夹的时候不能以"."开头(但是文件以多个点开头并且还有其他合法字符的话就是合法的) 但是在windows系统中确实见过以一个点".& ...
- hdu 1170 Balloon Comes!
Balloon Comes! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)To ...
- Javascript之三种按钮点击事件
学习Javascript必须要先掌握基本的事件方法和语法,这些都是我们学过的也是最基本的.以前忘了总结,所以现在回顾,综合地总结一下,温故而知新. Javascript有三种按钮点击事件,分别为ale ...
- OpenGL7-3快速绘制(索引方式)
代码下载#include "CELLWinApp.hpp"#include <gl/GLU.h>#include <assert.h>#include &l ...