原文出处:http://blog.csdn.net/weekyhuang/article/details/4433369
关于这一部分 的blog,所有的内容均摘自自己的工作总结笔记,在很多网站都发现了自己写的技术总结的转载感到很高兴,虽然我还是个菜鸟,但是我会继续努力。另外关于 wlan驱动这方面的资料真的很少,我基本上是靠自己读代码来理解那些繁琐的寄存器读写、802.11/e/h/d等标准的,真的比较辛苦。不过好在算是 慢慢的搞清楚了这个流程,在此之前我们仍然要补习一下关于在2.6版本内核中写驱动的知识。
有关linux设备模型这一块比较复杂,我不敢断定自己理解的肯定正确,但是我会在做这个驱动的过程中回过头来修改自己的笔记并且纠正自己在blog上贴 的并不正确的地方。另外,我的无线网卡是挂接在SDIO总线上的,所以呢,我们之前会先介绍一点SDIO的驱动,当然并不在这篇blog上,这篇blog 会是总领性的关于基础知识的介绍。下面是笔记:
在进入正式的驱动代码之前,我们不得不补充一点基础知识,也就是在 2.6 版本内核的现在,内核是如何管理总线,驱动,设备之间的关系的,关于 bus_type 、 device_driver 、 device 这三个内核结构在内核代码中可以找到。由于这三个结构的重要性,我们在这里先将它们贴出来,我会用红色的注释标注。我在笔记中将会提到的一些结构成员以其代表的意义,这样便于对照。(我不得不承认,这三个结构的代码枯燥复杂,但我可以保证,在看完我总结的笔记之后,你会对这三个结构中重要的数据成员有个非常不错的了解,当然你得对内核和驱动有基本的了解。如果我误导了你,请指正我,所以我的建议是不妨先看完了笔记再来看这些结构)
1、设备结构的定义:
struct device {
struct klist klist_children;
struct klist_node knode_parent; /* node in sibling list */
struct klist_node knode_driver;
struct klist_node knode_bus;
struct device *parent;
struct kobject kobj; //kobject结构,关于这个结构与kset结构以及subsystem结构,笔记中会有描述。
char bus_id[BUS_ID_SIZE ]; /* position on parent bus */
struct device_type *type;
unsigned is_registered:1;
unsigned uevent_suppress:1;
struct semaphore sem; /* semaphore to synchronize calls to
* its driver.
*/
struct bus_type * bus; /* type of bus device is on */ //这个设备挂接的总线的类型
struct device_driver *driver; /* which driver has allocated this device */ //这个设备挂接的驱动
void *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data, device core doesn't touch it */
struct dev_pm_info power;
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/ * Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */
/* arch specific additions */
struct dev_archdata archdata;
spinlock_t devres_lock;
struct list_head devres_head;
/* class_device migration path */
struct list_head node;
struct class *class;
dev_t devt; /* dev_t, creates the sysfs "dev" */
struct attribute_group **groups; /* optional groups */
void (*release)(struct device * dev);
};
2、设备驱动的结构:
struct device_driver {
const char * name; //设备驱动的名字
struct bus_type * bus; //设备驱动挂接的总线的类型
struct kobject kobj; //kobject结构
struct klist klist_devices; //这个驱动对应的设备的链表
struct klist_node knode_bus;
struct module * owner;
const char * mod_name; /* used for built-in modules */
struct module_kobject * mkobj;
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);
};
3、总线结构:
struct bus_type {
const char * name; //总线的名字
struct module * owner;
struct kset subsys; //与该总线相关的subsystem
struct kset drivers; //挂接在该总线上的驱动的集合
struct kset devices; //挂接在该总线上的设备的集合
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
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);
unsigned int drivers_autoprobe:1;
};
我们注意到只有在 bus_type 结构中有 kset 结构,其他两个结构中则没有,我们知道 kset 结构是用于存放相同类型的 kobject 的,这究竟是个什么意思呢? kset 又是为什么而存在的呢?为什么不能就是 kobject 呢?(关于kobject结构,我们很难抽象的形容,尽管它就是一个抽象的概念,我们将留待看代码的时候介绍,这里可以将kobject看成一个基类,kset就是容器了),下面我会按照自己的理解来回答这个问题(建议通读一下《 linux 设备驱动第三版》的 linux 设备模型章节)
首先不管是设备还是驱动,都是挂接在某条总线上的,也就是说我们根据总线类型的不同来区分各种设备和驱动。(但是我们也要注意到,一个设备和驱动是可以挂接在不同的总线上的,比如网卡可以挂接在 pci 和 sdio 总线上,但这并不是说在 linux 设备模型中就可以同时挂接在两个总线上,我们只能选择其中的一种挂接)。
在内核代码中我们找到了 bus_type 结构,我们发现了它使用了三个 kset 结构,分别是: struct kset subsys 、 struct kset drivers 、 struct kset devices 。我们先抛开 subsys 因为它是用来向上挂接的。这里我们先看 drivers 与 devices 两个 kset 结构的意义。我们从发现一个设备或者驱动说起吧,一个设备或者驱动向内核注册的时候(对于设备来说就是被插入了;对于驱动来说就是 .ko 模块被加载了),对于每一次设备注册或者驱动注册,我们都得分配一个 device 结构或者 device_drive 结构,每一次我们都需要将 device 结构挂入 drivers 或 devices(kset 结构 ) 链表中,这样我们能通过总线找到挂接在这个总线上的所有设备和驱动。但是这里我们注意到仅仅将设备们和驱动们挂接在总线上并不能表明设备和驱动之间的关系,这样的处理仅仅表明了驱动、设备与总线的关系,它们申明了我现在挂接在这条总线下,以后操作我就请通过这条总线。
那么设备如何认出驱动,或者驱动如何认出设备呢?是的,我们是使用的 probe 函数。 那么需要完成哪些过程了?在这些结构总是如何关联的?这才是我们关心的问题。所以这里我们将不得不在说明一下 klist 结构的作用。在内核代码中我们再次找到了 device 结构和 device_drive 结构。我们注意到在 device 结构中存在一个 struct device_driver *driver 这样的声明,而在 device_drive 中却并没有同样的包含 device 结构。我们这样想就明白了:对于一个设备来说,我们只能绑定一个驱动;而对于一个驱动来说,我们是可以对应于多个设备的。 也就是说这里 device 中的driver 指针将会指向其绑定的驱动。那么回到 probe 探测函数,在我们对一个设备驱动进行注册的过程中,我们会在其相应的总线(也就是其挂接的总线)上发出一个探测,这个探测会搜寻所有挂接在这个总线上的尚未被绑定的设备(也就是 driver 指针为 NULL ),然后将 driver 指针指向这个驱动的结构,同时将这个设备的 device 结构挂接在 device_driver 结构中的 klist 链表中。 另外要提及一点就是我居然发现在 device 结构中也发现了一个这样的结构 struct klist_node knode_driver ,它看起来跟 klist 有关,但是我得说我确实不认为 device 需要一个 klist 来挂上它能使用的 driver 。同样,当一个设备被注册时,它也会去寻找挂接在同一条总线上的驱动,并将自己与这个驱动联系起来。
关于基础知识大致就这么些,如果需要知道的更细,可以查看《linux设备驱动第三版》,后面的我们会结合代码叙述注册设备,发现设备(对于驱动来说这里的工作其实很少,如果想知道内核做了些什么,就请跟着我一起看看内核的奥秘),以及数据传输的驱动代码
阅读(1189) | 评论(0) | 转发(0) |