驱动 私有数据传参点灯

news2025/7/11 14:56:37

1.在串口工具进行输入:   
    echo 1 > /dev/myled0 ---->led1灯点亮
    echo 0 > /dev/myled0 ---->led1灯熄灭
    echo 1 > /dev/myled1 ---->led1灯点亮
    echo 0 > /dev/myled1 ---->led1灯熄灭
    echo 1 > /dev/myled2 ---->led1灯点亮
    echo 0 > /dev/myled2 ---->led1灯熄灭
linux@ubuntu:/sys/class/myled$ ls /dev/myled* -ll
    
crw------- 1 root root 236, 0 Nov 18 14:55 /dev/myled0 ----->控制PE10(LED1)
    crw------- 1 root root 236, 1 Nov 18 14:55 /dev/myled1----->控制PF10(LED2)
    crw------- 1 root root 236, 2 Nov 18 14:55 /dev/myled2----->控制PE8(LED3)

2.驱动:
    open:在open函数中获取到次设备号,用私有数据传参,传递给write函数
    write:在write函数,判断次设备号,就知道操作的是哪盏灯

3.要求:
    1)分部实现注册字符设备驱动
    2)自动创建设备节点
    3)通过结构体对led灯地址进行映射
    4)次设备号完成私有数据传参

#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/ioctl.h>
#include <linux/cdev.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <uapi/linux/kdev_t.h>
#include "myled.h"

#define CNAME "myled"
char kbuf[128] = {0};
struct class *cls;
struct device *dev;
//虚拟地址
gpio_t *virt_gpioe;           //PE
gpio_t *virt_gpiof;             //PF
volatile unsigned int *virt_rcc;    //RCC

