字符設備驅動要點

一、字符設備註冊流程

1、申請設備號 

申請函數:

register_chrdev_region() 用於已知設備號的情況

alloc_chrdev_region() 用於未知設備號的情況,向系統申請未被佔用的設備號

2、註冊設備

3、創建設備節點

mknod /dev/NAME  設備類型  major  minor   


示例1

#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>

#define SECOND_MAJOR 248    /*預設的second的主設備號*/                       
                                                                             
static int second_major = SECOND_MAJOR;                                      
                                                                             
/*second設備結構體*/                                                         
struct second_dev {                                                          
  struct cdev cdev; /*cdev結構體*/                                           
  atomic_t counter;/* 一共經歷了多少秒?*/                                   
  struct timer_list s_timer; /*設備要使用的定時器*/                          
};                                                                           
                                                                             
struct second_dev *second_devp; /*設備結構體指針*/                           
                                                                             
/*定時器處理函數*/                                                           
static void second_timer_handle(unsigned long arg)                           
{                                                                            
  mod_timer(&second_devp->s_timer,jiffies + HZ);                             
  atomic_inc(&second_devp->counter);                                         
                                                                             
  printk(KERN_NOTICE "current jiffies is %ld\n", jiffies);                   
}                                                                            
                                                                             
/*文件打開函數*/                                                             
int second_open(struct inode *inode, struct file *filp)                      
{                                                                            
  /*初始化定時器*/                                                           
  init_timer(&second_devp->s_timer);                                         
  second_devp->s_timer.function = &second_timer_handle;                      
  second_devp->s_timer.expires = jiffies + HZ;                               
                                                                             
  add_timer(&second_devp->s_timer); /*添加(註冊)定時器*/                   
                                                                             
  atomic_set(&second_devp->counter,0); //計數清0                             
                                                                             
  return 0;                                                                  
}                                                                            
/*文件釋放函數*/                                                             
int second_release(struct inode *inode, struct file *filp)                   
{                                                                            
  del_timer(&second_devp->s_timer);                                          
                                                                             
  return 0;                                                                  
}                                                                            
                                                                             
/*讀函數*/                                                                   
static ssize_t second_read(struct file *filp, char __user *buf, size_t count,
  loff_t *ppos)                                                              
{                                                                            
  int counter;                                                               
                                                                             
  counter = atomic_read(&second_devp->counter);                              
  if(put_user(counter, (int*)buf))                                           
  	return - EFAULT;                                                         
  else                                                                       
  	return sizeof(unsigned int);                                             
}                                                                            
                                                                             
/*文件操作結構體*/                                                           
static const struct file_operations second_fops = {                          
  .owner = THIS_MODULE,                                                      
  .open = second_open,                                                       
  .release = second_release,                                                 
  .read = second_read,                                                       
};                                                                           
                                                                             
/*初始化並註冊cdev*/                                                         
static void second_setup_cdev(struct second_dev *dev, int index)             
{                                                                            
  int err, devno = MKDEV(second_major, index);                               
                                                                             
  cdev_init(&dev->cdev, &second_fops);                                       
  dev->cdev.owner = THIS_MODULE;                                             
  err = cdev_add(&dev->cdev, devno, 1);                                      
  if (err)                                                                   
    printk(KERN_NOTICE "Error %d adding LED%d", err, index);                 
}                                                                            
                                                                             
/*設備驅動模塊加載函數*/                                                     
int second_init(void)                                                        
{                                                                            
  int ret;                                                                   
  dev_t devno = MKDEV(second_major, 0);                                      
                                                                             
  /* 申請設備號*/                                                            
  if (second_major)                                                          
    ret = register_chrdev_region(devno, 1, "second");                        
  else { /* 動態申請設備號 */                                                
    ret = alloc_chrdev_region(&devno, 0, 1, "second");                       
    second_major = MAJOR(devno);                                             
  }                                                                          
  if (ret < 0)                                                               
    return ret;                                                              
  /* 動態申請設備結構體的內存*/                                              
  second_devp = kmalloc(sizeof(struct second_dev), GFP_KERNEL);              
  if (!second_devp) {   /*申請失敗*/                                         
    ret =  - ENOMEM;                                                         
    goto fail_malloc;                                                        
  }                                                                          

  memset(second_devp, 0, sizeof(struct second_dev));                         

  second_setup_cdev(second_devp, 0);                                         

  return 0;                                                                  

fail_malloc:
  unregister_chrdev_region(devno, 1);
  return ret;                           
}                                                                            

/*模塊卸載函數*/                                                             
void second_exit(void)                                                       
{                                                                            
  cdev_del(&second_devp->cdev);   /*註銷cdev*/                               
  kfree(second_devp);     /*釋放設備結構體內存*/                             
  unregister_chrdev_region(MKDEV(second_major, 0), 1); /*釋放設備號*/        
}                                                                            
                                                                             
MODULE_AUTHOR("Barry Song <[email protected]>");                             
MODULE_LICENSE("Dual BSD/GPL");                                              
                                                                             
module_param(second_major, int, S_IRUGO);                                    
                                                                             
module_init(second_init);                                                    
module_exit(second_exit);                                                    
示例一需要手動創建 設備節點 

示例2:


#include <linux/module.h>
#include <linux/device.h>
#include <linux/fs.h>

#define DEVICE_NAME "zhanli" /* 加載模式後,執行”cat /proc/devices”命令看到的設備名稱 */
#define LED_MAJOR 231 /* 主設備號 */

static int file_open(struct inode *inode, struct file *file)
{
	return 0;
}

static int file_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	return 0;
}

static struct file_operations EmbedSky_leds_fops =
{
	.owner = THIS_MODULE, 
	.open = file_open,
	.unlocked_ioctl = file_ioctl,
};

static char __initdata banner[] = "TQ2440/SKY2440 LEDS, (c) 2008,2009 www.embedsky.net\n";
static struct class *led_class;

static int __init init_dev(void)
{
	int ret;
	printk(banner);
	/* 註冊字符設備驅動程序
	* 參數爲主設備號、設備名字、file_operations 結構;
	* 這樣,主設備號就和具體的 file_operations 結構聯繫起來了,
	* 操作主設備爲 LED_MAJOR 的設備文件時,就會調用 EmbedSky_leds_fops 中的相關成員函數
	* LED_MAJOR 可以設爲 0,表示由內核自動分配主設備號
	*/
	ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &EmbedSky_leds_fops);
	if (ret < 0)
	{
		printk(DEVICE_NAME " can't register major number\n");
		return ret;
	}
	//註冊一個類,使 mdev 可以在"/dev/"目錄下面建立設備節點
	
	led_class = class_create(THIS_MODULE, DEVICE_NAME);
	if(IS_ERR(led_class))
	{
		printk("Err: failed in EmbedSky-leds class. \n");
		return -1;
	}
	//創建一個設備節點,節點名爲 DEVICE_NAME
	device_create(led_class, NULL, MKDEV(LED_MAJOR, 0), NULL, DEVICE_NAME);
	printk(DEVICE_NAME " initialized\n");
	return 0;

}

static void __exit exit_dev(void)
{
	unregister_chrdev(LED_MAJOR, DEVICE_NAME);
	device_destroy(led_class, MKDEV(LED_MAJOR, 0)); //刪掉設備節點
	class_destroy(led_class); //註銷類
}

module_init(init_dev);
module_exit(exit_dev);
MODULE_AUTHOR("zl");
MODULE_LISENCE("GPL");




發佈了27 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章