• 《C语言编程思想 — 用结构体实现面向对象和分离》


    说明: 

      以下示例是看到Linux中驱动一个比较简单的架构,然后记录下来。

      示例的功能是:将led通用的一些驱动代码和硬件相关代码分离开。

      什么是通用的驱动代码:比如注册file_operation结构体啊,class类等一些。就算我们修改驱动,这些也不会变动的代码。

      硬件相关代码:比如led的引脚地址

    为什么要这样做?

      1.减少耦合性。将通用代码和硬件相关代码分离开。这样,当我们修改LED的驱动的时候,就不用看一段很长的代码。只需要单独修改跟硬件相关代码的那个文件。

      2.扩展性。我们需要去驱动其他板卡的LED的时候,那么我们也只需要修改跟硬件相关代码的那个文件。并且可以同时支持一个驱动代码对应多个不同的板卡。

     led_opr.h

     1 #ifndef _LED_OPR_H
     2 #define _LED_OPR_H
     3 
     4 struct led_operations {
     5     int (*init) (int which); /* 初始化LED, which-哪个LED */       
     6     int (*ctl) (int which, char status); /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
     7 };
     8 
     9 struct led_operations *get_board_led_opr(void);
    10 
    11 
    12 #endif

      led_opr.h中定义了一个结构体,结构体里面定义了函数指针init和ctl。并且有一个指针函数,返回的是led_operations类型的结构体指针

      首先分析一下为什么要使用函数指针。

      函数指针就是一个指向函数的指针,我们可以把写好的函数赋给这个函数指针。其他.c文件就可以直接用led_operations->init(参数)来调用我们在其他文件编写好的函数。就不需要每次都要声明一下函数,然后再调用,也不用担心函数名的问题。

      为什么要使用指针函数?

      指针函数就是返回指针的函数。我们需要把在board_demo.c中定义的led_operations结构体变量给其他.c的函数用。

    board_demo.c

     1 board_demo.c
     2 
     3 #include <linux/module.h>
     4 
     5 #include <linux/fs.h>
     6 #include <linux/errno.h>
     7 #include <linux/miscdevice.h>
     8 #include <linux/kernel.h>
     9 #include <linux/major.h>
    10 #include <linux/mutex.h>
    11 #include <linux/proc_fs.h>
    12 #include <linux/seq_file.h>
    13 #include <linux/stat.h>
    14 #include <linux/init.h>
    15 #include <linux/device.h>
    16 #include <linux/tty.h>
    17 #include <linux/kmod.h>
    18 #include <linux/gfp.h>
    19 #include "led_opr.h"
    20 
    21 static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */       
    22 {
    23     
    24     printk("%s %s line %d, led %d
    ", __FILE__, __FUNCTION__, __LINE__, which);
    25     return 0;
    26 }
    27 
    28 static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
    29 {
    30     printk("%s %s line %d, led %d, %s
    ", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");
    31     return 0;
    32 }
    33 
    34 static struct led_operations board_demo_led_opr = {
    35     .init = board_demo_led_init,
    36     .ctl  = board_demo_led_ctl,
    37 };
    38 
    39 struct led_operations *get_board_led_opr(void)
    40 {
    41     return &board_demo_led_opr;
    42 }

       在board_demo.c中实现了board_demo_led_init和board_demo_led_ctl两个函数。然后将这两个函数赋给led_operations类型结构体变量board_demo_led_opr中的成员init和ctl。然后通过get_board_led_opr函数(指针函数:返回led_operations *类型的指针)。这样就可以在leddrv.c中获取到board_demo_led_opr变量的地址,在其他.c中可以调用board_demo_led_init和board_demo_led_ctl这两个函数。

    leddrv.c

      1 #include <linux/module.h>
      2 
      3 #include <linux/fs.h>
      4 #include <linux/errno.h>
      5 #include <linux/miscdevice.h>
      6 #include <linux/kernel.h>
      7 #include <linux/major.h>
      8 #include <linux/mutex.h>
      9 #include <linux/proc_fs.h>
     10 #include <linux/seq_file.h>
     11 #include <linux/stat.h>
     12 #include <linux/init.h>
     13 #include <linux/device.h>
     14 #include <linux/tty.h>
     15 #include <linux/kmod.h>
     16 #include <linux/gfp.h>
     17 
     18 #include "led_opr.h"
     19 
     20 #define LED_NUM 2
     21 
     22 /* 1. 确定主设备号                                                                 */
     23 static int major = 0;
     24 static struct class *led_class;
     25 struct led_operations *p_led_opr;
     26 
     27 
     28 #define MIN(a, b) (a < b ? a : b)
     29 
     30 /* 3. 实现对应的open/read/write等函数,填入file_operations结构体                   */
     31 static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
     32 {
     33     printk("%s %s line %d
    ", __FILE__, __FUNCTION__, __LINE__);
     34     return 0;
     35 }
     36 
     37 /* write(fd, &val, 1); */
     38 static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
     39 {
     40     int err;
     41     char status;
     42     struct inode *inode = file_inode(file);
     43     int minor = iminor(inode);
     44     
     45     printk("%s %s line %d
    ", __FILE__, __FUNCTION__, __LINE__);
     46     err = copy_from_user(&status, buf, 1);
     47 
     48     /* 根据次设备号和status控制LED */
     49     p_led_opr->ctl(minor, status);
     50     
     51     return 1;
     52 }
     53 
     54 static int led_drv_open (struct inode *node, struct file *file)
     55 {
     56     int minor = iminor(node);
     57     
     58     printk("%s %s line %d
    ", __FILE__, __FUNCTION__, __LINE__);
     59     /* 根据次设备号初始化LED */
     60     p_led_opr->init(minor);
     61     
     62     return 0;
     63 }
     64 
     65 static int led_drv_close (struct inode *node, struct file *file)
     66 {
     67     printk("%s %s line %d
    ", __FILE__, __FUNCTION__, __LINE__);
     68     return 0;
     69 }
     70 
     71 /* 2. 定义自己的file_operations结构体                                              */
     72 static struct file_operations led_drv = {
     73     .owner     = THIS_MODULE,
     74     .open    = led_drv_open,
     75     .read    = led_drv_read,
     76     .write   = led_drv_write,
     77     .release = led_drv_close,
     78 };
     79 
     80 /* 4. 把file_operations结构体告诉内核:注册驱动程序                                */
     81 /* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
     82 static int __init led_init(void)
     83 {
     84     int err;
     85     int i;
     86     
     87     printk("%s %s line %d
    ", __FILE__, __FUNCTION__, __LINE__);
     88     major = register_chrdev(0, "100ask_led", &led_drv);  /* /dev/led */
     89 
     90 
     91     led_class = class_create(THIS_MODULE, "100ask_led_class");
     92     err = PTR_ERR(led_class);
     93     if (IS_ERR(led_class)) {
     94         printk("%s %s line %d
    ", __FILE__, __FUNCTION__, __LINE__);
     95         unregister_chrdev(major, "led");
     96         return -1;
     97     }
     98 
     99     for (i = 0; i < LED_NUM; i++)
    100         device_create(led_class, NULL, MKDEV(major, i), NULL, "100ask_led%d", i); /* /dev/100ask_led0,1,... */
    101 
    102     p_led_opr = get_board_led_opr();
    103     
    104     return 0;
    105 }
    106 
    107 /* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数           */
    108 static void __exit led_exit(void)
    109 {
    110     int i;
    111     printk("%s %s line %d
    ", __FILE__, __FUNCTION__, __LINE__);
    112 
    113     for (i = 0; i < LED_NUM; i++)
    114         device_destroy(led_class, MKDEV(major, i)); /* /dev/100ask_led0,1,... */
    115 
    116     device_destroy(led_class, MKDEV(major, 0));
    117     class_destroy(led_class);
    118     unregister_chrdev(major, "100ask_led");
    119 }
    120 
    121 
    122 /* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
    123 
    124 module_init(led_init);
    125 module_exit(led_exit);
    126 
    127 MODULE_LICENSE("GPL");

      25行struct led_operations *p_led_opr,定义了一个led_operations结构体指针变量。

      102行中get_board_led_opr()函数(就是一个指针函数,返回一个led_operations结构体变量)。

      49行和60行通过p_led_opr去调用在board_demo.c中写好的函数。








  • 相关阅读:
    hadoop自定义数据类型
    hadoop worldcount小程序
    windows下eclipse连接ubuntu伪分布式hadoop2.6.0
    Hadoop2.6.0伪分布式搭建
    解决hadoop no dataNode to stop问题
    hadoop 2.6.0 伪分布式部署安装遇到的问题
    Hadoop执行bin/stop-all.sh时no namenode to stop异常
    Hadoop伪分布式安装步骤(hadoop0.20.2版本)
    《Hadoop基础教程》之初识Hadoop(转载)
    自定义Json格式
  • 原文地址:https://www.cnblogs.com/zhuangquan/p/12180652.html
Copyright © 2020-2023  润新知