Linux驱动之利用ioctl函数和字符设备驱动对象分布注册点亮小灯

news2024/9/24 7:24:57

 

实验结果

 

头文件代码

#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 <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/io.h>
#include "head2.h"

struct cdev *cdev;      // 定义接收字符设备驱动对象的指针
unsigned int major = 0; // 定义主设备号
unsigned int minor = 0; // 定义次设备号
dev_t devno;            // 定义第一个设备号,动态申请设备号时要用到
struct class *cls;      // 向上传递目录的指针
struct device *dev;     // 向上传递设备节点的指针

char kbuf[128] = {0}; // 定义内核中用来接收数据的一块空间

gpio_t *vir_led1;      // 定义用来接收LED1地址映射的指针变量
gpio_t *vir_led2;      // 定义用来接收LED2地址映射的指针变量
gpio_t *vir_led3;      // 定义用来接收LED3地址映射的指针变量
unsigned int *vir_rcc; // 定义用来接收RCC地址映射的指针变量

// 封装操作方法
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
// 通过ioctl进行io功能的控制
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int which; // 因为传递过来的是用户空间的地址,在驱动中定义一个which将用户空间地址中的内容
               // 拷贝下来,实现指针的传递
    int ret = copy_from_user(&which, (unsigned int *)arg, 4);
    if (ret)
    {
        printk("copy_from_user err\n");
        return ret;
    }
    // 根据用户空间功能码cmd的不同实现硬件不同的控制
    switch (cmd)
    {
    case LED_ON:       // 开灯
        switch (which) // 根据传递的参数来决定哪一盏灯开
        {
        case 1:
            vir_led1->ODR |= (0X1 << 10); // LED1亮
            break;
        case 2:
            vir_led2->ODR |= (0X1 << 10); // LED亮
            break;
        case 3:
            vir_led3->ODR |= (0X1 << 8); // LED3亮
            break;
        default:
            break;
        }
        break;
    case LED_OFF: // 关灯
        switch (which)
        {
        case 1:
            vir_led1->ODR &= (~(0X1 << 10));
            break;
        case 2:
            vir_led2->ODR &= (~(0X1 << 10));
            break;
        case 3:
            vir_led3->ODR &= (~(0X1 << 8));
            break;
        default:
            break;
        }
        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,
    .read = mycdev_read,
    .write = mycdev_write,
    .release = mycdev_close,
    .unlocked_ioctl = mycdev_ioctl,
};

//灯的初始化
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 = 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(&devno, minor, 3, "mycdev");
        if (ret)
        {
            printk("静态指定设备号失败\n");
            goto OUT2;
        }
        major = MINOR(devno); // 根据设备号获取次设备号
        major = MAJOR(devno); // 根据设备号获取主设备号
    }
    printk("申请设备号成功\n");

    // 3、注册字符设备驱动对象
    ret = cdev_add(cdev, MKDEV(major, minor), 3);
    if (ret)
    {
        printk("注册字符设备驱动失败\n");
        goto OUT3;
    }

    // 4、向上提供目录
    cls = class_create(THIS_MODULE, "mycdev");
    if (IS_ERR(cls))
    {
        printk("向上提供目录失败\n");
        ret = -PTR_ERR(cls);
        goto OUT4;
    }
    printk("向上提供目录信息成功\n");

    // 5、向上提供设备信息节点
    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(dev);
            goto OUT5;
        }
    }
    printk("向上提交设备节点成功\n");

    // 寄存器映射以及初始化
    all_led_init();
    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);
    // 注销字符设备驱动对象
    cdev_del(cdev);
    // 释放设备号
    unregister_chrdev_region(MKDEV(major, minor), 3);
    // 释放 对象空间
    kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
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>
#include<sys/ioctl.h>
#include"head.h"
 
 
int main(int argc, char const *argv[])
{
    char buf[128]={0};
    int a,b;
    int fd=open("/dev/mycdev0",O_RDWR);
    if(fd<0)
    {
        printf("打开设备文件失败\n");
        exit(-1);
    }
    while(1)
    {
        printf("请输入要实现的功能:1(开灯)0(关灯>)");
        scanf("%d",&a);
        printf("请输入要控制的灯:1(LED1) 2(LED2) 3(LED3)>");
        scanf("%d",&b);
        switch(a)
        {
            case 1:
                ioctl(fd,LED_ON,&b);
                break;
            case 0:
                ioctl(fd,LED_OFF,&b);
                break;
        }
    }
 
    
    close(fd);
 
    return 0;
}

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

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

