程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 一個簡單的字符設備驅動

一個簡單的字符設備驅動

編輯:C++入門知識

1.字符設備驅動源碼


[cpp]
#include<linux/module.h>  
#include<linux/init.h>  
#include<linux/types.h>  
#include<linux/fs.h>  
#include<linux/errno.h>  
#include<linux/mm.h>  
#include<linux/sched.h>  
#include<linux/cdev.h>  
#include<asm/io.h>  
#include<asm/system.h>  
#include<asm/uaccess.h>  
 
#include<linux/slab.h> /*kmalloc頭文件*/  
#include<linux/semaphore.h>/*信號量頭文件*/  
 
#define MEMDEV_MAJOR 251 /*預設的mem的主設備號*/  
#define MEMDEV_NUM 2     /*設備數*/  
#define MEMDEV_SIZE 1024 /*分配的內存大小*/  
 
struct mem_dev 

    unsigned int size; 
    char *data; 
    struct semaphore sem; 
}; 
 
static int mem_major = MEMDEV_MAJOR; /*預設的mem的主設備號*/ 
struct cdev mem_cdev; 
struct mem_dev *mem_devp; /*設備結構體指針*/ 
 
/*文件打開函數*/ 
static int 
mem_open(struct inode *inode,struct file *filp) 

    struct mem_dev *dev; 
    unsigned int num; 
    printk("mem_open.\n"); 
 
    num= MINOR(inode->i_rdev); /*獲得次設備號*/ 
    if(num>(MEMDEV_NUM-1)) 
    return -ENODEV; 
     
    dev = &mem_devp[num]; 
    filp->private_data = dev; /*將設備結構保存為私有數據*/ 
     
    return 0; 

 
/*關閉時調用*/ 
static int 
mem_release(struct inode *inode,struct file *filp) 

    printk("mem_release.\n"); 
    return 0; 

 
/*讀函數*/ 
static ssize_t 
mem_read(struct file *filp,char __user *buf,size_t size,loff_t *ppos) 

    int ret = 0; 
    struct mem_dev *dev; 
    unsigned long p; 
    unsigned long count; 
     
    printk("mem_read.\n"); 
     
    dev = filp->private_data; /*獲得設備結構*/ 
    count = size; 
    p = *ppos; 
     
    /*檢查偏移量和數據大小的有效性*/ 
    if(p > MEMDEV_SIZE) 
        return 0; 
    if(count >(MEMDEV_SIZE-p)) 
        count = MEMDEV_SIZE - p; 
    if(down_interruptible(&dev->sem)) /*鎖定互斥信號量*/ 
        return -ERESTARTSYS; 
    /*讀取數據到用戶空間*/ 
    if(copy_to_user(buf,dev->data+p,count)) 
    { 
        ret = -EFAULT; 
        printk("copyfrom user failed\n"); 
    } 
    else 
    { 
        *ppos +=count; 
        ret = count; 
        printk("read %d bytes from dev\n",count); 
    } 
        up(&dev->sem); /*解鎖互斥信號量*/ 
        return ret; 

 
/*寫函數*/ 
static ssize_t 
mem_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos) 

    int ret = 0; 
    struct mem_dev *dev; 
    unsigned long p; 
    unsigned long count; 
     
    printk("mem_write.\n"); 
    dev = filp->private_data; 
    count = size; 
     
    p = *ppos; 
    if(p>MEMDEV_SIZE) 
    { 
        return 0; 
    } 
    if(count >(MEMDEV_SIZE- p)) 
    count = MEMDEV_SIZE - p; 
    if(down_interruptible(&dev->sem)) 
        return -ERESTARTSYS; 
    if(copy_from_user(dev->data+p,buf,count)) 
    { 
        ret = -EFAULT; 
        printk("copyfrom user failed\n"); 
    } 
    else 
    { 
        *ppos+=count; 
        ret = count; 
        printk("writed %d bytes to dev\n",count); 
    } 
    up(&dev->sem); 
 
    return ret; 

 
/*修改文件當前的讀寫位置*/ 
static loff_t 
mem_llseek(struct file *filp,loff_t offset,int whence) 

    int newpos; 
    printk("mem_llsek.\n"); 
    switch(whence) 
    { 
        case 0 : 
            newpos =offset; 
            break; 
        case 1: 
            newpos = filp->f_pos +offset; 
            break; 
        case 2: 
            newpos = MEMDEV_SIZE - 1 +offset; 
            break; 
        default : 
            return -EINVAL; 
    } 
    if((newpos<0)||(newpos>(MEMDEV_SIZE - 1))) 
        return -EINVAL; 
    filp->f_pos = newpos; 
    return newpos; 

 
