platform总线、设备、驱动模型之led驱动实例

原创 2016年05月30日 16:23:04

Linux 2.6 的设备驱动模型中,关心总线、设备和驱动这 3 个实体,总线将设备和驱动绑定。在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。

注意,所谓的platform_device并不是与字符设备、块设备和网络设备并列的概念,而是 Linux系统提供的一种附加手段


platform.device结构体
1 struct platform_device {
2 const char * name; / * 设备名 */
3 u32 id;
4 struct device dev;
5 u32 num_resources; / * 设备所使用各类资源数量 */
6 struct resource * resource; / * 资源 */
7 };


platform_driver 这个结构体中包含 probe()remove()shutdown()suspend()resume()函数,通常也需要由驱动实现。
1 struct platform_driver {
2 int (*probe)(struct platform_device *);
3 int (*remove)(struct platform_device *);
4 void (*shutdown)(struct platform_device *);
5 int (*suspend)(struct platform_device *, pm_message_t state);
6 int (*suspend_late)(struct platform_device *, pm_message_t state);
7 int (*resume_early)(struct platform_device *);
8 int (*resume)(struct platform_device *);
9 struct pm_ext_ops *pm;
10 struct device_driver driver;
11};



系统中为platform 总线定义了一个 bus_type 的实例 platform_bus_type。
1 struct bus_type platform_bus_type = {
2 .name = "platform",
3 .dev_attrs = platform_dev_attrs,
4 .match = platform_match,
5 .uevent = platform_uevent,
6 .pm = PLATFORM_PM_OPS_PTR,
7 };
8 EXPORT_SYMBOL_GPL(platform_bus_type);


这里要重点关注其match()成员函数,正是此成员函数确定了platform_device platform_driver之间如何匹配。
1 static int platform_match(struct device *dev, struct device_driver *drv)
2 {
3 struct platform_device *pdev;
4
5 pdev = container_of(dev, struct platform_device, dev);
6 return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
7 }

匹配platform_device platform_driver 主要看两者的 name字段是否相同。

匹配实例:以触摸屏驱动分析;
平台设备部分:


平台设备列表:

将设备结构s3c_device_ts 注册进内核:


平台驱动部分;

内核启动过程中, 当平台设备的名字“ s3c64xx-ts” 和平台驱动 ID 列表成员的名字匹配时, probe函数被执行,这里是函数 s3c2410ts_probe()。

platform_device 的定义通常在 BSP 的板文件中实现,在板文件中,将 platform_device归纳为一个数组,最终通过platform_add_devices()函数统一注册。platform_add_devices()函数可以将平台设备添加到系统中,这个函数的原型为:
int platform_add_devices(struct platform_device **devs, int num);

该函数的第一个参数为平台设备数组的指针,第二个参数为平台设备的数量,它内部调用了platform_device_register()函数用于注册单个的平台设备

platform_device结构体定义的第 56行,描述了 platform_device的资源,资源本身由 resource 结构体描述:
1 struct resource {
2 resource__size_t start;
3 resource_size_t end;
4 const char *name;
5 unsigned long flags;
6 struct resource *parent, *sibling, *child;
7 };


设备驱动中引入platform 的概念至少有如下两大好处:
1)使得设备被挂接在一个总线上,因此,符合Linux 2.6 的设备模型。其结果是,配套的sysfs 结点、设备电源管理都成为可能。
2)隔离 BSP 和驱动。在 BSP 中定义 platform 设备和设备使用的资源、设备的具体配置信息,而在驱动中,只需要通过通用API 去获取资源和数据,做到了板相关代码和驱动代码的分离,使得驱动具有更好的可扩展性和跨平台性。



led platform驱动实例:

led_dev.c:定义资源
#include <linux/module.h>
#include <linux/version.h>

#include <linux/init.h>

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>


/* 分配/设置/注册一个platform_device */

static struct resource led_resource[] = {
    [0] = {
        .start = 0xE0200C40,
        .end   = 0xE0200C40 + 8 - 1,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = 4,
        .end   = 4,
        .flags = IORESOURCE_IRQ,
    }

};

static void led_release(struct device * dev)
{
}


static struct platform_device led_dev = {
    .name         = "<span style="color:#ff6666;">myled</span>",
    .id       = -1,
    .num_resources    = ARRAY_SIZE(led_resource),
    .resource     = led_resource,
    .dev = { 
    	.release = led_release, 
	},
};

static int led_dev_init(void)
{
	platform_device_register(&led_dev);
	return 0;
}

static void led_dev_exit(void)
{
	platform_device_unregister(&led_dev);
}

module_init(led_dev_init);
module_exit(led_dev_exit);

MODULE_LICENSE("GPL");



led_drv.c驱动程序:
/* 分配/设置/注册一个platform_driver */

#include <linux/module.h>
#include <linux/version.h>

#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>

static int major;


static struct class *cls;
static volatile unsigned long *gpio_con;
static volatile unsigned long *gpio_dat;
static int pin;


