先留个联系方式 ,有一起学习驱动程序的加qq295699450
字符设备驱动:
这篇比较恼火。加载成功,但是读不出来数据,有知道怎么回事的,留个言,一起讨论下:
数据结构
struct scull_mem{
void *data;
struct scull_mem *next;
};
struct scull_dev{
struct cdev cdev;
unsigned long size;
struct scull_mem *data;
}*dev;
整个驱动程序代码如下:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#define BUFFERSIZE 4096
ssize_t scull_read (struct file *filp,char __user* buf,size_t count,loff_t *offset);
ssize_t scull_write(struct file *filp,const char __user*buf,size_t count,loff_t *offset);
int scull_open(struct inode *inode,struct file *filp);
int scull_release(struct inode *inode,struct file *filp);
struct scull_mem{
void *data;
struct scull_mem *next;
};
struct scull_dev{
struct cdev cdev;
unsigned long size;
struct scull_mem *data;
}*dev;
dev_t scull_dev_num=0;
int major,minor;
int cdev_registered=0;
void scull_trim(void)
{
struct scull_mem *ptr,*tmp;
for(ptr=dev->data;ptr!=NULL;ptr=tmp){
tmp=ptr->next;
if(ptr->data!=NULL){
kfree(ptr->data);
}
kfree(ptr);
}
dev->data=NULL;
dev->size=0;
}
int scull_open(struct inode *inode,struct file *filp)
{
printk(KERN_ALERT "Scull is opened!\n");
if((filp->f_flags&O_ACCMODE)==O_WRONLY)
scull_trim();
return 0;
}
int scull_release(struct inode *inode,struct file *filp)
{
printk(KERN_ALERT "Scull is released!\n");
return 0;
}
struct scull_mem * scull_follow(int item)
{
struct scull_mem *tmp,*ptr=NULL;
int times=item;
for(tmp=dev->data;item-->=0;tmp=tmp->next){
if(tmp==NULL){
if((tmp=(struct scull_mem *)kmalloc(sizeof(struct scull_mem),GFP_KERNEL))==NULL)
return NULL;
tmp->next=NULL;
if((tmp->data=kmalloc(BUFFERSIZE,GFP_KERNEL))==NULL){
return NULL;
}
memset(tmp->data,0,BUFFERSIZE);
if(times==0){
dev->data=tmp;
times++;
}
}
ptr=tmp;
}
return ptr;
}
ssize_t scull_read (struct file *filp,char __user* buf,size_t count,loff_t *offset)
{
ssize_t retval=0;
size_t item,pos;
struct scull_mem *ptr;
item=*offset / BUFFERSIZE;
pos=*offset % BUFFERSIZE;
ptr=scull_follow(item);
if(ptr==NULL||ptr->data==NULL){
goto out;
}
if(*offset+count>dev->size)
count=dev->size-*offset;
count=count > (BUFFERSIZE-pos)? (BUFFERSIZE-pos):count;
if(copy_to_user(buf,ptr->data+pos,count)){
retval=-EFAULT;
goto out;
}
*offset+=count;
retval=count;
out:
return retval;
}
ssize_t scull_write(struct file *filp,const char __user*buf,size_t count,loff_t *offset)
{
ssize_t retval=0;
size_t item,pos;
struct scull_mem *ptr;
item=*offset / BUFFERSIZE;
pos=*offset % BUFFERSIZE;
ptr=scull_follow(item);
if(ptr==NULL||ptr->data==NULL){
goto out;
}
count=count > (BUFFERSIZE-pos)? (BUFFERSIZE-pos):count;
if(copy_from_user(ptr->data+pos,buf,count)){
retval=-EFAULT;
goto out;
}
*offset+=count;
retval=count;
dev->size+=count;
out:
return retval;
}
loff_t scull_llseek(struct file *filp,loff_t offset,int start)
{
loff_t new;
switch(start)
{
case 0:
new=offset;
break;
case 1:
new=filp->f_pos+offset;
break;
case 2:
new=dev->size+offset;
break;
default:
return -EINVAL;
}
if(new<0) return -EINVAL;
filp->f_pos=new;
return new;
}
struct file_operations scull_ops={
.owner=THIS_MODULE,
.open=scull_open,
.read=scull_read,
.write=scull_write,
.release=scull_release,
.llseek=scull_llseek,
.unlocked_ioctl=NULL,
};
void cleanup(void)
{
if(cdev_registered)
cdev_del(&dev->cdev);
if(dev!=NULL){
scull_trim();
kfree(dev);
}
if(scull_dev_num!=0)
unregister_chrdev_region(scull_dev_num,1);
}
static int __init scull_init(void)
{
int retval=0;
/*first,requset device number*/
if((retval=alloc_chrdev_region(&scull_dev_num,0,1,"scull_jakilll"))<0)
goto fail;
major=MAJOR(scull_dev_num);
minor=MINOR(scull_dev_num);
/*then alloc device structure*/
if((dev=kmalloc(sizeof(struct scull_dev),GFP_KERNEL))==NULL){
retval=-ENOMEM;
goto fail;
}
dev->size=0;
dev->data=NULL;
/*finally,register cdev*/
cdev_init(&dev->cdev,&scull_ops);
dev->cdev.owner=THIS_MODULE;
dev->cdev.ops=&scull_ops;
if((retval=cdev_add(&dev->cdev,scull_dev_num,1))<0)
goto fail;
cdev_registered=1;
printk(KERN_ALERT "Scull inited ok!\n");
return retval;
fail:
cleanup();
return retval;
}
static void __exit scull_exit(void)
{
cleanup();
printk(KERN_ALERT "Scull cleanuped!\n");
}
module_init(scull_init);
module_exit(scull_exit);
MODULE_LICENSE("GPL");
初始化:
根据设备名使用alloc_chrdev_region()申请设备号,给scull_dev分配内存,使用cdev_init()初始化cdev设备,并初始化dev里面的各个成员,接着cdev_add()讲dev中的cdev添加到内核里面,初始化结束
卸载:
先从内核闪出sucll_dev->cdev结构,然后kfree scull_dev结构,最后使用unregister_chrdev_region()卸载设备
就是如上流程,读写程序随便写