【北京迅为】i.MX6ULL终结者Linux MISC驱动编写实验程序

在本实验中,使用misc设备驱动的方式来编写蜂鸣器的驱动,用 platform 来实现总线、设备和驱动,misc 主要负责完成字符设备的创建。

1 修改设备树文件

设备树中的beep设备节点直接使用36.3.2中创建的beep设备节点即可。

2 编写驱动程序

本实验例程路径:i.MX6UL终结者光盘资料/06_Linux驱动例程/16_beep_misc
创建beep_misc.c文件,具体内容如下:

  1 #include <linux/types.h>
  2 #include <linux/kernel.h>
  3 #include <linux/delay.h>
  4 #include <linux/ide.h>
  5 #include <linux/init.h>
  6 #include <linux/module.h>
  7 #include <linux/errno.h>
  8 #include <linux/gpio.h>
  9 #include <linux/cdev.h>
 10 #include <linux/device.h>
 11 #include <linux/of.h>
 12 #include <linux/of_address.h>
 13 #include <linux/of_gpio.h>
 14 #include <linux/platform_device.h>
 15 #include <linux/miscdevice.h>
 16 #include <asm/mach/map.h>
 17 #include <asm/uaccess.h>
 18 #include <asm/io.h>
 19 
 20 #define MISCBEEP_NAME           "miscbeep"      /* 名字         */
 21 #define MISCBEEP_MINOR          144              /* 子设备号 */
 22 #define BEEPOFF                         0      /* 关蜂鸣器 */
 23 #define BEEPON                          1     /* 开蜂鸣器 */
 24 
 25 /* miscbeep设备结构体 */
 26 struct miscbeep_dev{
    
    
 27         dev_t devid;                    /* 设备号*/
 28         struct cdev cdev;               /* cdev    */
 29         struct class *class;            /* 类  */
 30         struct device *device;          /* 设备*/
 31         struct device_node  *nd; /* 设备节点 */
 32         int beep_gpio;           /* beep所使用的GPIO编号 */
 33 };
 34 
 35 struct miscbeep_dev miscbeep;           /* beep设备 */
 36 
 37 /*
 38  * @description         : 打开设备
 39  * @param - inode       : 传递给驱动的inode
 40  * @param - filp        : 设备文件,file结构体有个叫做private_data的成员变量
 41  *  一般在open的时候将private_data指向设备结构体。
 42  * @return      : 0 成功;其他 失败
 43  */
 44 static int miscbeep_open(struct inode *inode, struct file *filp)
 45 {
    
    
 46         filp->private_data = &miscbeep; /* 设置私有数据 */
 47         return 0;
 48 }
 49 
 50 /*
 51  * @description         : 向设备写数据 
 52  * @param - filp        : 设备文件,表示打开的文件描述符
 53  * @param - buf         : 要写给设备写入的数据
 54  * @param - cnt         : 要写入的数据长度
 55  * @param - offt        : 相对于文件首地址的偏移
 56  * @return                      : 写入的字节数,如果为负值,表示写入失败
 57  */
 58 static ssize_t miscbeep_write(struct file *filp, const char __user *buf, 
size_t cnt, loff_t *offt)
 59 {
    
    
 60         int retvalue;
 61         unsigned char databuf[1];
 62         unsigned char beepstat;
 63         struct miscbeep_dev *dev = filp->private_data;
 64 
 65         retvalue = copy_from_user(databuf, buf, cnt);
 66         if(retvalue < 0) {
    
    
 67                 printk("kernel write failed!\r\n");
 68                 return -EFAULT;
 69         }
 70 
 71         beepstat = databuf[0];          /* 获取状态值 */
 72         if(beepstat == BEEPON) {
    
    
 73                 gpio_set_value(dev->beep_gpio, 1);      /* 打开蜂鸣器 */
 74         } else if(beepstat == BEEPOFF) {
    
    
 75                 gpio_set_value(dev->beep_gpio, 0);      /* 关闭蜂鸣器 */
 76         }
 77         return 0;
 78 }
 79 
 80 /* 设备操作函数 */
 81 static struct file_operations miscbeep_fops = {
    
    
 82         .owner = THIS_MODULE,
 83         .open = miscbeep_open,
 84         .write = miscbeep_write,
 85 };
 86 
 87 /* MISC设备结构体 */
 88 static struct miscdevice beep_miscdev = {
    
    
 89         .minor = MISCBEEP_MINOR,
 90         .name = MISCBEEP_NAME,
 91         .fops = &miscbeep_fops,
 92 };
 93 
 94  /*
 95   * @description     : flatform驱动的probe函数,当驱动与
 96   *                    设备匹配以后此函数就会执行
 97   * @param - dev     : platform设备
 98   * @return          : 0,成功;其他负值,失败
 99   */
