Linux驱动结构学习笔记
系统中任一设备都有一个device对象描述,定义在linux/include/linux/device.h
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; //内嵌的kobject对象
char bus_id[BUS_ID_SIZE]; //在总线上的位置
struct device_type *type; //设备类型
unsigned is_registered:1; //标识该设备是否已经被注册过,仅一位
unsigned uevent_suppress:1;
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; /* NUMA node this device is close to */
#endif
u64 *dma_mask; // dma掩码
u64 coherent_dma_mask;///设备一致性DMA的屏蔽字。
struct list_head dma_pools; // dma缓冲池
struct dma_coherent_mem *dma_mem; //指向设备所使用的一致性DMA存储器描述符的指针
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; //
struct attribute_group **groups; //附加属性的数组
void (*release)(struct device * dev); //释放设备的方法
};
linux内核系统了一系列完整的对device操作的函数。
1、其中device_register()函数用来将一个新的device对象插入设备模型。它在linux/drivers/base/core.c中被实现:
int device_register(struct device *dev){
device_initialize(dev);
return device_add(dev);}
该函数首先是调用device_initialize()初始化device结构,具体是初始化嵌入的kobject结构dev->kobj,初始化列表中的孩子列表kobj->klist_children,初始化DMA缓冲池dev->dma_pools,初始化自旋锁dev->devres_lock等。接下来device_add()函数才真正将该device对象dev插入设备模型中。device_add()函数首先是通过kboject_add()函数将它添加到kobject层次,再把它添加都全局和兄弟链表中,最后添加到其他相关的子系统的驱动程序模型,完成device对象的注册。
2、device_unregister()完成相反的过程,定义在/linux/drivers/base/core.c
void device_unregister(struct device * dev){
pr_debug("DEV: Unregistering device. ID = '%s'/n", dev->bus_id);
device_del(dev);
put_device(dev);}
它会先以KERN_DEBUG级别打印注销设备的信息,然后才真正删除设备,减少设备对象的引用计数。
3、get_device()和put_device()分别是增加和减少设备对象的引用计数。这两个函数都定义在/linux/drivers/base/core.c中。具体是应用在注册device对象时,device_add()函数会调用get_device()增加对该device对象的引用计数。在注销设备对象时device_unregister()函数直接调用put_device()函数减少对该device对象的引用计数。