本文基于imx6ull-pro百问网开发板进行驱动开发设计

编写驱动就好比是创建一个游戏并注册一个角色,每一步都是有意义的

对于这个游戏本身,我们也是管理者。首先先把游戏的初始化、退出框架搭好,然后提供自己的合法证书跟签名,别忘了把制作游戏的工具(头文件)也准备好

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>module_init(dtsled_init);
module_exit(dtsled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("louis");

初始化

游戏准备好了就可以创建角色(设备)了,可以自己提前设置好账号也可以向系统申请账号(设备号),为了方便管理这些账号,我们特意在初始化外设计了一种结构体方便管理(角色)设备。

这里特别说明一下cdev结构体,它里面包括了设备号以及最重要的ops函数(file_operations)可以理解为存储着账号和用户的技能面板可以理解为账户

在设备结构体 dtsled_dev 中添加了成员变量 nd,nd 是 device_node 结构体类型指针,表示设备节点。如果我们要读取设备树某个节点的属性值,首先要先得到这个节点,一般在设备结构体中添加 device_node 指针变量来存放这个节点。

/* dtsled设备结构体 */
struct dtsled_dev{dev_t devid;          /* 设备号   */struct cdev cdev;        /* cdev     */struct class *class;      /* 类        */struct device *device;    /* 设备    */int major;               /* 主设备号   */int minor;              /* 次设备号   */struct device_node  *nd; /* 设备节点 */
};struct dtsled_dev dtsled; /* led设备 */

接着从服务器(设备树)中获得相应的游戏组件数据:设备树节点、compatible、status、reg属性

u32 val = 0;int ret;u32 regdata[14];const char *str;struct property *proper;/* 获取设备树中的属性数据 *//* 1、获取设备节点:alphaled */dtsled.nd = of_find_node_by_path("/alphaled");if(dtsled.nd == NULL) {printk("alphaled node nost find!\r\n");return -EINVAL;} else {printk("alphaled node find!\r\n");}/* 2、获取compatible属性内容 */proper = of_find_property(dtsled.nd, "compatible", NULL);if(proper == NULL) {printk("compatible property find failed\r\n");} else {printk("compatible = %s\r\n", (char*)proper->value);}/* 3、获取status属性内容 */ret = of_property_read_string(dtsled.nd, "status", &str);if(ret < 0){printk("status read failed!\r\n");} else {printk("status = %s\r\n",str);}/* 4、获取reg属性内容 */ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10);if(ret < 0) {printk("reg property read failed!\r\n");} else {u8 i = 0;printk("reg data:\r\n");for(i = 0; i < 10; i++)printk("%#X ", regdata[i]);printk("\r\n");}

之后是对要操作的寄存器进行虚拟地址与物理地址的映射
下面是在设备树里添加的节点

 alphaled {#address-cells = <1>;#size-cells = <1>;compatible = "atkalpha-led";status = "okay";reg = <    0X020C406C 0X04 /* CCM_CCGR1_BASE */0X02290014 0X04 /* SW_MUX_GPIO5_IO03_BASE */0X02290058 0X04 /* SW_PAD_GPIO5_IO03_BASE */0X020AC000 0X04 /* GPIO5_DR_BASE */0X020AC004 0X04 >; /* GPIO5_GDIR_BASE     */};

使用 of_iomap 函数一次性完成读取 reg 属性以及内存映射,of_iomap 函数是设备树推荐使用的 OF 函数。

 IMX6U_CCM_CCGR1 = of_iomap(dtsled.nd, 0);SW_MUX_GPIO5_IO03 = of_iomap(dtsled.nd, 1);SW_PAD_GPIO5_IO03 = of_iomap(dtsled.nd, 2);GPIO5_DR = of_iomap(dtsled.nd, 3);GPIO5_GDIR = of_iomap(dtsled.nd, 4);

拿到了寄存器的地址就可以编写硬件寄存器的初始化了

val = readl(IMX6U_CCM_CCGR1);val &= ~(3 << 26);  /* 清楚以前的设置 */val |= (3 << 26);   /* 设置新值 */writel(val, IMX6U_CCM_CCGR1);/* 3、设置GPIO5_IO03的复用功能,将其复用为*    GPIO5_IO03,最后设置IO属性。*/writel(5, SW_MUX_GPIO5_IO03);/*寄存器SW_PAD_GPIO5_IO03设置IO属性*bit 16:0 HYS关闭*bit [15:14]: 00 默认下拉*bit [13]: 0 kepper功能*bit [12]: 1 pull/keeper使能*bit [11]: 0 关闭开路输出*bit [7:6]: 10 速度100Mhz*bit [5:3]: 110 R0/6驱动能力*bit [0]: 0 低转换率*/writel(0x10B0, SW_PAD_GPIO5_IO03);/* 4、设置GPIO5_IO03为输出功能 */val = readl(GPIO5_GDIR);val &= ~(1 << 3);    /* 清除以前的设置 */val |= (1 << 3);    /* 设置为输出 */writel(val, GPIO5_GDIR);/* 5、默认关闭LED */val = readl(GPIO5_DR);val |= (1 << 3);    writel(val, GPIO5_DR);

这里注册设备,类似于创建账号,可以自定义账号也可以按系统随机分配

/* 注册字符设备驱动 *//* 1、创建设备号 */if (dtsled.major) {       /*  定义了设备号 */dtsled.devid = MKDEV(dtsled.major, 0);register_chrdev_region(dtsled.devid, DTSLED_CNT, DTSLED_NAME);} else {                      /* 没有定义设备号 */alloc_chrdev_region(&dtsled.devid, 0, DTSLED_CNT, DTSLED_NAME);    /* 申请设备号 */dtsled.major = MAJOR(dtsled.devid); /* 获取分配号的主设备号 */dtsled.minor = MINOR(dtsled.devid);    /* 获取分配号的次设备号 */}printk("dtsled major=%d,minor=%d\r\n",dtsled.major, dtsled.minor); 

然后就是初始化账户组件

/* 2、初始化cdev */
dtsled.cdev.owner = THIS_MODULE;
cdev_init(&dtsled.cdev, &dtsled_fops);

将新创建的账户添加进系统

/* 3、添加一个cdev */
cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT);

