设备文件和设备绑定

news2024/11/18 17:28:10

实验目的:使用函数让设备文件和设备绑定,完成对LED的简单控制

在test.c中完成硬件逻辑控制

test.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include "head.h"

void LED_CONTROL()
{
    int a, b, fd;
    while (1)
    {
        printf("需要控制的灯1(LED1) 2(LED2) 3(LED3) > \n");
        scanf("%d", &a);
        switch (a)
        {
        case 1:
            fd = open("/dev/mycdev0", O_RDWR);
            break;
        case 2:
            fd = open("/dev/mycdev1", O_RDWR);
            break;
        case 3:
            fd = open("/dev/mycdev2", O_RDWR);
            break;
        default:
            break;
        }

        if (fd < 0)
        {
            printf("打开设备失败\n");
            exit(-1);
        }
        printf("实现功能:1(开灯) 0(关灯) > \n");
        scanf("%d", &b);
        switch (b)
        {
        case 1:
            ioctl(fd, LED_ON, &a);
            break;
        case 0:
            ioctl(fd, LED_OFF, &a);
            break;
        default:
            break;
        }
        close(fd);
    }
}

int main(int argc, const char *argv[])
{
    LED_CONTROL();
    return 0;
}

Character_device.c

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

unsigned int major = 0;
unsigned int minor = 0;

gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;

struct cdev *cdev;
dev_t devnum;

// 向上申请的结构体目录信息
struct class *cls;
// 向上申请的结构体节点信息
struct device *dev;

spinlock_t lock;

// 封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    unsigned int minor = MINOR(inode->i_rdev); // 获取操作的文件的次设备号
    file->private_data = (void *)minor;        // 将次设备号当做file对象的私有数据存放
    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;
}

long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    unsigned int which = (unsigned int)file->private_data; // 获取open中得到的文件次设备号
    int ret = copy_from_user(&which, (unsigned int *)arg, 4);
    if (ret)
    {
        printk("copy_from_user is ERR\n");
        return ret;
    }
    spin_lock(&lock);
    switch (which)
    {
    case 1:
        switch (cmd)
        {
        case LED_ON:
            vir_led1->ODR |= 0x1 << 10;
            break;
        case LED_OFF:
            vir_led1->ODR &= (~(0x1 << 10));
            break;
        default:
            break;
        }
        break;
    case 2:
        switch (cmd)
        {
        case LED_ON:
            vir_led2->ODR |= 0x1 << 10;
            break;
        case LED_OFF:
            vir_led2->ODR &= (~(0x1 << 10));
            break;
        default:
            break;
        }
        break;
    case 3:
        switch (cmd)
        {
        case LED_ON:
            vir_led3->ODR |= 0x1 << 8;
            break;
        case LED_OFF:
            vir_led3->ODR &= (~(0x1 << 8));
            break;
        default:
            break;
        }
        break;
    default:
        break;
    }
    spin_unlock(&lock);
    return 0;
}

