基于platform实现

- #ifndef __HEAD_H__
- #define __HEAD_H__
-
- //构建LED开关的功能码,不添加ioctl第三个参数
- #define LED_ON _IO('l',1)
- #define LED_OFF _IO('l',0)
-
- #endif
- #include <stdlib.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/ioctl.h>
- #include "head.h"
-
-
- int main(int argc, char const *argv[])
- {
- int a;
- char buf[128] = {0};
- int fd = open("/dev/myplatform0", O_RDWR);
- if (fd < 0)
- {
- printf("打开设备文件失败\n");
- exit(-1);
- }
- while (1)
- {
- read(fd, buf, 1);
- switch (buf[0])
- {
- case 1:
- ioctl(fd, LED_ON); // 开灯
- break;
- case 0:
- ioctl(fd, LED_OFF); // 关灯
- }
- }
-
- close(fd);
-
- return 0;
- }
pdr.c
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <linux/uaccess.h>
- #include <linux/io.h>
- #include <linux/device.h>
- #include <linux/cdev.h>
- #include <linux/platform_device.h>
- #include <linux/mod_devicetable.h>
- #include <linux/of_gpio.h>
- #include <linux/slab.h>
- #include <linux/of.h>
- #include <linux/gpio.h>
- #include <linux/interrupt.h>
- #include "head.h"
-
- char number = 0;
-
- struct cdev *cdev;
- char kbuf[128] = {0};
- unsigned int major = 0;
- unsigned int minor = 0;
- dev_t devno;
- module_param(major, uint, 0664); // 方便在命令行传递major的值
- struct class *cls;
- struct device *dev;
- unsigned int irqno[3]; // 软中断号
- struct gpio_desc *gpiono[3]; // gpio对象
-
- unsigned int condition = 0;
- // 定义一个等待队列头
- wait_queue_head_t wq_head;
-
- // 定义中断处理函数
- irqreturn_t key_handler(int irq, void *dev)
- {
- int which = (int)dev;
- switch (which)
- {
- case 0:
- printk("KEY1\n");
- number ^= 1;
- condition = 1; // 表示硬件数据就绪
- wake_up_interruptible(&wq_head);
- break;
- case 1:
-
- break;
- case 2:
-
- break;
- default:
- break;
- }
- return IRQ_HANDLED;
- }
-
- // 封装操作方法
- int mycdev_open(struct inode *inode, struct file *file)
- {
- int min = MINOR(inode->i_rdev); // 根据打开的文件对应的设备号获取次设备号
- file->private_data = (void *)min;
- printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
- return 0;
- }
-
- ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
- {
- int ret;
- // 判断IO方式
- if (file->f_flags & O_NONBLOCK) // 非阻塞
- {
- }
- else // 阻塞
- {
- wait_event_interruptible(wq_head, condition); // 先检查condition再将进程休眠
- }
- ret = copy_to_user(ubuf, &number, size);
- if (ret)
- {
- printk("copy_to_user err\n");
- return -EIO;
- }
- condition = 0; // 下一次硬件数据没有就绪
- return 0;
- }
-
- long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- {
-
- int min = (int)file->private_data;
- switch (min)
- {
- case 0: // 控制LED1
- switch (cmd)
- {
- case LED_ON:
- // 开灯
- gpiod_set_value(gpiono[0], 1);
- break;
- case LED_OFF:
- // 关灯
- gpiod_set_value(gpiono[0], 0);
- break;
- }
- break;
- case 1: // 控制LED2
- switch (cmd)
- {
- case LED_ON:
- // 开灯
- gpiod_set_value(gpiono[1], 1);
- break;
- case LED_OFF:
- // 关灯
- gpiod_set_value(gpiono[1], 0);
- break;
- }
- break;
- case 2: // 控制LED3
- switch (cmd)
- {
- case LED_ON:
- // 开灯
- gpiod_set_value(gpiono[2], 1);
- break;
- case LED_OFF:
- // 关灯
- gpiod_set_value(gpiono[2], 0);
- break;
- }
- break;
- }
- return 0;
- }
-
- int mycdev_close(struct inode *inode, struct file *file)
- {
- printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
- return 0;
- }
-
- struct file_operations fops = {
- .open = mycdev_open,
- .read = mycdev_read,
- .unlocked_ioctl = mycdev_ioctl,
- .release = mycdev_close,
- };
-
- // 封装probe函数
- int pdrv_probe(struct platform_device *pdev)
- {
- int ret;
- // 初始化等待队列
- init_waitqueue_head(&wq_head);
- // 字符设备注册
- // 1.申请驱动对象
- cdev = cdev_alloc();
- if (cdev == NULL)
- {
- printk("申请对象空间失败!\n");
- ret = -EFAULT;
- goto out1;
- }
- printk("申请对象成功!\n");
- // 2.初始化驱动对象
- cdev_init(cdev, &fops);
- printk("初始化对象成功!\n");
-
- // 3.申请主设备号和一定数量设备资源
- if (major > 0) // 静态指定设备号
- {
- ret = register_chrdev_region(MKDEV(major, minor), 3, "myplatform");
- if (ret)
- {
- printk("静态申请设备号失败!\n");
- goto out2;
- }
- }
- else if (major == 0) // 动态申请设备号
- {
- ret = alloc_chrdev_region(&devno, 0, 3, "myplatform");
- if (ret)
- {
- printk("动态申请设备号失败!\n");
- goto out2;
- }
- major = MAJOR(devno); // 获取主设备号
- minor = MINOR(devno); // 获取此设备号
- }
- printk("申请设备号成功!\n");
-
- // 4.根据申请的设备号和驱动对象注册驱动
- ret = cdev_add(cdev, MKDEV(major, minor), 3);
- if (ret)
- {
- printk("驱动注册失败!\n");
- goto out3;
- }
- printk("注册驱动成功!\n");
-
- // 5.向上提交目录信息
- cls = class_create(THIS_MODULE, "myplatform");
- if (IS_ERR(cls))
- {
- printk("向上提交目录失败!\n");
- ret = -PTR_ERR(cls);
- goto out4;
- }
- printk("向上提交目录成功!\n");
-
- // 6.向上提交设备信息文件
- int i;
- for (i = 0; i < 3; i++)
- {
- dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myplatform%d", i);
- if (IS_ERR(dev))
- {
- printk("向上提交设备信息失败!\n");
- ret = -PTR_ERR(dev);
- goto out5;
- }
- }
- printk("向上提交设备信息文件成功!\n");
-
- // 获取中断类型的资源
-
- for (i = 0; i < 3; i++)
- {
- // 根据节点解析软中断号
- irqno[i] = platform_get_irq(pdev, i);
- if (!irqno[i])
- {
- printk("获取软中断号失败!\n");
- return -ENXIO;
- }
- printk("获取软中断号成功!%d\n", irqno[i]);
-
- // 注册软中断号
- ret = request_irq(irqno[i], key_handler, IRQF_TRIGGER_FALLING, "key_int", (void *)i);
- if (ret < 0)
- {
- printk("注册软中断号失败!\n");
- return ret;
- }
- printk("注册软中断号成功!\n");
-
- gpiono[i] = gpiod_get_from_of_node(pdev->dev.of_node, "led-gpios", i, GPIOD_OUT_LOW, NULL);
- if (IS_ERR(gpiono[i]))
- {
- printk("解析GPIO管脚信息失败\n");
- return -ENXIO;
- }
- printk("解析GPIO管脚信息成功\n");
- }
- return 0;
- out5:
- for (--i; i > -1; i--)
- {
- device_destroy(cls, MKDEV(major, i));
- }
- class_destroy(cls);
- out4:
- cdev_del(cdev);
- out3:
- unregister_chrdev_region(MKDEV(major, minor), 3);
- out2:
- kfree(cdev);
- out1:
- return ret;
- }
- // 封装remove函数
- int pdrv_remove(struct platform_device *pdev)
- {
- // 销毁设备信息文件
- int i;
- for (i = 0; i < 3; i++)
- {
- device_destroy(cls, MKDEV(major, i));
- }
- // 销毁设备类目录
- class_destroy(cls);
- // 注销驱动
- cdev_del(cdev);
- // 注销设备号
- unregister_chrdev_region(MKDEV(major, minor), 3);
- // 释放cdev对象
- kfree(cdev);
-
- for (i = 0; i < 3; i++)
- {
- // 注销中断
- free_irq(irqno[i], (void *)i);
-
- // 熄灭led灯
- gpiod_set_value(gpiono[i], 0);
-
- // 释放gpio对象
- gpiod_put(gpiono[i]);
- }
- printk("注销中断成功!\n");
- return 0;
- }
-
- // 构建设备树匹配表
- struct of_device_id oftable[] = {
- {.compatible = "hqyj,myplatform"},
- {/* end node */}, // 防止数组越界
- };
-
- // 定义驱动信息对象并初始化
- struct platform_driver pdrv = {
- .probe = pdrv_probe,
- .remove = pdrv_remove,
- .driver = {
- .name = "aaa",
- .of_match_table = oftable, // 用于设备树匹配
- },
- };
-
- // 一键注册宏
- module_platform_driver(pdrv);
- MODULE_LICENSE("GPL");