• 我们的目的写出一个容易扩展到各种芯片、各种板子的按键驱动程序,所以驱动程序分为上下两层:

    button_drv.c 分配/设置/注册 file_operations 结构体
    起承上启下的作用,向上提供 button_open,button_read 供 APP 调用。
    而这 2 个函数又会调用底层硬件提供的 p_button_opr 中的 init、read 函数操作硬件。
    board_xxx.c 分配/设置/注册 button_operations 结构体
    这个结构体是我们自己抽象出来的,里面定义单板 xxx 的按键操作函数。

    • image.png
    • 抽象出button_opeartions结构体 ```c struct button_operations { int count; void (init) (int which); int (read) (int which); };

    void register_button_operations(struct button_operations *opr); void unregister_button_operations(void);

    1. - 实现button_opeartions结构体,并注册到上层的按键驱动程序中
    2. ```c
    3. static void board_xxx_button_init_gpio (int which)
    4. {
    5. printk("%s %s %d, init gpio for button %d\n", __FILE__, __FUNCTION__, __LINE__, which);
    6. }
    7. static int board_xxx_button_read_gpio (int which)
    8. {
    9. printk("%s %s %d, read gpio for button %d\n", __FILE__, __FUNCTION__, __LINE__, which);
    10. return 1;
    11. }
    12. static struct button_operations my_buttons_ops ={
    13. .count = 2,
    14. .init = board_xxx_button_init_gpio,
    15. .read = board_xxx_button_read_gpio,
    16. };
    17. int board_xxx_button_init(void)
    18. {
    19. register_button_operations(&my_buttons_ops);
    20. return 0;
    21. }
    22. void board_xxx_button_exit(void)
    23. {
    24. unregister_button_operations();
    25. }
    26. module_init(board_xxx_button_init);
    27. module_exit(board_xxx_button_exit);
    28. MODULE_LICENSE("GPL");
    • 实现上层的按键驱动 ```c static int major = 0;

    static struct button_operations p_button_opr; static struct class button_class;

    static int button_open (struct inode inode, struct file file) { int minor = iminor(inode); p_button_opr->init(minor); return 0; }

    static ssize_t button_read (struct file file, char __user buf, size_t size, loff_t *off) { unsigned int minor = iminor(file_inode(file)); char level; int err;

    1. level = p_button_opr->read(minor);
    2. err = copy_to_user(buf, &level, 1);
    3. return 1;

    }

    static struct file_operations button_fops = { .open = button_open, .read = button_read, };

    void register_button_operations(struct button_operations *opr) { int i;

    1. p_button_opr = opr;
    2. for (i = 0; i < opr->count; i++)
    3. {
    4. /* 在底层代码注册button_operations时创建device */
    5. device_create(button_class, NULL, MKDEV(major, i), NULL, "100ask_button%d", i);
    6. }

    }

    void unregister_button_operations(void) { int i;

    1. for (i = 0; i < p_button_opr->count; i++)
    2. {
    3. device_destroy(button_class, MKDEV(major, i));
    4. }

    }

    EXPORT_SYMBOL(register_button_operations); EXPORT_SYMBOL(unregister_button_operations);

    int button_init(void) { major = register_chrdev(0, “100ask_button”, &button_fops);

    1. button_class = class_create(THIS_MODULE, "100ask_button");
    2. if (IS_ERR(button_class))
    3. return -1;
    4. return 0;

    }

    void button_exit(void) { class_destroy(button_class); unregister_chrdev(major, “100ask_button”); }

    module_init(button_init); module_exit(button_exit); MODULE_LICENSE(“GPL”); ```

    • 将上层的按键驱动和底层board的驱动程序都编译成.ko模块(底层board依赖于上层)
    • 底层代码调用 register_button_operations 函数,向上提供button_operations这个结构体指针