• 为安卓编写Linux内核驱动程序


    参考博文:https://blog.csdn.net/Luoshengyang/article/details/6568411
    参考博文:
    https://www.jianshu.com/p/4ea84d1ce4e5

    为安卓编写一个简单的设备驱动

    环境:Andriod12 + kernel 5.*内核 + 一部手机

    我们在配置硬件较多的地方创建freg目录及其相关文件

    ---Android源码
    ------kernel5.*
    ---------drivers/
    ------------freg/
    ---------------freg.c
    ---------------freg.h
    ---------------Makefile
    ---------------Kconfig
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    freg.c

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include "freg.h"
    
    static int freg_major = 0;
    static int freg_minor = 0;
    
    static struct class* freg_class = NULL;
    static struct fake_reg_dev* freg_dev = NULL;
    
    static int freg_open(struct inode* inode, struct file* filp);
    static int freg_release(struct inode* inode, struct file* filp);
    static ssize_t freg_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);
    static ssize_t freg_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);
    
    static struct file_operations freg_fops = {
        .owner = THIS_MODULE,
        .open = freg_open,
        .release = freg_release,
        .read = freg_read,
        .write = freg_write,
    };
    
    #define SEQ_printf(m, x...)     \
        do {                \
            if (m)          \
                seq_printf(m, x);   \
            else            \
                pr_err(x);      \
        } while (0)
    
    static int freg_proc_show(struct seq_file *m, void *v)
    {
        SEQ_printf(m, "%d\n", freg_dev->val);
        return 0;
    }
    
    static int freg_proc_open(struct inode *inode, struct file *file)
    {
        return single_open(file, freg_proc_show, inode->i_private);
    }
    
    static ssize_t __freg_set_val(struct fake_reg_dev* dev, const char* buf, size_t count){
        int val = 0;
    
        val = simple_strtol(buf, NULL, 10);
    
        if(down_interruptible(&(dev->sem))){
            return -ERESTARTSYS;
        }
    
        dev->val = val;
        up(&(dev->sem));
    
        return count;
    }
    
    /*
    static ssize_t freg_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data){
        if(off >0 ){
            *eof = 1;
            return 0;
        }
    
        return __freg_get_val(freg_dev, page);
    }*/
    
    static ssize_t freg_proc_write(struct file *filp, const char *ubuf, size_t cnt, loff_t *data){
        int err = 0;
        char* page = NULL;
    
        if(cnt > PAGE_SIZE){
            printk(KERN_ALERT"The buff is too large: %lu.\n", cnt);
            return -EFAULT;
        }
    
        page = (char*) __get_free_page(GFP_KERNEL);
        if(!page){
            printk(KERN_ALERT"Failed to alloc page.\n");
            return -ENOMEM;
        }
    
        if(raw_copy_from_user(page, ubuf, cnt)){
            printk(KERN_ALERT"Failed to copy buff from user.\n");
            err = -EFAULT;
            goto out;
        }
    
        err = __freg_set_val(freg_dev, page, cnt);
    
    out:
        free_page((unsigned long)page);
        return err;
    }
    
    static const struct file_operations freg_proc_fops = {
        .open = freg_proc_open,
        .write = freg_proc_write,
        .read = seq_read,
        .llseek = seq_lseek,
        .release = single_release,
    };
    
    
    static ssize_t freg_val_show(struct device* dev, struct device_attribute* attr, char* buf);
    static ssize_t freg_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);
    
    static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, freg_val_show, freg_val_store);
    
    static int freg_open(struct inode * inode, struct file * filp){
        struct fake_reg_dev * dev;
    
        dev = container_of(inode->i_cdev, struct fake_reg_dev, dev);
        filp->private_data = dev;
    
        return 0;
    }
    
    static int freg_release(struct inode* inode, struct file* filp){
        return 0;
    }
    
    static ssize_t freg_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos){
        ssize_t err = 0;
        struct fake_reg_dev* dev = filp->private_data;
    
        if(down_interruptible(&(dev->sem))){
            return -ERESTARTSYS;
        }
    
        if(count < sizeof(dev->val)){
            goto out;
        }
    
        if(raw_copy_to_user(buf, &(dev->val), sizeof(dev->val))){
            err = -EFAULT;
            goto out;
        }
    
        err = sizeof(dev->val);
    
    out:
        up(&(dev->sem));
        return err;
    }
    
    static ssize_t freg_write(struct file * filp, const char __user * buf, size_t count, loff_t * f_pos){
        struct fake_reg_dev* dev = filp->private_data;
        ssize_t err = 0;
    
        if(down_interruptible(&(dev->sem))){
            return -ERESTARTSYS;
        }
    
        if(count != sizeof(dev->val)){
            goto out;
        }
    
        if(raw_copy_from_user(&(dev->val), buf, count)){
            err = -EFAULT;
            goto out;
        }
    
        err = sizeof(dev->val);
    
    out:
        up(&(dev->sem));
        return err;
    }
    
    static ssize_t __freg_get_val(struct fake_reg_dev* dev, char* buf){
        int val = 0;
    
        if(down_interruptible(&dev->sem)){
            return -ERESTARTSYS;
        }
    
        val = dev->val;
        up(&(dev->sem));
    
        return snprintf(buf, PAGE_SIZE, "%d\n", val);
    }
    
    
    static ssize_t freg_val_show(struct device* dev, struct device_attribute* attr, char* buf){
        struct fake_reg_dev* hdev = (struct fake_reg_dev*)dev_get_drvdata(dev);
    
        return __freg_get_val(hdev, buf);
    }
    
    static ssize_t freg_val_store(struct device*dev, struct device_attribute* attr, const char* buf, size_t count){
        struct fake_reg_dev* hdev = (struct fake_reg_dev*)dev_get_drvdata(dev);
    
        return __freg_set_val(hdev, buf, count);
    }
    
    
    static void freg_create_proc(void){
        proc_create(FREG_DEVICE_PROC_NAME, 0644, 0,  &freg_proc_fops);
    }
    
    static void freg_remove_proc(void){
        remove_proc_entry(FREG_DEVICE_PROC_NAME, NULL);
    }
    
    static int __freg_setup_dev(struct fake_reg_dev* dev){
        int err;
        dev_t devno = MKDEV(freg_major, freg_minor);
    
        memset(dev, 0, sizeof(struct fake_reg_dev));
    
        cdev_init(&(dev->dev), &freg_fops);
        dev->dev.owner = THIS_MODULE;
        dev->dev.ops = &freg_fops;
    
        err = cdev_add(&(dev->dev), devno, 1);
        if(err){
            return err;
        }
    
        //init_MUTEX(&(dev->sem));
        sema_init(&(dev->sem), 1);
        dev->val = 0;
    
        return 0;
    }
    
    static int __init freg_init(void){
        int err = -1;
        dev_t dev = 0;
        struct device* temp = NULL;
    
        printk(KERN_ALERT"Initializing freg device.\n");
    
        err = alloc_chrdev_region(&dev, 0, 1, FREG_DEVICE_NODE_NAME);
        if(err < 0){
            printk(KERN_ALERT"Failed to alloc char dev region.\n");
            goto fail;
        }
    
        freg_major = MAJOR(dev);
        freg_minor = MINOR(dev);
    
        freg_dev = kmalloc(sizeof(struct fake_reg_dev), GFP_KERNEL);
        if(!freg_dev){
            err = -ENOMEM;
            printk(KERN_ALERT"Failed to alloc freg device.\n");
            goto unregister;
        }
    
        err = __freg_setup_dev(freg_dev);
        if(err){
            printk(KERN_ALERT"Failed to setup freg device: %d.\n", err);
            goto cleanup;
        }
    
        freg_class = class_create(THIS_MODULE, FREG_DEVICE_CLASS_NAME);
        if(IS_ERR(freg_class)){
            err = PTR_ERR(freg_class);
            printk(KERN_ALERT"Failed to create freg device class.\n");
            goto destroy_cdev;
        }
    
        temp = device_create(freg_class, NULL, dev, NULL, "%s", FREG_DEVICE_FILE_NAME);
        if(IS_ERR(temp)){
            err = PTR_ERR(temp);
            printk(KERN_ALERT"Failed to create freg device.\n");
            goto destroy_class;
        }
    
        err = device_create_file(temp, &dev_attr_val);
        if(err < 0){
            printk(KERN_ALERT"Failed to create attribute val of freg device.\n");
            goto destroy_device;
        }
    
        dev_set_drvdata(temp, freg_dev);
    
        freg_create_proc();
    
        printk(KERN_ALERT"Succedded to initialize freg device.\n");
    
        return 0;
    
    destroy_device:
        device_destroy(freg_class, dev);
    destroy_class:
        class_destroy(freg_class);
    destroy_cdev:
        cdev_del(&(freg_dev->dev));
    cleanup:
        kfree(freg_dev);
    unregister:
        unregister_chrdev_region(MKDEV(freg_major, freg_minor), 1);
    fail:
        return err;
    }
    
    static void __exit freg_exit(void){
        dev_t devno = MKDEV(freg_major, freg_minor);
    
        printk(KERN_ALERT"Destory freg device.\n");
    
        freg_remove_proc();
    
        if(freg_class){
            device_destroy(freg_class, MKDEV(freg_major, freg_minor));
            class_destroy(freg_class);
        }
    
        if(freg_dev){
            cdev_del(&(freg_dev->dev));
            kfree(freg_dev);
        }
    
        unregister_chrdev_region(devno, 1);
    }
    
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("Fake Register Driver");
    
    module_init(freg_init);
    module_exit(freg_exit);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331

    此处代码参考第二篇博文,新内核弃用copy_from_user与copy_to_user 需要改成raw_copy_from_user与raw_copy_to_user

    freg.h

    #ifndef _FAKE_REG_H_
    #define _FAKE_REG_H_
    
    #include 
    #include 
    
    #define FREG_DEVICE_NODE_NAME  "freg"
    #define FREG_DEVICE_FILE_NAME  "freg"
    #define FREG_DEVICE_PROC_NAME  "freg"
    #define FREG_DEVICE_CLASS_NAME "freg"
    
    struct fake_reg_dev {
        int val;
        struct semaphore sem;
        struct cdev dev;
    };
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Kconfig

    config FREG
        tristate "Fake Register Driver"
        default y
        help
        This is the freg driver for android system.
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Makefile

    obj-$(CONFIG_FREG) += freg.o
    
    • 1

    然后我们要去修改上级目录的Kconfig文件与Makefile文件也就是/drivers下的2个文件

    在drivers中的Kconfig文件中我们需要在

    menu "Device Drivers"
    source "drivers/lizi/Kconfig"
    ...
    ...
    endmenu
    
    • 1
    • 2
    • 3
    • 4
    • 5

    menu 与 endmenu之间加下面这句话

    /drivers Kconfig

    source "drivers/freg/Kconfig"
    
    • 1

    /drivers Makefile

    obj-$(CONFIG_FREG) += freg/
    
    • 1

    到此我们就完成了代码部分,然后我们回到安卓源码目录下编译,不是kernel目录

    make bootimage -j4
    
    • 1

    然后我们在编译后生成的out目录下找到将boot.img刷到手机里通过adb shell命令进入可一看到proc和dev目录下有freg文件

    adb shell
    /proc/freg
    /dev/freg
    
    • 1
    • 2
    • 3

    我们在proc目录下输入

    cat freg
    0
    echo '5' > freg
    5
    
    • 1
    • 2
    • 3
    • 4

    此时我们可看到/sys/class/freg/freg/下的val值

    cat /sys/class/freg/freg/val
    
    • 1
  • 相关阅读:
    java面向对象
    基于恒功率PQ控制的三电平并网逆变器MATLAB仿真模型
    第54篇-网易易盾滑块请求参数分析【2022-11-16】
    C++类模板实例化与专门化
    目标检测——【Transformer】Accelerating DETR Convergence via Semantic-Aligned Matching
    Android 13.0 修改系统签名文件类型test-keys为release-keys
    mysql16
    一文看懂推荐系统:排序02:Multi-gate Mixture-of-Experts (MMoE)
    springboot在filter中设置跨域
    Pandas+Matplotlib 数据分析
  • 原文地址:https://blog.csdn.net/qq_43619680/article/details/126387538