技术中的形而上(一)----Linux下的usb四大家族

来源:互联网 发布:网络诈骗的常用方式 编辑:程序博客网 时间:2024/06/07 17:56

http://blog.sina.com.cn/s/blog_6100a4f10101ee3s.html


以前写的文章,搬到这里来.


http://blog.chinaunix.net/uid-103601-id-2961397.html(技术的形而上())

http://blog.chinaunix.net/uid-103601-id-2961403.html(技术的形而上())

http://blog.chinaunix.net/uid-103601-id-2961404.html(技术的形而上())

http://blog.chinaunix.net/uid-103601-id-2961405.html(技术的形而上())


    形而上学,在我们以马哲为教材的教育环境下,从开始就被灌输了形而上学是错误的,形而上学一直是被批判的。任何一种思想、认识世界的方法都有他合理的一面、局限的一面,我们需要在不同的阶段、不同的场合用不同的方法,没有一种方法是万能的。

    形而上者谓之道,形而下者谓之器。道德经中的这句话堪称经典。不同的关注点用不同的方法来研究。马哲崇尚辩证,这是正确的。我们也应该辩证的看待形而上:一切存在背后的存在。

下面是这个概念的来源:

概念来源

  形而上学(metaphysics)这种命名方式的出现是个巧合。亚里士多德的《形而上学》被誉为西方哲学的圣经,但是他本人生前倒是没有运用这种叫法,而是称为"being as being",即一切存在背后的存在,或可称之为道。他死后200多年,他的后继者着手编他的手稿,在编完了物理学《phusika》之后,开始编亚里士多德关于第一哲学的手稿,然而这个人却想不出合适的名称,于是干脆就叫《物理学之后诸卷》希腊文也就是〈ta meta ta phusika>然后人们去掉冠词,就成了〈metaphusika〉而正好meta这个前缀在希腊语中不仅有之后的意思,也有超越,基础的意思。这正好和亚里士多德第一哲学的概念相符合。

中文来源

   中文译名“形而上学”是根据《易经》中“形而上者谓之道,形而下者谓之器”一语,由日本人(明治时期)井上哲次郎metaphysic翻译而来。当时,严复抗拒这种翻译,自创“玄学”,可是并没有被接受,于是中文就翻译成形而上学了。换而言之“形而上学”就是西方“第一哲学(first philosophy)”的中文翻译。

形而上在嵌入式开发中的应用

在信息爆炸的时代,人类的思维能力远没有达到对其接收自如的程度。而每个人的求知欲望或者生存的压力使人类渴望把更多非我的东西转变成自我的东西,但现代社会非我的知识无限浩大,对未知的恐惧感使现代人承受着更多的心理压力,甚至象北京的交通一样造成了不必要的心理拥挤,这种状况就像一个无形的杀手,侵蚀着人类的心灵与健康。

作为一个it技术人员,更是不得不面对这层出不穷的新技术,难道我们这些工作在一线的技术人员真的没有办法么?难道真的要把自己囚困在这纷繁的技术细节中么?使我们无暇思考,变得麻木、盲从。