// 寄存器地址映射
int all_led_init(void)
{
    vir_led1 = ioremap(PHY_LED1_ADDR, sizeof(gpio_t));
    if (vir_led1 == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }

    vir_led2 = ioremap(PHY_LED2_ADDR, sizeof(gpio_t));
    if (vir_led2 == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    vir_led3 = vir_led1;

    vir_rcc = ioremap(PHY_RCC_ADDR, 4);
    if (vir_rcc == NULL)
    {
        printk("物理内存映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    printk("物理内存映射成功\n");
    // rcc
    (*vir_rcc) |= 0x3 << 4;
    // LED1
    vir_led1->MODER &= (~(0x3 << 20));
    vir_led1->MODER |= 0x1 << 20;
    vir_led1->ODR &= (~(0x1 << 10));
    // LED2
    vir_led2->MODER &= (~(0x3 << 20));
    vir_led2->MODER |= 0x1 << 20;
    vir_led2->ODR &= (~(0x1 << 10));
    // LED3
    vir_led3->MODER &= (~(0x3 << 16));
    vir_led3->MODER |= 0x1 << 16;
    vir_led3->ODR &= (~(0x1 << 8));

    return 0;
}

struct file_operations fops = {
    .open = mycdev_open,
    .release = mycdev_close,
    .read = mycdev_read,
    .write = mycdev_write,
    .unlocked_ioctl = mycdev_ioctl,
};

static int __init mycdev_init(void)
{
    int ret;
    // 1.分配字符设备驱动对象
    cdev = cdev_alloc();
    if (cdev == NULL)
    {
        printk("申请字符设备驱动对象失败\n");
        ret = -EFAULT;
        goto OUT1;
    }
    printk("申请字符设备驱动成功\n");
    // 2.初始化字符设备驱动对象
    cdev_init(cdev, &fops);
    // 3.申请设备号
    if (major > 0) // 静态指定
    {
        ret = register_chrdev_region(MKDEV(major, minor), 3, "mycdev");
        if (ret)
        {
            printk("静态指定设备号失败\n");
            goto OUT2;
        }
    }
    else
    {
        ret = alloc_chrdev_region(&devnum, minor, 3, "mycdev");
        if (ret)
        {
            printk("静态指定设备号失败\n");
            goto OUT2;
        }
        minor = MINOR(devnum);
        major = MAJOR(devnum);
    }
    printk("申请设备号成功\n");
    // 4.注册字符设备驱动对象
    ret = cdev_add(cdev, MKDEV(major, minor), 3);
    if (ret)
    {
        printk("注册字符设备驱动对象失败\n");
        goto OUT3;
    }
    printk("注册字符设备驱动对象成功\n");

    // 寄存器映射函数
    all_led_init();

    // 向上提交目录信息
    cls = class_create(THIS_MODULE, "mycdev");
    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, "mycdev%d", i);
        if (IS_ERR(dev))
        {
            printk("向上提交设备节点失败\n");
            ret = -PTR_ERR(cls);
            goto OUT5;
        }
    }
    printk("向上提交设备节点成功\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;
}

static void __exit mycdev_exit(void)
{
    // 取消物理映射
    iounmap(vir_led1);
    iounmap(vir_led2);
    iounmap(vir_rcc);

    // 销毁设备信息
    int i;
    for (i = 0; i < 3; i++)
        device_destroy(cls, MKDEV(major, i));

    // 销毁目录信息
    class_destroy(cls);
    // 注销字符设备驱动对象
    unregister_chrdev_region(MKDEV(major, minor), 3);
    // 释放空间对象
    kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

实现效果

串口查看:

实际现象:

 

 

 

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

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

相关文章

openGauss学习笔记-44 openGauss 高级数据管理-存储过程

文章目录 openGauss学习笔记-44 openGauss 高级数据管理-存储过程44.1 语法格式44.2 参数说明44.3 示例 openGauss学习笔记-44 openGauss 高级数据管理-存储过程 存储过程是能够完成特定功能的SQL语句集。用户可以进行反复调用&#xff0c;从而减少SQL语句的重复编写数量&…

eUICC 识别号 (EIN)

GSMA 是业界指定的一级 EID&#xff08;eUICC 标识符&#xff09;分配机构&#xff0c;负责协调 eUICC 标识号的发行和使用。每个 eSIM 都需要具有唯一、持久且安全的 EID&#xff0c;以识别嵌入式或可移动 eUICC&#xff0c;如SGP.29中所定义。 GSMA eUICC 身份方案为每个 eUI…

“智能查单轻松实现批量快递查询,高效掌握快递物流信息!“

亲爱的用户&#xff0c;你是否常常为了查询大量快递单号而感到烦恼&#xff1f;不用担心&#xff0c;我们已经为你提供了一种高效、智能的解决方案&#xff01;现在&#xff0c;只需一键操作&#xff0c;即可实现批量快递查询&#xff0c;迅速了解每个单号的详细物流信息。 首…

网络编程(基础)

一、OSI体系结构 ISO&#xff08;国际标准化组织&#xff09;制定了一个国际标准OSI&#xff08;开放式通讯系统互联参考模型&#xff09;&#xff0c;对通讯系统进行了标准化。 定义了7层模型&#xff1a; 二、TCP/IP协议介绍 OSI模型是一个理想化的模型已经很少使用&#x…

git merge规则

参考文档&#xff1a;https://juejin.cn/post/7129333439299321887 丹尼尔&#xff1a;Hi&#xff0c;蛋兄&#xff0c;周杰伦都出新专辑了&#xff0c;你咋还不更新啊&#xff0c;真的打算半年一更啊&#xff1f; 蛋先生&#xff1a;好像确实是这样&#xff0c;要不&#xff0…

【机器学习】— 2 图神经网络GNN

一、说明 在本文中&#xff0c;我们探讨了图神经网络&#xff08;GNN&#xff09;在推荐系统中的潜力&#xff0c;强调了它们相对于传统矩阵完成方法的优势。GNN为利用图论来改进推荐系统提供了一个强大的框架。在本文中&#xff0c;我们将在推荐系统的背景下概述图论和图神经网…

在“听得懂”之后“看得见、动起来”,实在智能首发“你说PC做”的大模型Agent

大洋彼岸种下了一颗AI的种子&#xff0c;拥有“算力魔法”的ChatGPT在海内外掀起一场“大”爆发——大型语言模型爆发&#xff0c;带动了AI大模型技术的新热潮。 “你问我答”的不仅是ChatGPT上的交互形态&#xff0c;更是一张名为“大模型”的问卷&#xff0c;答的是全球人工…

Python可视化在量化交易中的应用(13)_Seaborn直方图

Seaborn中带核密度的直方图的绘制方法 seaborn中绘制直方图使用的是sns.histlot()函数&#xff1a; sns.histplot(data,x,y,hue,weights,stat‘count’,bins‘auto’,binwidth,binrange,discrete,cumulative,common_bins,common_norm,multiple‘layer’,element‘bars’,fill,…

如何解决使用npm出现Cannot find module ‘XXX\node_modules\npm\bin\npm-cli.js’错误

遇到问题&#xff1a;用npm下载组件时出现Cannot find module ‘D&#xff1a;software\node_modules\npm\bin\npm-cli.js’ 问题&#xff0c;导致下载组件不能完成。 解决方法&#xff1a;下载缺少的npm文件即可解决放到指定node_modules目录下即可解决。 分析问题&#xff1…

KubeSphere 社区双周报 | Java functions framework 支持 SkyWalking | 2023.8.4-8.17

KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书、新增的讲师证书以及两周内提交过 commit 的贡献者&#xff0c;并对近期重要的 PR 进行解析&#xff0c;同时还包含了线上/线下活动和布道推广等一系列社区动态。 本次双周报涵盖时间为&#xff1a;2023.08.04-2023.…

CPU执行程序的三个阶段简单示例(取指,解码,执行)

基础知识 RAM&#xff1a;RAM是随机存取存储器&#xff08;random access memory&#xff09;&#xff0c;是计算机内部存储器中的一种&#xff0c;也是其中最重要的&#xff0c;计算机和手机中一般把其叫做&#xff08;运行&#xff09;内存&#xff0c;它的速度要比硬盘快得多…

JDK8知识点梳理

JDK8知识点梳理 一、lambda表达式1.标准格式2.实现原理3.省略模式4.前提条件 二、函数式接口1.函数式接口&#xff1a;FunctionalInterface2.接口默认方法3.接口静态方法4.供给型接口&#xff1a;Supplier5.消费型接口&#xff1a;Consumer6.消费供给型接口&#xff1a;Functio…

Redis中的分布式锁及其延生的问题

前言 本文将着重介绍Redis中的分布式锁及其与出现的死锁和锁误删问题 什么是分布式锁 首先问题就是什么是分布式锁&#xff0c;分布式锁就是分布式系统中实现并发控制的一种锁机制&#xff0c;它可以保证多个节点在同一个时间只有有一个能成功竞争到系统资源&#xff08;共享…

[oneAPI] 使用序列到序列网络和注意力进行翻译

[oneAPI] 使用序列到序列网络和注意力进行翻译 oneAPI特殊写法使用序列到序列网络和注意力进行翻译Intel Optimization for PyTorch导入包加载数据并对数据进行处理序列到序列网络和注意力模型与介绍编码器解码器简单解码器注意力解码器 训练过程准备训练数据训练模型可视化注意…

Ubuntu在自己的项目中使用pcl

1、建立一个文件夹&#xff0c;如pcl_demos&#xff0c;里面建立一个.cpp文件和一个cmake文件 2、打开终端并进入该文件夹下&#xff0c;建立一个build文件夹存放编译的结果并进入该文件夹 3、对上一级进行编译 cmake .. 4、生成可执行文件 make 5、运行该可执行文件 6、可视…

STL——stack和queue

一、stack和queue stl中提供了栈和队列配接器供我们使用&#xff0c;以后就可以直接使用了。不需要我们自己造轮子。 使用细节参考文档就可以&#xff0c;与之学过的容器并无二致。栈和队列的特性我们再学习数据结构时已经了解了。这里就不在赘述了。 stack - C Reference (…

FifthOne:计算机视觉提示和技巧

一、说明 欢迎来到我们每周的FiftyOne提示和技巧博客&#xff0c;我们回顾了最近在Slack&#xff0c;GitHub&#xff0c;Stack Overflow和Reddit上弹出的问题和答案。FiftyOne是一个开源机器学习工具集&#xff0c;使数据科学团队能够通过帮助他们策划高质量数据集、评估模型、…

Games 103 作业一

Games 103 作业一 整个作业一的内容其实就是要自己动手实现一遍Impulse和Shape Matching这两个方法。作业中给的示例场景如下&#xff1a; 场景中有个兔子的刚体&#xff0c;我们要模拟的就是给兔子一个初始的速度&#xff0c;让其在重力的影响下&#xff0c;与两堵墙发生碰撞的…

嵌入式开发中的抽象、封装与继承

嵌入式开发中的抽象、封装与继承 ## 1 何从实现&#xff1f; OOP 是 CPP 的显著特征&#xff0c;尽管它是一种多重范式的语言 第一部分谈的是产品的实现&#xff08;implement&#xff09;而非产品的设计&#xff0c;因为对于个人开发者而言&#xff0c;往往是知道如何实现产…

港科夜闻|香港科大校长叶玉如教授、香港科大(广州)校长倪明选教授等两校领导共同出席香港科大(广州)首批本科新生见面会...

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大校长叶玉如教授、香港科大(广州)校长倪明选教授等两校领导共同出席香港科大(广州)首批本科新生见面会。8月16日&#xff0c;香港科大(广州)首批本科新生参加了一次具有特殊意义的见面会。香港科大、香港科大(广州…