当前位置: 首页 > news >正文

驱动DAY9

驱动文件

#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>//获取资源结构体
struct resource *res;
//中断号
unsigned int irqno;
//gpio信息结构体
struct gpio_desc *gpiono;
//字符设备驱动对象空间首地址
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;
int number = 0;
unsigned int condition = 0;
wait_queue_head_t wq_head;//中断处理函数
irqreturn_t key_handler(int irq,void *dev)
{gpiod_set_value(gpiono,!(gpiod_get_value(gpiono)));number = !number;condition = 1;wake_up_interruptible(&wq_head);return IRQ_HANDLED;
}int mycdev_open(struct inode *inode, struct file *file)
{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)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);int ret;//向用户空间读取拷贝if(size>sizeof(number))//用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小size=sizeof(number);//切换进程为休眠态wait_event_interruptible(wq_head,condition);ret=copy_to_user(ubuf,&number,size);if(ret)//拷贝失败{printk("copy_to_user filed\n");return ret;}condition = 0;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,.release=mycdev_close,
};
//封装probe函数
int pdrv_probe(struct platform_device *pdev)
{int ret;// 为字符设备驱动对象申请空间cdev = cdev_alloc();if (cdev == NULL){printk("字符设备驱动对象申请空间失败\n");ret = -EFAULT;goto out1;}printk("申请对象空间成功\n");// 初始化字符设备驱动对象cdev_init(cdev, &fops);// 申请设备号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, minor, 3, "myplatform");if (ret){printk("动态申请设备号失败\n");goto out2;}major = MAJOR(devno); // 获取主设备号minor = MINOR(devno); // 获取次设备号}printk("申请设备号成功\n");// 注册字符设备驱动对象ret = cdev_add(cdev, MKDEV(major, minor), 3);if (ret){printk("注册字符设备驱动对象失败\n");goto out3;}printk("注册字符设备驱动对象成功\n");// 向上提交目录信息cls = class_create(THIS_MODULE, "myplatform");if (IS_ERR(cls)){printk("向上提交目录失败\n");ret = -PTR_ERR(cls);goto out4;}printk("向上提交目录成功\n");// 向上提交设备节点信息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");//初始化等待队列头init_waitqueue_head(&wq_head);//获取MEM类型的资源res = platform_get_resource(pdev,IORESOURCE_MEM,0);if(res == NULL){printk("获取MEM类型资源失败\n");return -ENXIO;}//获取中断类型的资源irqno = platform_get_irq(pdev,0);if(irqno < 0){printk("获取中断类型资源失败\n");return -ENXIO;}//注册中断int ret1 = request_irq(irqno,key_handler,IRQF_TRIGGER_FALLING,"key_int",NULL);if(ret1<0){printk("注册按键1中断失败\n");return ret1;}printk("注册按键1中断成功\n");printk("mem资源%llx\n",res->start);printk("irq资源%d\n",irqno);printk("%s;%s:%d\n",__FILE__,__func__,__LINE__);//设备树匹配成功后,设备树节点指针可以通过pdev->dev.of_node获取//基于设备树节点信息获取gpio_desc对象指针gpiono = gpiod_get_from_of_node(pdev->dev.of_node,"led1-gpio",0,GPIOD_OUT_LOW,NULL);if(IS_ERR(gpiono)){printk("解析GPIO管脚信息失败\n");return -ENXIO;}printk("解析GPIO管脚信息成功\n");return 0;
out5:// 释放前一次提交成功的设备信息for (--i; i >= 0; 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)
{//关灯gpiod_set_value(gpiono,0);//释放GPIO信息gpiod_put(gpiono);//注销中断free_irq(irqno,NULL);// 释放节点信息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);// 释放对象空间kfree(cdev);printk("%s;%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}
//构建设备树匹配表
struct of_device_id oftable[] = {{ .compatible = "hqyj,myplatform"},{ /* end node */ },//防止数组越界
};
//定义驱动信息对象并初始化
struct platform_driver pdrv = {.probe = pdrv_probe,.remove = pdrv_remove,.driver = {.name = "bbbbb",.of_match_table=oftable,//用于设备树匹配 },
};//一键注册宏
module_platform_driver(pdrv);MODULE_LICENSE("GPL");

应用程序

#include<stdlib.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
#include<string.h>int main(int argc, char const *argv[])
{int num;int fd=open("/dev/myplatform0",O_RDWR);if(fd<0){printf("打开设备文件失败\n");exit(-1);}while(1){read(fd,&num,sizeof(num));printf("num = %d\n",num);}close(fd);return 0;
}

http://www.lryc.cn/news/171036.html

相关文章:

  • 03贪心:摆动序列
  • javascript获取元素在浏览器中工作区域的左、右、上、下距离,或带滚动条的元素在页面中的大小
  • VSCode 安装使用教程 环境安装配置 保姆级教程
  • c盘中temp可以删除吗?appdata\local\temp可以删除吗?
  • Java手写聚类算法
  • 解密Java多线程中的锁机制:CAS与Synchronized的工作原理及优化策略
  • solid works草图绘制与设置零件特征的使用说明
  • vue3使用router.push()页面跳转后,该页面不刷新问题
  • 如何理解数字工厂管理系统的本质
  • 笔记1.3 数据交换
  • 实时车辆行人多目标检测与跟踪系统(含UI界面,Python代码)
  • 谷歌AI机器人Bard发布强大更新,支持插件功能并增强事实核查;全面整理高质量的人工智能、机器学习、大数据等技术资料
  • NI SCXI-1125 数字量控制模块
  • 链表oj题1(Leetcode)——移除链表元素,反转链表,链表的中间节点,
  • 【libuv】与uvgrtrp的_SSIZE_T_定义不同
  • 安卓ROM定制 修改必备常识-----初步了解system系统分区文件夹的基本含义 【二】
  • GPT会统治人类吗
  • win系统环境搭建(六)——Windows安装nginx
  • Java中使用BigDecimal类相除保留两位小数
  • 激光雷达在ADAS测试中的应用与方案
  • malloc与free
  • 计算周包材,日包材用来发送给外围系统
  • R语言柱状图直方图 histogram
  • Linux磁盘管理:最佳实践
  • uni-app:通过三目运算动态增加样式效果(class)
  • API安全
  • 手写一个翻页功能
  • element show-overflow-tooltip 复制
  • 【C语言】指针的进阶(三)—— 模拟实现qsort函数以及指针和数组的笔试题解析
  • Python 图像处理库PIL ImageOps笔记