相关文章

激活函数总结(十一):激活函数补充(Absolute、Bipolar、Bipolar Sigmoid)

激活函数总结&#xff08;十一&#xff09;&#xff1a;激活函数补充 1 引言2 激活函数2.1 Absolute激活函数2.2 Bipolar激活函数2.3 Bipolar Sigmoid激活函数 3. 总结 1 引言 在前面的文章中已经介绍了介绍了一系列激活函数 (Sigmoid、Tanh、ReLU、Leaky ReLU、PReLU、Swish、…

多维时序 | MATLAB实现PSO-CNN-BiLSTM多变量时间序列预测

多维时序 | MATLAB实现PSO-CNN-BiLSTM多变量时间序列预测 目录 多维时序 | MATLAB实现PSO-CNN-BiLSTM多变量时间序列预测基本介绍模型特点程序设计参考资料 基本介绍 本次运行测试环境MATLAB2021b&#xff0c;MATLAB实现PSO-CNN-BiLSTM多变量时间序列预测。代码说明&#xff1a…

掌握渗透测试,从Web漏洞靶场搭建开始

渗透测试切忌纸上谈兵&#xff0c;学习渗透测试知识的过程中&#xff0c;我们通常需要一个包含漏洞的测试环境来进行训练。而在非授权情况下&#xff0c;对于网站进行渗透测试攻击&#xff0c;是触及法律法规的&#xff0c;所以我们常常需要自己搭建一个漏洞靶场&#xff0c;避…

【CUDA】学习记录(4)-线程束的执行

线程模型 block&#xff1a;同一个block内共享内存&#xff0c;同一block中的thread可以彼此进行通信。 block&#xff1a;block-local synchronization。同一个块内的线程可以同步。 线程&#xff0c;可以根据blockIdx和threadIdx唯一的指定。 作者&#xff1a;不会code的程序…

02-前端基础第二天-HTML5

01-HTML标签&#xff08;下&#xff09;导读 目标&#xff1a; 能够书写表格能够写出无序列表能够写出3~4个常用input表单类型能够写出下拉列表表单能够使用表单元素实现注册页面能够独立查阅W3C文档 目录&#xff1a; 表格标签列表标签表单标签综合案例查阅文档 02-表格标…

pygame第6课——贪吃蛇小游戏

今天我们开始Pygame的第六课&#xff0c;前几节课的内容在这里【点我】&#xff0c;欢迎大家前去考古&#xff1a; 今天我们一起来学习制作一个小游戏【贪吃蛇】&#xff0c;这是一个非常经典的小游戏&#xff0c;那么我们一起开始吧 1、游戏准备工作 import pygame, random,o…

常用激活函数及其优缺点的总结与比较

文章目录 1、sigmoid2、Tanh3、ReLU4、Leaky ReLU5、Softmax 1、sigmoid 优点&#xff1a;将很大范围内的输入特征值压缩到0~1之间&#xff0c;适用于将预测概率作为输出的模型&#xff1b; 缺点&#xff1a; 1&#xff09;当输入非常大或非常小的时候&#xff0c;容易导致梯度…

Hadoop的DataNode无法启动的解决方案

Hadoop重启一次&#xff0c;里面的数据需要重新导入&#xff0c;发现无法导入数据&#xff0c;查看jps发现是DataNode没有启动&#xff0c;重新启动发现也无法启动&#xff0c;原因是前面重新启动NameNode&#xff0c;里面的文件格式化一次&#xff0c;DataNode的文件不一致&am…

jmeter监听器大家都会用,但我这个妙招能让你提早一小时下班!

使用过 jmeter 的同学&#xff0c;应该都会使用监听器&#xff0c;在每个监听器中&#xff0c;都会有一个“所有数据写入一个文件”的功能&#xff0c;那这个功能应该怎么用呢&#xff1f;今天&#xff0c;我们就来讲讲这个功能的使用。 几乎所有的监听器都有这样一个功能。 那…

LTD239次升级 | 可答题获取优惠券 • 官微中心菜单可折叠• 分享页表单客户可显示分享来源

