Linux裝置驅動模型摘抄(3)

來源:互聯網
上載者:User

 在Linux裝置驅動模型摘抄(2)中,我們通過追蹤amba_pl011.c中的驅動程式的註冊過程展示了一個裝置如何被統一到Linux統一裝置模型的一個過程,amba_pl011是一個generic的裝置下面我們以Android Goldfish TTY Driver為例,再次說明一下這個過程(/drivers/char/goldfish_tty.c):
       goldfish_tty_init(void)->platform_driver_register(&goldfish_tty);
       platform_driver_register()和goldfish_tty以及相關的定義如下:
      
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;
};

struct goldfish_tty {
        spinlock_t lock;
        uint32_t base;
        uint32_t irq;
        int opencount;
        struct tty_struct *tty;
        struct console console;
};

static struct platform_driver goldfish_tty = {
        .probe = goldfish_tty_probe,
        .remove = goldfish_tty_remove,
        .driver = {
                .name = "goldfish_tty"
        }
};

struct bus_type platform_bus_type = {
        .name           = "platform",
        .dev_attrs      = platform_dev_attrs,
        .match          = platform_match,
        .uevent         = platform_uevent,
        .suspend        = platform_suspend,
        .suspend_late   = platform_suspend_late,
        .resume_early   = platform_resume_early,
        .resume         = platform_resume,
};
int driver_register(struct device_driver *drv)
{
        int ret;

        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);
        ret = bus_add_driver(drv);
        if (ret)
                return ret;
        ret = driver_add_groups(drv, drv->groups);
        if (ret)
                bus_remove_driver(drv);
        return ret;
}
int platform_driver_register(struct platform_driver *drv)
{
        drv->driver.bus = &platform_bus_type;
        if (drv->probe)
                drv->driver.probe = platform_drv_probe;
        if (drv->remove)
                drv->driver.remove = platform_drv_remove;
        if (drv->shutdown)
                drv->driver.shutdown = platform_drv_shutdown;
        if (drv->suspend)
                drv->driver.suspend = platform_drv_suspend;
        if (drv->resume)
                drv->driver.resume = platform_drv_resume;
        return driver_register(&drv->driver);
}
    從這些代碼我們可以看出一條調用路徑如下:
platform_driver_register->driver_register->bus_add_driver->bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)->__driver_attach->really_probe
    really_probe->driver_sysfs_add(dev)->sysfs_create_link 在/sys/drivers/裡面/sys/dev/下面建立連結
                        ->dev->bus->probe(dev) ? 找不到可以調用的合適函數
                        ->drv->probe(dev)->platform_drv_probe->goldfish_tty_probe(); //

   從這個分析可以看出,(2)和(3)還是不同的,(2)使用兩次register來先註冊uart協議,再註冊amba匯流排,但是在(3)裡面,使用platform_driver_register(struct platform_driver)這樣一次性註冊,至於Bus和protocol的問題,在後面用probe方式回呼函數解決。

      最後一個問題,關於probe的過程,我們可以發現在goldfish_tty_probe裡面,關鍵性的函數是platform_get_resource(),這個函數可以擷取該裝置的base_addr和irq。但是platform_get_resource的過程依賴於在初始化階段的request_resource函數,如arch/arm/kernel/setup.c中所示。還有另外一種形式是resource直接賦值,例如:
   static struct resource udc_resources[] = {
        [0] = {
                .start = AT91RM9200_BASE_UDP,
                .end    = AT91RM9200_BASE_UDP + SZ_16K - 1,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
                .start = AT91RM9200_ID_UDP,
                .end    = AT91RM9200_ID_UDP,
                .flags = IORESOURCE_IRQ,
        },
};
static struct platform_device at91rm9200_udc_device = {
        .name           = "at91_udc",
        .id             = -1,
        .dev            = {
                                .platform_data          = &udc_data,
        },
        .resource       = udc_resources,
        .num_resources = ARRAY_SIZE(udc_resources),
};
    關於platform_device中的id是這樣的,如果id==-1,那麼這個裝置的名字就是定義的名字,如上所示,就是at91_udc,但是如果不是-1,那麼名字的格式將是name.id這個樣子,可能表示同樣的名字可以有多個裝置吧。
     直接用udc_resources給platform_device賦值,然後用probe來檢查這個裝置,找出一個可用的。

        在最後,我們再來看看這些結構體之間的關係:
   struct platform_device {
        const char      * name;
        int             id;
        struct device   dev;
        u32             num_resources;
        struct resource * resource;
};
struct resource {
        resource_size_t start;
        resource_size_t end;
        const char *name;
        unsigned long flags;
        struct resource *parent, *sibling, *child;
};
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;
};
      因此platform_driver類似device_driver, platform_device類似device, 關於他們之間的轉換,有下面函數可供參考:
        struct platform_driver *drv = to_platform_driver(struct *device->driver);
        struct platform_device *dev = to_platform_device(struct *device)

#define to_platform_driver(drv) (container_of((drv), struct platform_driver, driver))
#define to_platform_device(x) container_of((x), struct platform_device, dev)
    看這2個宏,我們就會發現,(3)比起(2)來,抽象程度似乎更高一些,統一性應該更好一些。而且在比較複雜的驅動如MMC,USB等裡面,使用platform_device和platform_driver也越來越多了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.