对这个驱动世界报了个到后,一直没进去游览过,而时间过得好快,转眼一个暑假就快过完了,从明天开始应该把这个美丽的世界走一遍了,同行的还有余秋雨教授,所以一路上应该不会孤单,我会一直安静地走下去,直到...
/********************************************************
* scull.h
********************************************************/
#ifndef _SCULL_H_
#define _SCULL_H_
#ifndef SCULL_MAJOR
#define SCULL_MAJOR 0 /*dynamic major by default*/
#endif
#ifndef SCULL_NR_DEVS
#define SCULL_NR_DEVS 4 /*scull0 through scull3 */
#endif
#ifndef SCULL_QUANTUM
#define SCULL_QUANTUM 4000
#endif
#ifndef SCULL_QSET
#define SCULL_QSET 1000
#endif
struct scull_qset{
void **data;
struct scull_qset *next;
};
struct scull_dev{
struct scull_qset *data;
int quantum;
int qset;
unsigned long size;
unsigned int access_key;
struct semaphore sem;
struct cdev cdev;
};
extern int scull_major;
extern int scull_nr_devs;
extern int scull_quantum;
extern int scull_qset;
static int scull_init_module(void);
void scull_cleanup_module(void);
static void scull_setup_cdev(struct scull_dev *dev,int index);
int scull_open(struct inode *inode,struct file *filp);
int scull_release(struct inode *inode,struct file *filp);
int scull_trim(struct scull_dev *dev);
ssize_t scull_read(struct file *filp,char __user *buf,size_t count,loff_t *f_pos);
ssize_t scull_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_pos);
struct scull_qset *scull_follow(struct scull_dev *dev,int n);
#endif /*_SCULL_H_ */
/********************************************************
* scull.c
********************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"scull.h"
MODULE_LICENSE("Dual BSD/GPL");
int scull_major = SCULL_MAJOR;
int scull_minor = 0;
int scull_nr_devs = SCULL_NR_DEVS; /*the number of the scull devices*/
int scull_quantum = SCULL_QUANTUM;
int scull_qset = SCULL_QSET;
module_param(scull_major, int, S_IRUGO);
module_param(scull_nr_devs, int, S_IRUGO);
module_param(scull_quantum, int, S_IRUGO);
module_param(scull_qset, int, S_IRUGO);
struct file_operations scull_fops = {
.owner = THIS_MODULE,
/* .llseek = scull_llseek,*/
.read = scull_read,
.write = scull_write,
/* .ioctl = xcull_ioctl, */
.open = scull_open,
.release= scull_release,
};
struct scull_dev *scull_devices;
static int scull_init_module(void)
{
int result,i;
dev_t dev = 0;
if(scull_major){
dev = MKDEV(scull_major,scull_minor);
result = register_chrdev_region(dev,scull_nr_devs,"scull");
}
else{
result = alloc_chrdev_region(&dev,scull_minor,scull_nr_devs,"scull");
scull_major = MAJOR(dev);
if(result < 0){
printk(KERN_WARNING "scull:can't get major %d\n",scull_major);
return result;
}
}
/*initial the devices*/
scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev),GFP_KERNEL);
if(!scull_devices){
result = -ENOMEM;
goto fail;
}
memset(scull_devices,0,scull_nr_devs * sizeof(struct scull_dev));
for(i = 0; i < scull_nr_devs ;i ++){
scull_devices[i].quantum = scull_quantum;
scull_devices[i].qset = scull_qset;
/*********************************************************
*void init_MUTEX (struct semaphore *sem);
*该函数用于初始化一个互斥锁,即它把信号量sem的值设置为1。
********************************************************/
init_MUTEX(&scull_devices[i].sem);
scull_setup_cdev(&scull_devices[i],i);
}
return 0;
fail:
scull_cleanup_module();
return result;
}
void scull_cleanup_module(void)
{
int i;
dev_t devno = MKDEV(scull_major,scull_minor);
if(scull_devices){
for(i = 0 ;i < scull_nr_devs ; i ++){
scull_trim(scull_devices + i);
cdev_del(&scull_devices[i].cdev);
}
kfree(scull_devices);
}
unregister_chrdev_region(devno,scull_nr_devs);
}
static void scull_setup_cdev(struct scull_dev *dev,int index)
{
int err,devno = MKDEV(scull_major,scull_minor + index);
cdev_init(&dev->cdev,&scull_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &scull_fops;
err = cdev_add(&dev->cdev,devno,1);
/*Fail gracefully if need be */
if(err)
printk(KERN_NOTICE "Error %d adding scull%d",err,index);
}
int scull_open(struct inode *inode,struct file *filp)
{
struct scull_dev *dev;
dev = container_of(inode->i_cdev,struct scull_dev,cdev);
filp->private_data = dev;
/*now trim to 0 the length of the device if open was write-only */
if((filp->f_flags & O_ACCMODE) == O_WRONLY){
scull_trim(dev); /*ignore errors*/
}
return 0;
}
int scull_release(struct inode *inode,struct file *filp)
{
return 0;
}
int scull_trim(struct scull_dev *dev)
{
struct scull_qset *next,*dptr;
int qset = dev->qset; /*"dev" is not null*/ /*why?????????*/
int i;
for(dptr = dev->data; dptr; dptr = next){ /*all the list items*/
if(dptr->data){
for(i = 0 ; i < qset ; i ++)
kfree(dptr->data[i]);
dptr->data = NULL;
}
next = dptr->next;
kfree(dptr);
}
dev->size = 0;
dev->quantum = scull_quantum;
dev->qset = scull_qset;
dev->data = NULL;
return 0;
}
ssize_t scull_read(struct file *filp,char __user *buf,size_t count,loff_t *f_pos)
{
struct scull_dev *dev = filp->private_data;
struct scull_qset *dptr; /*teh first listitem*/
int quantum = dev->quantum,qset = dev->qset;
int itemsize = quantum * qset;
int item,s_pos,q_pos,rest;
ssize_t retval = 0;
if(down_interruptible(&dev->sem))
return -ERESTARTSYS;
if(*f_pos >= dev->size)
goto out;
if(*f_pos + count > dev->size)
count = dev->size - *f_pos;
/*find listitem,qset index,and offset in the quantum */
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest /quantum;
q_pos = rest %quantum;
/*follow the list up to the right position ()defined elsewhere) */
dptr = scull_follow(dev,item);
if(dptr == NULL || !dptr->data || !dptr->data[s_pos])
goto out; /*don't fill holes*/
/*read oly up to the end of this quantum */
if(count > quantum - q_pos)
count = quantum - q_pos;
if(copy_to_user(buf,dptr->data[s_pos] + q_pos,count)){
retval = -EFAULT;
goto out;
}
*f_pos += count;
retval = count;
out:
up(&dev->sem);
return retval;
}
ssize_t scull_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_pos)
{
struct scull_dev *dev = filp->private_data;
struct scull_qset *dptr;
int quantum = dev->quantum,qset = dev->qset;
int itemsize = quantum *qset;
int item,s_pos,q_pos,rest;
ssize_t retval = -ENOMEM; /*value use in "goto out" statement*/
if(down_interruptible(&dev->sem))
return -ERESTARTSYS;
/*find listitem,qset index and offset in the quantum*/
item = (long)*f_pos /itemsize;
rest = (long)*f_pos %itemsize;
s_pos = rest/quantum;
q_pos = rest %quantum;
/*follow the list up to the right position */
dptr = scull_follow(dev,item);
if(dptr == NULL)
goto out;
if(!dptr->data){
dptr->data = kmalloc(qset * sizeof(char *),GFP_KERNEL);
if(!dptr->data)
goto out;
memset(dptr->data,0,qset *sizeof(char *));
}
if(!dptr->data[s_pos]){
dptr->data[s_pos] = kmalloc(quantum,GFP_KERNEL);
if(!dptr->data[s_pos])
goto out;
}
/*write only up to the end of this quantum */
if(count > quantum - q_pos)
count = quantum - q_pos;
if(copy_from_user(dptr->data[s_pos] + q_pos,buf,count)){
retval = -EFAULT;
goto out;
}
*f_pos += count;
retval = count;
/*updata the size*/
if(dev->size < *f_pos)
dev->size = *f_pos;
out:
up(&dev->sem);
return retval;
}
struct scull_qset *scull_follow(struct scull_dev *dev,int n)
{
struct scull_qset *qs = dev->data;
if(!qs){
qs = dev->data = kmalloc(sizeof(struct scull_qset),GFP_KERNEL);
if(qs == NULL)
return NULL;
memset(qs,0,sizeof(struct scull_qset));
while(n--){
if(!qs->next){
qs->next = kmalloc(sizeof(struct scull_qset),GFP_KERNEL);
if(qs->next == NULL)
return NULL;
memset(qs->next,0,sizeof(struct scull_qset));
}
qs = qs->next;
}
}
return qs;
}
module_init(scull_init_module);
module_exit(scull_cleanup_module);
/***************************************************************
* scull_load
***************************************************************/
#!/bin/sh
2 module="scull"
3 device="scull"
4 mode="664"
5
6 #invoke insmod with all arguments we got
7 #and use a pathnamea,as newer modutils don't look in , by default
8 /sbin/insmod ./$module.ko $* || exit 1
9
10 #remove stale nodes
11 rm -f /dev/${device}[0-3]
12
13 major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)
14
15 mknod /dev/${device}0 c $major 0
16 mknod /dev/${device}1 c $major 1
17 mknod /dev/${device}2 c $major 2
18 mknod /dev/${device}3 c $major 3
19
20 chmod $mode /dev/${device}[0-3]
/*************************************************************
scull_unload
**************************************************************/
1 #!/bin/sh
2 module="scull"
3 device="scull"
4
5 #invoke rmmod with all arguments we got
6 /sbin/rmmod $module $* || exit 1
7
8 #Remove state nodes
9
10 rm -f /dev/${device}[0-3]
~
/**************************************************************
* test
**************************************************************/
[root@localhost myscull]# vi tt
[root@localhost myscull]# cp tt /dev/scull0
cp:是否覆盖“/dev/scull0”? y
[root@localhost myscull]# cat /dev/scull0
This is just a test.
http://blog.csdn.net/freedom1013/archive/2007/02/08/1504970.aspx