为了让用户有更好的体验,我们还要设计一个自动登录和自动注销的组件,对此驱动设备也有一套自动创建和销毁的函数,前提条件是创建一个设备才可以调用

/* 4、创建类 */
dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);
if (IS_ERR(dtsled.class)) {return PTR_ERR(dtsled.class);
}/* 5、创建设备 */
dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);if (IS_ERR(dtsled.device)) {return PTR_ERR(dtsled.device);}

**

OPS函数的编写

**
游戏初始化以后就可以设置,角色的具体操作了
先列好大纲,我的角色的技能有哪些(基本操作函数:读、写、打开设备、关闭设备)

/* 设备操作函数 */
static struct file_operations dtsled_fops = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release =     led_release,
};

在写基本函数前,先封装好写寄存器的操作函数,之后方便直接调用

void led_switch(u8 sta)
{u32 val = 0;if(sta == LEDON) {val = readl(GPIO1_DR);val &= ~(1 << 3);   writel(val, GPIO1_DR);}else if(sta == LEDOFF) {val = readl(GPIO1_DR);val|= (1 << 3);  writel(val, GPIO1_DR);}
}
static int led_open(struct inode *inode, struct file *filp)
{filp->private_data = &dtsled; /* 设置私有数据 */return 0;
}static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{return 0;
}/** @description      : 向设备写数据 * @param - filp   : 设备文件,表示打开的文件描述符* @param - buf     : 要写给设备写入的数据* @param - cnt     : 要写入的数据长度* @param - offt  : 相对于文件首地址的偏移* @return             : 写入的字节数,如果为负值,表示写入失败*/
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{int retvalue;unsigned char databuf[1];unsigned char ledstat;retvalue = copy_from_user(databuf, buf, cnt);if(retvalue < 0) {printk("kernel write failed!\r\n");return -EFAULT;}ledstat = databuf[0];     /* 获取状态值 */if(ledstat == LEDON) { led_switch(LEDON);      /* 打开LED灯 */} else if(ledstat == LEDOFF) {led_switch(LEDOFF); /* 关闭LED灯 */}return 0;
}static int led_release(struct inode *inode, struct file *filp)
{return 0;
}

EXIT

不管是做游戏还是写代码都要有头有尾
最后退出时把硬件的映射消除,要注销账号,还要把之前创建的设备类给销毁

static void __exit led_exit(void)
{/* 取消映射 */iounmap(IMX6U_CCM_CCGR1);iounmap(SW_MUX_GPIO1_IO03);iounmap(SW_PAD_GPIO1_IO03);iounmap(GPIO1_DR);iounmap(GPIO1_GDIR);/* 注销字符设备驱动 */cdev_del(&dtsled.cdev);/*  删除cdev */unregister_chrdev_region(dtsled.devid, DTSLED_CNT); /* 注销设备号 */device_destroy(dtsled.class, dtsled.devid);class_destroy(dtsled.class);
}

至此整个驱动已经完整的写好了