/*文件操作結構體*/ 
static const struct file_operations mem_fops ={ 
    .owner = THIS_MODULE, 
    .open =mem_open, 
    .write =mem_write, 
    .read = mem_read, 
    .release = mem_release, 
    .llseek=mem_llseek, 
    }; 
 
/*設備驅動模型加載函數*/ 
static int 
__init memdev_init(void) 

    int result; 
    int err; 
    int i; 
     
    /*申請設備號*/ 
    dev_t devno = MKDEV(mem_major,0); 
     
    if(mem_major) 
    /*注意靜態申請的dev_t參數和動態dev_t參數的區別*/ 
    result = register_chrdev_region(devno,MEMDEV_NUM,"memdev"); 
    else 
    { 
        result = alloc_chrdev_region(&devno,0,MEMDEV_NUM,"memdev"); 
        mem_major = MAJOR(devno); 
    } 
    if(result<0) 
    { 
        printk("can not get major devno:%d\n",mem_major); 
        return result; 
    } 
 
    /*注冊設備驅動*/ 
    cdev_init(&mem_cdev,&mem_fops);/*初始化cdev結構*/ 
 
    mem_cdev.owner = THIS_MODULE; 
 
    /*注冊字符驅動設備*/ 
    err = cdev_add(&mem_cdev,MKDEV(mem_major,0),MEMDEV_NUM); 
    if(err) 
        printk("addcdev faild,err is %d\n",err); 
 
    /*分配設備內存*/ 
    mem_devp = kmalloc(MEMDEV_NUM*(sizeof(struct mem_dev)),GFP_KERNEL); 
    if(!mem_devp) 
    { 
        result = -ENOMEM; 
        goto fail_malloc; 
    } 
 
    memset(mem_devp,0,MEMDEV_NUM*(sizeof(struct mem_dev))); 
     
    for(i=0;i<MEMDEV_NUM;i++) 
    { 
        mem_devp[i].size = MEMDEV_SIZE; 
        mem_devp[i].data = kmalloc(MEMDEV_SIZE,GFP_KERNEL); 
        memset(mem_devp[i].data,0,MEMDEV_SIZE); 
    //  init_MUTEX(&mem_devp[i].sem); /*初始化互斥鎖*/  
        sema_init(&mem_devp[i].sem,1); 
    } 
 
    return result; 
 
fail_malloc: 
    unregister_chrdev_region(MKDEV(mem_major,0),MEMDEV_NUM); 
    return result; 

 
 
/*設備驅動模型卸載函數*/ 
static void 
memdev_exit(void) 

    cdev_del(&mem_cdev); 
    /*注意釋放的設備號個數一定要和申請的設備號個數一致,否則會導致設備號資源流失*/ 
    unregister_chrdev_region(MKDEV(mem_major,0),MEMDEV_NUM); 
    printk("memdev_exit\n"); 

 
module_init(memdev_init); 
module_exit(memdev_exit); 
 
MODULE_AUTHOR("BQL"); 
MODULE_LICENSE("GPL"); 

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

#include<linux/slab.h> /*kmalloc頭文件*/
#include<linux/semaphore.h>/*信號量頭文件*/

#define MEMDEV_MAJOR 251 /*預設的mem的主設備號*/
#define MEMDEV_NUM 2     /*設備數*/
#define MEMDEV_SIZE 1024 /*分配的內存大小*/

struct mem_dev
{
 unsigned int size;
 char *data;
 struct semaphore sem;
};

static int mem_major = MEMDEV_MAJOR; /*預設的mem的主設備號*/
struct cdev mem_cdev;
struct mem_dev *mem_devp; /*設備結構體指針*/

/*文件打開函數*/
static int
mem_open(struct inode *inode,struct file *filp)
{
 struct mem_dev *dev;
 unsigned int num;
 printk("mem_open.\n");

 num= MINOR(inode->i_rdev); /*獲得次設備號*/
 if(num>(MEMDEV_NUM-1))
 return -ENODEV;
 
 dev = &mem_devp[num];
 filp->private_data = dev; /*將設備結構保存為私有數據*/
 
 return 0;
}

/*關閉時調用*/
static int
mem_release(struct inode *inode,struct file *filp)
{
 printk("mem_release.\n");
 return 0;
}

/*讀函數*/
static ssize_t
mem_read(struct file *filp,char __user *buf,size_t size,loff_t *ppos)
{
 int ret = 0;
 struct mem_dev *dev;
 unsigned long p;
 unsigned long count;
 
 printk("mem_read.\n");
 
 dev = filp->private_data; /*獲得設備結構*/
 count = size;
 p = *ppos;
 
 /*檢查偏移量和數據大小的有效性*/
 if(p > MEMDEV_SIZE)
  return 0;
 if(count >(MEMDEV_SIZE-p))
   count = MEMDEV_SIZE - p;
 if(down_interruptible(&dev->sem)) /*鎖定互斥信號量*/
  return -ERESTARTSYS;
 /*讀取數據到用戶空間*/
 if(copy_to_user(buf,dev->data+p,count))
 {
  ret = -EFAULT;
  printk("copyfrom user failed\n");
 }
 else
 {
  *ppos +=count;
  ret = count;
  printk("read %d bytes from dev\n",count);
 }
  up(&dev->sem); /*解鎖互斥信號量*/
  return ret;
}

