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

简介: 这篇文章是关于如何在基于Amlogic T972的Android 9.0系统上,通过自动分配设备号和自动创建设备节点文件的方式,开发字符设备驱动程序的教程。

一、前言

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

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

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

二、系列文章

第1篇:基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
第2篇:基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备
第3篇:基于Amlogic 安卓9.0, 驱动简说(三):使用misc框架,让驱动更简单
第4篇:基于Amlogic 安卓9.0, 驱动简说(四):Platform平台驱动,驱动与设备的分离

三、替换部分

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 #

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

七、源码下载

百看不如一试……

git clone git@gitee.com:amizhou/amlogic_t972_android9_driver.git

八、篇尾

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

相关文章
|
17天前
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(五):基于GPIO、LED子系统的LED驱动
这篇文章是关于如何在基于Amlogic T972的Android 9.0系统上,使用GPIO和LED子系统来实现LED驱动的教程,包括了DTS设备树配置、驱动源码编写以及如何在用户空间控制LED的亮度和开关。
21 0
基于Amlogic 安卓9.0, 驱动简说(五):基于GPIO、LED子系统的LED驱动
|
17天前
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(四):Platform平台驱动,驱动与设备的分离
本文介绍了如何在基于Amlogic T972的Android 9.0系统上使用Platform平台驱动框架和设备树(DTS),实现设备与驱动的分离,并通过静态枚举在设备树中描述设备,自动触发驱动程序的加载和设备创建。
7 0
基于Amlogic 安卓9.0, 驱动简说(四):Platform平台驱动,驱动与设备的分离
|
17天前
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(三):使用misc框架,让驱动更简单
如何使用Amlogic T972安卓9.0系统上的misc框架来简化驱动程序开发,通过misc框架自动分配设备号并创建设备文件,从而减少代码量并避免设备号冲突。
21 0
基于Amlogic 安卓9.0, 驱动简说(三):使用misc框架,让驱动更简单
|
17天前
|
自然语言处理 Shell Linux
基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
本文是关于在Amlogic安卓9.0平台上创建字符设备驱动的教程,详细介绍了驱动程序的编写、编译、部署和测试过程,并提供了完整的源码和应用层调用示例。
32 0
基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
|
3天前
|
IDE 开发工具 Android开发
安卓与iOS开发对比:平台选择对项目成功的影响
【9月更文挑战第10天】在移动应用开发的世界中,选择正确的平台是至关重要的。本文将深入探讨安卓和iOS这两大主要移动操作系统的开发环境,通过比较它们的市场份额、开发工具、编程语言和用户群体等方面,为开发者提供一个清晰的指南。我们将分析这两个平台的优势和劣势,并讨论如何根据项目需求和目标受众来做出最佳选择。无论你是初学者还是有经验的开发者,这篇文章都将帮助你更好地理解每个平台的特性,并指导你做出明智的决策。
|
1天前
|
API Android开发 iOS开发
安卓与iOS开发中的线程管理对比
【9月更文挑战第12天】在移动应用的世界中,安卓和iOS平台各自拥有庞大的用户群体。开发者们在这两个平台上构建应用时,线程管理是他们必须面对的关键挑战之一。本文将深入探讨两大平台在线程管理方面的异同,通过直观的代码示例,揭示它们各自的设计理念和实现方式,帮助读者更好地理解如何在安卓与iOS开发中高效地处理多线程任务。
|
3天前
|
开发框架 Android开发 iOS开发
探索安卓与iOS开发的差异:构建未来应用的指南
在移动应用开发的广阔天地中,安卓与iOS两大平台各占半壁江山。本文将深入浅出地对比这两大操作系统的开发环境、工具和用户体验设计,揭示它们在编程语言、开发工具以及市场定位上的根本差异。我们将从开发者的视角出发,逐步剖析如何根据项目需求和目标受众选择适合的平台,同时探讨跨平台开发框架的利与弊,为那些立志于打造下一个热门应用的开发者提供一份实用的指南。
14 5
|
3天前
|
开发工具 Android开发 iOS开发
安卓与iOS开发:平台选择的艺术与科学
在移动应用开发的广阔天地中,安卓与iOS两大平台如同东西方哲学的碰撞,既有共通之处又各具特色。本文将深入探讨这两个平台的设计理念、开发工具和市场定位,旨在为开发者提供一份简明扼要的指南,帮助他们在这场技术与商业的博弈中找到自己的道路。通过比较分析,我们将揭示每个平台的优势与局限,以及它们如何影响应用的性能、用户体验和市场接受度。无论你是初涉江湖的新手,还是经验丰富的老手,这篇文章都将为你的选择提供新的视角和思考。
16 5