/*功能实现 在stm32开发板上实现功能
1.使用阻塞IO读取number变量的值,当number的值改变时打印number的值
2.注册KEY1按键的驱动和LED1的驱动以及对应的设备文件,
3.按键和指示灯设备信息放在同一个设备树的节点中
4.当KEY1按下时LED1灯的状态取反,number的值取反,number值为0或1
5.使用paltform_device驱动总线匹配设备树节点硬件信息进行控制
*/
主要打开设备文件,通过阻塞的方式读取文件中number变量的值
#include "user.h"
int main(int argc, const char* argv[])
{
int fd;
int status;
if ((fd = open("/dev/myled1", O_RDWR)) == -1) {
perror("open error");
exit(EXIT_FAILURE);
}
while (1) {
read(fd, &status, sizeof(status));
printf("status = %d\n", status);
}
close(fd);
return 0;
}
1.设备文件的注册 2.中断,GPIO的注册 3.驱动总线匹配设备树节点信息获取信息 4.实现变量以及LED状态的改变
#include "cdev.h"
/*功能实现 在stm32开发板上实现功能
1.使用阻塞IO读取number变量的值,当number的值改变时打印number的值
2.注册KEY1按键的驱动和LED1的驱动以及对应的设备文件,
3.按键和指示灯设备信息放在同一个设备树的节点中
4.当KEY1按下时LED1灯的状态取反,number的值取反,number值为0或1
*/
// 中断处理函数
int led_work(void);
irqreturn_t myirq_handler(int irqno, void *dev_id)
{
printk("软中断号%d的处理\n", irqno);
// 改变LED灯的状态
gpiod_set_value(gpiono_led1, !gpiod_get_value(gpiono_led1));
// 改变number的值
// 改变标志
condition = 1;
// 唤醒可中断进程
wake_up_interruptible(&wq_head);
return IRQ_HANDLED;
}
// 中断信息初始化函数
int request_interrupts(struct platform_device *pdev)
{
// 准备:在设备树中添加gpiof组控制按键的节点信息
// 2.根据节点地址寻找key对应的软中断号 irq_of_parse_and_map
// 获取KEY按键对应的软中断号 参2的索引的值在于你的自定义节点GPIO控制所在位置,
// myirq{
// interrupts-extended=<&gpiof 9 0>,<&gpiof 7 0>,<&gpiof8 0>;
// };KEDY1对应<&gpiof 9 0>索引为0,KEY2对应<&gpiof 7 0>,索引为1,类似数组依次对应
myirq_key[0] = irq_of_parse_and_map(pdev->dev.of_node, 0);
if (!myirq_key[0])
{
printk("key1软中断号获取失败\n");
return ENOMEM;
}
printk("key1软中断号获取成功\n");
// 3.注册中断号 包括对应的软中断号,中断执行的处理函数,中断的检测方式,中断名
// 注册KEY对应的软中断号
// 参1:中断号对应的软中断号 参2:中断的处理函数 参3:中断触发的方式 参4:为中断起一个名字 参5:给中断函数传递的值
// KEY1
ret = request_irq(myirq_key[0], myirq_handler, IRQF_TRIGGER_FALLING, irq_key1_name, 0);
if (ret < 0)
{
printk("key1中断注册失败\n");
return ret;
}
printk("key1中断注册成功\n");
return 0;
}
// LED灯的初始化
int request_LED(struct platform_device *pdev)
{
// 2.通过节点信息获取GPIO对象
// 2.1申请LED1对应资源
gpiono_led1 = gpiod_get_from_of_node(pdev->dev.of_node, "led1", 0, GPIOD_OUT_LOW, NULL);
if (IS_ERR(gpiono_led1))
{
printk("LED1资源申请失败\n");
return -PTR_ERR(gpiono_led1);
}
printk("LED1资源申请成功\n");
return 0;
}
//在驱动中创建一个用于设备树匹配的表
struct of_device_id oftable[]={
{.compatible="hqyj,myplatform",},
{.compatible="hqyj,myplatform1",},
{.compatible="hqyj,myplatform2",},
{},
};
int pdrv_probe(struct platform_device *pdev)
{
printk("匹配成功:%d\n",__LINE__);
printk("设备名=%s\n",pdev->name);
/****初始化区域_begin****/
// 中断初始化
request_interrupts(pdev);
// LED灯初始化
request_LED(pdev);
// 初始化等待队列头
init_waitqueue_head(&wq_head);
//设备文件的初始化
led_work();
return 0;
}
int prdv_remove(struct platform_device *pdev)
{
// 关灯
gpiod_set_value(gpiono_led1, 0);
// 释放申请的LED资源
gpiod_put(gpiono_led1);
// 销毁设备信息
device_destroy(cls, MKDEV(major, 0));
// 销毁目录
class_destroy(cls);
// 注销字符设备驱动
unregister_chrdev(major, "myled");
return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
// 向用户空间读取拷贝
if (size > sizeof(kbuf)) // 用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
size = sizeof(kbuf);
// 判断condition的值,为1则改变number的值
wait_event_interruptible(wq_head, condition);
if (number==1)
{
number = 0;
}
else if(number==0)
{
number = 1;
}
ret = copy_to_user(ubuf, &number, size);
if (ret) // 拷贝失败
{
printk("copy_to_user filed\n");
return ret;
}
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
struct file_operations fops = {
.read = mycdev_read,
};
int led_work(void)
{
/*****LED灯的驱动安装流程*****/
// 1.安装驱动获取mojor设备号
printk("LED灯驱动安装\n");
major = register_chrdev(0, "myled", &fops); // 系统动态申请主设备号
if (major < 0)
{
printk("主设备号申请失败\n");
return major;
}
printk("主设备号申请成功:major=%d\n", major);
// 3.向上提交目录
cls = class_create(THIS_MODULE, "myled");
if (IS_ERR(cls))
{
printk("向上提交目录失败\n");
return PTR_ERR(cls);
}
printk("向上提交目录成功\n");
/*
cls=class_create(THIS_MODULE,"mychrdev1");
cls=class_create(THIS_MODULE,"mychrdev2");
*/
// 4.向上提交设备节点信息,分别为每一个灯创建设备文件
dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "myled1");
if (IS_ERR(dev))
{
printk("向上提交设备信息myled1失败\n");
return PTR_ERR(dev);
}
printk("向上提交设备信息myled1成功\n");
return 0;
}
//驱动信息初始化
struct platform_driver pdrv={
.probe=pdrv_probe,
.remove=pdrv_probe,
.driver={
.name="pdrv",
.of_match_table=oftable,//指点使用设备树表
},
};
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");