在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)---- 终端设备驱动的更多相关文章

  1. 乾坤合一~Linux设备驱动之终端设备驱动

    多想拥你在我的怀里 却无法超越那距离 美好回忆渐渐地远去 盼望今生出现奇迹 无尽的想念 荒了容颜 无助的爱恋 从未改变 这是今天的旋律,,,,今生今世,遥不可及~ 1 终端设备 终端是一种字符型设备, ...

  2. ARM-Linux S5PV210 UART驱动(4)----串口驱动初始化过程

    对于S5PV210 UART驱动来说,主要关心的就是drivers/serial下的samsung.c和s5pv210.c连个文件. 由drivers/serial/Kconfig: config S ...

  3. ARM-Linux S5PV210 UART驱动(转)

    ARM-Linux S5PV210 UART驱动(3)----串口核心层.关键结构体.接口关系 尽管一个特定的UART设备驱动完全可以按照tty驱动的设计方法来设计,即定义tty_driver并实现t ...

  4. arm linux利用alsa驱动并使用usb音频设备

    一.背景: arm linux的内核版本是3.13.0 二.准备工作 添加alsa驱动到内核中,也就是在编译内核的时候加入以下选项: 接下来就重新编译内核即可 三.交叉编译alsa-lib和alsa- ...

  5. ARM Linux驱动篇 学习温度传感器ds18b20的驱动编写过程

    ARM Linux驱动篇 学习温度传感器ds18b20的驱动编写过程 原文地址:http://www.cnblogs.com/NickQ/p/9026545.html 一.开发板与ds18b20的入门 ...

  6. [转]Linux芯片级移植与底层驱动(基于3.7.4内核)

      1.   SoC Linux底层驱动的组成和现状 为了让Linux在一个全新的ARM SoC上运行,需要提供大量的底层支撑,如定时器节拍.中断控制器.SMP启动.CPU hotplug以及底层的G ...

  7. 让天堂的归天堂,让尘土的归尘土——谈Linux的总线、设备、驱动模型

    本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 公元1951年5月15日的国会听证上, ...

  8. Linux下smi/mdio总线驱动

    Linux下smi/mdio总线驱动 韩大卫@吉林师范大学 MII(媒体独立接口), 是IEEE802.3定义的以太网行业标准接口, smi是mii中的标准管理接口, 有两跟管脚, mdio 和mdc ...

  9. 【Linux高级驱动】rtc驱动开发

    [1.分层思想] 1.1 rtc-dev.c   //设备接口层,功能:给用户提供接口 subsys_initcall(rtc_init);   , RTC_DEV_MAX, "rtc&qu ...

随机推荐

  1. 琐碎-hadoop2.2.0伪分布式和完全分布式安装(centos6.4)

    环境是centos6.4-32,hadoop2.2.0 伪分布式文档:http://pan.baidu.com/s/1kTrAcWB 完全分布式文档:http://pan.baidu.com/s/1s ...

  2. FE—— Code First 初体验 01(转)

    EF Code First 初体验   Code First 顾名思义就是先代码,再由代码生成数据库的开发方式. 废话不多说,直接来一发看看:在VS2010里新建一个空白解决方案,再依次添加两个类库项 ...

  3. struts2.1笔记02:servlet简介

    1.     Servlet 是在服务器上运行的小程序.这个词是在 Java applet的环境中创造的,Java applet 是一种当作单独文件跟网页一起发送的小程序,它通常用于在客户端运行,结果 ...

  4. 关于Excle中的VLookUp的函数的使用

    VLookUp函数的使用,VLookUp中的V是垂直的(vertical)意思,此外与此相类似的函数还有HLOOKUP(Horizonal水平的)意思. 下面主要谈谈VLookUp的使用方法. VLo ...

  5. 对微信小程序的看法,不吹不黑

    今日微信小程序正式上线了,昨天也稍稍地研究了一下小程序的概念以及开发过程.简而言之,微信小程序就是一款在微信端的轻应用,其实在支付宝也有类似的功能,只不过支付宝没有开放接口,而微信开放了接口供开发者开 ...

  6. MySQL同主机不同数据库的复制命令

    MySQL同主机不同数据库的复制命令:注意运行在Terminal中,不运行在MySQL命令行中. 1 mysqldump Portal_DEV -u root -ppassword1$ --add-d ...

  7. PHP之自定义会话控制---使用文件处理

    前三篇简单的总结了下会话控制和文件操作,这一篇说说会话控制的自定义处理方式.既然知道了文件的基本读写,而且在会话控制中,也有人提到,session数据可以保存到缓存或数据库中,实际上当然不会是直接利用 ...

  8. HTTP - 摘要认证

    基本认证便捷灵活,但极不安全.用户名和密码都是以明文形式传送的,也没有采取任何措施防止对报文的篡改.安全使用基本认证的唯一方式就是将其与 SSL 配合使用. 摘要认证是另一种 HTTP 认证协议,它与 ...

  9. 【AngularJs】---"Error: [ng:areq] Argument 'fn' is not a function, got undefined"

    项目中把controller.service抽取出来 一步一步没有报错 index那里加 <script src="js/controllers/XXController.js&quo ...

  10. 32位和64位Ghost版Win8.1系统大全下载最新版

    Ghost版Win8.1系统企业版,下载完成后一定要使用校验工具验证GHO文件MD5值,如果不符请不要安装,不然安装失败后果自负.GHO文件路径一定不要带中文,否则无法安装.安装完成第一次进入桌面会黑 ...