【驱动开发day4作业】

头文件代码

#ifndef __HEAD_H__
#define __HEAD_H__ 
typedef struct{
    unsigned int MODER;
    unsigned int OTYPER;
    unsigned int OSPEEDR;
    unsigned int PUPDR;
    unsigned int IDR;
    unsigned int ODR;
}gpio_t;
#define PHY_LED1_ADDR 0X50006000
#define PHY_LED2_ADDR 0X50007000
#define PHY_LED3_ADDR 0X50006000
#define PHY_RCC_ADDR  0X50000A28
//功能码
#define LED_ON _IOW('l',1,int)
#define LED_OFF _IOW('l',0,int)

#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[])
{
    char buf[128] = {0};
    int a, b;
    int fd;
    while (1)
    {
        // 从终端读取
        printf("请输入要打开哪个设备>");
        printf("0:LED1 1:LED2 2:LED3\n");
        printf("请输入>");
        scanf("%d", &b);
        if (b == 0)
        {
            fd = open("/dev/mycdev0", O_RDWR);
        }
        else if (b == 1)
        {
            fd = open("/dev/mycdev1", O_RDWR);
        }
        else if (b == 2)
        {
            fd = open("/dev/mycdev2", O_RDWR);
        }

        if (fd < 0)
        {
            printf("打开设备文件失败\n");
            exit(-1);
        }

        printf("请输入指令\n");
        printf("0(关灯) 1(开灯)\n");
        printf("请输入>");
        scanf("%d", &a);
        switch (a)
        {
        case 1:
            ioctl(fd, LED_ON); // 开灯
            break;
        case 0:
            ioctl(fd, LED_OFF);
            break;
        }

        close(fd);
    }

    return 0;
}

 驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include<linux/slab.h>
#include<linux/cdev.h>
#include "head.h"

dev_t devid;
struct cdev *cdev;
unsigned int major = 500;
unsigned int minor = 0;
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;
struct class *cls;
struct device *dev;
int mycdev_open(struct inode *inode, struct file *file)
{
    //获取当前设备文件对应的设备号
    int which_dev = inode->i_rdev;
    //将次设备号保存到当前文件的file结构中
    file->private_data = (void *)MINOR(which_dev);
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    unsigned int which_dev = (unsigned int)file->private_data; 
     switch(which_dev)
    {
        case 0:
            //LED1控制逻辑;
            if(cmd == LED_ON)
            {
                 vir_led1->ODR |= (0x1 << 10); // LED1开灯
            }
            else if(cmd == LED_OFF)
            {
                vir_led1->ODR &= (~(0X1 << 10));
            }
            break;   
        case 1:
            //LED2控制逻辑;
            if(cmd == LED_ON)
            {
                 vir_led2->ODR |= (0x1 << 10); // LED2开灯
            }
            else if(cmd == LED_OFF)
            {
                vir_led2->ODR &= (~(0X1 << 10));
            }
            break; 
        case 2:
            //LED3控制逻辑;
            if(cmd == LED_ON)
            {
                 vir_led3->ODR |= (0x1 << 8); // LED3开灯
            }
            else if(cmd == LED_OFF)
            {
                vir_led3->ODR &= (~(0X1 << 8));
            }
            break;                          
    }
    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__);
    return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
    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;
}

// 定义操作方法风扇结构体变量并赋值
struct file_operations fops = {

    .open = mycdev_open,
    .unlocked_ioctl = mycdev_ioctl,
    .release = mycdev_close,
    .read = mycdev_read,
    .write = mycdev_write,
};


