linux內核驅動三類註冊方式

1.   2.6之後的註冊方式:

#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>

//#define DEVICE_NAME     "leds"      /* 驅動名稱 */
//#define LEDS_MAJOR       231        /* 次設備號 */

//-------------------------------------------------------------------------
#define CHAR_DEV_DEVICE_NAME   "cdev_leds"   // 設備名

struct class *char_dev_class;  // class結構用於自動創建設備結點
static int major = 0;

static struct cdev char_dev_devs;// 定義一個cdev結構

static unsigned long led_table [] = {
     S3C2410_GPB(5),
     S3C2410_GPB(6),
     S3C2410_GPB(7),
     S3C2410_GPB(8),
};

static unsigned int led_cfg_table [] = {
     S3C2410_GPIO_OUTPUT,
     S3C2410_GPIO_OUTPUT,
     S3C2410_GPIO_OUTPUT,
     S3C2410_GPIO_OUTPUT,
};
    
/*驅動程序,提供這個接口*/
static int sbc2440_leds_ioctl(
    struct inode *inode, /*內核裏面的兩個結構體*/
    struct file *file,
    unsigned int cmd, /*開關燈*/
    unsigned long arg)/*第幾個燈*/
{
     switch (cmd) {
     case 0:   /*空,不執行*/
     case 1:
          if (arg >=4) {
               return -EINVAL;/*返回錯誤*/
          }
          s3c2410_gpio_setpin(led_table[arg], !cmd);/*條件具備(arg小於4時候執行本函數)把第幾個腳設置低電平,燈亮*/
          return 0;
     default:
          return -EINVAL;
     }
}

// 設備建立子函數,被char_dev_init函數調用
static void char_dev_setup_cdev(struct cdev *dev, int minor, struct file_operations *fops)
{
     int err, devno = MKDEV(major, minor);

     cdev_init(dev, fops);
     dev->owner = THIS_MODULE;
     dev->ops = fops;//這句可以不寫,已經在cdev_init()函數裏實現了。

     err = cdev_add(dev, devno, 1);  //註冊設備
     if ( err )
     {
          printk(KERN_NOTICE "Error %d adding char_dev %d\n", err, minor);
     }

}

//  file_operations 結構體設置,該設備的所有對外接口在這裏明確,此處只寫出了幾常用的
static struct file_operations char_dev_fops =
{
     .owner = THIS_MODULE,
              /*     .open  = char_dev_open,      // 打開設備
                  .release = char_dev_release, // 關閉設備
                  .read  = char_dev_read,      // 實現設備讀功能
                  .write = char_dev_write,     // 實現設備寫功能 */
        .ioctl = sbc2440_leds_ioctl,     //實現設備控制功能
};

//   設備初始化
static int char_dev_init(void)
{
     int result;
     dev_t dev = MKDEV(major, 0);

     if ( major )
     {
          // 給定設備號註冊
          result =DEV_DEV
 register_chrdev_region(dev, 1, CHAR_ICE_NAME);
     }

     else
     {
          // 動態分配設備號並註冊
          result = alloc_chrdev_region(&dev, 0, 1, CHAR_DEV_DEVICE_NAME);
          major = MAJOR(dev);
     }


     char_dev_setup_cdev(&char_dev_devs, 0, &char_dev_fops);
     printk("The major of the char_dev device is %d\n", major);

//==== 有中斷的可以在此註冊中斷:request_irq,並要實現中斷服務程序 ===//

// 創建設備結點
     char_dev_class = class_create(THIS_MODULE,CHAR_DEV_DEVICE_NAME);

     if (IS_ERR(char_dev_class))
     {
          printk("Err: failed in creating class.\n");

          return 0;
     }
     device_create(char_dev_class, NULL, dev, NULL, CHAR_DEV_DEVICE_NAME);
     return 0;
}

// 設備註銷
static void char_dev_cleanup(void)
{
     cdev_del(&char_dev_devs);//字符設備的註銷*/
     unregister_chrdev_region(MKDEV(major, 0), 1);//設備號的註銷
     device_destroy(char_dev_class,MKDEV(major,0));
     class_destroy(char_dev_class);


//========  有中斷的可以在此註銷中斷:free_irq  ======//

     printk("char_dev device uninstalled\n");
}

module_init(char_dev_init);   //模塊初始化接口
module_exit(char_dev_cleanup);//模塊註銷接口

