一、platform自动匹配
- 定义一个
platform_driver,告诉内核:我是一个正规驱动- 内核会自动去设备树里找匹配的硬件(compatible)
- 找到后自动调用
probe函数- 在
probe里:
- 读取设备树地址
- ioremap 映射寄存器
- 注册 misc 设备
- 设备拔掉 → remove
- 驱动卸载 → 自动清理
- 应用层通过
/dev/led控制亮灭它是标准 Linux 驱动结构,内核统一管理。
内核自动匹配,只看 compatible,不关心路径。
这是 Linux 驱动最核心思想:驱动与设备分离。
copy_to_user:内核 → 用户copy_from_user:用户 → 内核
cs
字符串替换
:%s/led/key/g
二、key驱动(linux/of_irq.h)
cs
#include <linux/init.h>
#include <linux/printk.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/export.h>
#include <asm/uaccess.h>
#include <asm/string.h>
#include <asm/io.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/of_irq.h>
#include <linux/wait.h>
#include <linux/sched.h>
#define DEV_NAME "key"
static unsigned int irq_key_num;
#define key_ON 0
#define key_OFF 1
static int arg = 100;
static wait_queue_head_t wq;
static int condition;
static irqreturn_t key_irq_handler(int dev_num, void * dev)
{
condition = 1;
wake_up_interruptible(&wq);
printk("dev_num = %d dev = %d\n", dev_num, *(int *)dev);
return IRQ_HANDLED;
}
static int open(struct inode * node, struct file * file)
{
printk("key open...\n");
return 0;
}
static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * offset)
{
condition = 0;
wait_event_interruptible(wq, condition);
//copy_to_user();
printk("key read...\n");
return 0;
}
static int close(struct inode * node, struct file * file)
{
printk("key close...\n");
return 0;
}
static struct file_operations fops =
{
.owner = THIS_MODULE,
.open = open,
.read = read,
.release = close
};
static struct miscdevice misc =
{
.minor = MISC_DYNAMIC_MINOR,
.name = DEV_NAME,
.fops = &fops
};
static int probe(struct platform_device * pdev)
{
struct device_node * pnode;
int ret = misc_register(&misc);
if(IS_ERR_VALUE(ret))
goto err_misc;
pnode = of_find_node_by_path("/pt_key");
if(IS_ERR(pnode))
{
ret = PTR_ERR(pnode);
goto err_find_node;
}
irq_key_num = irq_of_parse_and_map(pnode, 0);
if(irq_key_num < 0)
{
ret = irq_key_num;
goto err_of_parse;
}
ret = request_irq(irq_key_num, key_irq_handler, IRQF_TRIGGER_FALLING, "key_irq", &arg);
if(ret < 0)
goto err_request_irq;
init_waitqueue_head(&wq);
printk("probe key misc_register ##############\n");
return 0;
err_request_irq:
disable_irq(irq_key_num);
free_irq(irq_key_num, &arg);
printk("key err_request_irq\n");
err_of_parse:
printk("key err_of_parse\n");
err_find_node:
printk("of_find_node_by_path err\n");
err_misc:
printk("key probe faikey ret = %d\n", ret);
misc_deregister(&misc);
return ret;
}
static int remove(struct platform_device * pdev)
{
disable_irq(irq_key_num);
free_irq(irq_key_num, &arg);
misc_deregister(&misc);
printk("remove key misc_deregister ##############\n");
return 0;
}
static const struct of_device_id match_table[] =
{
[0] = {.compatible = "pt-key"}
};
static struct platform_driver drv =
{
.probe = probe,
.remove = remove,
.driver =
{
.name = DEV_NAME,
.of_match_table = match_table
}
};
static int __init key1_init(void)
{
int ret = platform_driver_register(&drv);
if(ret < 0)
goto err_reg;
printk("platform_driver_register ...\n");
return 0;
err_reg:
printk("platform_driver_register faikey ret = %d\n", ret);
platform_driver_unregister(&drv);
return ret;
}
static void __exit key1_exit(void)
{
platform_driver_unregister(&drv);
printk("platform_driver_unregister ...\n");
}
module_init(key1_init);
module_exit(key1_exit);
MODULE_LICENSE("GPL");