字符设备驱动分步注册实现LED驱动的编写

头文件

#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 RCC            0x50000A28
#define LED1_ADDR      0x50006000
#define LED2_ADDR      0x50007000
#define LED3_ADDR      0x50006000#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[])
{int fd;fd=open("/dev/myled0",O_RDWR);if(fd<0){printf("打开设备文件失败\n");exit(-1);}int a,b;while (1){printf("请输入要实现的功能\n");printf("0关灯,1开灯\n");printf("请输入>");scanf("%d",&a);printf("请输入控制的灯\n");printf("1(LED1)2(LED2)3(LED3)\n");scanf("%d",&b);switch (a){case 1:ioctl(fd,LED_ON,&b);break;case 0:ioctl(fd,LED_OFF,&b);break;default:printf("输入错误\n");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/slab.h>
#include<linux/cdev.h>
#include<linux/uaccess.h>#include"head.h"struct cdev *cdev;
unsigned int major=0;//主设备号
unsigned int minor=0;//次设备号char kbuf[128]={0};struct class *cls;
struct device *dev;unsigned int *vir_rcc;
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;dev_t devno;int mycdev_open(struct inode *inode,struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);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__);unsigned long ret;if(size>sizeof(kbuf))size=sizeof(kbuf);ret=copy_to_user(ubuf,kbuf,size);if(ret){printk("copy_to_user filed\n");return ret;}return 0;}ssize_t mycdev_write(struct file *file, const char  *ubuf, size_t size, loff_t *lof)
{unsigned long ret;if(size>sizeof(kbuf))size=sizeof(kbuf);ret=copy_from_user(kbuf,ubuf,size);if(ret){printk("copy_to_user filed\n");return ret;}return 0;
}
long mycdev_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{int wh;int ret=copy_from_user(&wh,(void*)arg,4);if(ret){printk("copy_from_user filed\n");return ret;}switch(cmd){case LED_ON:switch(wh){case 1:vir_led1->ODR |= (1<<10);break;case 2:vir_led2->ODR |= (1<<10);break;case 3:vir_led3->ODR |= (1<<8);break;} break;case LED_OFF:switch(wh){case 1:vir_led1->ODR &= (~(1<<10));break;case 2:vir_led2->ODR &= (~(1<<10));break;case 3:vir_led3->ODR &= (~(1<<8));break;} break;}return 0;
}
int mycdev_close(struct inode *inode,struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}
int all_led_init(void)
{vir_led1=ioremap(LED1_ADDR,sizeof(gpio_t));if(vir_led1==NULL){printk("led1内存映射失败");return -ENOMEM;}printk("led1内存映射成功");vir_led2=ioremap(LED2_ADDR,sizeof(gpio_t));if(vir_led2==NULL){printk("led2内存映射失败");return -ENOMEM;}printk("led2内存映射成功");vir_led3=ioremap(LED3_ADDR,sizeof(gpio_t));if(vir_led3==NULL){printk("led3内存映射失败");}printk("led3内存映射成功");vir_rcc=ioremap(RCC,4);if(vir_rcc==NULL){printk("rcc内存映射失败");}printk("rcc内存映射成功");//rcc(*vir_rcc) |= (3<<4);//led1vir_led1->MODER &= (~(3<<20));vir_led1->MODER |= (1<<20);vir_led1->ODR   &= (~(1<<10));//led2vir_led2->MODER &= (~(3<<20));vir_led2->MODER |= (1<<20);vir_led2->ODR   &= (~(1<<10));//led3vir_led3->MODER &= (~(3<<16));vir_led3->MODER |= (1<<16);vir_led3->ODR   &= (~(1<<8));printk("寄存器初始化成功\n");return 0;
}
struct file_operations fops=
{.open=mycdev_open,.read=mycdev_read,.write=mycdev_write,.unlocked_ioctl=mycdev_ioctl,.release=mycdev_close,
};
static int __init mycdev_init(void)
{int ret;//申请字符设备的驱动空间cdev = cdev_alloc();if (cdev == NULL){return -EFAULT;}printk("字符设备驱动对象申请成功\n");//初始化驱动对象cdev_init(cdev,&fops);//动态申请if(major==0){ret=alloc_chrdev_region(&devno,minor, 3,"myled");if(ret){printk("动态申请设备号失败\n");goto out1;}major=MAJOR(devno);minor=MAJOR(devno);}//静态指定else{ret=register_chrdev_region(MKDEV(major,minor), 3,"myled");if(ret){printk("静态申请设备号失败\n");goto out1;}}printk("设备号申请成功\n");//注册驱动ret=cdev_add(cdev,MKDEV(major,minor),3);if(ret){printk("注册驱动失败\n");goto out2;}printk("注册驱动成功\n");//向上提交目录cls=class_create(THIS_MODULE,"led");if(IS_ERR(cls)){printk("向上提交目录失败\n");ret=-PTR_ERR(cls);goto out3;}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");ret=-PTR_ERR(dev);goto out4;}}printk("向上提交设备信息成功\n");//寄存器映射以及初始化all_led_init();return 0;
out4:
//销毁提交设备成功的设备信息for ( --i; i>=0; i--){device_destroy(cls,MKDEV(major,i));/* code */}class_destroy(cls);
out3:cdev_del(cdev);
out2:unregister_chrdev_region(MKDEV(major,minor),3);
out1:kfree(cdev);return ret;}
static void __exit mycdev_exit(void)
{//取消地址映射iounmap(vir_rcc); iounmap(vir_led1);iounmap(vir_led2);iounmap(vir_led3);//销毁设备节点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");

makefile

arch?=arm
modname?=register_dev_c
ifeq ($(arch),arm)
KERNELDIR:=/home/ubuntu/linux-5.10.61
else
KERNELDIR:=/lib/modules/$(shell uname -r)/build
endif
PWD:=$(shell pwd)all:make -C $(KERNELDIR) M=$(PWD) modules
clean:make -C $(KERNELDIR) M=$(PWD) clean 
obj-m:= $(modname).o

执行效果

开发板效果

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无形的伤害

有时候 我们往往很注意和陌生人或朋友之间的交往&#xff0c;关注情绪&#xff0c;语气&#xff0c;声调等等&#xff0c;生怕冲撞唐突了对方。 但往往会忽略身边人的感受&#xff0c;尤其是亲人和亲密的朋友&#xff0c;把他们对我们的关心当做理所当然的&#xff0c;和他们交…

Centos7挂载磁盘

1 查看未挂载的磁盘 命令&#xff1a; fdisk -l红框圈中的即是本次要挂载的磁盘&#xff0c;/dev/vdb 与 /dev/vda 相比&#xff0c;其没有下方的 /dev/vda1 等信息&#xff0c;代表 /dev/vdb 磁盘并没有进行过分区操作&#xff0c;是一个新加的硬盘。 2 对新建的磁盘进行分…

- 语言经验 - 《使用google profiler 对c++应用进行性能热点分析》

本文属于专栏《构建工业级QPS百万级服务》​​​​​ 性能优化&#xff0c;是工业应用中的重要一环。因为当我们的重要目的之一是盈利时&#xff0c;那么成本就十分重要。而性能优化的前提是&#xff0c;我们知道哪一部分功能&#xff0c;是最耗费资源的&#xff0c;才…

离谱!用ChatGPT进行审稿!

离谱&#xff01;用ChatGPT进行审稿&#xff01; 关注微信公众号: DeepGoAI 在这个信息爆炸的时代&#xff0c;AI已经跑到了学术会议的后台&#xff0c;偷偷摸摸地开始“帮忙”审稿了&#xff01;&#x1f916; 最近&#xff0c;一位教授的LinkedIn动态可谓是火了一把&#xf…

qt-C++笔记之捕获鼠标滚轮事件并输出滚轮角度增量

qt-C笔记之捕获鼠标滚轮事件并输出滚轮角度增量 code review! 文章目录 qt-C笔记之捕获鼠标滚轮事件并输出滚轮角度增量1.运行2.main.cpp3.main.pro 1.运行 2.main.cpp #include <QApplication> #include <QWidget> #include <QWheelEvent> #include <…

ADC--模拟量转换成数字量

目录 一、ADC硬件组成七大部分&#xff1a; 二、单次转换&#xff0c;连续转换&#xff0c;不连续采样模式&#xff0c;扫描模式区别 1、举例(5种组合情况) 2、模拟看门狗中断的作用&#xff1a; 三、MCU使用ADC步骤 一、ADC硬件组成七大部分&#xff1a; ①输入电压&#…

7.1 Qt 中输入行与按钮

目录 前言&#xff1a; 技能&#xff1a; 内容&#xff1a; 参考&#xff1a; 前言&#xff1a; line edit 与pushbotton的一点联动 当输入行有内容时&#xff0c;按钮才能使用&#xff0c;并能读出输入行的内容 技能&#xff1a; pushButton->setEnabled(false) 按钮不…

C++学习Day06之继承方式

目录 一、程序及输出1.1 公共继承1.1.1 父类中公共成员&#xff0c;子类可以正常访问1.1.2 父类中保护成员&#xff0c;子类类外不可以访问1.1.3 父类中私有成员&#xff0c;子类无法访问 1.2 保护继承1.2.1 父类中公共权限 子类中变为 保护权限1.2.2 父类中保护权限 子类中变为…

1.2 操作系统的发展与分类

文章目录 1.2 操作系统的发展与分类&#xff08;一&#xff09;手工操作阶段&#xff08;二&#xff09;批处理阶段——单道批处理系统&#xff08;三&#xff09;批处理阶段——多道批处理系统&#xff08;四&#xff09;分时操作系统&#xff08;五&#xff09;实时操作系统&…

基于51/STM32单片机智能衣柜 智能衣橱 换气除湿制系统 紫外线消毒

功能介绍 以51/STM32单片机作为主控系统&#xff1b; DHT11温湿度采集当前环境温度和湿度 lcd1602液晶显示当前衣柜温度&#xff0c;湿度&#xff0c;模式 AUTO&#xff1a;自动模式 MANUAL&#xff1a;手动模式 当湿度大于设置湿度上限液晶闪烁提醒 …

Jetpack Compose 第 2 课:布局

点击查看&#xff1a;Jetpack Compose 教程 点击查看&#xff1a;Composetutorial 代码 简介 Jetpack Compose 是用于构建原生 Android 界面的新工具包。它使用更少的代码、强大的工具和直观的 Kotlin API&#xff0c;可以帮助您简化并加快 Android 界面开发。 在本教程中&a…

PCB的介质损耗角是什么“∠”?

1、什么叫介质 介质是指在某种特定条件下能够传递力、能量或信息的物质或者空间。在物理学和工程学中&#xff0c;介质通常是指固体、液体或气体&#xff0c;它们能够传递机械波、电磁波等。例如&#xff0c;在声学中&#xff0c;空气、水和固体都可以作为声波的传播介质&…