platform總線

1.一個重要思想
分離思想:將設備和驅動進行分離,各自管理。直到一端加入到總線,進行匹配。
模型
2、什麼是platform總線?
相對於USB、PCI、I2C、SPI等物理總線來說,platform總線是一種虛擬、抽象出來的總線,實際中並不存在這樣的總線。那爲什麼需要platform總線呢?其實是Linux設備驅動模型爲了保持設備驅動的統一性而虛擬出來的總線。因爲對於usb設備、i2c設備、pci設備、spi設備等等,他們與cpu的通信都是直接掛在相應的總線下面與我們的cpu進行數據交互的,但是在我們的嵌入式系統當中,並不是所有的設備都能夠歸屬於這些常見的總線,在嵌入式系統裏面,SoC系統中集成的獨立的外設控制器、掛接在SoC內存空間的外設卻不依附與此類總線。所以Linux驅動模型爲了保持完整性,將這些設備掛在一條虛擬的總線上(platform總線),而不至於使得有些設備掛在總線上,另一些設備沒有掛在總線上。
platform總線相關代碼聲明:linux/platform_device.h 文件

3、platform總線的兩個重點結構體platform_device和platform_driver
對於任何一種Linux設備驅動模型下的總線都由兩個部分組成:描述設備相關的結構體和描述驅動相關的結構體在platform總線下就是platform_device和platform_driver,下面是對兩個結構體的各個元素進行分析:
(1)platform_device結構體及其中的結構體分析

struct platform_device {           
      const char * name;      //平臺設備的名字
      int id;                 //ID區分設備名字,如果一個驅動對應一個設備,傳-1
      struct device dev;      //描述設備信息device結構體
      u32 num_resources;      //資源結構體數量,資源信息結構體數組的大小
      struct resource * resource; //資源結構體,一般定義一個數組
};
struct device {
    struct device_driver *driver;  //設備驅動的結構體指針
    struct device_node *of_node;   //設備樹節點
    u32 id;	
    void (*release)(struct device *dev);  //設備端卸載的時候,須調用的函數
};
struct resource {
	resource_size_t start;      //起始地址
	resource_size_t end;        //結束地址
	const char *name;           //資源名字
	unsigned long flags;        //標誌 IORESOURCE_IO IORESOURCE_MEM 
                               //IORESOURCE_IRQ
}; 

設備端調用的代碼

int platform_device_register(struct platform_device *pdev);
功能:platfrom平臺總線設備註冊
參數:
    @pdev    platform平臺總線設備端結構體指針
返回值:成功返回0,失敗返回負數錯誤碼

void platform_device_unregister(struct platform_device *); 
功能:platfrom平臺總線設備卸載
參數:
    @pdev    platform平臺總線設備端結構體指針
返回值:成功返回0,失敗返回負數錯誤碼

(2)platform_driver結構體及其中的結構體分析

struct platform_driver {
	int (*probe)(struct platform_device *);   //獲取設備信息,在匹配成功調用
	int (*remove)(struct platform_device *);   //在移除的時候調用
	struct device_driver driver;
	const struct platform_device_id *id_table; //id_table表
};

struct device_driver {
	const char		*name;    //名字  匹配
	struct bus_type		*bus;     //總線信息結構體
	struct module		*owner;   //THIS_MODULE
	const struct of_device_id	*of_match_table;    //設備樹的相關信息
};

struct platform_device_id {
	char name[PLATFORM_NAME_SIZE];   //名字
	kernel_ulong_t driver_dat;
};

驅動端調用的代碼

int platform_driver_register(struct platform_driver *pdrv);
功能:platform平臺總線驅動端註冊函數
參數:
    @pdrv   platform平臺總線驅動端結構體指針
返回值:成功返回0,失敗返回負數錯誤碼    

void platform_driver_unregister(struct platform_driver *);
功能:platform平臺總線驅動端卸載函數
參數:
    @pdrv   platform平臺總線驅動端結構體指針
返回值:成功返回0,失敗返回負數錯誤碼  

重點:
一.platform驅動註冊過程:

platform_driver_register
  --->>>driver_register(&drv->driver);
      --->>>bus_add_driver(drv);
          --->>>driver_attach(drv);   //驅動綁定設備
                  /*遍歷設備端的鏈表,完成匹配*/
              --->>>bus_for_each_dev(drv->bus, NULL, drv,__driver_attach); 
                  --->>>__driver_attach
                      --->>>driver_match_device(drv, dev)
static int platform_match(struct device *dev, struct device_driver *drv)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct platform_driver *pdrv = to_platform_driver(drv);
    /*和設備樹進行匹配*/
	if (of_driver_match_device(dev, drv))
		return 1;

	/* 和id_table表進行匹配 */
	if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* 和名字進行匹配*/
	return (strcmp(pdev->name, drv->name) == 0);
}

二.platform設備端註冊:

platform_device_register
  --->>>platform_device_add(pdev);
    --->>>device_add(&pdev->dev);
       --->>>bus_probe_device(dev);
         --->>>device_attach(dev);
           --->>>bus_for_each_drv(dev->bus, NULL, dev, __device_attach);

以上調用的最後:

**driver_probe_device**

總結:platform平臺總線,設備和驅動在註冊的過程中,都會遍歷對方的鏈表,來查找是否有匹配的,如果有匹配的,就會調用驅動中的probe探測函數,獲取設備信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章