common-android15-6.6 kernel环境下,编写并编译一个helloworld驱动模块

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
相关推荐
TeDi TIVE2 小时前
mysql-connector-java 和 mysql-connector-j的区别
android·java·mysql
私人珍藏库2 小时前
[Android] 快捷记账_4.11.0 GF
android·app·工具·软件·多功能
Kapaseker2 小时前
你的进度条与众不同 — Compose 条纹
android·kotlin
Hello.Reader2 小时前
零成本在手机上跑 Gemma 4安卓+iPhone 本地离线多模态实战指南
android·智能手机·iphone
y小花2 小时前
安卓StorageManagerService
android·java
码王吴彦祖2 小时前
AI 逆向分析国航 AirChina FECU 参数来源并实现离线生成
android·java·javascript
黄林晴2 小时前
Compose 原生 FlexBox 正式上线,告别布局妥协
android
lKWO OMET2 小时前
图文详述:MySQL的下载、安装、配置、使用
android·mysql·adb
hhkSUC8PD2 小时前
Laravel AI SDK 正式发布
android·人工智能·laravel