// 以下兩句不能省略,否則編譯不通過
MODULE_AUTHOR("www.arm.com");
MODULE_LICENSE("GPL");


2.早期註冊設備:

/*MODULE_LICENSE(),MODULE_AUTHOR(),module_init(),module_exit(),MODULE_DESCRIPTION()*/
#include <linux/module.h>

/* register_chrdev(),unregister_chrdev(),struct file_operations */
#include <linux/fs.h>

/*定義設備名*/
#define DEV_NAME   "first_chardev"

int major = 0;

int first_chardev_open (struct inode *inode, struct file *file)
{
     printk(KERN_EMERG"open() call\r\n");

     return 0 ;
}


ssize_t first_chardev_read (struct file *file, char __user *buf, size_t size, loff_t * off)
{
     printk(KERN_EMERG"read() call\r\n");
     return size;
}


ssize_t first_chardev_write (struct file *file, const char __user *buf, size_t size, loff_t *off)
{
     printk(KERN_EMERG"write() call\r\n");

     return size;

}

int first_chardev_ioctrl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
     printk(KERN_EMERG"ioctl() call\r\n");    
     return 0;
}
int first_chardev_close (struct inode *inode, struct file *file)
{
     printk(KERN_EMERG"release() call\r\n");    

     return 0;
}
loff_t first_chardev_llseek(struct file *file, loff_t loff, int origin )
{
       printk(KERN_EMERG"llseek() call\r\n");       
     printk(KERN_EMERG"loff:%d; origin:%d\r\n",loff,origin);    
     return loff;
}

static const struct file_operations  first_chardev_fops=
{
     .open = first_chardev_open,
     .release = first_chardev_close,
     .read = first_chardev_read,
     .write = first_chardev_write,
     .ioctl = first_chardev_ioctrl,
     .llseek = first_chardev_llseek,
};

static  int __init  first_chardev_init(void)
{
    printk(KERN_EMERG"module init now!\r\n");

     major = register_chrdev(major,DEV_NAME,&first_chardev_fops);    //註冊設備     printk(KERN_EMERG"major:%d\r\n",major);
    
     return 0;
}


static __exit void  first_chardev_exit(void)
{
     printk(KERN_EMERG"module remove now!\r\n");
     unregister_chrdev(major,DEV_NAME);                 //註銷設備
}

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ARM Inc.");
module_init(first_chardev_init);
module_exit(first_chardev_exit);
MODULE_DESCRIPTION("this is simlpe fist driver test!\r\n");



3.雜項設備的註冊:

/*提供接口函數給內核,在dev目錄下生成設備節點*/
static struct file_operations dev_fops = {
     .owner     =     THIS_MODULE,/*初始化加載模式  就是個聲明,模塊加1*/
     .ioctl     =     sbc2440_leds_ioctl,/*控制函數*/

                   };
/*註冊(報到)*/
static struct miscdevice misc = {
     .minor = LEDS_MAJOR, /*次設備號    .minor是結構題裏面的一個元素(變量)  */
     .name  = DEVICE_NAME,/*設備號*/
     .fops  = &dev_fops,/*功能函數  &取地址*/


                            };
/*初始化,內存優化*/
static int __init dev_init(void)//(開機運行一次)
{
     int ret;

     int i;

     for (i = 0; i < 4; i++) {
          s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);/*gpio口配置,設置輸入輸出        內核自帶函數  ,四個I/O設置輸出   */
          s3c2410_gpio_setpin(led_table[i], 1);/*設爲高電平,所有燈關掉*/
     }

     ret = misc_register(&misc);/*雜選設備註冊,主設備號固定,註冊函數*/

     printk (DEVICE_NAME"\tinitialized\n");

     return ret;
}
/*退出函數*/
static void __exit dev_exit(void)/*__編譯器用的 __exit編譯器規定要加的*/
{
     misc_deregister(&misc);/*釋放註冊*/
}

module_init(dev_init);/*聲明初始化函數(從哪裏進來)初始化加載用的*/
module_exit(dev_exit);/*聲明退出函數*/
MODULE_LICENSE("GPL");/*聲明遵循GPL協議(開源協議)*/
MODULE_AUTHOR("ARM Inc.");/*
發佈了11 篇原創文章 · 獲贊 5 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章