100 static int miscbeep_probe(struct platform_device *dev)
101 {
    
    
102         int ret = 0;
103 
104         printk("beep driver and device was matched!\r\n");
105         /* 设置BEEP所使用的GPIO */
106         /* 1、获取设备节点:beep */
107         miscbeep.nd = of_find_node_by_path("/beep");
108         if(miscbeep.nd == NULL) {
    
    
109                 printk("beep node not find!\r\n");
110                 return -EINVAL;
111         }
112 
113         /* 2、 获取设备树中的gpio属性,得到BEEP所使用的BEEP编号 */
114         miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd, "beep-gpio", 0);
115         if(miscbeep.beep_gpio < 0) {
    
    
116                 printk("can't get beep-gpio");
117                 return -EINVAL;
118         }
119 
120         /* 3、设置GPIO5_IO01为输出,并且输出低电平,默认关闭BEEP */
121         ret = gpio_direction_output(miscbeep.beep_gpio, 0);
122         if(ret < 0) {
    
    
123                 printk("can't set gpio!\r\n");
124         }
125 
126        /* 一般情况下会注册对应的字符设备,但是这里我们使用MISC设备
127        * 所以我们不需要自己注册字符设备驱动,只需要注册misc设备驱动即可
128        */
129         ret = misc_register(&beep_miscdev);
130         if(ret < 0){
    
    
131                 printk("misc device register failed!\r\n");
132                 return -EFAULT;
133         }
134 
135         return 0;
136 }
137 
138 /*
139  * @description     : platform驱动的remove函数,移除platform驱动
的时候此函数会执行
140  * @param - dev     : platform设备
141  * @return          : 0,成功;其他负值,失败
142  */
143 static int miscbeep_remove(struct platform_device *dev)
144 {
    
    
145         /* 注销设备的时候关闭LED灯 */
146         gpio_set_value(miscbeep.beep_gpio, 1);
147 
148         /* 注销misc设备 */
149         misc_deregister(&beep_miscdev);
150         return 0;
151 }
152 
153  /* 匹配列表 */
154  static const struct of_device_id beep_of_match[] = {
    
    
155      {
    
     .compatible = "beep" },
156      {
    
     /* Sentinel */ }
157  };
158 
159  /* platform驱动结构体 */
160 static struct platform_driver beep_driver = {
    
    
161      .driver     = {
    
    
162          .name   = "imx6ul-beep",         /* 驱动名字,用于和设备匹配 */
163          .of_match_table = beep_of_match, /* 设备树匹配表*/
164      },
165      .probe      = miscbeep_probe,
166      .remove     = miscbeep_remove,
167 };
168 
169 /*
170  * @description : 驱动出口函数
171  * @param               : 无
172  * @return              : 无
173  */
174 static int __init miscbeep_init(void)
175 {
    
    
176         return platform_driver_register(&beep_driver);
177 }
178 
179 /*
180  * @description : 驱动出口函数
181  * @param               : 无
182  * @return              : 无
183  */
184 static void __exit miscbeep_exit(void)
185 {
    
    
186         platform_driver_unregister(&beep_driver);
187 }
188 
189 module_init(miscbeep_init);
190 module_exit(miscbeep_exit);
191 MODULE_LICENSE("GPL");
192 MODULE_AUTHOR("topeet");

第 88~92 行,misc 设备结构体 beep_miscdev,第 89 行设置子设备号为 144,第 90 行设置设备名字为“miscbeep”,这样当系统启动以后就会在/dev/目录下存在一个名为“miscbeep”的设备文件。第 91 行,设置 misc 设备的操作函数集合,为 file_operations 类型。
第 100~136 行,platform 框架的 probe 函数,当驱动与设备匹配以后此函数就会执行,首先在此函数中初始化 BEEP 所使用的 IO。最后在 129 行通过 misc_register 函数向 Linux 内核注册misc 设备,也就是前面定义的 beep_miscdev。
第 143~151 行,platform 框架的 remove 函数,在此函数中调用 misc_deregister 函数来注销misc 设备。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/BeiJingXunWei/article/details/112002906