我们应该抽出一些时间来留给自己去思考这些问题,也许我们能够找到答案,至少我们应该努力去寻找。

 

      那么什么是技术?技术包括以物质方式呈现的如,如芯片、机器或建筑,也包括以某种经验呈现的如,如系统架构、组织方法和生产技巧等等。抽象的说,技术是人类根据生产经验和对自然界现象的理解所总结出来的认知自然的方法和技能。

       技术的源头是什么?把你在小黑屋里关10年,你能创造出什么技术么?有难度。为什么?因为没有和大自然接触,闭门是造不出车的。试想将一个新生的婴儿,放在某个封闭的环境下成长,那么他所掌握的知识将仅限与这个环境之内。所以人类所掌握、创造的技术、知识都来源于大自然,各种各样的自然现象、自然规律给了我们启发,才孕育了人类的文明。在追逐各种新技术的同时,有没有考虑一下这种技术的精神呢?每一种具体的技术都是一种让人看得见的形,除了形还有形而上的东西存在,是源于大自然的某种现象。形而上者谓之道,也就是西方哲学所说的存在背后的存在。

       如果你认同了技术源于自然界,那么了解了自然界,面对纷繁复杂的技术,你就可以举一反三,从容的对待。剥去技术表面的华丽,看到技术表象背后的本质。

       技术是由条件的,他的正确性局限在某种特定的环境下。我们的芯片只能在正负40之间正常工作,这就是条件。那么在认知一种技术时就要想到他正常发挥作用的条件。

       技术是有目的性的,技术是某个人为了达到某种目的而创造出来的,是用来满足人的某种需要的。没有目的成不了技术。技术的目的性告诉了我们一种认知技术的方法,想了解一项技术,可以问问自己:这是干什么用的?为什么要这么做?想达到什么目的?如果是我会怎么做?这样你在试图掌握这项技术时就会化被动为主动,与技术的发明者进行形之上的交流。

       从高中我们就开始学习马克思哲学,什么方法论、辩证法、世界观等等。大多数人认为没什么用,因为他太空洞,太抽象。但是当这种东西找到了具体的载体,将这种思维方式应用到具体的生活中时,也许就有了一朝悟道的感觉了。尤其是我们这种整天忙于技术、和程序打交道的人来说,整天接触的都是具体的代码、模块等等,无休无止,陷进去很可能就出不来了,而这种具体的东西正是哲学思想最好的载体。谁缺少了谁都会变得暗淡,一个变得空洞,一个变得迷失。

       曾被我们抛弃的西方第一哲学,一门研究世界本质的哲学流派,说哲学这两个字总是让人觉得精神不正常,我们可以称其为认知世界的一种思维方式。第一哲学在中国叫做形而上学。而我们一直学习的是马克思的辩证法。其实两者并不冲突。比如做一个芯片,你可能要考虑整体的架构,这种宏观的东西,这就会涉及到形而上的思维方式,考虑某个具体的细节,比如这个芯片的频率能跑到多少,这就要用到形而下的思维方式,就是充满逻辑的辩证法。

形而上者谓之道,形而下者谓之器。两者缺一不可。两者试用在不同的环境之下。


注意:形而上学是研究存在背后的存在、形而上的东西,有好读书不求甚解的意思,辩证法是研究具体的逻辑关系。

