|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2010-4-17 20:22:44
|
显示全部楼层
原文:
花费2个星期的时间学习linux tty驱动程序。这2个星期的时间对我的linux驱动学习来说是一个相当生猛的突破:每当一个内容不了解的时候,会挖空心思去寻找与他相关的内容,当再次回到那一个点的时候,发现自己真的又学到不少东西。
在这过程中,看到一句话出自陈莉君老师等翻译的《深入理解linux内核 涵盖2.6》,用于自勉。现摘录进来:成长是跳跃式的,要经过量的积累,在积累的过程中,往往要伴随着扬弃,所以常常会跌入低谷,面对linux这个需要长期孜孜以求的学习对象,无疑这种震荡会加重我们的疑虑,降低我们的信心消磨我们的意志,使我们轻易认为达到了自己的成长上线...更需要执着...会有“蓦然回首,那人却在灯火阑珊处”的感觉。
转入正题:
TTY设备的全程是Teletype即电传打印机的意思(如果对电传打印机意思不太明白,可以参看维基百科)是最早出现的终端设备。千万不要把现在所用的串行9针rs232串行接口认为是一个终端设备,这是一个相当错误的认为。rs232不是一tty终端设备,他只是一个接口,用于连接支持串行rs232通信的终端设备如调制解调器。调制解调器才是一个tty终端设备。计算机发展至今,很多外设被淘汰,若不是设计嵌入式开发会很少接触到rs232串口,而且现在计算机大部分主板上已经不再扩展rs232接口。现在撇开伪终端、控制台终端,将深入支持rs232串口的终端的设备驱动程序。由于时间的原因,我们已经使用tty来简称各种类型的终端。
一、tty设备驱动综述(这里讲到的tty设备驱动是一个大框架,rs232的tty只是其中的一个子集)
tty驱动程序最本质的一点,要有发送和接收数据的功能。这是他最基本的功能。linux的tty设备驱动功能不只有这一点。linux OS不但要面向不同的平台,也要面向不同的设备。所以linux 的设计者在tty的驱动兼容性下了很大的功夫。一般来说linux tty驱动分为3个层次,从上到下分别是:
1)tty核心层
2)线路规程
3)tty驱动程序
tty核心层是对tty设备的更高层抽象,线路规程主要用来处理tty终端设备内部的协议(ppp线路规程),tty驱动程序则直接和硬件打交道。tty终端设备不需要使用快读写数据,所以在驱动的较高层,将使用字符型设备(这里假设提出一个驱动层的较高层和较低层概念,将在后续论述)。这里备忘我当时走的弯路:rs232终端驱动其实一般不需要在linux驱动层里面实现线路规程,对rs232串口驱动,你只要做到的是给他什么比特流,他把它发出去或收回来就好了。在ppp拨号里面,线路规程ppp协议并没有直接加入在rs232linux驱动里面,而是线路规程也是作为一个内核的部件以及应用层的守护进程,调用/dev/ttyS0通过串口向调制解调器发送已经被协议栈处理好的数据内容,当数据内容是命令时,控制调制解调器(如AT命令),若是单纯的数据则给调制解调器进行信号变换DAC,发送给远程服务器。linux是为了兼容调制解调器以外的设备,所以linux扩展了tty设备驱动程序的框架。
二、为了理解tty驱动思想而涉及的linux设备模型
首先Cz.提出一个自己的思想假设(欢迎拍砖):把驱动层进一步分为驱动层的较高层、驱动层的较低层。
驱动层的较高层:负责与用户交互,比如fileoperation的指针设置。
驱动层的较低层:完全负责用硬件打交道,带有资源管理性质。如根据硬件设计在内核里面开辟IO空间,对硬件模块进行寄存器寻址达到配置硬件模块的目的。比如在platform机制中的probe函数设置,在这里面实施对io空间的开辟等等。
这里Cz.写下笔记,记录阅读陈莉君老师编写的《深入理解Linux内核》的第十三章读书笔记:
Cz.认为Linux内核的设计者真的是介于牛A和牛C之间的人,他们不断的抽象,体现在内核体系的设计当中。前几天发邮件给陈莉君老师,陈老师告诉我platform机制一般用于直接挂接在cpu内核总线的设备模块的驱动。Cz.个人认为platform也是linux设备模型思想的一种相当牛B的体现。
Cz.发现linux内核设备模型中的层次结构跟pc的硬件实现层次相当的相似.
/sys— —>总线 ——> pci总线——> 驱动——>串口(左代表最上,画得不清楚可以看《深入理解linux内核》P529页)
最上端的总线认为是CPU的数据/地址总线(主总线),下一层的PCI则是挂载在主总线上的桥芯片PCI控制器,接着下几层则可以共同认为挂载在pci总线上的一个设备的驱动以及对应的设备。
驱动的层次是依靠内核中的数据结构kobject(可以认为是一个基类)不断的嵌入(派生)在另一个更高层次的数据结构当中这样一个派生行为构成一个层次结构。查看源代码发现,kobject被嵌入在kset中,kobject的层次则被相应的提高。当kset在此被嵌入至subsystem时,kset的层次依然相应的提高。也就是在subsystem中kobject被迭代继承了2层,使容器数据结构的层次提高2次。可以认为subsystem(子系统)的层次是最高的,也就是CPU的主总线。这符合PC机的原理,挂载在主总线上的一类设备被认为是一类subsystem(子系统),比如挂载在主总线的北桥芯片。他被抽象为pci子系统。我们pc电脑上的串口设备集成在北桥芯片上,所以属于PCI子系统。一个相应的驱动程序可以操作一类设备,比如一个tty驱动程序可以控制对个rs232串口。在设备模型里面,一个驱动程序是一个kset层次,其所能控制的一类设备则属于一类kobject:这句话也正好反映了linux设计者的一个思想:kset是具有相同类型的kobject的集合。
在linux驱动模型中,kobject是组织层次的基类,还有另外三个内核基类,分别是:struct bus_type、 struct device_driver和struct device。从字面意思上可以看出这两个是关于总线类型、设备驱动、设备的三种抽象。前面已经提到PCI是一种PCI总线类型的驱动,由北桥芯片挂载在CPU的主总线上。这里的stuct bus_type用于描述一类挂载在主总线上的其他总线类型(如PCI总线)。内核把pci总线以及挂载在pci总线上的设备全部认为是一个子系统,这句话在struct bus_type得到验证,可以查看sturct bus_type的源代码,里面内嵌kset、subststym2个数据结构。
再佩服一下linux内核设计者,linux内核设计者在驱动模型最基本思想上,建立了一个platform驱动设计机制。这里,感谢陈莉君老师对我的提醒:platform也是一种与pci总线(或者pci子系统)同等地位的总线类型设备,这些设备一般有一个共同点,就是挂载在CPU的主总线上。(在这里Cz.突然惊呼:so buautiful!~,原有开始先前认为的假设都归一了)。SOC芯片一般的设计思路就是集成一颗内核,然后把接口模块如串口、spi模块(可以认为是一颗8250)等连接在主总线上。比如ARM芯片等等。
在这里简单的备忘一下platform机制:platform机制有2个类组成:platform_device 和 platfor_driver组成,在platform_device内嵌了resurce结构,抽象了系统的资源,IO、中断等。当用platform_driver_register()和platform_add_devices向内核注册后,probe函数将对设备进行内存分配、中断设置等等。
以上被忘了linux驱动中的较下层。貌似从上面看来,linux驱动模型并没有对linux设备进行分类,看不出linux字符、块、网络等设备。是的!Cz.认为这些分类将在linux驱动较上层体现。
拿linux字符设备来说,从linux字符设备的框架分析,linux字符设备的程序写法主要想内核获取、注册了设备(也就是对cdev中的kobject进行注册),其后,为其指定了VFS的具体操作。(Cz.说:这也跟我当初的假设一样)。叫上层次的驱动要管用户的操作,所以才区分了字符设备、块设备、网络设备。这也是分着写设备的原因,字符设备不带缓冲,块设备不能随机读,网络设备我不知道。不管你操作方法如何变,对于底层,也就那么几根线跟CPU相连.
分析完毕!
Linux为了照顾、兼容尽可能多的设备,不得已统一接口、统一框架。也是为了让linux内核更具模块化,内核开发人员设计了如此多的经典数据结构,这也是linux的博大精深所在!
Cz.@Joker~~~ |
|