/*寫函數*/
static ssize_t
mem_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos)
{
 int ret = 0;
 struct mem_dev *dev;
 unsigned long p;
 unsigned long count;
 
 printk("mem_write.\n");
 dev = filp->private_data;
 count = size;
 
 p = *ppos;
 if(p>MEMDEV_SIZE)
 {
  return 0;
 }
 if(count >(MEMDEV_SIZE- p))
 count = MEMDEV_SIZE - p;
 if(down_interruptible(&dev->sem))
  return -ERESTARTSYS;
 if(copy_from_user(dev->data+p,buf,count))
 {
  ret = -EFAULT;
  printk("copyfrom user failed\n");
 }
 else
 {
  *ppos+=count;
  ret = count;
  printk("writed %d bytes to dev\n",count);
 }
 up(&dev->sem);

 return ret;
}

/*修改文件當前的讀寫位置*/
static loff_t
mem_llseek(struct file *filp,loff_t offset,int whence)
{
 int newpos;
 printk("mem_llsek.\n");
 switch(whence)
 {
  case 0 :
   newpos =offset;
    break;
  case 1:
   newpos = filp->f_pos +offset;
   break;
  case 2:
   newpos = MEMDEV_SIZE - 1 +offset;
   break;
  default :
   return -EINVAL;
 }
 if((newpos<0)||(newpos>(MEMDEV_SIZE - 1)))
  return -EINVAL;
 filp->f_pos = newpos;
 return newpos;
}

/*文件操作結構體*/
static const struct file_operations mem_fops ={
 .owner = THIS_MODULE,
 .open =mem_open,
 .write =mem_write,
 .read = mem_read,
 .release = mem_release,
 .llseek=mem_llseek,
 };

/*設備驅動模型加載函數*/
static int
__init memdev_init(void)
{
 int result;
 int err;
 int i;
 
 /*申請設備號*/
 dev_t devno = MKDEV(mem_major,0);
 
 if(mem_major)
 /*注意靜態申請的dev_t參數和動態dev_t參數的區別*/
 result = register_chrdev_region(devno,MEMDEV_NUM,"memdev");
 else
 {
  result = alloc_chrdev_region(&devno,0,MEMDEV_NUM,"memdev");
  mem_major = MAJOR(devno);
 }
 if(result<0)
 {
  printk("can not get major devno:%d\n",mem_major);
  return result;
 }

 /*注冊設備驅動*/
 cdev_init(&mem_cdev,&mem_fops);/*初始化cdev結構*/

 mem_cdev.owner = THIS_MODULE;

 /*注冊字符驅動設備*/
 err = cdev_add(&mem_cdev,MKDEV(mem_major,0),MEMDEV_NUM);
 if(err)
  printk("addcdev faild,err is %d\n",err);

 /*分配設備內存*/
 mem_devp = kmalloc(MEMDEV_NUM*(sizeof(struct mem_dev)),GFP_KERNEL);
 if(!mem_devp)
 {
  result = -ENOMEM;
  goto fail_malloc;
 }

 memset(mem_devp,0,MEMDEV_NUM*(sizeof(struct mem_dev)));
 
 for(i=0;i<MEMDEV_NUM;i++)
 {
  mem_devp[i].size = MEMDEV_SIZE;
  mem_devp[i].data = kmalloc(MEMDEV_SIZE,GFP_KERNEL);
  memset(mem_devp[i].data,0,MEMDEV_SIZE);
 // init_MUTEX(&mem_devp[i].sem); /*初始化互斥鎖*/
  sema_init(&mem_devp[i].sem,1);
 }

 return result;

fail_malloc:
 unregister_chrdev_region(MKDEV(mem_major,0),MEMDEV_NUM);
 return result;
}


/*設備驅動模型卸載函數*/
static void
memdev_exit(void)
{
 cdev_del(&mem_cdev);
 /*注意釋放的設備號個數一定要和申請的設備號個數一致,否則會導致設備號資源流失*/
 unregister_chrdev_region(MKDEV(mem_major,0),MEMDEV_NUM);
 printk("memdev_exit\n");
}

module_init(memdev_init);
module_exit(memdev_exit);

MODULE_AUTHOR("BQL");
MODULE_LICENSE("GPL");


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved