天天看點

Linxu MISC咋雜項驅動

1. MISC 裝置驅動簡介

2. 實驗程式編寫

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define MISCBEEP_NAME   "miscbeep"  /* 名字   */
#define MISCBEEP_MINOR    144     /* 子裝置号 */
#define BEEPOFF       0     /* 關蜂鳴器 */
#define BEEPON        1     /* 開蜂鳴器 */

/* miscbeep裝置結構體 */
struct miscbeep_dev{
  dev_t devid;      /* 裝置号   */
  struct cdev cdev;   /* cdev   */
  struct class *class;  /* 類    */
  struct device *device;  /* 裝置    */
  struct device_node  *nd; /* 裝置節點 */
  int beep_gpio;      /* beep所使用的GPIO編号   */
};


struct miscbeep_dev miscbeep;   /* beep裝置 */

/*
 * @description   : 打開裝置
 * @param - inode   : 傳遞給驅動的inode
 * @param - filp  : 裝置檔案,file結構體有個叫做private_data的成員變量
 *            一般在open的時候将private_data指向裝置結構體。
 * @return      : 0 成功;其他 失敗
 */
static int miscbeep_open(struct inode *inode, struct file *filp)
{
  filp->private_data = &miscbeep; /* 設定私有資料 */
  return 0;
}

/*
 * @description   : 向裝置寫資料 
 * @param - filp  : 裝置檔案,表示打開的檔案描述符
 * @param - buf   : 要寫給裝置寫入的資料
 * @param - cnt   : 要寫入的資料長度
 * @param - offt  : 相對于檔案首位址的偏移
 * @return      : 寫入的位元組數,如果為負值,表示寫入失敗
 */
static ssize_t miscbeep_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
  int retvalue;
  unsigned char databuf[1];
  unsigned char beepstat;
  struct miscbeep_dev *dev = filp->private_data;

  retvalue = copy_from_user(databuf, buf, cnt);
  if(retvalue < 0) {
    printk("kernel write failed!\r\n");
    return -EFAULT;
  }

beepstat = databuf[0];    /* 擷取狀态值 */

  if(beepstat == BEEPON) {  
    gpio_set_value(dev->beep_gpio, 0);  /* 打開蜂鳴器 */
  } else if(beepstat == BEEPOFF) {
    gpio_set_value(dev->beep_gpio, 1);  /* 關閉蜂鳴器 */
  }
  return 0;
}

/* 裝置操作函數 */
static struct file_operations miscbeep_fops = {
  .owner = THIS_MODULE,
  .open = miscbeep_open,
  .write = miscbeep_write,
};

/* MISC裝置結構體 */
static struct miscdevice beep_miscdev = {
  .minor = MISCBEEP_MINOR,
  .name = MISCBEEP_NAME,
  .fops = &miscbeep_fops,
};

 /*
  * @description     : flatform驅動的probe函數,當驅動與
  *                    裝置比對以後此函數就會執行
  * @param - dev     : platform裝置
  * @return          : 0,成功;其他負值,失敗
  */
static int miscbeep_probe(struct platform_device *dev)
{
  int ret = 0;

  printk("beep driver and device was matched!\r\n");
  /* 設定BEEP所使用的GPIO */
  /* 1、擷取裝置節點:beep */
  miscbeep.nd = of_find_node_by_path("/beep");
  if(miscbeep.nd == NULL) {
    printk("beep node not find!\r\n");
    return -EINVAL;
  } 

  /* 2、 擷取裝置樹中的gpio屬性,得到BEEP所使用的BEEP編号 */
  miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd, "beep-gpios", 0);
  
  if(miscbeep.beep_gpio < 0) {
    printk("can't get beep-gpio");
    return -EINVAL;
  }
  /* 3、設定GPIO5_IO01為輸出,并且輸出高電平,預設關閉BEEP */
  ret = gpio_direction_output(miscbeep.beep_gpio, 1);
  if(ret < 0) {
    printk("can't set gpio!\r\n");
  }
  
  /* 一般情況下會注冊對應的字元裝置,但是這裡我們使用MISC裝置
     * 是以我們不需要自己注冊字元裝置驅動,隻需要注冊misc裝置驅動即可
   */
  ret = misc_register(&beep_miscdev);
  if(ret < 0){
    printk("misc device register failed!\r\n");
    return -EFAULT;
  }

  return 0;
}

/*
 * @description     : platform驅動的remove函數,移除platform驅動的時候此函數會執行
 * @param - dev     : platform裝置
 * @return          : 0,成功;其他負值,失敗
 */
static int miscbeep_remove(struct platform_device *dev)
{
  /* 登出裝置的時候關閉LED燈 */
  gpio_set_value(miscbeep.beep_gpio, 1);

  /* 登出misc裝置 */
  misc_deregister(&beep_miscdev);
  return 0;
}

 /* 比對清單 */
 static const struct of_device_id beep_of_match[] = {
     { .compatible = "shaozheming,beep" },
     { /* Sentinel */ }
 };


 /* platform驅動結構體 */
static struct platform_driver beep_driver = {
     .driver     = {
         .name   = "imx6ul-beep",         /* 驅動名字,用于和裝置比對 */
         .of_match_table = beep_of_match, /* 裝置樹比對表          */
     },
     .probe      = miscbeep_probe,
     .remove     = miscbeep_remove,
};

/*
 * @description : 驅動出口函數
 * @param     : 無
 * @return    : 無
 */
static int __init miscbeep_init(void)
{
  return platform_driver_register(&beep_driver);
}

/*
 * @description : 驅動出口函數
 * @param     : 無
 * @return    : 無
 */
static void __exit miscbeep_exit(void)
{
  platform_driver_unregister(&beep_driver);
}

module_init(miscbeep_init);
module_exit(miscbeep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("shaozheming");      

繼續閱讀