1. 程式人生 > >struct device / device_driver 結構體

struct device / device_driver 結構體

linux/include/linux/device.h

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;        


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);
};

二、作用:
用於描述裝置相關的資訊裝置之間的層次關係,以及裝置與匯流排、驅動的關係。
三、詳解:
1、struct klist            klist_children;
struct klist被定義在linux/include/linux/klist.h中,原型是:
struct klist {        
spinlock_t k_lock;        
struct list_head k_list;        
void (*get)(struct klist_node *);       
void (*put)(struct klist_node *);
};

可見它是對struct list_head的擴充套件,在此它的作用是連線裝置列表中的孩子列表。
2、struct klist_node       knode_parent; /* node in sibling list */
struct klist_node被定義在linux/include/linux/klist.h,原型是:
struct klist_node {        
struct klist * n_klist;       
struct list_head n_node;       
struct kref n_ref;        
struct completion n_removed;
};

在此它的作用是表示它的兄弟節點。
3、struct klist_node       knode_driver;
表示它的驅動節點。
4、struct klist_node       knode_bus;
表示匯流排節點。
5、struct device           *parent;
指向其父裝置。
6、struct kobject kobj;
這裡http://blog.chinaunix.net/u1/55599/showart.php?id=1086478有對kobject的解釋,此處

它是內嵌的一個kobject物件。
7、char    bus_id[BUS_ID_SIZE]; 
bus_id表示其在父總線上的位置。BUS_ID_SIZE被定義為:
#define KOBJ_NAME_LEN 20 /*linux/include/linux/kobject.h*/
#define BUS_ID_SIZE KOBJ_NAME_LEN /*linux/include/linux/device.h*/

所以表示位置的字串長度不能超過20。
8、struct device_type      *type;
被定義在/linux/include/linux/device.h中,原型是:
struct device_type {        
const char *name;        
struct attribute_group **groups;        
int (*uevent)(struct device *dev, char **envp, int num_envp,char *buffer, int

buffer_size);        
void (*release)(struct device *dev);        
int (*suspend)(struct device * dev, pm_message_t state);        
int (*resume)(struct device * dev);
};

device_type結構表示裝置的型別。一個裝置類或者匯流排可以包含不同型別的裝置,例如“分割槽

”和“磁碟” , “滑鼠”和“事件” 。device_type就可以標識某個裝置型別和該裝置的特有

資訊,它就等同於kobject結構中的kobj_type一樣。如果name資料成員被指定,那麼uevent成員

函式就會把它包含在DEVTYPE變數中。
9、unsigned is_registered:1;
標識該裝置是否已經被註冊過。is_registered:1這樣的形式表示is_registered這個變數只有一

位。在32位linux系統下,unsigned是4位元組32位,而經過is_registered:1這樣的限制後,變數

is_registered只有一位,其取值只能是1或者0,相當於聲明瞭一個boolean型別的變數。在此種

用法中,後面指定資料寬度的值只能大於0且小於本身的資料寬度。
10、struct bus_type * bus;
指向所連線匯流排的指標。
11、struct device_driver *driver; 
指向被分配到該裝置的裝置驅動。
12、u64 *dma_mask;    /*指向裝置DMA遮蔽字。*/
u64 coherent_dma_mask;/*裝置一致性DMA的遮蔽字。*/
struct list_head dma_pools; /*聚集的DMA緩衝池。*/
struct dma_coherent_mem *dma_mem; /*指向裝置所使用的一致性DMA儲存器描述符的指標*/
13、spinlock_t devres_lock;
定義一個裝置自旋鎖,用於互斥訪問裝置。關於自旋鎖的詳細講解參考:
http://www.deansys.com/doc/ldd3/ch05s05.html
14、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物件的引用計數。

device_driver

系統的每一個驅動程式都由struct device_driver,定義在/include/linux/device.h:
struct device_driver {
        const char              * name; 

 /*裝置驅動程式的名稱。在呼叫driver_register()往裝置驅動程式模型中插入一個新的device_driver物件時,driver_register()函式會呼叫bus_add_driver()函式,bus_add_driver()呼叫kobject_set_name()函式將name賦給drv>kobj.name或者drv->kobj.k_name。注:drv為要呼叫driver_register()註冊的device_driver型別的物件。*/
        struct bus_type         * bus;   //指向匯流排描述符的指標,匯流排連線所支援的裝置
        struct kobject          kobj;     //內嵌的kobject結構,主要用於計數
        struct klist            klist_devices;  
        struct klist_node       knode_bus;
        struct module           * owner;
        const char              * mod_name;     
        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);   //將掛起的驅動恢復執行
};

呼叫函式:

1、driver_register()函式:/linux/drivers/base/driver.c 
int driver_register(struct device_driver * drv)
 {if ((drv->bus->probe && drv->probe) ||(drv->bus->remove && drv->remove) ||(drv->bus->shutdown && drv->shutdown)) 
  {printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods/n", drv->name);}
klist_init(&drv->klist_devices, NULL, NULL);
return bus_add_driver(drv);} 
函式首先是檢查device_driver型別的drv物件和其bus域的回撥函式是否已經被賦值,如果為空,則列印警告。核心的註冊是呼叫bus_add_driver()函式實現。在bus_add_driver()函式中,首先是檢查drv->bus,如果為空可立即返回EINVAL(無效的變數),註冊失敗,可見bus域必須提前初始化好才行。接下來是對kobj域進行初始化,檢查bus域等。最後呼叫add_bind_files()函式(實際上是由add_bind_files()函式呼叫driver_create_file()函式)在sys檔案系統下為其建立一個新的目錄。

2、driver_unregister()函式:/linux/drivers/base/driver.c/linux/drivers/base/driver.c
void driver_unregister(struct device_driver * drv)
{
        bus_remove_driver(drv);
}
呼叫bus_remove_driver在/linux/drivers/base/bus.c:
void bus_remove_driver(struct device_driver * drv)
{
        if (!drv->bus)
                return;

        remove_bind_files(drv);
        driver_remove_attrs(drv->bus, drv);
        klist_remove(&drv->knode_bus);
        pr_debug("bus %s: remove driver %s/n", drv->bus->name, drv->name);
        driver_detach(drv);
        module_remove_driver(drv);
        kobject_unregister(&drv->kobj);
        put_bus(drv->bus);
}

在bus_remove_driver()函式中首先是檢查要解除安裝的device_driver型別的物件drv的bus域,如果為空則返回。此種情況會發生在呼叫driver_register()函式註冊drv時沒有檢查返回值,註冊失敗,但程式依然向下執行,到driver_unregister()時就會到688行處返回。接下來會刪除在呼叫driver_register()函式註冊時在sys檔案系統中建立的目錄,然後刪除drv物件的屬性,(屬性是記錄在檔案中的,刪除屬性其實是刪除記錄drv->bus屬性的檔案),刪除驅動模組,減少對drv->bus的引用計數等。

3、get_driver()和put_driver()函式:分別是增加和減少對該device_drvier型別的物件的引用計數。

4、int driver_create_file(struct device_driver * drv, struct driver_attribute * attr); 

    void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr);

分別是在sys檔案系統中為device_driver物件建立和刪除目錄