// 灯的寄存器映射以及初始化
int all_led_init(void)
{
    // 寄存器地址的映射
    vir_led1 = ioremap(PHY_LED1_ADDR, sizeof(gpio_t));
    if (vir_led1 == NULL)
    {
        printk("ioremap filed:%d\n", __LINE__);
        return -ENOMEM;
    }
    vir_led2 = ioremap(PHY_LED2_ADDR, sizeof(gpio_t));
    if (vir_led2 == NULL)
    {
        printk("ioremap filed:%d\n", __LINE__);
        return -ENOMEM;
    }
    vir_led3 = vir_led1;
    vir_rcc = ioremap(PHY_RCC_ADDR, 4);
    if (vir_rcc == NULL)
    {
        printk("ioremap filed:%d\n", __LINE__);
        return -ENOMEM;
    }
    printk("物理地址映射成功\n");
    // 寄存器的初始化
    // rcc
    (*vir_rcc) |= (3 << 4);
    // led1
    vir_led1->MODER &= (~(3 << 20));
    vir_led1->MODER |= (1 << 20);
    vir_led1->ODR &= (~(1 << 10));
    // led2
    vir_led2->MODER &= (~(3 << 20));
    vir_led2->MODER |= (1 << 20);
    vir_led2->ODR &= (~(1 << 10));
    // led3
    vir_led3->MODER &= (~(3 << 16));
    vir_led1->MODER |= (1 << 16);
    vir_led1->ODR &= (~(1 << 8));
    printk("灯的寄存器初始化成功\n");

    return 0;
}





static int __init mycdev_init(void)
{
    int ret;
    // 1.申请对象空间 cdev_alloc
    cdev = cdev_alloc();
    if (cdev == NULL)
    {
        printk("申请驱动对象空间失败\n");
        ret = -EFAULT;
        goto OUT1;
    }
    printk("申请驱动对象空间成功\n");

    // 2.初始化对象  cdev_init
    cdev_init(cdev, &fops);
    // 3.申请设备号  register_chrdev_region()/alloc_chrdev_region()
    // 动态申请
    if (major == 0)
    {
        ret = alloc_chrdev_region(&devid, minor, 3, "mycdev");
        if (ret != 0)
        {
            printk("动态申请设备号失败\n");
            goto OUT2;
        }
        //统一后面的操作
        major = MAJOR(devid); //根据设备号获取主设备号
        minor = MINOR(devid);
    }
    //静态指定申请
    else
    {
        ret = register_chrdev_region(MKDEV(major,minor),3,"mycdev");
        if(ret != 0)
        {
            printk("静态指定设备号失败\n");
            goto OUT2;
        }
    }
    printk("申请设备号成功\n");
    
    // 4.注册驱动对象 cdev_add()
    ret = cdev_add(cdev, MKDEV(major,minor), 3);
    if (ret != 0)
    {
        printk("注册设备驱动对象失败\n");
        goto OUT3;
    }
    printk("注册设备驱动对象成功\n");

    // 5.向上提交目录  class_create()
    cls = class_create(THIS_MODULE, "mycdev");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        goto OUT4;
    }
    printk("向上提交目录成功\n");

    // 6.向上提交设备信息 device_create()
    int i;
    for (i = 0; i < 3; i++)
    {
        dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d",i);
    }

    if (IS_ERR(dev))
    {
        printk("向上提交设备节点信息失败\n");
        goto OUT5;
    }
    printk("向上提交设备节点信息成功\n");


    // 灯的寄存器映射以及初始化
    all_led_init();


    return 0;
OUT5:
//将提交成功的设备信息销毁
for(--i;i>=0;i--)
{
    device_destroy(cls,MKDEV(major,i));
}
OUT4:
    class_destroy(cls);
OUT3:
    unregister_chrdev_region(MKDEV(major,minor), 3);
OUT2:
    kfree(cdev);
OUT1:
    return ret;
}