//cdev结构体指针
struct cdev *cdev;
#if 1
unsigned int major=0;   //动态申请设备号
#else
unsigned int major=500; //静态申请设备号
#endif
int minor = 0;
const int count=3;
int mycdev_open(struct inode *inode, struct file *file)
{
    
    int minor;
    minor=MINOR(inode->i_rdev);
    file->private_data=(void*)minor;
    
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{
  
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return size;
}
ssize_t mycdev_write (struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{
    
    int minor;
    int ret;
    minor=(int)file->private_data;
    
    switch(minor)
    {
        case 0:     //LED1---->PE10
            if(size > sizeof(kbuf))
            {
             size=sizeof(kbuf);
            }
            ret=copy_from_user(kbuf,ubuf,size);
            if(ret)
            {
                printk("传递数据失败\n");
                return -EIO;
            }
            if('0'==kbuf[0])
            {
                virt_gpioe->ODR &= (~(0x1<<10));
            }
            else
            {
                virt_gpioe->ODR |=(0x1<<10);
            }
        break;
        case 1:     //LED2---->PF10
            if(size > sizeof(kbuf))
            {
             size=sizeof(kbuf);
            }
            ret=copy_from_user(kbuf,ubuf,size);
            if(ret)
            {
                printk("传递数据失败\n");
                return -EIO;
            }
            if('0'==kbuf[0])
            {
                virt_gpiof->ODR &= (~(0x1<<10));
            }
            else
            {
                virt_gpiof->ODR |=(0x1<<10);
            }
        break;
        case 2:     //LED3---->PE8
            if(size > sizeof(kbuf))
            {
             size=sizeof(kbuf);
            }
            ret=copy_from_user(kbuf,ubuf,size);
            if(ret)
            {
                printk("传递数据失败\n");
                return -EIO;
            }
            if('0'==kbuf[0])
            {
                virt_gpioe->ODR &= (~(0x1<<8));
            }
            else
            {
                virt_gpioe->ODR |=(0x1<<8);
            }
        break;
    }
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return size;
}
long mycdev_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
int  mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
//操作方法结构体
const struct file_operations fops =
{
   .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .unlocked_ioctl = mycdev_ioctl,
    .release = mycdev_close,
};
//入口
static int __init mycdev_init(void)
{
    int i;
    int ret;
    dev_t devno;    //动态分配的设备号
    //1.分配cdev结构体
    cdev=cdev_alloc();
    if(NULL==cdev)
    {
        printk("cdev_alloc fail\n");
        goto ERR1;
        return -EIO;
    }
    //2.初始化结构体
    cdev_init(cdev,&fops);
    //3.申请设备号
    if(major>0)
    {
        //静态
        ret=register_chrdev_region(MKDEV(major,minor),count,CNAME);
        if(ret)
        {
            printk("静态申请设备号失败\n");
            ret=-ENOMEM;
            goto ERR2;
        }
    }
    else
    {
        //动态申请设备号
        ret=alloc_chrdev_region(&devno,0,count,CNAME);
        if(ret)
        {
            printk("动态申请设备失败\n");
            ret=-ENOMEM;
            goto ERR2;
        }
        major=MAJOR(devno);
        minor=MINOR(devno);
    }

    //4.驱动的注册
    ret=cdev_add(cdev,MKDEV(major,minor),count);
    if(ret)
    {
        printk("驱动注册失败\n");
        return -EIO;
        goto ERR3;
    }
    //5.自动创建设备节点
    cls=class_create(THIS_MODULE,CNAME);
    if(IS_ERR(cls))
    {
        printk("向上层提交目录信息失败\n");
        ret=PTR_ERR(cls);
        goto ERR4;
    }
    //提交设备结点信息
    for(i=0;i<count;i++)
    {
        dev=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
        if(IS_ERR(dev))
        {
            printk("提交设备结点信息失败\n");
            ret=PTR_ERR(dev);
            goto ERR5;
        }
    }
    //对灯地址进行映射
    virt_rcc=ioremap(PHY_RCC,4);
    if(NULL==virt_rcc)
    {
        printk("RCC映射失败\n");
        return -ENOMEM;
    }
    virt_gpioe=ioremap(PHY_GPIOE,sizeof(gpio_t));
    if(NULL==virt_gpioe)
    {
        printk("GPIOE映射失败");
        return -ENOMEM;
    }
    virt_gpiof=ioremap(PHY_GPIOF,sizeof(gpio_t));
    if(NULL==virt_gpiof)
    {
        printk("GPIOF映射失败\n");
        return -ENOMEM;
    }
    //对灯进行初始化
    //RCC使能
    *virt_rcc |= (0x3 << 4);
    //1.对LED1--->PE10初始化
   //设置PE10引脚为输出模式
    virt_gpioe->MODER &= (~(0x3 << 20));
    virt_gpioe->MODER |= (0x1 << 20);
    //设置PE10引脚默认为低电平
    virt_gpioe->ODR &= (~(0x1 << 10));

    //2.对LED2--->PF10初始化
    //设置PF10引脚为输出模式
    virt_gpiof->MODER &= (~(0x3 << 20));
    virt_gpiof->MODER |= (0x1 << 20);
    //设置PF10引脚默认为低电平
    virt_gpiof->ODR &= (~(0x1 << 10));

    //3.对LED3--->PE8初始化
    //设置PE8引脚为输出模式
    virt_gpioe->MODER &= (~(0x3 << 16));
    virt_gpioe->MODER |= (0x1 << 16);
    //设置PE8引脚默认为低电平
    virt_gpioe->ODR &= (~(0x1 << 8));
    return 0;
    ERR5:
        for(--i;i>0;i--)
        {
            device_destroy(cls,MKDEV(major,i));
        }
        class_destroy(cls);
    ERR4:
        cdev_del(cdev);
    ERR3:
        unregister_chrdev_region(MKDEV(major,minor),count);
    ERR2:
        kfree(cdev);
    ERR1:
        //返回错误码
        return -EIO;
}
//出口
static void __exit mycdev_exit(void)
{
    int i;
    //1。销毁设备节点信息
    for(i=0;i<count;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    //2.销毁目录信息
    class_destroy(cls);
    //3.驱动的注销
    cdev_del(cdev);
    //4.销毁设备号
    unregister_chrdev_region(MKDEV(major,minor),count);
    //5.释放cdev结构体
    kfree(cdev);
}
//指定入口地址
module_init(mycdev_init);
module_exit(mycdev_exit);
//指定出口地址
//许可证
MODULE_LICENSE("GPL");

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/17969.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

243 h160 相交链表

题解 本题关键: acbbca // 243 h160 相交链表public ListNode getIntersectionNode(ListNode headA, ListNode headB) {ListNode pointAheadA,pointBheadB;int rount2;while (rount>0){if (pointApointB){return pointA;}pointApointA.next;pointBpointB.next;if (pointAnul…

【树莓派不吃灰】命令篇⑥ 了解树莓派Boot分区,学习Linux启动流程

目录1. Linux启动过程1.1 内核引导1.2 运行init初始化进程 —— 初始化系统环境1.3 运行级别 —— runlevel1.4 系统初始化 —— 加载开机启动程序1.5 用户登录1.5.1 方式1&#xff1a;命令行登录1.5.2 方式2&#xff1a;ssh登录&#xff08;常用&#xff09;1.5.3 方式3&#…

[附源码]计算机毕业设计JAVA恒星学院网络计费系统

[附源码]计算机毕业设计JAVA恒星学院网络计费系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM my…

Lingo软硬件划分 实例

文章目录一、SM2 加密算法软硬件划分1.1 实验目标1.2 实验过程&#xff08;1&#xff09; 综合考虑使得系统整体性能最&#xff08;2&#xff09;只考虑硬面积&#xff0c;即系统硬件面积最小&#xff08;3&#xff09;只考虑功耗&#xff0c;即系统功耗最小&#xff08;4&…

SpringBoot实用开发篇复习4(实用开发篇完)

在上面一节&#xff0c;我们学习了SpringBoot整合第三方技术&#xff0c;这次我们主要学习监控技术&#xff0c;主要包含四个部分&#xff0c;分别为监控的意义&#xff0c;可视化监控平台&#xff0c;监控的原理&#xff0c;自定义监控指标等&#xff0c;下面一起来学习吧。 …

nodejs+vue+elementui前台美食网上订餐点菜系统 vscode项目

前端技术&#xff1a;nodejsvueelementui 前端&#xff1a;HTML5,CSS3、JavaScript、VUE 系统分为不同的层次&#xff1a;视图层&#xff08;vue页面&#xff09;&#xff0c;表现层&#xff08;控制器类&#xff09;&#xff0c;业务层&#xff08;接口类&#xff09;和持久层…

SSM框架+LayUi+Mysql实现的物流配送管理系统(功能包含分角色,登录/注册、车辆管理/路线管理/运单管理/调度安排/信息管理等)

博客目录SSM框架LayUiMysql实现的物流配送管理系统实现功能截图系统功能使用技术代码完整源码SSM框架LayUiMysql实现的物流配送管理系统 本系统为了解决物流平台的配送难题&#xff0c;将司机/物流配送的整体流程话&#xff0c;便于物流公司的统一管理&#xff0c;提高了物流日…

JUC学习笔记——共享模型之内存

在本系列内容中我们会对JUC做一个系统的学习&#xff0c;本片将会介绍JUC的内存部分 我们会分为以下几部分进行介绍&#xff1a; Java内存模型可见性模式之两阶段终止模式之Balking原理之指令级并行有序性volatile原理 Java内存模型 我们首先来介绍一下Java内存模型&#xf…

博途1200PLC编码器速度信号采集和滤波处理

速度估算有M法和T法测速2种常用方法,工业控制PLC上基本采用M法测速,M法测速的详细原理,这里不再赘述。感兴趣的可以参看下面的文章链接: PLC通过编码器反馈值计算速度的推荐做法(算法解析+ST代码)_RXXW_Dor的博客-CSDN博客PLC如何测量采集编码器的位置数据,不清楚的可以…

spring框架源码十七、Bean对象创建子流程

Bean对象创建子流程Bean对象创建子流程new ClassPathXmlApplicationContextClassPathXmlApplicationContext#ClassPathXmlApplicationContext(java.lang.String)ClassPathXmlApplicationContext#ClassPathXmlApplicationContext(java.lang.String[], boolean, org.springframew…

冒泡事件在Vue中的应用

什么是事件冒泡&#xff1f; 一想到“冒泡”这两个词会想到什么&#xff1f;想必然&#xff0c;那就是气泡自下而上的从水底往上生的场景&#xff0c;但是我们也知道&#xff0c;水在往上升的过程中&#xff0c;也会经历不同的高度。由此场景&#xff0c;那么想必然&#xff0c…

JavaEE 进阶:Spring 核⼼与设计思想

文章目录一、Spring 是什么1、什么是容器2、什么是 IoC① 传统程序开发Ⅰ 轮胎尺寸固定a. 代码b. 缺陷Ⅱ 轮胎尺寸改变a. 代码b. 缺陷② 控制反转式程序开发Ⅰ 控制反转Ⅱ 需求增加Ⅲ 优点③ 对⽐总结规律3、理解 Spring IoC4、DI 概念说明一、Spring 是什么 Spring是当前Java…

Windows安装nginx

Windows安装nginx1.下载Nginx2.Nginx的使用2.1 修改nginx.conf2.2 启动nginx3.可能出现的问题观前提示&#xff1a; 本文所使用的系统Windows10。 1.下载Nginx Nginx官网&#xff0c;点击download下载 根据需求下载自己所需版本&#xff0c;这里我下载的是稳定版本 2.Nginx的…

链表

章节目录&#xff1a;一、链表1.1 概述二、单向链表2.1 实现思路2.2 代码示例三、双向链表3.1 实现思路3.2 代码示例四、单向环形链表4.1 约瑟夫问题4.2 实现思路4.3 代码示例五、结束语一、链表 1.1 概述 链表是一种物理存储单元上非连续、非顺序的存储结构&#xff0c;数据元…

谷粒学院(一) 项目环境搭建

一、数据库设计 数据库设计规约 以下规约只针对本模块&#xff0c;更全面的文档参考《阿里巴巴Java开发手册》&#xff1a;五、MySQL数据库 1、库名与应用名称尽量一致 2、表名、字段名必须使用小写字母或数字&#xff0c;禁止出现数字开头&#xff0c; 3、表名不使用复数名…

idea导入springboot项目运行教程

前置要求 ①具备Java环境&#xff0c;并且可以通过Maven进行安装项目依赖&#xff1b; ②具备IntelliJ IDEA工具&#xff0c;推荐专业版&#xff0c;社区版也不影响&#xff1b; ③具备Mysql5.7或以上版本数据库&#xff1b; ④具备Navicat数据库可视化管理工具&#xff1b;…

力扣(LeetCode)14. 最长公共前缀(C++)

模拟 取出 strsstrsstrs 的第一个字符串 strs[0]strs[0]strs[0] &#xff0c; 遍历strs[0]strs[0]strs[0] &#xff0c; 依次比较所有串的当前位置的字符&#xff0c;是否和 strs[0]strs[0]strs[0] 的当前字符相同。 代码展示 class Solution { public:string longestCommon…

现代修谱,如何处理族员离婚再娶,配偶携子改嫁同服弟等情况

现代修谱的那些糟心事 现代修谱过程中&#xff0c;会遇到各种突发情况以及非常棘手的问题。比如说族员离婚再娶&#xff0c;配偶携子改嫁同服弟的情况&#xff0c;族谱该如何记载&#xff1f;很多人都以为这是笔者在说笑&#xff0c;但这种情况在修谱时&#xff0c;不能说很难…

Qt源码解析11-QLineEdit与QValidator关系源码解析

Qt源码解析 索引 Qt源码解析11-QLineEdit与QValidator关系源码解析 测试 本想了解QRegExpValidator的正则表达式如何生效的&#xff0c;发现分析起来比想象的复杂。 测试实例&#xff1a; // regexp: optional - followed by between 1 and 3 digitsQRegExp rx("-?\…

JUC学习笔记——共享模型之管程

在本系列内容中我们会对JUC做一个系统的学习&#xff0c;本片将会介绍JUC的管程部分 我们会分为以下几部分进行介绍&#xff1a; 共享问题共享问题解决方案线程安全分析Monitorsynchronized锁Wait/notify模式之保护性暂停模式之生产者消费者park线程状态转换详解多锁操作活跃…