Linux TTY 驱动

相关链接:

http://blog.csdn.net/dongliqiang2006/archive/2009/09/05/4523563.aspx

 

字符设备

1,字符设备层
在Linux中是作为一个文件来出现的,所有对字符设备的操作都是通过file_operations接口来进行的:
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
void cdev_init(struct cdev *, const struct file_operations *);
这个函数初始化指定的cdev结构:其中最重要的步骤就是设置ops
static struct kobj_map *cdev_map;
int cdev_add(struct cdev *, dev_t, unsigned);
cdev_map应该是所有cdev的一个集合,cdev_add函数负责把指定的cdev加入到这个集合中,以便以后的查询
2,line_discipline层(线路规程)
这一层通过tty_struct的ldisc成员实现不同的线路规程,负责连接上层的文件操作和下层的tty操作,并且加入线路规程层的处理逻辑;例如tty_write是导出给上层文件的写操作函数,这个函数一般会调用线路规程
成员ldisc
的write函数,再由后者调用tty驱动(例如n_tty中就是调用write_chan的),全部的导出函数如下:
static const struct file_operations tty_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
.ioctl = tty_ioctl,
.open = tty_open,//tty_open是个比较重要的函数,因为这个函数会调用init_dev,后者会初始化重要的结构tty_struct,并且设置file的private_data为tty_struct实例
.release = tty_release,
.fasync = tty_fasync,
};
3,tty层
介于线路规程层和硬件驱动之间,向上为线路规程提供接口(tty_driver),向下则提供硬件管理(例如tty_operations.start);
写操作
(例如tty_operations.write)向线路规程层提供(因为些操作一般都是线路规程层主动发起,而读操作则是硬件层主动发起),所有的写操作数据都是进入到tty层的一个circle buffer中,tty层会在适当的时候调用硬件层的写操作来输出这些数据;而读操作(例如tty_insert_flip_string)则向硬件层提供,所有读入数据都存放在tty的read buffer中,在适当的时候read buffer中的数据会通过flush_to_ldisc函数推送到线路规程层(具体的硬件驱动在完成数据接收后,需要调用tty_flip_buffer_push函数来推送数据)
注:tty_bufhead结构中有一个work_struct结构,这个结构负责跑
flush_to_ldisc(这个结构会在适当的时候加入到全局工作队列keventd_wq中,tty_io.c中调用schedule_delayed_work)
4,硬件驱动层
和tty层交互,主要处理发送和接收
5,硬件驱动的结构
1)一般会包含一些简易驱动例程
1.1)申明一个console结构
1.2) console_initcall(...)
这样这个简易驱动就可以提供内核启动过程中的信息输出了
2)对tty层的支持,这部分比较复杂,一般会使用中断的工作方式
2.1) 提供tx和rx中断处理函数,分别处理硬件的发送和接收中断事件
2.2)和tty层的交互,tty层提供给硬件层的接口分别是tty_insert_flip_string或者tty_insert_flip_string_flags:用于rx处理,所有接收的数据都是存放在tty_buffer中,和circ_buf:用于tx处理,所有要发送的数据都是存放在circ_buf中
2.3)提供uart_driver结构以及module_init(...)申明

附录1:注册的三个阶段
a,uart_register_driver,由具体的硬件驱动调用,这个函数会分配一个tty_driver结构,然后调用
b,tty_register_driver,注册tty_driver,在这个函数中比较重要的操作是
c,cdev_init,参见上面1中说明
d,另外硬件驱动在调用完
uart_register_driver后,还需要调用uart_add_one_port函数注册端口结构(uart_port),这个结构中最重要的成员就是uart_ops类型的ops了,这个成员包含了所有uart硬件的操作

附录2:重要对象关系及初始化时间
整个结构由具体的硬件驱动程序申明
struct uart_driver {
...
struct uart_state *state;//在uart_add_one_port中初始化
struct tty_driver *tty_driver;//在
uart_register_driver中初始化

};
每个uart_port会有一个对应的uart_state结构,整个结构在uart_register_driver中分配,其成员是在各个函数中逐步初始化的
struct uart_state {
...
struct uart_info *info;//在uart_get中初始化
struct uart_port *port;
//在uart_add_one_port中初始化
...
}
struct uart_port {
...
struct uart_info *info;
//在uart_get中初始化,这个info和state->info指向同一个uart_info结构
...
const struct uart_ops *ops;//由具体的硬件驱动初始化

...
}
调用static struct uart_state *uart_get(struct uart_driver *drv, int line)时,如果对应port的uart_state的info未初始化,则会分配一个uart_info结构并初始化
struct uart_info {
struct tty_struct *tty;
struct circ_buf xmit;//环形缓冲区,在uart_startup中初始化
...
struct tasklet_struct tlet;
//在uart_get中初始化,跑的uart_tasklet_action函数,后者有会调用tty_wakeup
wait_queue_head_t open_wait;//在uart_get中初始化
wait_queue_head_t delta_msr_wait;//在uart_get中初始化
}
整个结构在init_dev中分配
struct tty_struct {
...
struct tty_driver *driver;//在init_dev中初始化
...
struct tty_ldisc ldisc;//在initialize_tty_struct中初始化为默认值n_tty
...
struct tty_bufhead buf;//硬件层写入缓冲区
...
wait_queue_head_t write_wait;//circle buffer写等待队列,
wait_queue_head_t read_wait;//head buffer读等待队列
...
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值