v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} st1\:*{behavior:url(#ieooui) }

那么我们要讨论的是如何在技术不断更新、涌现的当下,不至于被技术所绑架,而没有时间去静静地思考,所以我们在这个背景下可以考虑用形而上学的思维方式来接触、了解这些新技术。

<</span>我认为世界是不可认知的,技术作为一种经验的总结,是在某个局部的、相对静止的环境中所作出的貌似正确的认知结论,在某个更广阔的范围也许就不是正确的了,说这些的目的就是时刻提醒着我们,我们所接触的知识都是以某种假设为基础所搭建起来的,在没有遇到无法解释的问题时,我们理应认可这种假设的正确性。同时这种方式也告诉我们,在我们理解一件事物时,完全可以创建自己的假设,融入自己思考问题的方式,也许在别人看来并不正确,没有关系,只要能够在自己的思维体系中和谐的共存就ok>

       对于一个以前没有接触过的新事物,我们会用什么样的方式就了解他呢?

下面我以linux下的usb作为实例,讲述一下这个系统下的usb家族的组成和工作方式,如果读的过程中或读完后你看到的只是usb,而不是具体事物usb之后的东西,那说明我的讲解没有到位或者说你的理解没有到位,请记住being as being

 

       一个事物只能存在于一个环境之中,他的价值、成长是在这个环境、团队中得以体现的,usb是一项技术,存在于我们伟大的计算机操作系统之中(当然也可以不在,我们这里讲的是linux系统中的usb)。操作系统是什么?是一个管理者,让各种软件,应用软件、驱动软件等能够正常的和谐的工作和生活。是一个国家的政府,让每一位老百姓尽量公平的享受着硬件资源,合理的调度、合理的享受着那紧张的内存。现实生活中的一些行政部门,我们似乎看不到他的具体作用,没有创造出实实在在的社会财富、没有造出好的芯片,但是他确实存在的,为了能够让整个社会正常的运转,也可以说我们在做具体的事情时还需要一些部门的支持,linux下的usb也一样,仅有操作系统是不够的,他的正常工作还需要很多其他的东西,东西太多会让我们混乱,我们只关注重要的、我们需要的。

我将Linux系统下的usb部分分为四个部门或者叫做四大家族,他们是host控制器驱动、hub驱动、usb core、设备类驱动他们共同配合着完成了对usb设备的访问操作。这4个家族可以说都是混在linux系统驱动层的,分管着不同的工作。每一个家族都在各尽其职,勇敢的担当着自己的责任,有人在幕后,有人在台前,有人统领大局、左右逢源,有人风光无限。但是他们的存在、工作机制、配合的默契程度都离不开另外一个势力:linux下的设备驱动模型。就如同红楼梦中的薛、王、贾、史四大家族离不开封建礼制一样,要了解linuxusb系统,首先要了解设备驱动模型,可以说,了解了linux下的设备驱动模型,就如同练就了内功心法一样,无论将来开发什么驱动,都不会感到陌生,到那时你就会发现原来设备驱动模型才是老大,usb下的这四个部分只不过是个配角。环境是重要的,当你要调试某个具体的功能时,那就是配置寄存器的事情了。

 linux下设备驱动模型

了解设备驱动模型之前,首先要清楚什么是设备?不管你是不是驱动开发人员,稍微有点计算机知识的起码能说出一点来,就是那些总线和通过总线连接的各种硬件设备,如内存、键盘等等。现在的设备太多了,linux也会与时俱进,寻找着管理上的新方式。搞个模型出来,在模型中划分出层次结构,这就便于管理了,所有的设备都按照设备模型的规范来,设备是一层又一层,仰望是parent,俯视是children 规范、标准就是老大,老大确实是必需的,他能带我们走的更远。你会发现,有了设备驱动模型的框架,开发设备驱动的思路是如此的清晰。

       强大的事物总是隐藏在背后,让人捉摸不透。Linux模型很强大,模型这种东西很虚的(虚,可不是说它没有用),是隐藏在具体表现形式之后的。要想从整体来理解他是比较困难的,我们需要通过模型中几个具体的角色来一点一点的来了解它。理解虚的就要从具体的开始。有时我们要从整体入手,有时我们却需要从具体入手,水无常形。就如同要了解我们周围的生态环境,就需要从某种具体的生物入手一样,所有的知识都来源于大自然。

1.1设备模型之总线、驱动、设备

       我们看一下首先出场的3位主角:总线、驱动、设备。这可是设备模型中的重量级角色。

       上面已经说了,设备模型是用来管理设备的。怎么管理?主要管理什么?大家应该都装过电脑。设备是通过总线连接到CPU上的,设备是需要驱动才能正常工作起来的。总线是如何发现设备的,驱动又是如何和设备正确的联系起来的呢?设备模型的重要工作就是将他们联系起来,让每一个设备成为一张大网之上的一个节点,让操作系统能够轻松的找到每一个设备,也能够知道每一个设备的情况,任何情况。

       在设备模型中,所有的 device 都是通过总线 bus 连接,这里的 bus 包括通常意义的总线如 usbpci,也包括虚拟的 platform总线(收留那些没有归宿的设备)

进入/sys/busls一下我们看看是不是有platform这个虚拟总线。我理解那些不包括在普通总线内的设备都挂接在虚拟总线上,来保证模型的通用性。虚拟总线诞生的目的应该就是如此吧。

mengfandong@icp-desktop:/sys/bus$ ls

MCA  acpi  eisa  hid  i2c  isa  mdio_bus  mmc  pci  pci_express  platform  pnp  scsi  sdio  serio  spi  usb

设备模型在系统目录中对应的是sys文件夹。

mengfandong@icp-desktop:/sys$ ls

block  bus  class  dev  devices  firmware  fs  kernel  module  power

在这个文件夹下有我们马上要介绍的driverbusdevice三个目录。

1.2 初始3位结构体

       Linux下的结构体通常都很长,但只需要关注我们目前关心的成员,少了哪个成员都不行,但我们哪管得了那么多。

struct bus_type {

       const char             *name;

       struct bus_attribute *bus_attrs;

       struct device_attribute    *dev_attrs;

       struct driver_attribute    *drv_attrs;

 

       int (*match)(struct device *dev, struct device_driver *drv);

       int (*uevent)(struct device *dev, struct kobj_uevent_env *env);

       int (*probe)(struct device *dev);

       int (*remove)(struct device *dev);

       void (*shutdown)(struct device *dev);

 

       int (*suspend)(struct device *dev, pm_message_t state);

       int (*suspend_late)(struct device *dev, pm_message_t state);

       int (*resume_early)(struct device *dev);

       int (*resume)(struct device *dev);

 

       struct dev_pm_ops *pm;

       struct bus_type_private *p;

};

 

struct bus_type_private {

       struct kset subsys;

       struct kset *drivers_kset;

       struct kset *devices_kset;

       struct klist klist_devices;

       struct klist klist_drivers;

       struct blocking_notifier_head bus_notifier;

       unsigned int drivers_autoprobe:1;

       struct bus_type *bus;

};

 


 

 

 

struct device_driver {

       const char             *name;

       struct bus_type             *bus;

 

       struct module         *owner;

       const char            *mod_name;   

 

       int (*probe) (struct device *dev);

       int (*remove) (struct device *dev);

       void (*shutdown) (struct device *dev);

       int (*suspend) (struct device *dev, pm_message_t state);

       int (*resume) (struct device *dev);

       struct attribute_group **groups;

 

       struct dev_pm_ops *pm;

 

       struct driver_private *p;

};

struct driver_private {

       struct kobject kobj;

       struct klist klist_devices;

       struct klist_node knode_bus;

       struct module_kobject *mkobj;

       struct device_driver *driver;

};

 

struct device {

       struct klist             klist_children;

       struct klist_node     knode_parent; 

       struct klist_node     knode_driver;

       struct klist_node     knode_bus;

       struct device          *parent;

 

       struct kobject kobj;

       char bus_id[BUS_ID_SIZE];  

       unsigned         uevent_suppress:1;

       const char             *init_name;

       struct device_type  *type;

 

       struct semaphore    sem;       

 

       struct bus_type      *bus;             

       struct device_driver *driver;  

       void        *driver_data;   

       void        *platform_data;      

       struct dev_pm_info       power;

 

#ifdef CONFIG_NUMA

       int           numa_node;    

#endif

       u64         *dma_mask;   

       u64         coherent_dma_mask;

 

       struct device_dma_parameters *dma_parms;

 

       struct list_head       dma_pools;     

 

       struct dma_coherent_mem    *dma_mem;

       

       struct dev_archdata       archdata;

 

       dev_t                    devt;       

 

       spinlock_t              devres_lock;

       struct list_head       devres_head;

 

       struct klist_node     knode_class;

       struct class            *class;

       struct attribute_group    **groups;       

 

       void (*release)(struct device *dev);

};

 

通常device结构不单独使用,而是包含在更大的结构中作为一个子结构使用,比如PCI设备的struct pci_dev,其中的dev域就是一个device对象。

注意这3个结构体中,每个结构体中标记蓝色的那两行。冷静下来好好看看这6行。想想这6行和这3者之间的关系。不要着急往下进行,一定要静下心来、闭上眼睛把这3个结构体的关系从纸面上的暧昧发展到逻辑上的依赖,那就差不多了(这时并不需要了解的太深,毕竟我们关注的是usb,要读书不求甚解,即使在这里我们想深入研究,效果可能也不会太好,因为没有将他放在某个应用环境中,当他和usb驱动联合起来共同工作时,对他才会有更深入的理解)。我们在学习前人的知识,但是我们依然可以从一个设计者的角度去理解这些知识,如果历史给你这个机会,你会怎么设计这个设备驱动模型。

冷静,这里需要耐心!

对上面有了一定的感觉后,我们已经迈出了一大步了。

下面我们应该总结出对3个结构体的简单认识:

struct bus_type中的klist_driversklist_devices分别表示了这个总线上拥有哪些设备和哪些驱动。

struct device_driver中的bus表示这个驱动属于哪个总线,klist_devices表示这个驱动都支持哪些设备,一个驱动是可以支持多个设备的,一个设备却只能有一个主儿,所以这里的device是个复数 and list。

struct device中的bus表示这个设备连到哪个总线上,driver表示这个设备的驱动是哪个驱动。

List是什么?linux 起名字还是很地道的。链表!从bus结构体中可以看到其中包含设备链表和驱动链表。无论是系统刚刚启动还是运行后设备的突然插入,设备的驱动程序都需要将这个设备的一切信息上报给总线,给他创建一个device结构体,挂到bus的设备列表中。当发现有新的设备加入时,总线会为其寻找驱动,如果找到合适的driver后,更新device中的driver成员,并一并更新driver中的klist_devices成员,这就是一个match的过程,同时将他们绑定,有点媒婆的感觉。关于match,我们也许会想:怎么match?是的,怎么match!每个总线都有一个match函数,代表着自己match driverdevice的原则。有些是依靠名字来match,设备和驱动有同样的名字就match成功;usb设备是依靠vidpid

由于热插拔及驱动模块动态加载的出现,先有driver还是先有device已经无从考究。不过不管是先有谁,都将在另一条链表中努力寻找自己的另一半(设备链表和驱动链表)

总线的媒婆角色也发挥得淋漓尽致。努力的撮合着devicedriver链表中的每一个成员。

总线上是可以继续挂接总线设备的。就如PCI总线下有usb总线一样。因为每个usb控制器是作为一个pci设备工作的。每一层总线负责管理好自己分管的设备---注意是物理上的。

总线 (bus) 可以挂接一类设备 (device)

驱动(driver)可以驱动一类设备(device)

我们举个usb总线的例子,usb总线的bus定义:

struct bus_type usb_bus_type = {

       .name =          "usb",

       .match = usb_device_match,

       .uevent = usb_uevent,

};

蓝色的就是总线功能中具体担当媒婆角色的处理函数。

static int usb_device_match(struct device *dev, struct device_driver *drv)

device一直努力寻找自己的driverdriver也一直在努力实现自己的价值,为更多的device服务。


       社会上的剩男剩女越来越多了,devicedriver也越来越多了,bus诞生了。婚姻介绍所也诞生了。努力的撮合着双方,为其找到生命中的另一半。当一对撮合成功后,他们就注册登记了,不再漂泊了。这一对苦命鸳鸯就开始在围城里工作、学习和生活。不同的是现实是一夫一妻制,而那里是可以一夫多妻制的。Linix设备模型虽然强大,可他怎么也强不过大自然,逃不过大自然的模型。自然界才是最伟大的模型。用自然界的现象来理解知识。

1.2 真实的kobject kset

       这一节有兴趣的话可以读一下,跳过去也没有太大影响。

linux设备模型到底为什么会诞生?以前没有他,linux也活得好好的!就是为了能够让内核更好的了解系统整体的信息。所以新来的小弟(设备、驱动)是需要报个到注册的,做到有据可查。

总线、注册这些东西总是让人感觉很虚幻,太抽象。这么多总线是怎么联系起来的,和现实中实实在在的设备又有什么关系?精神世界再强大最终也得回归到真实的物质世界。

现实中的各个设备是如何在物理拓扑上联系起来的?逻辑和物理总是如影随形!

1.2.1 基本要素

kobject,一猜就知道,kernel object。设备模型是管理设备的,linux中正是使用kobject这个小人物来担当了这个重任。每一个设备在内核眼中都是一个对象。设备模型诞生的目的就是内核希望能够统一的管理所有设备,包括他们之间的逻辑关系以及物理连接关系。逻辑关系在上面我们已经讲过了,物理连接就是通过kobject来实现的。

看一下这个结构体:

Kobject结构定义为:

struct kobject {

char * k name; 指向设备名称的指针

char name[KOBJ NAME LEN]; 设备名称

struct kref kref; 对象引用计数

struct list head entry; 挂接到所在kset中去的单元

struct kobject * parent; 指向父对象的指针

struct kset * kset; 所属kset的指针

struct kobj type * ktype; 指向其对象类型描述符的指针

struct dentry * dentry; sysfs文件系统中与该对象对应的文件节点路径指针

};

每一个设备,内核对象都会内嵌一个kobject,就像一个gps定位系统。记录着每一个对象的血统,他属于谁,他有多少个后代,责任重大,但他却从不走向幕前,一直作为结构体中的一个内嵌成员出现,可以说是默默无闻,但却是他才能让linux设备模型真正的工作起来。

       结构体中的kref是一个记录该设备有多少个child(大家都叫引用计数)的数字,相当的重要。他的值决定着这个对象是否有存在的必要。别看device很拽,内核并不相信他,当内核发现kobject中的kref0时,会毫不留情的干掉这个device释放它占用的资源。Kref 作为device结构体成员的一部分,颇有点大义灭亲的感觉。

       既然是层次就不应该只有kobject一层,kobject之上为ksetKset是相同类型kobject的集合。

struct kset {

struct subsystem * subsys; 所在的subsystem的指针

struct kobj type * ktype; 指向该kset对象类型描述符的指针

struct list head list; 用于连接该kset中所有kobject的链表头

struct kobject kobj; 嵌入的kobject

struct kset hotplug ops * hotplug ops; 指向热插拔操作表的指针

};

Kset数据结构中内嵌了一个kobject对象,所有属于这个kset kobject对象的parent域均指向这个内嵌的对象。Kset的引用计数是靠kobj来维护的:kset的引用计数实际上就是内嵌的kobject对象的引用计数。


0 0