https://blog.csdn.net/Railshiqian/article/details/160374693?spm=1011.2124.3001.6209
本章的目的,是编写一个helloworld驱动模块,此驱动模块会初始化一个/dev/hello_char驱动节点,提供文件读写能力,并编译出android系统可以加载的helloworld.ko文件。
1,准备helloworld源码
cd kernel工程/common-modules/virtual-device
创建helloworld文件夹和helloworld.c文件
bash
mkdir helloworld
cd helloworld
touch helloworld.c
helloworld.c里的内容如下:
c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#define DEVICE_NAME "hello_char"
#define CLASS_NAME "hello_class"
#define BUF_SIZE 128
static dev_t dev_num;
static struct cdev hello_cdev;
static struct class *hello_class;
static char kernel_buf[BUF_SIZE];
static size_t data_len;
/* open */
static int hello_open(struct inode *inode, struct file *file)
{
pr_info("hello_char: device opened\n");
return 0;
}
/* read */
static ssize_t hello_read(struct file *file,
char __user *buf,
size_t count,
loff_t *ppos)
{
if (*ppos >= data_len)
return 0;
if (count > data_len - *ppos)
count = data_len - *ppos;
if (copy_to_user(buf, kernel_buf + *ppos, count))
return -EFAULT;
*ppos += count;
return count;
}
/* write */
static ssize_t hello_write(struct file *file,
const char __user *buf,
size_t count,
loff_t *ppos)
{
if (count > BUF_SIZE)
count = BUF_SIZE;
if (copy_from_user(kernel_buf, buf, count))
return -EFAULT;
data_len = count;
pr_info("hello_char: write %zu bytes: %.*s\n",
count, (int)count, kernel_buf);
return count;
}
/* file operations */
static const struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.read = hello_read,
.write = hello_write,
};
static int __init hello_init(void)
{
int ret;
/* 1. alloc major/minor */
ret = alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME);
if (ret)
return ret;
/* 2. init cdev */
cdev_init(&hello_cdev, &hello_fops);
ret = cdev_add(&hello_cdev, dev_num, 1);
if (ret)
goto err_cdev;
/* 3. create class */
hello_class = class_create(CLASS_NAME);
if (IS_ERR(hello_class)) {
ret = PTR_ERR(hello_class);
goto err_class;
}
/* 4. create device node: /dev/hello_char */
device_create(hello_class, NULL,
dev_num, NULL, DEVICE_NAME);
pr_info("hello_char: init success\n");
return 0;
err_class:
cdev_del(&hello_cdev);
err_cdev:
unregister_chrdev_region(dev_num, 1);
return ret;
}
static void __exit hello_exit(void)
{
device_destroy(hello_class, dev_num);
class_destroy(hello_class);
cdev_del(&hello_cdev);
unregister_chrdev_region(dev_num, 1);
pr_info("hello_char: exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Example");
MODULE_DESCRIPTION("Android Kernel Char Device Example");
2,配置helloworld模块编译
修改kernel工程/common-modules/virtual-device/BUILD.bazel文件,进行以下修改:
bash
diff --git a/BUILD.bazel b/BUILD.bazel
index 2deb1f7..8455d4f 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -79,6 +79,13 @@ filegroup(
],
)
+filegroup(
+ name = "helloworld_sources",
+ srcs = [
+ "helloworld/helloworld.c",
+ ],
+)
+
filegroup(
name = "vkms_sources",
srcs = [
@@ -250,6 +257,14 @@ ddk_module(
deps = [":common_headers_x86_64"],
)
+ddk_module(
+ name = "x86_64/helloworld",
+ srcs = [":helloworld_sources"],
+ out = "helloworld.ko",
+ kernel_build = ":virtual_device_x86_64",
+ deps = [":common_headers_x86_64"],
+)
+
ddk_module(
name = "x86_64/vkms",
srcs = [":vkms_sources"],
@@ -265,6 +280,7 @@ kernel_module_group(
":x86_64/goldfish_drivers/goldfish_pipe",
":x86_64/goldfish_drivers/goldfish_sync",
":x86_64/v4l2loopback",
+ ":x86_64/helloworld",
":x86_64/vkms",
"//common-modules/virtio-media/driver:x86_64/virtio-media",
],
3,编译出helloworld.ko文件
用上一章节同样的编译命令,进行重新编译,就可以得到helloworld.ko:
在kernel工程根目录下,执行编译命令:
bash
tools/bazel run //common-modules/virtual-device:virtual_device_x86_64_dist --distdir=out
输出:
bash
......
[dist] DEBUG: Copying file: out/virtual_device_x86_64/dist/helloworld.ko
......
4,将ko文件推到模拟器设备里进行加载和卸载,以及文件调试
bash
推ko文件到设备:adb push out/virtual_device_x86_64/dist/helloworld.ko /data/
进android shell环境:adb shell
通过insmod 命令加载ko模块:insmod /data/helloworld.ko
确认helloworld模块已初始化:
adb logcat -b all |tee ~/temp.log |grep -Ei "hello"
04-21 15:23:01.383 0 0 I hello_char: exit
04-21 15:23:12.901 0 0 I hello_char: init success
确认/dev/hello_char驱动文件节点已创建:
emulator_car64_x86_64:/ # file /dev/hello_char
/dev/hello_char: character special (504/0)
对文件进行写 + 读:
emulator_car64_x86_64:/ # echo hello > /dev/hello_char
emulator_car64_x86_64:/ # cat /dev/hello_char
hello