platform平台总线
?
一、platform設備模型
從Linux 2.6起引入了一套新的驅動管理和注冊機制,platform_device和platform_driver,Linux中大部分的設備驅動都可以使用這套機制。platform是一條虛擬總線。設備用platform_device表示,驅動用platform_driver進行注冊,linux platform driver機制和傳統的device driver機制(通過driver_register進行注冊)相比,一個明顯的優勢在于platform機制將設備本身的資源注冊進內核,由內核統一管理,在驅動中使用這些資源時通過platform device提供的標準結構進行申請并使用。這樣提高了驅動和資源的獨立性,并且具有較好的可移植性和安全性(這些標準接口是安全的)。當我們將設備和驅動注冊到虛擬總線上(內核)時,會互相尋找一次對方。如果device和driver中的name這個字符串是想相同的話platform_bus就會調用driver中的.probe函數。設備和驅動的關系是多對一的關系,即多個相同設備可使用一個driver,靠device(設備)中的id號來區別。
通過platform機制開發底層驅動的大致流程為:
定義platform_deviece -->注冊platform_device -->定義platform_driver --> 注冊platform_driver。
?
二、注冊platform_device
在內核源碼中添加arch/arm/mach-s5pv210/include/mach/leds-gpio.h文件
/* arch/arm/mach-s5pv210/include/mach/leds-gpio.h** Copyright (c) 2006 Simtec Electronics* http://armlinux.simtec.co.uk/* Ben Dooks <ben@simtec.co.uk>** s5pv210 - LEDs GPIO connector** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License version 2 as* published by the Free Software Foundation. */#ifndef __ASM_ARCH_LEDSGPIO_H #define __ASM_ARCH_LEDSGPIO_H "leds-gpio.h"#define S5PV210_LEDF_ACTLOW (1<<0) /* LED is on when GPIO low */ #define S5PV210_LEDF_TRISTATE (1<<1) /* tristate to turn off */struct s5pv210_led_platdata {unsigned int gpio;unsigned int flags;char *name;char *def_trigger; };#endif /* __ASM_ARCH_LEDSGPIO_H */在內核arch/arm/mach-s5pv210/mach-x210.c文件中添加如下代碼
/* LEDS */ static struct s5pv210_led_platdata x210_led1_pdata = {.name = "led1",.gpio = S5PV210_GPJ0(3),.flags = S5PV210_LEDF_ACTLOW | S5PV210_LEDF_TRISTATE,.def_trigger = "", };static struct s5pv210_led_platdata x210_led2_pdata = {.name = "led2",.gpio = S5PV210_GPJ0(4),.flags = S5PV210_LEDF_ACTLOW | S5PV210_LEDF_TRISTATE,.def_trigger = "", };static struct s5pv210_led_platdata x210_led3_pdata = {.name = "led3",.gpio = S5PV210_GPJ0(5),.flags = S5PV210_LEDF_ACTLOW | S5PV210_LEDF_TRISTATE,.def_trigger = "", };static struct platform_device x210_led1 = {.name = "s5pv210_led",.id = 0,.dev = {.platform_data = &x210_led1_pdata,}, };static struct platform_device x210_led2 = {.name = "s5pv210_led",.id = 1,.dev = {.platform_data = &x210_led2_pdata,}, };static struct platform_device x210_led3 = {.name = "s5pv210_led",.id = 2,.dev = {.platform_data = &x210_led3_pdata,}, };static struct platform_device *smdkc110_devices[] __initdata = {...&x210_led1,&x210_led2,&x210_led3, };重新編譯內核,三個led設備就會被注冊到platform中,在/sys/bus/platform/devices中可以進行查看
?
三、注冊platform_driver
#include <linux/module.h> #include <linux/init.h> #include <linux/leds.h> #include <mach/gpio.h> #include <linux/platform_device.h> #include <mach/leds-gpio.h> #include <linux/slab.h>struct s5pv210_gpio_led {struct led_classdev cdev;struct s5pv210_led_platdata *pdata; };static inline struct s5pv210_gpio_led *pdev_to_gpio(struct platform_device *dev) {return platform_get_drvdata(dev); }static inline struct s5pv210_gpio_led *to_gpio(struct led_classdev *led_cdev) {return container_of(led_cdev, struct s5pv210_gpio_led, cdev); }static void s5pv210_led_set(struct led_classdev *led_cdev, enum led_brightness value) {struct s5pv210_gpio_led *led = to_gpio(led_cdev);struct s5pv210_led_platdata *pd = led->pdata;printk(KERN_INFO "s5pv210_led_set\n");/* 設置gpio狀態 */if (value == LED_OFF)gpio_set_value(pd->gpio, 1);elsegpio_set_value(pd->gpio, 0); }static int s5pv210_led_probe(struct platform_device *dev) {struct s5pv210_led_platdata *pdata = dev->dev.platform_data;struct s5pv210_gpio_led *led;int ret = -1;printk(KERN_INFO "s5pv210_led_probe\n");led = kzalloc(sizeof(struct s5pv210_gpio_led), GFP_KERNEL);if (led == NULL) {dev_err(&dev->dev, "No memory for device\n");return -ENOMEM;}platform_set_drvdata(dev, led);/* 申請gpio資源 */if (gpio_request(pdata->gpio, pdata->name)){printk(KERN_ERR "gpio_request failed\n");return -EINVAL;}/* 設置gpio方向為輸出 */gpio_direction_output(pdata->gpio, 1);led->cdev.name = pdata->name;led->cdev.brightness = 0; led->cdev.brightness_set = s5pv210_led_set;led->pdata = pdata;/* 注冊led設備 */ret = led_classdev_register(&dev->dev, &led->cdev);if (ret < 0) {printk(KERN_ERR "led_classdev_register failed\n");return ret;}return 0; }static int s5pv210_led_remove(struct platform_device *dev) {struct s5pv210_gpio_led *led = pdev_to_gpio(dev);struct s5pv210_led_platdata *pd = led->pdata;/* 注銷led設備 */led_classdev_unregister(&led->cdev);/* 釋放gpio資源 */gpio_free(pd->gpio);kfree(led);return 0; }static struct platform_driver s5pv210_led_driver = {.probe = s5pv210_led_probe,.remove = s5pv210_led_remove,.driver = {.name = "s5pv210_led",.owner = THIS_MODULE,}, };static int __init s5pv210_led_init(void) {return platform_driver_register(&s5pv210_led_driver); }static void __exit s5pv210_led_exit(void) {platform_driver_unregister(&s5pv210_led_driver); }module_init(s5pv210_led_init); module_exit(s5pv210_led_exit);// MODULE_xxx這種宏作用是用來添加模塊描述信息 MODULE_LICENSE("GPL"); // 描述模塊的許可證 MODULE_AUTHOR("lsm"); // 描述模塊的作者 MODULE_DESCRIPTION("s5pv210 led driver"); // 描述模塊的介紹信息 MODULE_ALIAS("s5pv210_led"); // 描述模塊的別名信息加載驅動之后,在/sys/bus/platform/drivers中可以進行查看
?
四、測試
加載好led驅動之后,進入/sys/class/leds
?
?
新人創作打卡挑戰賽發博客就能抽獎!定制產品紅包拿不停!總結
以上是生活随笔為你收集整理的platform平台总线的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 柱状图用腻了?玉玦图给你更美的数据呈现
- 下一篇: 送书!1991-2018,区块链的那点事