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