作业day4

news2024/12/28 5:31:38

1.通过字符设备驱动分步注册方式编写LED灯的驱动,应用程序使用ioctl函数编写硬件控制逻辑

head.h

#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('1',1,int)
#define LED_OFF _IOW('1',0,int)
#endif

test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include "head.h"
int main(int argc,const char * argv[])
{   

        int a,b;
        char buf[128] ={};
        int fd =open("/dev/mycdev",O_RDWR);
        if(fd < 0)
        {
            printf("open device file error\n");
            exit(-1);
        }
        printf("open device file successful!\n");
        while(1)
        {
            printf("请选择功能要控制的灯");
            scanf("%d",&b);
            printf("请选择要1开灯 0关灯");
            scanf("%d",&a);
            switch(a)
            {
                case 1:
                    ioctl(fd,LED_ON,&b);
                    break;
                case 0:
                    ioctl(fd,LED_OFF,&b);
                    break;

            }

        }
        close(fd);
        return 0;
}

mycdev.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include "head.h"
struct cdev *cdev;
unsigned int major=0;
unsigned int minor=0;
dev_t devno;


char kbuf[128] = {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)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int which;
    int ret=copy_from_user(&which,(unsigned int *)arg,4);
    if(ret)
    {
        printk("copy_from_user err\n");
        return ret;
    }
    // 根据用户空间功能码的不同实现硬件不同的控制
    switch (cmd)
    {
    case LED_ON: // 开灯
        switch (which)
        {
        case 1: // LED1
            vir_led1->ODR |= (0X1 << 10);
            break;
        case 2: // LED2
            vir_led2->ODR |= (0X1 << 10);
            break;
        case 3: // LED3
            vir_led3->ODR |= (0X1 << 8);
            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;
        }

        break;
    }
    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,
};
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_led1->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;
        }
        minor=MINOR(devno);//根据设备号获取次设备号
        major=MAJOR(devno);//根据设备号获取主设备号
        
    }
    printk("字符设备驱动注册成功:major=%d\n", major);
    printk("申请设备号成功\n");
    //4.注册字符设备驱动对象
    ret=cdev_add(cdev,MKDEV(major,minor),3);
    if(ret)
    {
        printk("注册字符设备驱动对象失败\n");
       goto OUT3;
    }
    printk("注册字符设备驱动对象成功\n");
    //向上提交目录
    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(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");

串口显示

 

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

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

相关文章

主机防护的重要性和方式

01 主机防护的重要性 主机防护是网络安全的重要组成部分。在互联网时代&#xff0c;网络攻击成为了一种常见的威胁&#xff0c;而主机防护则是保护计算机系统免受网络攻击的重要手段。 主机防护可以防范各种网络攻击&#xff0c;如病毒、木马、黑客攻击等&#xff0c;从而保…

如何做好会员管理,有哪些好用的会员管理系统?

会员管理对于企业或中小商户来说非常重要&#xff0c;会员管理可以建立和维护与顾客之间的紧密关系&#xff0c;通过会员管理系统记录和分析会员的购买历史、偏好和行为&#xff0c;可以更好地了解他们的需求和兴趣&#xff0c;增加销售机会和满意度。 那么我们应该如何做好会员…

【深度学习 | 感知器 MLP(BP神经网络)】掌握感知的艺术: 感知器和MLP-BP如何革新神经网络

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

使用教程|CloudQuery: 数据库操作管控云平台初体验

&#x1f600;前言 前言&#xff1a;就在刚刚&#xff0c;在一个技术交流群里了解到了一场活动&#xff1a;CloudQuery 社区的有奖征文活动。除了有丰厚的礼物&#xff0c;使用过程中还有技术同学的支持。但是 CloudQuery 这个产品我也没有过多的了解&#xff0c;抱着对产品的好…

AndroidStudio升级Gradle之坑

最近在做旧工程的升级&#xff0c;原来的Gradle版本是4.6的&#xff0c;需要升级到7.6&#xff0c;JDK从8升级到17&#xff0c;一路淌了很多坑&#xff0c;逐个记录下吧 1、Maven仓库需要升级到https 你会遇到这个报错 Using insecure protocols with repositories, without …

item_search-按关键字搜索淘宝商品

一、接口参数说明&#xff1a; item_search-按关键字搜索淘宝商品&#xff0c;点击更多API调试&#xff0c;请移步注册API账号点击获取测试key和secret 公共参数 请求地址: https://api-gw.onebound.cn/taobao/item_search 名称类型必须描述keyString是调用key&#xff08;点…

边缘计算节点BEC典型实践:如何快速上手PC-Farm服务器?

百度智能云边缘计算节点BEC&#xff08;Baidu Edge Computing&#xff09;基于运营商边缘节点和网络构建&#xff0c;一站式提供靠近终端用户的弹性计算资源。边缘计算节点在海外覆盖五大洲&#xff0c;在国内覆盖全国七大区、三大运营商。BEC通过就近计算和处理&#xff0c;大…

【Linux命令详解 | tar命令】 tar命令用于打包和解压文件,常用于备份和压缩文件

文章标题 简介一&#xff0c;参数列表二&#xff0c;使用介绍1. 打包文件和目录2. 解包归档文件3. 压缩归档文件4. 列出归档文件内容5. 排除特定文件6. 保留文件权限和所有权7. 保留时间戳8. 增量备份9. 使用文件列表10. 压缩级别控制 总结 简介 在Linux中&#xff0c;tar命令…

游戏出海工具都有哪些?

游戏出海是一个复杂的过程&#xff0c;需要运用多种工具来进行市场分析、推广、本地化等工作。以下是一些常用的游戏出海工具&#xff1a; 一、必备工具&#xff1a; 1、游戏平台&#xff1a;要想进行游戏出海运营&#xff0c;游戏平台时必不可少的&#xff0c;选择游戏平台时…

一节网课中有哪些“黑科技”,猿辅导给出了这样的答案

近年来&#xff0c;AI正以润物细无声的方式重塑多个行业的面貌&#xff0c;教育行业也不例外。同时&#xff0c;随着Chat GPT对社会带来的冲击不断加强&#xff0c;AI教育已经成为整个行业不可逆转的趋势。作为最早踏入智能教育领域的企业之一&#xff0c;猿辅导深谙技术革新对…

如何正确使用生成式 AI?

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可二次编辑的3D应用场景 在过去几年中&#xff0c;数据的创建速度呈指数级增长&#xff0c;这主要意味着数字世界的日益扩散。 估计吧&#xff1f;仅在过去两年中&#xff0c;世界上90%的数据就产生了。 我们以各种形式与互…

Android 命令行如何运行 JAR 文件

​ 最近有位老哥问了一个问题&#xff0c;说如果将java的jar文件在Android中执行&#xff1f;这个其实很简单的一个问题&#xff0c;直接写个App放里面不就可以了么&#xff1f;但是人家说没有App&#xff0c;直接使用命令行去运行。说明这个需求的时候&#xff0c;把我给整懵了…

人尽其才、数尽其用,Smartbi Eagle智慧数据运营平台全新亮相

数据是企业数字化转型的基石&#xff0c;也是赢得未来的核心资产和竞争力。数字化转型的关键&#xff0c;是在全公司建立一种数据驱动的组织和机制&#xff0c;营造数据文化的氛围&#xff0c;让更多的用户、在更多的场景中&#xff0c;有意愿、有能力使用数据&#xff0c;从而…

COMSOL光电仿真专题第三十五期线上通知

培训背景&#xff1a; COMSOL多物理场仿真软件以高效的计算性能和杰出的多场耦合分析能力实现了精确的数值仿真&#xff0c;已被广泛应用于各个领域的科学研究以及工程计算&#xff0c;为工程界和科学界解决了复杂的多物理场建模问题。光电作为物理类专业课程中极为重要的一部…

Jmeter 快速生成测试报告

我们使用Jmeter工具进行接口测试或性能测试后一般是通过察看结果数、聚合报告等监听器来查看响应结果。如果要跟领导汇报测试结果&#xff0c;无法直接通过监听器的结果来进行展示和汇报&#xff0c;因为太low了&#xff0c;因此测试完成后去整理一个数据齐全且美观的报告是非常…

OSM模型案例:以游戏陪练app为例

OSM模型的概念 O指目标Objective&#xff1a;整个业务、乃至局部的小功能 能解决什么问题&#xff0c;提供什么样的用户价值&#xff0c;满足用户什么需求&#xff1f; S指策略Strategy&#xff1a;如何达成目标&#xff0c;以什么方式达成目标&#xff1f; M指度量Measure&…

RabbitMq-发布确认高级(避坑指南版)

在初学rabbitMq的时候&#xff0c;伙伴们肯定已经接触到了“发布确认”的概念&#xff0c;但是到了后期学习中&#xff0c;会接触到“springboot”中使用“发布确认”高级的概念。后者主要是解决什么问题呢&#xff1f;或者是什么样的场景引出这样的概念呢&#xff1f; 在生产环…

前端原生写自定义旋转变换轮播图

html部分&#xff1a; <div class"banner_box"><div class"swiperWrapper" v-show"bannerList.length>0"><div class"swiper-item" :id"swiperSlide${index}" :class"{active:index0,next:index1,pr…

耗资170亿美元?三星电子在得克萨斯州建设新的半导体工厂

据报道&#xff0c;三星电子在得克萨斯州泰勒市建设的新的半导体工厂预计将于2024年下半年投入运营。这座工厂将成为三星电子在美国的第二座芯片代工厂&#xff0c;与位于得克萨斯州奥斯汀市的第一座工厂相距不远。 此次投资将耗资约170亿美元&#xff0c;显示了三星电子在半导…

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

实验结果 头文件代码 #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 0X5…