本文是“驱动简说”的第2篇,是本人的读书总结,对于大多数人来说,看看这些例子就已经够用!回顾前文的驱动,有如下两个缺点,本篇文章,就以经典例子,来解决这两个问题:
本文基于Amlogic T972 , Android 9.0, 内核版本 4.9.113
第1篇:基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
第2篇:基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备
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;}
/* 注册 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);
#include /* 模块初始化、卸载的接口头文件 */
#include /* 字符设备头文件 */
#include
#include /* class和device依赖 的头文件 */#define DEVICE_NAME "aml_char"
#define CLASS_NAME DEVICE_NAMEstatic 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_charclass_destroy(amlClass); // 移除 /sys/class/aml_charcdev_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.");
#
# 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篇
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!
:/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
保持持续学习, 欢迎私信交流。