1、新增答题获取优惠券应用 2、官微中心支持左侧菜单折叠、批量上传可设置排序值 3、分享页表单客户可显示分享来源 4、iOS App支持设置名片卡片图片 5、新增一款产品列表展示模块 01 网站应用 新增答题获取优惠券应用 本次升级中&#xff0c;新增了一款答题获取优惠券的小程序…

MAC钓鱼并Root权限上线CS并权限维持,以及所有的坑如何解决

本文转载于&#xff1a;https://www.freebuf.com/articles/web/350592.html 作者&#xff1a;文鸯涂鸦智能安全实验室 制作MAC 一、下载工具 首先从github上下载CrossC2。链接&#xff1a;https://github.com/gloxec/CrossC2/releases/tag/v3.1.0。 根据你CS客户端的操作系统选…

基于 BEM 规范实现简单的 全局 scss

前言 BEM 是 css 常用的命名规范BEM &#xff1a;block(块)、 element(元素)、 modify(修饰符)以 namespace-block__element、namespace-block---modify 格式为例&#xff08;namespace 一般是 ui 库的前缀&#xff0c;如 element-ui 的 el 前缀&#xff09;scss 的使用请参考…

计算机竞赛 Yolov安全帽佩戴检测 危险区域进入检测 - 深度学习 opencv

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; Yolov安全帽佩戴检测 危险区域进入检测 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&am…

驱动 day4

通过字符设备驱动分步注册方式编写LED灯的驱动&#xff0c;应用程序使用ioctl函数编写硬件控制 mycdev.c #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #inc…

【中文竞技场】大模型深度体验与测评

简介&#xff1a;本次&#xff0c;我深入体验了中文竞技场中的大语言模型&#xff0c;尝试了写作创作、代码编写和中文游戏三个领域&#xff0c;以下是我详细的评测报告。 一、开篇 在科技日新月异的今天&#xff0c;中文竞技场提供了一系列大模型供我们体验。涉及的领域包括写…

HLS实现FIR低通滤波器+System Generator仿真

硬件&#xff1a;ZYNQ7010 软件&#xff1a;MATLAB 2019b、Vivado 2017.4、HLS 2017.4、System Generator 2017.4 1、MATLAB设计低通滤波器 FPGA系统时钟 50MHz&#xff0c;也是采样频率。用 MATLAB 生成 1MHz 和 10MHz 的正弦波叠加的信号&#xff0c;并量化为 14bit 整数。把…

也许你正处于《孤注一掷》中的“团队”,要留心了

看完这部电影&#xff0c;心情久久不能平静&#xff0c;想了很多&#xff0c;倒不是担心自己哪天也成为“消失的yaozi”&#xff0c;而是在想&#xff0c;我们每天所赖以生存的工作&#xff0c;跟电影里他们的工作比&#xff0c;差别在哪里呢&#xff1f; 目录 1. 产品的本质…

【UniApp开发小程序】商品详情展示+评论、评论展示、评论点赞+商品收藏【后端基于若依管理系统开发】

文章目录 界面效果界面实现工具js页面日期格式化 后端收藏ControllerServicemapper 评论ControllerServiceMapper 商品Controller 阅读Service 界面效果 【说明】 界面中商品的图片来源于闲鱼&#xff0c;若侵权请联系删除 【商品详情】 【评论】 界面实现 工具js 该工…

即拼七人拼团模式怎么玩?如何留存消费者?

如今&#xff0c;流量稀缺&#xff0c;任何流量都需要付出一定的成本&#xff0c;商家做私域亦是如此。我们能做的就是降低预算&#xff0c;探索属于自己的方法。如何进行私域引流&#xff1f; 现阶段&#xff0c;新消费品牌提升品牌力的关键就在于构建品牌与消费者之间的信任关…

大家gobigger连接后不能调亮度(亮度不能保存)解决办法

关于gobigger连接后不能调亮度&#xff0c;会不会感觉是gobigger很爽的一点&#xff1f;其实不是&#xff0c;可以通过以下方法解决。如果解决你的问题给记得点赞&#xff0c;感谢支持。 现象&#xff1a; 数据线连接后&#xff0c;用滚轮调节亮度到最高点&#xff0c;当时是很…