static int leds_open(struct inode *inode, struct file *file)
{
    printk("led_open\n");

	*gpio_con = 0x11111111;
	
    return 0;
}



static long leds_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) 
{  
	printk("use ioctl\n");
	
	
	if(cmd == 1){
		printk("arg = = %d\n",arg);
		printk("cmd = = %d\n",cmd);
		*gpio_dat =0x1f;// ~(0<<4);
		printk("gpio_dat == %0x\n",*gpio_dat);
	}
	else
   		*gpio_dat &= 0x00;
} 


static struct file_operations led_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
	.open    = leds_open,
    .unlocked_ioctl = leds_ioctl,
};

static int led_probe(struct platform_device *pdev)
{

	struct resource *res;

	res = platform_get_resource(pdev,IORESOURCE_MEM,0);
	gpio_con = ioremap(res->start,res->end - res->start + 1);
	gpio_dat = gpio_con + 1;

	res = platform_get_resourse(pdev,IORESOURCE_IRQ,0);
	pin = res -> start;

	printk("led probe\n");

	major = register_chrdev(0 , "myled", &led_fops);

	cls = class_create(THIS_MODULE,"myled");

	class_device_create(cls,NULL,MKDEV(major,0),NULL,"led");
	
	return 0;
}

static int led_remove(struct platform_device *pdev)
{
	printk("led remove\n");
	
	return 0;
}


struct platform_driver led_drv = {
	.probe		= led_probe,
	.remove		= led_remove,
	.driver		= {
		.name	= "<span style="color:#ff6666;">myled</span>",
	}
};


static int led_drv_init(void)
{
	platform_driver_register(&led_drv);
	return 0;
}

static void led_drv_exit(void)
{
	platform_driver_unregister(&led_drv);
}

module_init(led_drv_init);
module_exit(led_drv_exit);

MODULE_LICENSE("GPL");




内核启动过程中, 当平台设备的名字“myled"驱动 ID 列表成员的名字匹配时, probe函数被执行,这里是函数 s3c2410ts_probe()








linux平台总线驱动设备模型之点亮LED

上一节中,我们引入Linux input子系统的分离分层概念,发现这样的架构特别容易移植,因为有一部分是已经相对稳定,它已经把公共的部分抽象出来,不用驱动工程师再去修改,只需要添加符合输入设备的设备驱...

ok6410学习笔记(15.platform平台总线驱动模型之混杂设备驱动led)

本节知识点: 1.这里就一个知识点设备资源: 设备资源前面说过,这里就不多说了 主要说说,在platform模型中,设备资源是定义在device模块中的,而使用是在driver模块中pr...

字符设备驱动之LED-平台设备驱动(platform设备驱动)

怎么利用平台设备驱动机制来写驱动: ------------------------------------------------------------------------- 1.先实现设...

君正X系列开发---GPIO在用户空间使用&platform_device驱动&gpiolib库的使用5

可以通过导出gpio sys节点到用户空间,在用户空间操作。 内核的gpio驱动基于gpio子系统的实现,所以其他驱动程序可以通过内核提供的 libgpio 接口很方面的控制,例如,gpio_r...

platform总线和普通总线,驱动模型间的一些关系和理解

(本原创文章发表于Sailor_forever 的个人blog,未经本人许可,不得用于商业用途。任何个人、媒体、其他网站不得私自抄袭;网络媒体转载请注明出处,增加原文链接,否则属于侵权行为。如 有任何...

Linux 设备驱动开发 —— platform设备驱动应用实例解析

前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 —— platform 设备驱动 ,下面将通过一个实例来深入我们的学习。         一、platform 驱动的工作过程...

Linux Platform驱动模型(二) _驱动方法

在Linux设备树语法详解和Linux Platform驱动模型(一) _设备信息中我们讨论了设备信息的写法,本文主要讨论平台总线中另外一部分-驱动方法,将试图回答下面几个问题: 如何填充pla...

platform_driver_register( )过程追踪

以下代码源于linux3.1.9。 platform_driver_register( ) 是内核中非常著名的函数 。platform_driver_register( )负责注册平台驱动程序,...

BootStrap运行流程解析

       基于ARM的嵌入式系统的启动都需要引导程序,引导过程可以有两种,一种是先运行小型的bootstrap完成所谓的low level初始化,再调用如Uboot,RedBOOT等功能强大的引导...
  • cskywit
  • cskywit
  • 2010年11月02日 15:41
  • 5239

linux驱动模型开发——linux platform总线机制讲解与实例开发

1、概述: 通常在Linux中,把SoC系统中集成的独立外设单元(如:I2C、IIS、RTC、看门狗等)都被当作平台设备来处理。 从Linux2.6起,引入了一套新的驱动管理和注册机制:P...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:platform总线、设备、驱动模型之led驱动实例
举报原因:
原因补充:

(最多只允许输入30个字)