N22 key驱动

一、platform自动匹配

  1. 定义一个 platform_driver,告诉内核:我是一个正规驱动
  2. 内核会自动去设备树里找匹配的硬件(compatible)
  3. 找到后自动调用 probe 函数
  4. probe 里:
    • 读取设备树地址
    • ioremap 映射寄存器
    • 注册 misc 设备
  5. 设备拔掉 → remove
  6. 驱动卸载 → 自动清理
  7. 应用层通过 /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");
相关推荐
大地的一角2 小时前
(计算机网络)网络层原理与网络大致结构
服务器·网络·tcp/ip
c++逐梦人2 小时前
Linux多线程
linux·服务器
WangJunXiang62 小时前
LVS 负载均衡群集
运维·负载均衡·lvs
开心码农1号2 小时前
RabbitMQ 生产运维命令大全
linux·开发语言·ruby
百结2142 小时前
LVS 负载均衡群集
运维·负载均衡·lvs
IMPYLH2 小时前
Linux 的 nl 命令
linux·运维·服务器·bash
卤炖阑尾炎2 小时前
从原理到实战:LVS 负载均衡集群全解析(OpenEuler 环境)
运维·负载均衡·lvs
咖喱o2 小时前
路由策略
linux·服务器·网络
南境十里·墨染春水2 小时前
linux学习进展 主函数的参数
linux·运维·学习