驱动day4作业

news2024/10/4 18:29:37

通过字符设备驱动的分步实现编写LED驱动,另外实现特备文件和设备的绑定

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

demo1.c

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

char kbuf[128]={0};
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;
struct cdev *cdev;
dev_t devno;
unsigned int major=0;
unsigned int minor=0;
struct class *cls;
struct device *dev;
int mycdev_open(struct inode *inode, struct file *file)
{
	int min=MINOR(inode->i_rdev);
	file->private_data=(void*)min;
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}
long mycdev_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
	int min=(int)file->private_data;
	switch(min)
	{
	case 0:
		switch (cmd)
		{
		case LED_ON:
			vir_led1->ODR |= (0x1 << 10);
			break;
		case LED_OFF:
			vir_led1->ODR &= (~(0X1 << 10));
			break;
		}
		break;
	case 1:
		switch (cmd)
		{
		case LED_ON:
			vir_led2->ODR |= (0X1 << 10);
			break;
		case LED_OFF:
			vir_led2->ODR &= (~(0X1 << 10));
			break;
		}
		break;
	case 2:
		switch (cmd)
		{
		case LED_ON:
			vir_led3->ODR |= (0X1 << 8);
			break;
		case LED_OFF:
			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_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;
    cdev=cdev_alloc();
    if(cdev == NULL)
    {
        printk("申请对象失败\n");
        ret=-EFAULT;
        goto out1;
    }
    printk("申请对象成功\n");
    cdev_init(cdev,&fops);
    if(major == 0)
    {
        ret = alloc_chrdev_region(&devno,minor,3,"mychrdev");
        if(ret)
        {
            printk("申请设备号失败\n");
            goto out2;
        }
        printk("申请设备号成功\n");
        major=MAJOR(devno);
        minor=MINOR(devno);
    }
    ret=cdev_add(cdev,MKDEV(major,minor),3);
    if(ret)
    {
        printk("注册对象失败\n");
        goto out3;
    }
    printk("注册对象成功\n");
 

    cls=class_create(THIS_MODULE,"mychrdev");
    if(IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        goto out4;
    }
    printk("向上提交目录成功\n");
    int i;
    for(i=0;i<3;i++)
    {
        dev=device_create(cls,NULL,MKDEV(major,i),NULL,"myled%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));
    }
    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");

text.c

#include<stdlib.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include<unistd.h>
#include<string.h>
#include "head.h"
 
 
int main(int argc, char const *argv[])
{
	int fd;
	char name[20]={0};
	int a,b;
	while(1)
	{
        printf("请选择要控制的灯:1(LED1)2(LED2) 3(LED3)\n");
        printf("请输入>");
        scanf("%d",&b);
		switch(b)
		{
			case 1:
				strcpy(name,"/dev/myled0");
				break;
			case 2:
				strcpy(name,"/dev/myled1");
				break;
			case 3:
				strcpy(name,"/dev/myled2");
				break;
		}
		fd=open(name,O_RDWR);
		if(fd<0)
		{
			printf("打开设备文件失败\n");
			exit(-1);
		}
        //从终端读取
        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;
}

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

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

相关文章

2007-2022 年上市公司国内外专利授权情况数据

2007-2022 年上市公司国内外专利授权情况 1、来源&#xff1a;国家知识产权局 2、时间&#xff1a;2007-2022 年 3、范围&#xff1a;上市公司 4、指标&#xff1a; 证券代码、年份、省份、城市、行业代码、授权地区、申请类型、专利、发明专利、实用新型、外观设计 5、…

SpringBoot读取Resource下文件的几种方式读取jar里的excel,文件损坏

在项目中涉及到Excle的导入功能&#xff0c;通常是我们定义完模板供用户下载&#xff0c;用户按照模板填写完后上传&#xff1b; 这里待下载模板位置为resource/template/员工基础信息导入模板.xlsx&#xff0c; 分别尝试了四种读取方式&#xff0c;并且测试了四种读取方式分别…

Multi-task Classification Model Based On Multi-modal Glioma Data

框架 体会 为什么不对三个任务用一个CNN呢&#xff1f; 作者未公布代码

解决VMware虚拟机更新17.5.0版本后,启动虚拟机导致电脑重启的问题。(建议收藏)

今天VMware虚拟机又迎来了新的一次更新&#xff0c;这次更新重点在于安全性提高了不少。 更新也是花了不少时间&#xff0c;更新完成后&#xff0c;我满怀着激动欣喜的心情打开了我的Kali&#xff0c;。。。哎&#xff0c;不是&#xff0c;怎么黑屏了&#xff0c;然后看到了物…

报错:The supplied javaHome seems to be invalid. I cannot find the java executable

AS 升级遇到的问题 问题 升级 Android Studio&#xff0c;碰到无法检测到 java The supplied javaHome seems to be invalid. I cannot find the java executable. Tried location: D:\Program Files\Android\Android Studio\jre\bin\java.exe 然后去网上找解决思路。 终于…

【Java集合类面试六】、 HashMap有什么特点?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;HashMap有什么特点&…

订水商城H5实战教程-02系统登录

目录 1 创建数据源2 创建自定义应用3 创建全局变量4 实现登录功能5 控制弹窗是否显示6 最终的效果 上一篇我们分析了订水商城的功能&#xff0c;功能分析好了之后&#xff0c;就需要开发功能。用户登录商城的第一步就是进行登录&#xff0c;登录的时候需要同意用户协议&#xf…

Apollo插件:个性化你的开发流程

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

网络安全(黑客技术)—自学

目录 一、自学网络安全学习的误区和陷阱 二、学习网络安全的一些前期准备 三、网络安全学习路线 四、学习资料的推荐 想自学网络安全&#xff08;黑客技术&#xff09;首先你得了解什么是网络安全&#xff01;什么是黑客&#xff01; 网络安全可以基于攻击和防御视角来分类&am…

SpringBoot AOP + Redis 延时双删功能实战

一、业务场景 在多线程并发情况下&#xff0c;假设有两个数据库修改请求&#xff0c;为保证数据库与redis的数据一致性&#xff0c;修改请求的实现中需要修改数据库后&#xff0c;级联修改Redis中的数据。 请求一&#xff1a;A修改数据库数据 B修改Redis数据 请求二&#xff…

【Java集合类面试八】、 介绍一下HashMap底层的实现原理

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a; 介绍一下HashMap底层的…

SSM - Springboot - MyBatis-Plus 全栈体系(三十五)

第八章 项目实战 四、后台功能开发 2. 首页模块开发 2.1 查询首页分类 2.1.1 需求描述 进入新闻首页,查询所有分类并动态展示新闻类别栏位 2.1.2 接口描述 url 地址&#xff1a;portal/findAllTypes 请求方式&#xff1a;get 请求参数&#xff1a;无 响应数据&#xff…

一文解读 SmartX 超融合虚拟化下的网络 I/O 虚拟化技术

随着技术的不断发展&#xff0c;不少行业应用都对网络性能和隔离性有着越来越高的要求。例如&#xff1a; 低延迟&#xff1a;一些期货行业用户选择在期货公司机房托管服务器并自行编写交易程序&#xff0c;以实现对市场波动的快速&#xff08;微秒级&#xff09;反应。尤其是在…

DYC算法开发与测试(基于ModelBase实现)

ModelBase是经纬恒润开发的车辆仿真软件&#xff0c;包含两个大版本&#xff1a;动力学版本、智能驾驶版本。动力学版包含高精度动力学模型&#xff0c;能很好地复现车辆在实际道路中运行的各种状态变化&#xff0c;可用于乘用车、商用车动力底盘系统算法开发、控制器仿真测试&…

2023深圳CPSE安博会亮点指引

一、深圳安博会开展预告 10月25-28日&#xff0c;第十九届中国国际社会公共安全博览会&#xff08;简称“CPSE安博会”&#xff09;即将在深圳会展中心&#xff08;福田&#xff09;拉开帷幕。110,000㎡展示面积&#xff0c;130,000名专业观众&#xff0c;1000参展企业&#x…

如何制作自己的数字人

如何制作自己的数字人呢&#xff1f;不用担心平台的使用授权&#xff0c;也不用担心哪一天自己自媒体被号被无故封杀&#xff0c;那么SadTalker将是你的首选&#xff0c;他是完全开源的数字人软件&#xff0c;现已达到Apache2的授权&#xff0c;完全自由的开源软件。作者自己试…

Java中,字符串有多个空格如何截取

笔者在开发中&#xff0c;遇到需要对三方接口返回的报文进行处理&#xff0c;将对方填充的所有空格干掉&#xff0c;截取成list 使用正则表达式&#xff1a;split(“\s”) public static void main(String[] args) {String str "1111 22 33 888";// …

离线直线度测量仪的自动检测之旅!

离线直线度测量仪更适用于产品的抽检&#xff0c;虽然是离线检测设备&#xff0c;但需人工操作的工作非常少&#xff0c;是智能化的检测设备&#xff0c;本来来简单的介绍一下该测量设备。 离线直线度测量仪采用光电测头的直径和位置测量原理进行测量&#xff0c;测量仪采用成9…

【QT开发(11)】QT 线程QThread

Qt的线程支持与平台无关的&#xff1a; 线程类、一个线程安全的发送事件方式跨线程的信号-槽的关联 这使得可以从分利用多处理器机器&#xff0c;有效解决不冻结一份应用程序用户界面的情况下&#xff0c;处理一个耗时操作的问题。 文章目录 1、QThread 一个与平台无关的线程…