基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备

news2024/12/23 10:33:56

文章目录

  • 一、前言
  • 二、系列文章
  • 三、替换部分
    • 3.1 自动分配设备号
    • 3.2 自动创建设备
  • 四、解析:完整源码
    • 4.1 helloworld_amlogic_char_driver_auto_mknode.c
    • 4.2 Makefile
  • 五、编译执行
    • (1)编译及部署
    • (2)加载ko文件
    • (3)查看结果
  • 六、应用层调用
  • 七、源码下载
  • 八、篇尾

一、前言

本文是“驱动简说”的第2篇,是本人的读书总结,对于大多数人来说,看看这些例子就已经够用!回顾前文的驱动,有如下两个缺点,本篇文章,就以经典例子,来解决这两个问题:

  • 1.主设备号是手动创建的,而不是分配的;
  • 2.设备文件还需要手动创建。(应用层需要通过此窗口文件,以系统调用的方式,访问硬件设备)

本文基于Amlogic T972 , Android 9.0, 内核版本 4.9.113

二、系列文章

第1篇:基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
第2篇:基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备

三、替换部分

3.1 自动分配设备号

  • 使用下面的函数,将由内核自动分配一个未使用的设备号。

int alloc_chrdev_region(dev_t *dev, unsigned baseMinor, unsigned count, const char *);

dev:输出参数,存放分配的第一个设备编号。
baseminor:起始从设备编号。
count:请求从设备编号的数量。
name:关联的设备或驱动的名称。

	/* 让系统自动分配一个设备号,同时再注册并获取此设备号 */
	ret = alloc_chrdev_region(&dev_no, 0, 1, "aml_char");
	if (ret < 0){
		pr_info("Failed: alloc_chrdev_region \n");
		return ret;
	}

3.2 自动创建设备

  • 函数的参数一目了然,需要更进一步的可以百度。
	/* 注册 device class */
	amlClass = class_create(THIS_MODULE, CLASS_NAME);
	if (IS_ERR(amlClass)){
		unregister_chrdev_region(dev_num, 1);
		cdev_del(&aml_cdev);
	    pr_info("Failed: register device class\n");
	    return PTR_ERR(amlClass);
	}
	pr_info("/sys/class/%s auto created!\n", CLASS_NAME);

	/* 创建设备节点文件:  /dev/your-dev-name */
	amlDevice = device_create(amlClass, NULL, dev_num, NULL, DEVICE_NAME);
	if (IS_ERR(amlDevice)){
	    class_destroy(amlClass);
	    cdev_del(&aml_cdev);
	    unregister_chrdev_region(dev_num, 1);
	    pr_info("Failed to create the device\n");
	    return PTR_ERR(amlDevice);
	}
	pr_info("/dev/%s auto created!\n", CLASS_NAME);

四、解析:完整源码

4.1 helloworld_amlogic_char_driver_auto_mknode.c

  • 文件,参考位置:android9.0\common\drivers\amlogic\input\helloworld_amlogic_char_driver_auto_mknode.c
#include <linux/module.h> /* 模块初始化、卸载的接口头文件  */
#include <linux/cdev.h> /* 字符设备头文件 */
#include <linux/fs.h>
#include <linux/device.h> /* class和device依赖 的头文件 */


#define DEVICE_NAME "aml_char"
#define CLASS_NAME DEVICE_NAME

static struct cdev aml_cdev;
static dev_t dev_num;
static struct class*  amlClass;



/* 应用层系统调用:open()、fopen 打开设备节点文件时,将回调此函数  */
static int aml_cdev_open(struct inode *inode, struct file *file)
{
	pr_info("aml_cdev_open() is called.\n");
	return 0;
}

/* 应用层系统调用:close()、fclose 关闭设备节点文件时,将回调此函数  */
static int aml_cdev_close(struct inode *inode, struct file *file)
{
	pr_info("aml_cdev_close() is called.\n");
	return 0;
}

/*  应用层系统调用:ioctrl() 操作设备节点文件时,将回调此函数  */
static long aml_cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	pr_info("aml_cdev_ioctl() is called. cmd = %d, arg = %ld\n", cmd, arg);
	return 0;
}

/* 注册回调函数:只需要实现需要的接口即可 */
static const struct file_operations aml_cdev_fops = {
	.owner = THIS_MODULE,
	.open = aml_cdev_open,
	.release = aml_cdev_close,
	.unlocked_ioctl = aml_cdev_ioctl,
};

/* 模块初始化函数  */
static int __init aml_cdev_init(void)
{
	int ret;
	dev_t dev_no;
	int major, minor;
	struct device* amlDevice;
	
	pr_info("aml_cdev_init \n");
	/* 让系统自动分配一个设备号,同时再注册并获取此设备号 */
	ret = alloc_chrdev_region(&dev_no, 0, 1, DEVICE_NAME);
	if (ret < 0){
		pr_info("Failed: alloc_chrdev_region \n");
		return ret;
	}
		
	major = MAJOR(dev_no);
	minor = MINOR(dev_no);
	dev_num = MKDEV(major,0);
	pr_info("alloc major(%d), minor(%d)\n", major, minor);
	
	/* 初始化aml_cdev,并将其添加内核中*/
	cdev_init(&aml_cdev, &aml_cdev_fops);
	ret= cdev_add(&aml_cdev, dev_num, 1);
	if (ret < 0){
		unregister_chrdev_region(dev_num, 1);
		pr_info("Failed: add cdev\n");
		return ret;
	}

	/* 注册 device class */
	amlClass = class_create(THIS_MODULE, CLASS_NAME);
	if (IS_ERR(amlClass)){
		unregister_chrdev_region(dev_num, 1);
		cdev_del(&aml_cdev);
	    pr_info("Failed: register device class\n");
	    return PTR_ERR(amlClass);
	}
	pr_info("/sys/class/%s auto created!\n", CLASS_NAME);

	/* 创建设备节点文件:  /dev/your-dev-name */
	amlDevice = device_create(amlClass, NULL, dev_num, NULL, DEVICE_NAME);
	if (IS_ERR(amlDevice)){
	    class_destroy(amlClass);
	    cdev_del(&aml_cdev);
	    unregister_chrdev_region(dev_num, 1);
	    pr_info("Failed to create the device\n");
	    return PTR_ERR(amlDevice);
	}
	pr_info("/dev/%s auto created!\n", CLASS_NAME);
	return 0;
}

/* 模块退出时执行卸载操作  */
static void __exit aml_cdev_exit(void)
{
	pr_info("aml_cdev_exit\n");
	device_destroy(amlClass, dev_num); // 移除 /dev/aml_char
	class_destroy(amlClass);           // 移除   /sys/class/aml_char
	cdev_del(&aml_cdev);//删除内核cdev设备
	unregister_chrdev_region(dev_num, 1); //注销设备号
}


/* 固定的模板部分,将导出模块的初始化和卸载接口符号 */
module_init(aml_cdev_init);
module_exit(aml_cdev_exit);

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("szhou <66176468@qq.com>");
MODULE_DESCRIPTION("This is a amlogic debug tool.");

4.2 Makefile

  • android9.0\common\drivers\amlogic\input\Makefile
#
# Makefile for the input core drivers.
#

# Each configuration option enables a list of files.

obj-$(CONFIG_AMLOGIC_AVIN_DETECT) += avin_detect/

obj-$(CONFIG_AMLOGIC_INPUT_KEYBOARD) += keyboard/

obj-$(CONFIG_AMLOGIC_REMOTE) += remote/

obj-$(CONFIG_AMLOGIC_TOUCHSCREEN) += touchscreen/

obj-$(CONFIG_AMLOGIC_SENSOR) += sensor/

# 添加下面语句,并将helloworld_amlogic_char_driver_auto_mknode.c放在同一目录下
obj-m +=  helloworld_amlogic_char_driver_auto_mknode.o


五、编译执行

(1)编译及部署

参考系列文章,第1篇

(2)加载ko文件

  • 串口上执行
30|:/data # insmod helloworld_amlogic_char_driver_auto_mknode.ko              

[31886.544855@3]- aml_cdev_init 
[31886.544869@3]- alloc major(488), minor(0)
[31886.544991@3]- /sys/class/aml_char auto created!
[31886.546043@0]- /dev/aml_char auto created!

(3)查看结果

  • 如下所示,可见为设备自动分配的主次设备号为: major(488), minor(0)

:/data # ls -l /dev/aml_char 
crw------- 1 root root 488,   0 2022-12-28 22:03 /dev/aml_char


