[Beijing Xunwei] i.MX6ULL Terminator Linux MISC driver writing experimental program

In this experiment, use the misc device driver to write the driver of the buzzer, and use the platform to implement the bus, device and driver. Misc is mainly responsible for the creation of character devices.

1 Modify the device tree file

The beep device node in the device tree can directly use the beep device node created in 36.3.2.

2 Write the driver

The path of the experiment routine: i.MX6UL Terminator CD-ROM information/06_Linux driver routine/16_beep_misc to
create beep_misc.c file, the specific content is as follows:

  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");

Lines 88~92, misc device structure beep_miscdev, line 89 sets the sub-device number to 144, and line 90 sets the device name to "miscbeep", so that when the system starts, there will be a file named "miscbeep" in the /dev/ directory. "Miscbeep" device file. Line 91, set the operation function set of the misc device, which is of type file_operations.
Line 100~136, the probe function of the platform framework. This function will be executed when the driver matches the device. First, initialize the IO used by BEEP in this function. Finally, register the misc device to the Linux kernel through the misc_register function on line 129, which is the beep_miscdev defined earlier.
Lines 143~151, remove function of platform framework, call misc_deregister function in this function to deregister misc device.

Insert picture description here

Guess you like

Origin blog.csdn.net/BeiJingXunWei/article/details/112002906