华清远见:驱动点灯第N回目
创始人
2024-02-01 04:10:49
0

1.在串口工具进行输入:

echo 1 > /dev/myled0 ---->led1灯点亮

echo 0 > /dev/myled0 ---->led1灯熄灭

echo 1 > /dev/myled1 ---->led1灯点亮

echo 0 > /dev/myled1 ---->led1灯熄灭

echo 1 > /dev/myled2 ---->led1灯点亮

echo 0 > /dev/myled2 ---->led1灯熄灭

linux@ubuntu:/sys/class/myled$ ls /dev/myled* -ll

crw------- 1 root root 236, 0 Nov 18 14:55 /dev/myled0 ----->控制PE10(LED1)

crw------- 1 root root 236, 1 Nov 18 14:55 /dev/myled1----->控制PF10(LED2)

crw------- 1 root root 236, 2 Nov 18 14:55 /dev/myled2----->控制PE8(LED3)

2.驱动:

open:在open函数中获取到次设备号,用私有数据传参,传递给write函数

write:在write函数,判断次设备号,就知道操作的是哪盏灯

3.要求:

1)分部实现注册字符设备驱动

2)自动创建设备节点

3)通过结构体对led灯地址进行映射

4)次设备号完成私有数据传参

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include "demo2.h"#define CNAME "myled" //宏定义设备名//定义设备号
#if 1
unsigned int major = 0; //动态设备号
#else
unsigned int major = 500; //动态设备号
#endif//int all_led_init();
const int count = 3;int mnior = 0;      //次设备号
struct cdev *cdev;  //
struct class *cls;  //目录句柄
struct device *dev; //gpio_t *led1;
unsigned int *RCC;
gpio_t *led2;
gpio_t *led3;//打开
int mydemo_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);file->private_data = (void*)(MINOR(inode->i_rdev));return 0;
}//读
ssize_t mydemo_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
//写
ssize_t mydemo_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{char kbuf[10]={0};int ret;int a;if(size>sizeof(kbuf))size=sizeof(kbuf);a=(int)file->private_data;printk("myled%d open\n",a);printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);ret = copy_from_user(kbuf, ubuf, size);if (ret){printk("copy from user is error\n");return -EIO;}//接收第一个灯信息if (kbuf[0] == '1') //开灯{if (a == 0)led1->ODR |= (1 << 10);else if (a == 1)led2->ODR |= (1 << 10);else if (a == 2)led3->ODR |= (1 << 8);}else if (kbuf[0] == '0') //关灯{if (a == 0)led1->ODR &= ~(1 << 10);else if (a == 1)led2->ODR &= ~(1 << 10);else if (a == 2)led3->ODR &= ~(1 << 8);}return size;
}
//关闭int mydemo_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}//操作方法结构体初始化
const struct file_operations fops =
{.open = mydemo_open,.read = mydemo_read,.write = mydemo_write,.release = mydemo_close,
};int all_led_init(void)
{//映射地址//映射物理地址为虚拟地址RCC = ioremap(0x50000A28, 4);  // GPLOE使能led1 = ioremap(0x50006000, 4); // PE引脚设置为输出模式led2 = ioremap(0x50007000, 4);led3 = ioremap(0x50006000, 4);(*RCC) |= (0x3 << 4);// led1led1->MODER &= ~(0x3 << 20);led1->MODER |= (0x1 << 20);led1->ODR &= ~(0x1 << 10);// led2led2->MODER &= ~(0x3 << 20);led2->MODER |= (0x1 << 20);led2->ODR &= ~(0x1 << 10);// led3led3->MODER &= ~(0x3 << 16);led3->MODER |= (0x1 << 16);led3->ODR &= ~(0x1 << 8);return 0;
}//入口函数
static int __init demo_init(void)
{int ret, i;dev_t devno;printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);// 1.分配结构体对象cdev = cdev_alloc();if (NULL == cdev){printk("cdev alloc is error\n");ret = -ENOMEM;goto ERR1;}printk("cdev 分配成功\n");// 2.设备对象初始化cdev_init(cdev, &fops);// 3.设备号申请if (major == 0){ret = alloc_chrdev_region(&devno, mnior, count, CNAME); //动态申请设备号if (ret){printk("alloc_chrdev_register is error \n");goto ERR2;}major = MAJOR(devno);mnior = MINOR(devno);printk("动态申请设备号成功\n");}else{ret = register_chrdev_region(MKDEV(major, mnior), count, CNAME); //静态申请设备号if (ret){printk("静安申请设备号失败\n");goto ERR2;}printk("静态申请设备号成功\n");}// 4.注册字符设备驱动ret = cdev_add(cdev,MKDEV(major, mnior), count);if (ret){printk("字符设备驱动注册失败\n");goto ERR3;}printk("字符设备注册成功\n");// 5.自动创建设备结点cls = class_create(THIS_MODULE, "led");if (IS_ERR(cls)){printk("创建设备目录失败\n");ret = PTR_ERR(cls);goto ERR4;}//向上提交设备结点信息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 ERR5;}}printk("创建逻辑节点成功\n");//寄存器的初始化all_led_init();return 0;ERR5:for (--i; i >= 0; i--){device_destroy(cls, MKDEV(major, i));}class_destroy(cls);
ERR4:cdev_del(cdev);
ERR3:unregister_chrdev_region(MKDEV(major, mnior), count);
ERR2:kfree(cdev);
ERR1:return ret;
}//出口函数
static void __exit demo_exit(void)
{// 1.销毁设备节点int i;for (i = 0; i < count; i++){device_destroy(cls, MKDEV(major, i));}class_destroy(cls);// 2.注销字符设备驱动cdev_del(cdev);// 3.释放设备号unregister_chrdev_region(MKDEV(major, mnior), count);// 4.释放动态申请的空间kfree(cdev);printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
}//内核寻找入口出口宏封装
module_init(demo_init);
module_exit(demo_exit);//许可证
MODULE_LICENSE("GPL");

 

 

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...