学习linux设备驱动,第四章;
关于proc文件系统接口编程参见
procfs读取信息实例:http://blog.csdn.net/iamonlyme/article/details/7062237
procfs读写信息实例:http://blog.csdn.net/iamonlyme/article/details/7065243
本次修改的代码是属于main.c函数,主要是增加proc接口实现代码
/**********************************************
* Author: lewiyon@hotmail.com
* File name: scullmod.c
* Description: initialize and release function for scull
* Date: 2012-07-4
*********************************************/
#include <linux/init.h> /* module */
#include <linux/module.h> /* module */
#include <linux/moduleparam.h> /* module */
#include <linux/errno.h> /* error codes */
#include <linux/kernel.h> /* printk */
#include <linux/slab.h> /* kmalloc kfree */
#include <linux/types.h> /* dev_t */
#include <linux/proc_fs.h> /* dev_t */
/* local head files */
#include "scull.h"
#include "file.h"
#define SCULL_PROC_NAME "scull"
/* default parameters of module */
int scull_major = SCULL_MAJOR;
int scull_minor = 0;
int scull_nr_devs = SCULL_NR_DEVS;
int scull_quantum = SCULL_QUANTUM;
int scull_qset = SCULL_QSET;
/* input parameters of module */
module_param(scull_major, int, S_IRUGO);
module_param(scull_minor, 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 scull_dev *scull_devices;
static struct proc_dir_entry *scull_proc;
static struct proc_dir_entry *scull_info;
int scull_read_procmem(char *buf, char **start, off_t offset,
int count, int *eof, void *data)
{
int len;
struct scull_dev *dev;
len = 0;
dev = scull_devices;
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
len += sprintf(buf + len, "qset:%i\nquantum:%i\nsize:%li\n",
dev->qset, dev->quantum, dev->size);
up(&dev->sem);
*eof = 1;
return len;
}
/*
* scull_trim - 遍历链表,并释放所有找到的量子和量子集
* @dev: scull设备
*/
int scull_trim(struct scull_dev *dev)
{
int i, qset;
struct scull_qset *next, *dptr;
qset = dev->qset;
for (dptr = dev->data; dptr; dptr = next) {
if (dptr->data) {
for (i = 0; i < qset; i++)
kfree(dptr->data[i]);
kfree(dptr->data);
dptr->data = NULL;
}
next = dptr->next;
kfree(dptr);
}
dev->size = 0;
dev->quantum = scull_quantum;
dev->qset = scull_qset;
dev->data = NULL;
return 0;
}
static void scull_setup_cdev(struct scull_dev *dev, int index)
{
int err;
int devno;
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);
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}
static void scull_unregister(void)
{
int i;
dev_t devno;
devno = MKDEV(scull_major, scull_minor);
/* delete each entry */
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 */
unregister_chrdev_region(devno, scull_nr_devs);
}
/*
* initialze scull module
*/
void scull_cleanup_module(void)
{
remove_proc_entry("scullmem", scull_proc);
remove_proc_entry(SCULL_PROC_NAME, NULL);
scull_unregister();
printk(KERN_WARNING "scull: Bye!\n");
}
/*
* initialze scull module
*/
int scull_init_module(void)
{
int i, res;
dev_t dev = 0;
if (scull_major) {
dev = MKDEV(scull_major, scull_minor);
res = register_chrdev_region(dev, scull_nr_devs, "scull");
} else {
res = alloc_chrdev_region(&dev, scull_minor,
scull_nr_devs, "scull");
scull_major = MAJOR(dev);
}
if (res < 0) {
printk(KERN_WARNING "scull: can't get major %d\n", scull_major);
return res;
}
/*
* allocate the device struct cache
*/
scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev),
GFP_KERNEL);
if (NULL == scull_devices) {
res = -ENOMEM;
printk(KERN_WARNING "scull: NOMEM for scull!\n");
goto fail;
}
memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));
/* initialize each device */
for (i = 0; i < scull_nr_devs; i++) {
scull_devices[i].quantum = scull_quantum;
scull_devices[i].qset = scull_qset;
sema_init(&scull_devices[i].sem, 1);
scull_setup_cdev(&scull_devices[i], i);
}
printk(KERN_INFO "scull: OK!\n");
scull_proc = proc_mkdir(SCULL_PROC_NAME, NULL);
if (NULL == scull_proc)
{
res = -ENOMEM;
goto fail;
}
scull_info = create_proc_read_entry("scullmem", 0, scull_proc,
scull_read_procmem, NULL);
if (NULL == scull_info)
{
res = -ENOMEM;
goto info_err;
}
printk(KERN_INFO "scull proc: OK!\n");
return 0;
info_err:
remove_proc_entry(SCULL_PROC_NAME, NULL);
fail:
scull_unregister();
return res;
}
module_init(scull_init_module);
module_exit(scull_cleanup_module);
MODULE_AUTHOR("lewiyon@hotmail.com");
MODULE_LICENSE("GPL");