:/data # ls -l /sys/class/aml_char                                             
total 0
lrwxrwxrwx 1 root root 0 2022-12-28 22:04 aml_char -> ../../devices/virtual/aml_char/aml_char
:/data # 

效果如下图:
在这里插入图片描述

六、应用层调用

直接使用第1篇文章中的C语言编写的APP程序即可, 在串口上执行

:/data # ./hello_aml 
[31944.012506@1]- aml_cdev_open() is called.
[31944.012558@1]- aml_cdev_ioctl() is called. cmd = 18, arg = -1146742208
[31944.012566@1]- aml_cdev_close() is called.
:/data # 

效果如下图:
在这里插入图片描述

七、源码下载

百看不如一试……

  • 地址:https://gitee.com/amizhou/amlogic_t972_android9_driver/tree/master/index_01_simpleSay_drivers/lesson_02
git clone git@gitee.com:amizhou/amlogic_t972_android9_driver.git

八、篇尾

保持持续学习, 欢迎私信交流。

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

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

相关文章

HCIP作业三

文章目录一&#xff0c;建立拓扑图1&#xff0c;目的&#xff1a;实现全网可达二&#xff0c;在OSPF1区域1&#xff0c;所有路由器配置IP地址&#xff08;包含OSPF100区域&#xff09;2&#xff0c;进行O1的宣告&#xff0c;不能宣告ISP网段3&#xff0c;在O1区域的R3写缺省去I…

MIT6.830-2022-lab3实验思路详细讲解

文章目录一、实验概览二、实验过程成本估算&#xff08;Cost Estimation&#xff09;&#xff1a;基数和选择率Exercise 1: IntHistogramExercise 2: TableStatsExercise 3: Join Cost EstimationExercise 4: Join Cost EstimationExtra Credit总结一、实验概览 对于这次lab&a…

尚医通-数据字典接口-前端列表(十三)

目录&#xff1a; &#xff08;1&#xff09;数据字典接口-需求和准备 &#xff08;2&#xff09;数据字典接口-列表 &#xff08;3&#xff09; 数据字典前端-列表 &#xff08;1&#xff09;数据字典接口-需求和准备 前面我们完成了医院设置模块的开发&#xff0c;现在来…

js数组篇

数组定义 var arr1new Array(33,44,55,66); var arr2[A,B,C,D]; var arr3new Array(4); 数组常用方法 splice()方法用于替换数组中的指定项 splice(3,2,X,Y,Z)&#xff1a;从下标为3的项开始&#xff0c;连续替换2项 &#xff0c;插入XYZ var arr[A,B,C,D,E,F,G]; arr.spl…

Java线程间通信机制 (等待唤醒机制)

1.1 线程间通信 概念&#xff1a;多个线程在处理同一个资源&#xff0c;但是处理的动作&#xff08;线程的任务&#xff09;却不相同。 比如&#xff1a;线程A用来生成包子的&#xff0c;线程B用来吃包子的&#xff0c;包子可以理解为同一资源&#xff0c;线程A与线程B处理的动…

[JavaEE] Thread类及其常见方法

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录 1.Thread 的常见构造方法 2.Thread 的几个常见属性…

机器学习基石2(noise和error)

文章目录一、什么是noise&#xff1f;二、什么是error&#xff1f;三、常用error一、什么是noise&#xff1f; 我们之前的讨论都是一种理想化的说明&#xff0c;比如数据来源于目标函数fff&#xff0c;似乎我们手里拿到的数据是这样得来的&#xff0c;随机取一个输入&#xff0…

DOM算法系列009-判断给定节点是否为块级元素

UID: 20221227215215 aliases: tags: source: cssclass: created: 2022-12-27 块级元素 给定一个节点&#xff0c;如何判定它是否为块级元素呢&#xff1f; 首先&#xff0c;块级元素一定是元素节点&#xff0c;所以它的nodeType 1其次&#xff0c;我们思考&#xff0c;有什…

Redis分布式缓存、秒杀

目录一、单点Redis的问题二、RDB三、AOF四、Redis优化秒杀流程1、秒杀步骤&#xff1a;2、Redis优化秒杀步骤&#xff1a;3、秒杀的lua脚本4、调用秒杀的lua脚本5、通过线程池&#xff0c;操作阻塞队列五、基于Redis实现共享session登录NoSQL数据库进阶实战哪吒精品系列文章一、…

linux常用命令(二)-文件操作

