linux驱动开发之platform平台总线的编程(一)
2018-01-29 21:45
666 查看
总线分成三部分:
bus
driver
device
什么时候用平台总线
1, 只要有设备的地址和中断都可以用平台总线
2, 如果写的驱动需要在多个平台中升级使用
3, 平台总线只是一个功能代码:将操作方法和操作资源进行了分离。
注意:平台总线不属于子系统,只是一个功能。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201801/29/a139d2a1de7c6b3d5760a36c77902649)
图1 platform总线模型
(1)平台总线:struct bus_type总线对象
(2)pdev
(3)pdrv
注册和注销:
extern int platform_driver_register(struct platform_driver *);
extern void platform_driver_unregister(struct platform_driver *);
下面写设备程序plat_led_dev.c
接下来写驱动程序plat_led_drv.c
其中,platform_driver结构体中,
probe中要做事情:(下一个博客里面写)
//为用户提供接口
0, 实例化全局的设备对象– kzalloc
1, 申请主设备号—register_chrdev
2, 自动创建设备节点—class_create, device_create
3, 初始化硬件–ioremap
4,实现 file_operation
5,拿到pdev中的资源对硬件进行初始化
Makefile
这里,在开发板转载程序,可以不分先后顺序。
insmod plat_led_dev.ko
insmod plat_led_drv.ko
![](https://oscdn.geek-share.com/Uploads/Images/Content/201801/29/b9988c9320fbb992c0267de74dc2bdd8)
并且可以看到开发板上的两个LED灯亮了。
可在/sys/bus/platform/中查看程序是否成功加载到总线
程序代码:led_plat_v1.rar(链接:https://pan.baidu.com/s/1i5XRNHr 密码:qbx2)
bus
driver
device
什么时候用平台总线
1, 只要有设备的地址和中断都可以用平台总线
2, 如果写的驱动需要在多个平台中升级使用
3, 平台总线只是一个功能代码:将操作方法和操作资源进行了分离。
注意:平台总线不属于子系统,只是一个功能。
图1 platform总线模型
(1)平台总线:struct bus_type总线对象
struct bus_type platform_bus_type = { .name = "platform", .dev_attrs = platform_dev_attrs, .match = platform_match, //匹配方法 .uevent = platform_uevent, .pm = &platform_dev_pm_ops, };
(2)pdev
// 描述一个设备的信息 struct platform_device { const char * name; // 名字,用于匹配 int id; // 表示不同寄存器组的编号, 一般可以填-1 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; };
注册: int platform_device_register(struct platform_device *); 注销: void platform_device_unregister(struct platform_device *);
(3)pdrv
struct platform_driver { int (*probe)(struct platform_device *); //表示匹配之后的函数 int (*remove)(struct platform_device *); //解除匹配 struct device_driver driver; //父类 const struct platform_device_id *id_table; //可以匹配列表 };
注册和注销:
extern int platform_driver_register(struct platform_driver *);
extern void platform_driver_unregister(struct platform_driver *);
下面写设备程序plat_led_dev.c
#include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> //设备程序 #define LED_GPC0_CONF 0xE0200060 #define LED_GPC0_SIZE 8 //这里描述多个设备 struct resource led_resource[] = { [0] = { .start = LED_GPC0_CONF, .end = LED_GPC0_CONF + LED_GPC0_SIZE -1,//寄存器从0开始计算,所以要减1 .flags = IORESOURCE_MEM, //表示内存资源 }, // 以下部分为演示部分 [1] = { .start = 8888, .end = 8888, //中断是没有连续性的 .flags = IORESOURCE_IRQ, //表示中断资源 }, [2] = { .start = 0xE0200160, .end = 0xE0200160 + 8 -1, .flags = IORESOURCE_MEM, }, }; struct platform_device led_pdev = { .name = "s5pv210_led", //只要保证与pdrv一致就行 .id = -1, .num_resources = ARRAY_SIZE(led_resource), //求数组个数 .resource = led_resource, }; static int __init plat_led_dev_init(void) { printk("-------%s-----------------\n", __FUNCTION__); //注册一个pdev //int platform_device_register(struct platform_device *); //注册到总线上 return platform_device_register(&led_pdev); //正常情况返回0 } static void __exit plat_led_dev_exit(void) { printk("-------%s-----------------\n", __FUNCTION__); //void platform_device_unregister(struct platform_device *);//从总线上注销出来 platform_device_unregister(&led_pdev); //一般卸载类的没有返回值 } module_init(plat_led_dev_init); module_exit(plat_led_dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("752800373@qq.com");
接下来写驱动程序plat_led_drv.c
其中,platform_driver结构体中,
probe中要做事情:(下一个博客里面写)
//为用户提供接口
0, 实例化全局的设备对象– kzalloc
1, 申请主设备号—register_chrdev
2, 自动创建设备节点—class_create, device_create
3, 初始化硬件–ioremap
4,实现 file_operation
5,拿到pdev中的资源对硬件进行初始化
#include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> #include <asm/io.h> //驱动程序 volatile unsigned long *gpc0_conf; volatile unsigned long *gpc0_data; //led_drv_probe中主要任务是拿到资源 //匹配成功第一个要执行的函数 int led_drv_probe(struct platform_device *pdev)//这里的pdev指针是总线bus传过来的 { printk("-------%s-----------------\n", __FUNCTION__); /* 编写驱动的套路(下次文件里面写) 0, 实例化全局的设备对象-- kzalloc 1, 申请主设备号---register_chrdev 2, 自动创建设备节点---class_create, device_create 3, 初始化硬件--ioremap 4,实现 file_operation */ // 肯定拿到pdev中的资源对硬件进行初始化 //获取到内存资源 //参数2--拿到资源的类型 //参数3--相同资源中第几个,这里是第0个,记住是同一类的累加数字 //platform_get_resource_byname(struct platform_device *, unsigned int, const char *) struct resource *addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //ioremap第二个参数等价于addr_res->end - addr_res->start + 1 gpc0_conf = ioremap(addr_res->start, resource_size(addr_res)); gpc0_data = gpc0_conf + 1; //如果要对硬件进行初始化 *gpc0_conf &= ~(0xff<<12); *gpc0_conf |= (0x11<<12); *gpc0_data |= (0x3<<3); //亮灯 //如果要获取到中断资源(按键) //参数3--相同资源中第几个,这里是第0个,记住是同一类的累加数字 //struct resource *irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); //printk("irqno = %d\n", irq_res->start);//打印出起始地址 int irqno = platform_get_irq(pdev, 0); printk("irqno = %d\n", irqno); return 0; } int led_drv_remove(struct platform_device *pdev) { printk("-------%s-----------------\n", __FUNCTION__); return 0; } const struct platform_device_id led_id_table[] = { {"s5pv210_led", 0x5210},//一定要和pdev里面的name一致,这里优先匹配 {"s3c2410_led", 0x4444}, {"s3c6410_led", 0x4444}, }; #if 0 //用来参考的 struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); struct device_driver driver; const struct platform_device_id *id_table; }; #endif struct platform_driver led_pdrv = { .probe = led_drv_probe, //表示匹配之后的函数 .remove = led_drv_remove, //解除匹配 .driver = { .name = "samsung_led_drv", //随便写,但是一定要有 //可以用于和pdev进行匹配的,优先级较id_table低 }, .id_table =led_id_table , //一定是用于和pdev进行匹配, 优先进行匹配 }; static int __init plat_led_drv_init(void) { printk("-------%s-----------------\n", __FUNCTION__); //注册一个pdrv //extern int platform_driver_register(struct platform_driver *); return platform_driver_register(&led_pdrv); } static void __exit plat_led_drv_exit(void) { printk("-------%s-----------------\n", __FUNCTION__); platform_driver_unregister(&led_pdrv); } module_init(plat_led_drv_init); module_exit(plat_led_drv_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("752800373@qq.com");
Makefile
#指定内核源码的绝对路径 KERNEL_DIR = /home/ubuntu/s5pv210/kernel/linux-3.0.8 CUR_DIR = $(shell pwd) MYMODULE = plat_led_dev MYMODULE2 = plat_led_drv #MYAPP = buttons_v5 all: #make进入到内涵源码目录,将当前目录下的源程序作为内核模块一起编译 make -C $(KERNEL_DIR) M=$(CUR_DIR) modules #arm-none-linux-gnueabi-gcc -o $(MYAPP) $(MYAPP).c clean: #将编译生成的文件删除 make -C $(KERNEL_DIR) M=$(CUR_DIR) clean rm -rf (MYAPP) install: cp -raf $(MYAPP) *.ko /opt/rootfs/drv_module #指定编译哪个源文件 obj-m = $(MYMODULE).o obj-m += $(MYMODULE2).o
这里,在开发板转载程序,可以不分先后顺序。
insmod plat_led_dev.ko
insmod plat_led_drv.ko
并且可以看到开发板上的两个LED灯亮了。
可在/sys/bus/platform/中查看程序是否成功加载到总线
程序代码:led_plat_v1.rar(链接:https://pan.baidu.com/s/1i5XRNHr 密码:qbx2)
相关文章推荐
- 09-S3C2440驱动学习(三)嵌入式linux-platform平台总线驱动程序及分离分层构建驱动框架
- linux驱动模型开发——linux platform总线机制讲解与实例开发
- linux驱动模型开发——linux platform总线机制讲解与实例开发
- Linux驱动编程——platform总线的设备和驱动
- 嵌入式linux平台设备驱动(设备驱动模型)开发之linux内核中bus总线
- linux驱动platform平台设备总线
- linux驱动模型开发——linux platform总线机制讲解与实例开发
- Linux驱动开发-13、平台总线驱动模型
- linux驱动模型开发——linux platform总线机制讲解与实例开发
- linux驱动模型开发——linux platform总线机制讲解与实例开发
- linux驱动之platform平台总线工作原理(一)
- linux驱动模型开发——linux platform总线机制讲解与实例开发
- linux驱动模型开发——linux platform总线机制讲解与实例开发
- linux驱动模型开发——linux platform总线机制讲解与实例开发
- Linux学习:platform平台总线、平台设备、平台驱动
- Linux驱动学习——platform平台总线
- 20150226 IMX257 总线设备驱动模型编程之平台总线设备platform
- linux驱动模型开发——linux platform总线机制讲解与实例开发
- Linux下的platform总线驱动代码分析
- linux驱动之--平台总线