通过编写游戏程序的视角去编写字符驱动--设备树-百问imx6ull-pro相关推荐

  1. 用linux如何用vi编写c程序,linux中VI编写C程序。。。

    在linux中编写C程序时不像编写shell那样开头要#!/bin/bash,但是在C程序中要指定头文件(头文件是指输入输出,宏等,而且要首先声明,也是必须要开始就声明的) 写好C代码后要给C文件赋予 ...

  2. C语言(CED)编写一个程序,求两个字符之间的加减运算。

    (请先看置顶博文)https://blog.csdn.net/GenuineMonster/article/details/104495419 复习C语言,不同的心境遇到了不同的问题: 问题: 编写一 ...

  3. 简述如何编写java程序_1-4 简述 Eclipse 编写 Java 程序的流程。_学小易找答案

    [填空题]三四年级是英语入门初学阶段,更加注重( ). [单选题]不属于pos终端收银机的基本构成是( ). A . 显示器 B . 小票打印机 C . 键盘 D . 条形码电子称 [单选题]( ) ...

  4. linux编写多进程程序实验,实验7 编写多进程程序

    实验七编写多进程程序 学生姓名:李亚军学号:6100412196 专业班级:卓越计科121班 1.实验目的 通过编写多进程程序,使读者熟练掌握fork().exec().wait()和waitpid( ...

  5. 编写python程序的步骤_编写python程序和运行.py文件的方法步骤

    前提:已安装好 Subliume Test 3 且已经添加好python编译系统,已安装好python3.7 一.新建一个文本文档,将后缀名改为.py 二.使用 Subliume Test 3 打开该 ...

  6. 用计算机机器语言编写的程序可以,用机器语言编写的程序可读性最差

    正确答案: B 用机器语言编写的程序可读性最差 题目:下列叙述中,正确的是( ). 解析:只有机器语言才能被计算机直接识别,但机器语言可读性是最差的.汇编语言是符号化的机器语言,但不是机器语言,其程序 ...

  7. 用计算机语言编写累加程序,如何在S7-1200PLC编写程序时实现流量累积?

    在使用s7-1200PLC编写程序的时候,如果项目上需要用到流量累积功能,但是本款PLC并没有自带流量累积功能块.这时,就需要我们组态工程师自己编写一个具有流量累积功能程序,或者将该程序封装为FB块或 ...

  8. python源文件改写、编写一个程序,Python源文件改写.编写一个程序,读取一个Python源程序,将文件中所有除保留字外的小写字母换成大写字母...

    程序代码如下: importkeyword. s=keyword.kwlist. #建立保留字列表. n=input("输入一个文件名:"). f=open(n,"r&q ...

  9. 用c语言编写MIDI程序,使用C语言编写钢琴小程序

    网上搜索键盘钢琴,可以搜索到不少小游戏,最常玩的就是Flash小游戏,26个按键的. 后来想用C语言自己实现一个,没有界面--控制台的. 原理很简单,先在控制台中获取按键事件,在按键事件中,开一个线程 ...

最新文章

  1. GPU对决TPU,英伟达能否守住领先地位?
  2. 迪士尼研究院等将人造“神经纤维”用于软体机器人,赋予其“本体感知能力”!...
  3. iptables7层过滤,屏蔽(QQ,MSN,迅雷,PPTV等)
  4. Jenkins怎么启动和停止服务
  5. 行家来信 | 功能安全会成为自动驾驶的紧箍咒吗?
  6. dhcp服务器由谁维护,DHCP服务器管理维护的心得
  7. 滴水穿石-05数组排序
  8. android 调用.h文件,[Android Studio / NDK] 如何使用javah生成.h文件
  9. ZDB5202烧成控制器方法
  10. 视网膜New iPad与普通分辨率iPad页面的兼容处理
  11. 又是一种用于JavaScript的前端国际化方案
  12. sp_lock显示的信息说明
  13. LINUX使用wireshark
  14. java gui 保存文件_用JAVA编写一个GUI记事本程序,实现文本的输入,保存,修改,打开操作...
  15. 图片生成链接最简单的方法
  16. QT Designer 设计主窗口时如何更改工具栏默认顺序
  17. Python 元组大全
  18. 判断一个字符串能否通过添加一个字符变成回文串
  19. [PS教程]怎么用PS将图片印章的背景变透明
  20. Spring Boot安装及使用(2021.10.28)

热门文章

  1. shopify二次开发 产品详情页面的开发一(结构布局)
  2. open-能连接,但无法访问内网的问题
  3. 【计算机网络】(5)ping的过程分析+icmp协议
  4. 微信公众号网页分享功能开发
  5. android linux 休眠 深度睡眠 查看 方法 调试【转】
  6. 实战演练 | Navicat Premium 轻松连接阿里云云数据库
  7. 简单的微服务feign之间调用授权/安全验证
  8. 服务器支持 TLS Client-initiated 重协商攻击(CVE-2011-1473复现验证)
  9. oracle 19c ORA-00942: 表或视图不存在 ORA-02063: 紧接着 line
  10. 实时数据库:优势和报价