1.scull.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEV_NAME "scull"
static struct file_operations scull_fops;
static dev_t dev;
static int scull_major = 0;
static int scull_minor;
static int scull_dvnum;
struct scull_dev {
struct scull_qset *data;
int quantum;
int qset;
unsigned long size;
unsigned int access_key;
struct semaphore sem;
struct cdev cdev;
};
struct scull_qset {
void **data;
struct scull_qset *next;
};
struct scull_dev scull_dev;
static int scull_trim(struct scull_dev *dev)
{
struct scull_qset *next, *dptr;
int qset = dev->qset;
int i;
for(dptr=dev->data; dptr; dptr=next)
{
if(dptr->data)
{
for(i=0; idata[i]);
kfree(dptr->data);
dptr->data = NULL;
}
next = dptr->next;
kfree(dptr);
}
return 0;
}
static struct scull_qset *scull_follow(struct scull_dev *dev, int item)
{
struct scull_qset *next, *dptr;
int i;
dptr=dev->data;
for(i=0; i- next;
dptr = next;
}
return dptr;
}
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;
if((filp->f_flags && O_ACCMODE) == O_WRONLY)
{
scull_trim(dev);
}
printk(KERN_NOTICE "opened the file[%p]\n", filp);
return 0;
}
int scull_release(struct inode *inode, struct file *filp)
{
printk(KERN_NOTICE "closed the file[%p]\n", filp);
return 0;
}
//读scull字符设备
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;
int quantum = dev->quantum;
int 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;
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum;
q_pos = rest % quantum;
dptr = scull_follow(dev, item);
if(dptr==NULL || !dptr->data || !dptr->data[s_pos])
{
goto out;
}
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);
printk(KERN_NOTICE "read the file[%p]\n", filp);
return retval;
}
static void scull_setup_cdev(dev_t devno, struct scull_dev *dev, int index)
{
//int devno;
int err;
//devno = MKDEV(scull_major, scull_minor);
scull_fops.open = scull_open;
scull_fops.release = scull_release;
scull_fops.read = scull_read;
cdev_init(&dev->cdev, &scull_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &scull_fops;
err = cdev_add(&dev->cdev, devno, 1);
if(err)
printk(KERN_NOTICE "Error %d adding scull%d\n", err, index);
}
static int __init scull_init(void)
{
int ret;
printk("init module\n");
if(scull_major)
{
dev = MKDEV(scull_major, scull_minor);
ret = register_chrdev_region(dev, scull_dvnum, DEV_NAME);
}
else
{
scull_dvnum = 4;
scull_minor = 0;
ret = alloc_chrdev_region(&dev, scull_minor, scull_dvnum, DEV_NAME);
scull_major = MAJOR(dev);
}
if(ret < 0)
{
printk("scull: can't get major %d\n", scull_major);
}
scull_setup_cdev(dev, &scull_dev, 0);
return 0;
}
static void __exit scull_exit(void)
{
cdev_del(&scull_dev.cdev);
unregister_chrdev_region(dev, scull_dvnum);
printk("exit module, major=[%d]\n", scull_major);
}
module_init(scull_init);
module_exit(scull_exit);
2.编译模块
$ make
3.安装模块
# insmod
4.创建设备
# ./scull_load
5.打开, 读和关闭设备
# cat /dev/scull0
6.查看打印日志
# tail -n 4 /var/log/messages
Nov 6 00:02:41 linux kernel: [ 5831.619786] init module
Nov 6 00:02:45 linux kernel: [ 5835.560676] opened the file[ffff8800452738c0]
Nov 6 00:02:45 linux kernel: [ 5835.560687] read the file[ffff8800452738c0]
Nov 6 00:02:45 linux kernel: [ 5835.560692] closed the file[ffff8800452738c0]