使用文档
设备树修改
新增一个 LED 节点 arch/arm/boot/dts/arm/vexpress-v2p-ca9.dts
my_pl_led {
compatible = "cortex-a9-led";
status = "okay";
};
设备树编译
make dtbs
日志
DTC arch/arm/boot/dts/arm/vexpress-v2p-ca9.dtb
platform driver 源码
#include "linux/export.h"
#include "linux/ioport.h"
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
#define PLATFORM_DEVICE_NAME "my_pl_led" /* 匹配设备树节点的名字 */
static int my_probe(struct platform_device *device)
{
printk("platform driver probe\r\n");
struct device_node *my_device_node;
my_device_node = of_find_node_by_name(NULL, PLATFORM_DEVICE_NAME);
if (my_device_node) {
printk("device node name %s \r\n", my_device_node->name);
/* 获取 compatible 属性的字符串。*/
const char *compatible;
compatible = of_get_property(my_device_node, "compatible", NULL);
if (compatible) {
printk("Compatible property: %s\n", compatible);
} else {
printk("Compatible property not found\n");
}
/* 获取 status 属性的字符串。*/
compatible = of_get_property(my_device_node, "status", NULL);
if (compatible) {
printk("status property: %s\n", compatible);
} else {
printk("status property not found\n");
}
} else {
printk("can't find device node\r\n");
}
return 0;
}
static int my_remove(struct platform_device *device)
{
printk("platform driver remove\r\n");
return 0;
}
/**
* @brief include mod_devicetable.h.
*
*/
static const struct platform_device_id test_id_table = {
.name = PLATFORM_DEVICE_NAME, /* 和设备树匹配的名字。 */
};
/**
* @brief include platform_device.h
*
*/
static struct platform_driver platform_driver_test = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "my_pl_driver", /* platform driver 的名字 */
.owner = THIS_MODULE,
},
.id_table = &test_id_table,
};
static int __init platform_driver_init(void)
{
platform_driver_register(&platform_driver_test);
printk("k: platform driver module init!\r\n");
return 0;
}
static void __exit platform_driver_exit(void)
{
platform_driver_unregister(&platform_driver_test);
printk("k: platform driver module exit!\r\n");
}
module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("tyustli");
MODULE_INFO(intree, "Y"); /* loading out-of-tree module taints kernel */
makefile 源码
# 指定内核路径
KERNELDIR := /home/tyustli/code/open_source/kernel/linux-6.5.7
# 指定当前路径
CURRENT_PATH := $(shell pwd)
# 指定编译的模块名
obj-m := my_platform_driver.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
编译驱动
../my_module_build.sh ../0013_dtsplatform/
查看模块 ko 文件
ls /lib/modules/6.5.7+/
my_platform_driver.ko
查看 platform 设备
ls /sys/bus/platform/devices/my_pl_led/
driver_override power waiting_for_supplier
modalias subsystem
of_node uevent
platform 驱动
如果编译报错
error: ‘const struct platform_device_id’ has no member named ‘name’
解决
#include <linux/mod_devicetable.h>
platform_device_id 结构体原型
struct platform_device_id {
char name[PLATFORM_NAME_SIZE];
kernel_ulong_t driver_data;
};
platform 驱动模块安装
modprobe my_platform_driver
匹配成功日志
platform driver probe
device node name my_pl_led
Compatible property: cortex-a9-led
status property: okay
k: platform driver module init!
drm-clcd-pl111 10020000.clcd: DVI muxed to daughterboard 1 (core tile) CLCD
drm-clcd-pl111 10020000.clcd: initializing Versatile Express PL111
从结果可以看到 linux 6.5.7
版本的 platform driver
匹配的是 platform device
节点的名称,而不是 compatible
属性
查看 platform 驱动
ls /sys/bus/platform/drivers/my_pl_driver/
bind module uevent unbind
退出
Ctrl + a
x