文件创建 - touch 一般使用touch 来创建某个新增的文件 语法 touch [-acfm][文件名]a&#xff1a;改变档案的读取时间记录c&#xff1a;假如目的档案不存在&#xff0c;不会建立新的档案。与 --no-create 的效果一样。f&#xff1a;不使用&#xff0c;是为了与其他 unix 系统…

python的tkinter(图形用户界面)

目录标题什么是图形用户界面&#xff08;GUI&#xff09;Tinter函数和参数说明&#xff08;常用&#xff09;Lable(标签)&#xff1a;效果Button(按钮)效果Entry(文本框)效果Text &#xff08;多行文本框&#xff09;Canvas(画布)效果Message(消息弹窗)效果什么是图形用户界面&…

kaggle学习笔记-otto-baseline4-本地CV的构建

总览 步骤 1 - 生成候选 对于每个测试用户&#xff0c;我们生成可能的选择&#xff0c;即候选人。、我们从 5 个来源生成候选人&#xff1a; 点击、购物车、订单的用户历史记录测试周期间最受欢迎的 20 次点击、购物车、订单具有类型权重的点击/购物车/订单到购物车/订单的共…

中国芯片奇才,仅用三年打破欧美垄断,创造奇迹

有这么一位中国人&#xff0c;打破了欧美长达10年的芯片技术垄断。这位最该追的星&#xff0c;她是谁&#xff1f;又是如何让欧美芯片领域闻风丧胆。早在2017年&#xff0c;芯片国产化已接近50%&#xff0c;然而25g以上芯片却仅有3%&#xff0c;该技术一直掌握在欧美等发达国家…

融云任杰:激活组织生命力 让听见炮火的人做决策 | TGO专访

任杰&#xff0c;融云联合创始人兼首席科学家&#xff0c;TGO 鲲鹏会&#xff08;北京&#xff09;学员&#xff1b;曾就职于微软和神州泰岳等公司&#xff0c;在微软两次获得全球杰出员工奖&#xff0c;曾负责中国联通搭建 WAP 网关、增值业务管理平台&#xff1b;在神州泰岳期…

数据结构(线性表及顺序表)

目录 线性表 线性结构定义 常见线性结构 线性表 顺序表及其实现 顺序结构 顺序表的存储映像图 顺序表seqList及操作的定义&#xff08;seqList.h&#xff09; 顺序表基本操作的实现分析 查找操作 实现代码 插入操作 实现代码 删除操作 实现代码 顺序表应用——…

手绘图说电子元器件-集成电路

集成电路是高度集成化的电子器件,具有集成度高、功能完整、可靠性好、体积小、重量轻、功耗低的特点,已成为现代电子技术中不可或缺的核心器件。 集成电路可分为模拟集成电路和数字集成电路两大类,包括集成运放、时基集成电路、集成稳压器、门电路、触发器、计数器、译码器…

【 uniapp - 黑马优购 | 分类界面 】创建cate分支、数据获取、动态渲染

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大二在校生&#xff0c;讨厌编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;小新爱学习. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc…

【Lilishop商城】No4-4.业务逻辑的代码开发,涉及到:会员B端第三方登录的开发-web端第三方授权联合登录接口开发

仅涉及后端&#xff0c;全部目录看顶部专栏&#xff0c;代码、文档、接口路径在&#xff1a; 【Lilishop商城】记录一下B2B2C商城系统学习笔记~_清晨敲代码的博客-CSDN博客 全篇会结合业务介绍重点设计逻辑&#xff0c;其中重点包括接口类、业务类&#xff0c;具体的结合源代…

机器学习——支持向量机(SVM)

文章目录1. 优化目标2. 大间距的直观理解3. 大间距分类背后的数学支持向量机&#xff08;Support Vector Machines&#xff09;是广泛应用于工业界和学术界的一种监督学习算法&#xff0c;在学习复杂的非线性方程时提供了一种更为清晰&#xff0c;更加强大的方式。下面从SVM的优…

【nowcoder】笔试强训Day10

目录 一、选择题 二、编程题 2.1井字棋 2.2密码强度等级 一、选择题 1.下列运算符合法的是&#xff08; &#xff09; A. && B. <> C. if D. : 逻辑与&&语法规则&#xff1a;表达式1&&表达式2&#xff0c;其中两个表达式都是布尔表达式…