使用的内核版本为3.4.39,开发工具为Ubuntu的vim编辑器。
一、platform简介
是操作系统的一个通用型总线,操作系统中需要把设备和驱动挂接到总线当中供顶层应用使用,platform是所有类型的设备和驱动都可以挂接的一条通用型总线。操作系统中也有专用型总线,例如USB、I2C,一般如果有对应的专用型总线会优先考虑挂接到专用型总线上,通用型总线通常是退而求其次的选择。
二、供用户使用的派生类及方法
#include <linux/platform_device.h>
// 描述挂接到platform总线设备的结构体
struct platform_device {
const char * name; // 总线名称
int id; // 设备编号
struct device dev; // 基类
u32 num_resources; // 资料数目
struct resource * resource; // 指向资料结构体,用于信息传递
const struct platform_device_id *id_entry;
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
// 设备注册到总线中
extern int platform_device_register(struct platform_device *);
// 设备在总线中注销
extern void platform_device_unregister(struct platform_device *);
// 描述挂接到platform总线驱动的结构体
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 (*resume)(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 *);
// 获取设备通过resource传递的值
extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);
// 获取指定设备的中断号
extern int platform_get_irq(struct platform_device *, unsigned int);
// 将一个或多个平台设备添加到系统中,以便其驱动程序可以对它们进行初始化和管理
extern int platform_add_devices(struct platform_device **, int);
三、代码实现流程
操作系统已经存在一条platform总线,所以只需要使用platform的派生类和方法,注册设备和驱动即可,两个可以通过名称相同进行匹配,匹配成功后会执行驱动代码,也就是prob指向的部分代码。挂接到platform总线的设备和驱动分别可以在/sys/bus/platform/devices和/sys/bus/platform/drivers查看。
四、示例代码
Makefile
KERNEL_DIR = /opt/wkspace/kernel-build/kernel-3.4.39/
obj-m += mydev.o mydrv.o
all:
make modules M=`pwd` -C $(KERNEL_DIR) CROSS_COMPILE=/usr/local/arm/arm-eabi-4.8/bin/arm-eabi-
clean:
make modules clean M=`pwd` -C $(KERNEL_DIR) CROSS_COMPILE=/usr/local/arm/arm-eabi-4.8/bin/arm-eabi-
rm -rf app
mydev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/platform_device.h>
void platform_release(struct device *dev){
printk(KERN_INFO "platform release!\n");
return ;
}
struct platform_device mydev = {
.name = "platform_dev",
.id = 188,
.dev = {
.release = platform_release,
}
};
static int __init platform_dev_init(void){
printk(KERN_INFO "platform dev init!\n");
platform_device_register(&mydev);
return 0;
}
static void __exit platform_dev_exit(void){
printk(KERN_INFO "platform dev exit!\n");
platform_device_unregister(&mydev);
return ;
}
module_init(platform_dev_init);
module_exit(platform_dev_exit);
MODULE_LICENSE("GPL");
mydrv.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/platform_device.h>
int platform_probe(struct platform_device *dev){
printk(KERN_INFO "platform probe!\n");
return 0;
}
int platform_remove(struct platform_device *dev){
printk(KERN_INFO "platform remove!\n");
return 0;
}
struct platform_driver mydrv = {
.driver = {
.name = "platform_dev",
},
.probe = platform_probe,
.remove = platform_remove,
};
static int __init platform_drv_init(void){
printk(KERN_INFO "platform drv init!\n");
platform_driver_register(&mydrv);
return 0;
}
static void __exit platform_drv_exit(void){
printk(KERN_INFO "platform drv exit!\n");
platform_driver_unregister(&mydrv);
return ;
}
module_init(platform_drv_init);
module_exit(platform_drv_exit);
MODULE_LICENSE("GPL");