static void __exit mycdev_exit(void)
{
    // 取消地址映射
    iounmap(vir_led1);
    iounmap(vir_led2);
    iounmap(vir_rcc);
    // 1.销毁设备信息  device_destroy
    int i;
    for(i=0;i<3;i++)
    {
        device_destroy(cls,MKDEV(major,i));
    }
    // 2.销毁目录    class_destroy
    class_destroy(cls);
    // 3.注销驱动对象  cdev_del
    cdev_del(cdev);
    // 4.释放设备号   unregister_chrdev_region()
    unregister_chrdev_region(MKDEV(major,minor),3);

    // 5.释放对象空间   kfree()
    kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用Wps减小PDF文件的大小

第一步、打开左上角的文件 第二步、点击打印选项 第三步、点击打印按钮

[数据库]对数据库事务进行总结

文章目录 1、什么是事务2、事务的特性&#xff08;ACID&#xff09;3、并发事务带来的问题4、四个隔离级别&#xff1a; 1、什么是事务 事务是逻辑上的一组操作&#xff0c;要么都执行&#xff0c;要么都不执行。 事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红…

基于Fringe-Projection环形投影技术的人脸三维形状提取算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 .................................................................... figure; imshow(Im…

用windeployqt.exe打包Qt代码

首先找到我们编译Qt代码的对应Qt版本的dll目录&#xff0c;该目录下有windeployqt.exe&#xff1a; D:\DevTools\Qt\5.9\msvc2017_64\bin 在这个目录下打开cmd程序。 然后把要打包的exe放到一个单独的目录下&#xff0c;比如&#xff1a; 然后在cmd中调用&#xff1a; winde…

Qt : day4

1.思维导图 2.服务器 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//给服务器指针实例化空间server new QTcpServer(this);}Widget::~Widget() {delete ui;…

25.8 matlab里面的10中优化方法介绍—— 拉各朗日乘子法求最优化解(matlab程序)

1.简述 拉格朗日乘子法&#xff1a; 拉格朗日乘子法&#xff08;Lagrange multipliers&#xff09;是一种寻找多元函数在一组约束下的极值的方法。通过引入拉格朗日乘子&#xff0c;可将有 变量与 约束条件的最优化问题转化为具有变量的无约束优化问题求解 举个例子&#xff…

【MATLAB第60期】【更新中】基于MATLAB的ARMAX具有外生回归因子的移动平均自回归模型

【MATLAB第60期】【更新中】基于MATLAB的ARMAX具有外生回归因子的移动平均自回归模型 版本更新&#xff1a; 2023/7/29版本&#xff1a; 1.增加自定义参数&#xff0c;方便直接套数据运行。 pre_num3;%预采样数据个数 learn_pr0.85; %训练数据比例&#xff08;不包括预采样数…

使用 ChatGPT 进行研究的先进技术

在这篇文章中&#xff0c;您将探索改进您研究的先进技术。尤其&#xff0c; 分析和解释研究数据进行文献综述并找出研究差距废话不多说直接开始吧&#xff01;&#xff01;&#xff01; 分析和解释研究数据 一家小企业主希望分析客户满意度数据以改善客户服务。他们使用包含 10…

边缘计算对现代交通的重要作用

边缘计算之所以重要&#xff0c;是在于即使在5G真正商用之时&#xff0c;可以实现超大带宽&#xff08;eMBB&#xff09;的应用场景&#xff0c;但庞大数据量的涌现也就意味着需要在云和端传输过程中找到一个承接点&#xff0c;对数据进行预处理再选择是否上云。 边缘计算应用演…

源码学习初章-基础知识储备

文章目录 学前准备源码地址引言extern "C" 宏定义平台宏跨平台宏vstdio平台禁用警告宏 连接、双层宏定义函数宏系统函数宏自定义函数宏多语句执行宏do while0 普通宏定义 C的一些必备函数知识回调函数和函数指针回调函数wireshark-4.0.7源码例子函数指针wireshark4.0…

kafka集群搭建(Linux环境)

zookeeper搭建&#xff0c;可以搭建集群&#xff0c;也可以单机&#xff08;本地学习&#xff0c;没必要搭建zookeeper集群&#xff0c;单机完全够用了&#xff0c;主要学习的是kafka&#xff09; 1. 首先官网下载zookeeper&#xff1a;Apache ZooKeeper 2. 下载好之后上传到…

自动化测试框架unittest与pytest的区别!

引言 前面文章已经介绍了python单元测试框架&#xff0c;大家平时经常使用的是unittest&#xff0c;因为它比较基础&#xff0c;并且可以进行二次开发&#xff0c;如果你的开发水平很高&#xff0c;集成开发自动化测试平台也是可以的。而这篇文章主要讲unittest与pytest的区别&…

Grafana - TDEngine搭建数据监测报警系统

TDengine 与开源数据可视化系统 Grafana 快速集成搭建数据监测报警系统 一、介绍二、前置条件三、Grafana 安装及配置3.1 下载3.2 安装3.2.1 windows安装 - 图形界面3.2.2 linux安装 - 安装脚本 四、Grafana的TDEngine配置及使用4.1 登录4.2 安装 Grafana Plugin 并配置数据源4…

流数据湖平台Apache Paimon(一)概述

文章目录 第1章 概述1.1 简介1.2 核心特性1.3 基本概念1.3.1 Snapshot1.3.2 Partition1.3.3 Bucket1.3.4 Consistency Guarantees一致性保证 1.4 文件布局1.4.1 Snapshot Files1.4.2 Manifest Files1.4.3 Data Files1.4.4 LSM Trees 第1章 概述 1.1 简介 Flink 社区希望能够将…

10.python设计模式【代理模式】

内容&#xff1a;为其他对象提供一种代理一控制对这个对象的访问 应用场景&#xff1a; 远程代理&#xff1a; 为远程的对象提供代理虚代理&#xff1a;根据需要创建很大的对象保护代理&#xff1a;控制对原始对象的访问&#xff0c;用于对象有不同访问权限时 UML图 举个例…

新零售行业如何做会员管理和会员营销

蚓链数字化营销系统全渠道会员管理解决方案&#xff0c;线上线下统一管理&#xff0c;打造私域流量&#xff0c;微信、门店会员全渠道管理&#xff0c;打通私域流量池&#xff0c;实现裂变营销&#xff1a; 开启新零售之路&#xff0c;必然要摒弃原有的管理模式&#xff0c;大…

实训笔记7.27

实训笔记7.27 7.27笔记一、Hive数据仓库基本概念&#xff08;处理结构化数据&#xff09;1.1 Hive的组成架构1.1.1 Hive的客户端1.1.2 Hive的驱动程序1.1.3 Hive的元数据库 1.2 Hive和数据库的区别 二、Hive的安装配置三、Hive的相关配置项四、Hive的基本使用方式4.1 使用Hive的…

DMA传输原理与实现详解(超详细)

DMA&#xff08;Direct Memory Access&#xff0c;直接内存访问&#xff09;是一种计算机数据传输方式&#xff0c;允许外围设备直接访问系统内存&#xff0c;而无需CPU的干预。 文章目录 Part 1: DMA的工作原理配置阶段&#xff1a;数据传输阶段&#xff1a; Part 2: DMA数据…

Jmeter+MySQL链接+JDBC Connection配置元件+使用

参考大大的博客学习&#xff1a;怎么用JMeter操作MySQL数据库&#xff1f;看完秒懂&#xff01;_jmeter mysql_程序员馨馨的博客-CSDN博客 注&#xff1a;里面所有没打码的都是假数据&#xff0c;麻烦大家自行修改正确的信息。 一、背景 需要取数据库中的值&#xff0c;作为…

分布式操作系统会不会是操作系统的终端形态?

昨天一位网友私信我&#xff0c;提出一个问题&#xff1a;“Laxcus分布式操作系统会不会是操作系统发展的终极形态&#xff1f;”。今天觉得有必要把这件事说一说&#xff0c;所以就忙里偷闲写下这篇文章。 咱们先说结论&#xff1a;是也不是&#xff0c;需要具体情况具…