歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux設備驅動之platform

根據Linux設備模型可知,一個現實的Linux設備和驅動通常都需要掛接在一種總線上,對於本身依附於PCI、USB等的設備而言,這自然不是問題,但是在嵌入式系統裡面,SoC系統中集成的獨立的外設控制器、掛接在 SoC 內存空間的外設等卻不依附於此類總線。基於這一背景,Linux設計了一種虛擬的總線,稱為platform總線,相應的設備稱為platform_device,而驅動稱為platform_driver。


設計目的

  • 兼容設備模型

    使得設備被掛接在一個總線上,因此,符合 Linux 2.6 的設備模型。其結果是,配套的sysfs結點、設備電源管理都成為可能。
  • BSP和驅動隔離

    在BSP中定義platform設備和設備使用的資源、設備的具體配置信息。而在驅動中,只需要通過通用API去獲取資源和數據,做到了板相關代碼和驅動代碼的分離,使得驅動具有更好的可擴展性和跨平台性。

軟件架構

內核中Platform設備有關的實現位於include/linux/platform_device.h和drivers/base/platform.c兩個文件中,它的軟件架構如下:

由圖片可知,Platform設備在內核中的實現主要包括三個部分:

  • Platform Bus,基於底層bus模塊,抽象出一個虛擬的Platform bus,用於掛載Platform設備;
  • Platform Device,基於底層device模塊,抽象出Platform Device,用於表示Platform設備;
  • Platform Driver,基於底層device_driver模塊,抽象出Platform Driver,用於驅動Platform設備。

platform_device

注意,所謂的platform_device並不是與字符設備、塊設備和網絡設備並列的概念,而是Linux系統提供的一種附加手段,例如,在S3C2440處理器中,把內部集成的I2C、RTC、SPI、LCD、看門狗等控制器都歸納為platform_device,而它們本身就是字符設備。

/* defined in <linux/platform_device.h> */
struct platform_device {
    const char * name; / * 設備名 */
    u32 id; /* 用於標識該設備的ID */
    struct device dev; /* 真正的設備(Platform設備只是一個特殊的設備,因此其核心邏輯還是由底層的模塊實現)*/
    u32 num_resources; / * 設備所使用各類資源數量 */
    struct resource * resource; / * 資源 */
};

/* defined in <linux/ioport.h> */
struct resource {
    resource_size_t start; /* 資源起始 */
    resource_size_t end; /* 結束 */
    const char *name;
    unsigned long flags; /* 類型 */
    struct resource *parent, *sibling, *child;
};
/* 設備驅動獲取BSP定義的resource */
struct resource *platform_get_resource(struct platform_device *, unsigned int flags, unsigned int num);

#include <linux/platform_device.h>
int platform_device_register(struct platform_device *);   
void platform_device_unregister(struct platform_device *);

Tip: 和板級緊密相關的資源描述放在dev.paltform_data中。

paltform_driver

platform_driver這個結構體中包含probe()、remove()、shutdown()、suspend()、resume()函數,通常也需要由驅動實現:

struct platform_driver {
    int (*probe)(struct platform_device *);
    int (*remove)(struct platform_device *);
    void (*shutdown)(struct platform_device *);
    int (*suspend)(struct platform_device *, pm_message_t state);
    int (*suspend_late)(struct platform_device *, pm_message_t state);
    int (*resume_early)(struct platform_device *);
    int (*resume)(struct platform_device *);
    struct device_driver driver;
};

#include <linux/platform_device.h>
int platform_driver_register(struct platform_driver *);   
void platform_driver_unregister(struct platform_driver *);

platform_bus

系統中為platform總線定義了一個bus_type的實例platform_bus_type:

struct bus_type platform_bus_type = {
    .name = "platform",
    .dev_attrs = platform_dev_attrs,
    .match = platform_match,
    .uevent = platform_uevent,
    .pm = PLATFORM_PM_OPS_PTR,
};
EXPORT_SYMBOL_GPL(platform_bus_type);

這裡要重點關注其 match()成員函數,正是此成員函數確定了 platform_device 和 platform_driver之間如何匹配:

static int platform_match(struct device *dev, struct device_driver *drv)
{
    struct platform_device *pdev;
    pdev = container_of(dev, struct platform_device, dev);
    return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}

Copyright © Linux教程網 All Rights Reserved