platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。

  platform_match函数首先判断是否有id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数,其中对资源进行get、ioremap再注册驱动。

LED总线设备驱动模型程序示例:

1.device:主要设置硬件相关资源

/*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[] = {
[] = {
.start = 0x56000050, //led控制寄存器地址
.end = 0x56000050 + - ,
.flags = IORESOURCE_MEM, //内存资源
},
[] = {
.start = , //设置引脚号
.end = ,
.flags = IORESOURCE_IRQ, //中断资源
}
}; static void led_release(struct device * dev)
{
  //框架需求要设置一个release函数,不然会报错
} static struct platform_device led_dev = {
.name = "myled",
.id = -,
.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 ;
} static void led_dev_exit(void)
{
platform_device_unregister(&led_dev);
} module_init(led_dev_init);
module_exit(led_dev_exit); MODULE_LICENSE("GPL");

2.driver:注册平台驱动,匹配上设备后调用probe函数:获取device资源,分配、设置、注册字符设备,实现对设备的操作函数(open,read,write)

/*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 led_open(struct inode *inode, struct file *file)
{
//printk("first_drv_open\n");
/* 配置为输出 */
*gpio_con &= ~(0x3<<(pin*));
*gpio_con |= (0x1<<(pin*));
return ;
} static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
int val; //printk("first_drv_write\n"); copy_from_user(&val, buf, count); // copy_to_user(); if (val == )
{
// 点灯
*gpio_dat &= ~(<<pin);
}
else
{
// 灭灯
*gpio_dat |= (<<pin);
} return ;
} static struct file_operations led_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = led_open,
.write = led_write,
}; static int led_probe(struct platform_device *pdev)
{
struct resource *res; /* 根据platform_device的资源进行ioremap */
res = platform_get_resource(pdev, IORESOURCE_MEM, );
gpio_con = ioremap(res->start, res->end - res->start + );
gpio_dat = gpio_con + ; res = platform_get_resource(pdev, IORESOURCE_IRQ, );
pin = res->start; /* 注册字符设备驱动程序 */ printk("led_probe, found led\n"); major = register_chrdev(, "myled", &led_fops);
  //第一个参数指定类的所有者是哪个模块,第二个参数指定类名。
cls = class_create(THIS_MODULE, "myled");
  //第一个参数指定所要创建的设备所从属的类,第二个参数是这个设备的父设备,如果没有就指定为NULL,第三个参数是设备号,第四个参数是供回调使用的数据,第五个参数是设备名字。
class_device_create(cls, NULL, MKDEV(major, ), NULL, "led"); /* 自动创建设备节点/dev/led(也可手动mknod),新版为device_create(...)*/ return ;
} static int led_remove(struct platform_device *pdev)
{
/* 卸载字符设备驱动程序 */
/* iounmap */
printk("led_remove, remove led\n"); class_device_destroy(cls, MKDEV(major, ));
class_destroy(cls);
unregister_chrdev(major, "myled");
iounmap(gpio_con); return ;
} struct platform_driver led_drv = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "myled",
}
}; static int led_drv_init(void)
{
platform_driver_register(&led_drv);
return ;
} static void led_drv_exit(void)
{
platform_driver_unregister(&led_drv);
} module_init(led_drv_init);
module_exit(led_drv_exit); MODULE_LICENSE("GPL");

3.测试应用程序:

/*led_test.c*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h> /* led_test on
* led_test off
*/
int main(int argc, char **argv)
{
int fd;
int val = ;
fd = open("/dev/led", O_RDWR);
if (fd < )
{
printf("can't open!\n");
}
if (argc != )
{
printf("Usage :\n");
printf("%s <on|off>\n", argv[]);
return ;
} if (strcmp(argv[], "on") == )
{
val = ;
}
else
{
val = ;
} write(fd, &val, );
return ;
}

4.Makefile

KERN_DIR = /work/system/linux-2.6.22.6

all:
make -C $(KERN_DIR) M=`pwd` modules clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order obj-m += led_drv.o
obj-m += led_dev.o

最新文章

  1. 关于ReSharper
  2. Sharepoint学习笔记—习题系列--70-576习题解析 -(Q147-Q151)
  3. Power of Three
  4. poi 导出 excel
  5. HTML5----响应式(自适应)网页设计
  6. 终结者单身——setAccessible(true)
  7. HTML-input标签需设置的属性
  8. Docker----起步
  9. http://www.runoob.com/lua/lua-basic-syntax.html
  10. 基于kettle的简单HTTP接口监控
  11. fastJson--json与java格式的转换
  12. hibernate JPA 使用懒加载时代理对象
  13. Lucene的深入
  14. 配置JAVA 环境变量
  15. Visual Studio 2012自动添加注释(如版权信息等)
  16. /etc/tolmcat/Server.xml 实例说明
  17. 数据导入(一):Hive On HBase
  18. 深入理解JVM一垃圾回收器
  19. CC+语言 struct 深层探索——CC + language struct deep exploration
  20. [Leetcode] valid palindrome 验证回文

热门文章

  1. 关于Python中的ifelse、while和for循环的简单小结
  2. WAMP环境配置
  3. Python 编程快速上手 第十七章 操作图像
  4. HTML第十四章总结 HTML forms
  5. Android+Struts2实现简单的前后台交互--Android网络编程
  6. 2018-02-16 GetSameTypeQuestion
  7. android -------- Lint优化工具
  8. Vue自动化工具(Vue-CLI)的安装
  9. 优先队列优化dij算法
  10. 6月17 ThinkPHP连接数据库------数据的修改及删除