/\*4、自动创建设备节点\*/
newchrled.class = class\_create(THIS_MODULE, NEWCHRLED_NAME);
if (IS\_ERR(newchrled.class))
return PTR\_ERR(newchrled.class);
创建设备。
错误预警
如果使用的是心跳灯,必须关闭这个心跳灯,否则干扰实验现象。
echo none > /sys/class/leds/sys-led/trigger // 改变 LED 的触发模式
2022.5.21 p15
设置文件私有数据:
代码中在
open
使用filp的release:
在read write 里面访问设备的时候需要访问私有数据。
/\*\*
\*my first driver
\*
\*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#define LED\_MAJOR 200 //主设备号
#define LED\_NAME "LED" //驱动名称
#define NEWCHRLED\_NAME "newchrled"
#define NEWCHRLED\_COUNT 1
struct newchrled\_dev {
struct cdev cdev;
struct class \*class;/\*类:为了自动创建节点\*/
struct device \*device;/\*设备:为了自动创建节点\*/
dev\_t devid; //设备号
int major; //主设备号
int minor; //次设备号
};
struct newchrled\_dev newchrled; //led设备
/\*首先定义寄存器的物理地址\*/
#define CCM\_CCGR1\_BASE (0X020C406C)
#define SW\_MUX\_GPIO1\_IO03\_BASE (0X020E0068)
#define SW\_PAD\_GPIO1\_IO03\_BASE (0X020E02F4)
#define GPIO1\_DR\_BASE (0X0209C000)
#define GPIO1\_GDIR\_BASE (0X0209C004)
/\*地址映射后的虚拟地址映射\*/
static void __iomem \*IMX6U_CCM_CCGR1;
static void __iomem \*SW_MUX_GPIO1_IO03;
static void __iomem \*SW_PAD_GPIO1_IO03;
static void __iomem \*GPIO1_DR;
static void __iomem \*GPIO1_GDIR;
#define LEDOFF 0 /\*关闭\*/
#define LEDON 1 /\*打开\*/
static void led\_switch(u8 sta)
{
u32 val = 0;
if (sta == LEDON)
{
val = readl(GPIO1_DR);
val &= ~(1<<3);/\*bit3 清0 打开led\*/
writel(val,GPIO1_DR);
}else if(sta == LEDOFF){
val = readl(GPIO1_DR);
val |= 1<<3;/\*bit3 清0 打开led\*/
writel(val,GPIO1_DR);
}
}
static int newchrled\_open(struct inode \*inode, struct file \*filp)
{
/\*设置私有数据\*/
filp->private_data = &newchrled;
return 0;
}
static int newchrled\_release(struct inode \*inode, struct file \*filp)
{
struct newchrled\_dev \*dev = (struct newchrled\_dev \*)filp->private_data;
return 0;
}
static ssize\_t newchrled\_write(struct file \*filp, const char __user \*buf,size\_t count, loff\_t \*ppos)
{
int ret = 0;
unsigned char databuf[1];
ret = copy\_from\_user(databuf,buf,count);
if (ret<0){
printk("kernel\_write error");
return -EFAULT;
}
led\_switch(databuf[0]);
return 0;
}
/\*\*
\* 字符设备的操作集合
\*/
const struct file\_operations newchrled_fops = {
.owner = THIS_MODULE,
.open = newchrled_open,
.release = newchrled_release,
.write = newchrled_write,
};
static int __init newchrled\_init(void)
{
int ret = 0;
/\*1、初始化led\*/
u32 val = 0;
//初始化内存映射
IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE,4);
SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE,4);
SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE,4);
GPIO1_DR = ioremap(GPIO1_DR_BASE,4);
GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE,4);
/\*2、初始化\*/
val = readl(IMX6U_CCM_CCGR1);
val &= ~(3<<26);/\*清零bit26 27\*/
val |= (3<<26); /\*bit 26 27置1\*/
writel(val,IMX6U_CCM_CCGR1);
writel(0x5,SW_MUX_GPIO1_IO03);//设置复用
writel(0x10b0,SW_PAD_GPIO1_IO03);//设置电气属性
val = readl(GPIO1_GDIR);
val |= 1<<3;/\*bit3 置为1 设置为输出\*/
writel(val,GPIO1_GDIR);
val = readl(GPIO1_DR);
val &= ~(1<<3);/\*bit3 清0 打开led\*/
writel(val,GPIO1_DR);
/\*2、注册字符设备\*/
printk("newchrled\_init ok\r\n");
newchrled.major = 0;//设置为0,表示由系统申请设备号
if(newchrled.major) //给定主设备号
{
newchrled.devid = MKDEV(newchrled.major,0);
ret = register\_chrdev\_region(newchrled.devid,NEWCHRLED_COUNT,NEWCHRLED_NAME);
}else{
ret = alloc\_chrdev\_region(&newchrled.devid,0,NEWCHRLED_COUNT,NEWCHRLED_NAME);
newchrled.major = MAJOR(newchrled.devid);
newchrled.minor = MINOR(newchrled.devid);
}
if(ret < 0){
printk("newchrled chrdev\_region err\r\n");
return -1;
}
printk("newchrled majorid = %d,minorid = %d\r\n",newchrled.major,newchrled.minor);
/\*3、初始化cdev\*/
newchrled.cdev.owner = THIS_MODULE;
cdev\_init(&newchrled.cdev, &newchrled_fops);
cdev\_add(&newchrled.cdev,newchrled.devid,NEWCHRLED_COUNT);
/\* 4、创建类 \*/
newchrled.class = class\_create(THIS_MODULE, NEWCHRLED_NAME);
if (IS\_ERR(newchrled.class)) {
return PTR\_ERR(newchrled.class);
}
/\* 5、创建设备 \*/
newchrled.device = device\_create(newchrled.class, NULL, newchrled.devid, NULL, NEWCHRLED_NAME);
if (IS\_ERR(newchrled.device)) {
return PTR\_ERR(newchrled.device);
}
return 0;
}
static void __exit newchrled\_exit(void)
{
printk("newchrled\_exit ok\r\n");
/\*删除字符设备\*/
cdev\_del(&newchrled.cdev);
## 最后
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**
**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
![img](https://img-blog.csdnimg.cn/img_convert/25ac095ac89bda4b2c64f3a5e4bbe963.png)
![img](https://img-blog.csdnimg.cn/img_convert/8545c811055329f79424395b170bbbbf.jpeg)
![img](https://img-blog.csdnimg.cn/img_convert/29d99561425b25725df55d45b59ef54a.png)
![img](https://img-blog.csdnimg.cn/img_convert/247695f1cd2c8a073b9cd098f8ff15a1.png)
![img](https://img-blog.csdnimg.cn/img_convert/d51d8b6aa1f4144670c9a8182b0d8938.png)
![img](https://img-blog.csdnimg.cn/img_convert/f713c4c342f20477901da6cd1667d41b.png)
![](https://img-blog.csdnimg.cn/img_convert/51ea973734ad488dd8480134ee5b227e.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!
57626458)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!