Linux 驅動platform (驅動架構理解)

前言:對於博客,由於能力有限,很多問題都是自己的學習過程和筆記,現在還沒有能力說下自己的獨特見解;

前面的幾個博客都記錄了自己對Linux設備驅動的基礎知識,但是現實中的Linux驅動不是那個樣子的,要複雜的多些。簡單的驅動是device 和driver 一對一的結合,但是現實中一種驅動driver可能夠被多個device使用,總不能給一個設備單獨寫一個獨特的driver吧,Linux驅動架構出現了platform平臺,一般稱爲虛擬總線。platform就是把device和driver聯繫起來,實現驅動的重複使用。platform不是一個具體的實物總線,它是虛擬的用來管理設備和多功能的匹配關係的,這點理解很重要。

一、 瞭解兩個結構體:

(1)struct platform_device ,更好的來管理(RTC,LCD等設備);包含struct devicedev;

(2)struct platform_drivver, 更好的管理設備驅動,包含設備驅動結構體struct device_driver driver;

上面的兩個結構體是對簡單的驅動 device 和driver的更好的封裝,增加了更多的屬性信息。

注意:platform_driver地位對等的i2c_driver、spi_driver、usb_driver、pci_driver中都包含了device_driver結構體實例成員。它其實描述了各種xxx_driver(xxx是總線名)在驅動意義上的一些共性;

二、Linux的platform把不同的設備和驅動附在了一起,但是要實現特性設備的驅動,是通過1struct bus_type platform_bus_type 的成員match()函數實現的,match函數的功能是實現通過設備樹、ACPI、匹配ID表、設備名和驅動的名字四種匹配方法;

三、具體的使用platform_device是在板級支持包BSP文件中註冊,int platform_add_devices(struct platform_device **devs, int num);實際上是調用了platform_device_register()函數來註冊平臺設備。linux3.x之後可以使用設備樹註冊設備。

四、使用虛擬總線實現設備驅動程序:

我們以globalfifo爲例:

(1)probe函數:

static int globalfifo_probe(struct platform_device *pdev)
{
int ret;
dev_t devno = MKDEV(globalfifo_major, 0);

 if (globalfifo_major)
 ret = register_chrdev_region(devno, 1, "globalfifo");
 else {
 ret = alloc_chrdev_region(&devno, 0, 1, "globalfifo");
 globalfifo_major = MAJOR(devno);
 }
 if (ret < 0)
 return ret;

 globalfifo_devp = devm_kzalloc(&pdev->dev, sizeof(*globalfifo_devp),GFP_KERNEL);
 if (!globalfifo_devp) {
 ret = -ENOMEM;
 goto fail_malloc;
 }

 globalfifo_setup_cdev(globalfifo_devp, 0);

 mutex_init(&globalfifo_devp->mutex);
 init_waitqueue_head(&globalfifo_devp->r_wait);
 init_waitqueue_head(&globalfifo_devp->w_wait);
 return 0;

fail_malloc:
     unregister_chrdev_region(devno, 1);
    return ret;
}

(2)remove函數

static int globalfifo_remove(struct platform_device *pdev)
{
     cdev_del(&globalfifo_devp->cdev);
     unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1);

     return 0;
}

(3)platform_driver實現:

static struct platform_driver globalfifo_driver = {
 .driver = {
 .name = "globalfifo",
 .owner = THIS_MODULE,
},
 .probe = globalfifo_probe,
 .remove = globalfifo_remove,
};

module_platform_driver(globalfifo_driver);

(4)platform_device的實現(注意,這個在BSP的平臺文件中實現)

static struct platform_device globalfifo_device = {
    .name = "globalfifo",
    3 .id = -1,
};

(5)module_platform_driver()宏所定義的模塊加載和卸載函數僅僅通過platform_driver_register()、platform_driver_unregister()函數進行platform_driver的註冊與註銷。

 

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