设备驱动之一 - proc文件系统接口

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


 

posted on 2012-07-14 00:18  YoungerChina  阅读(432)  评论(0编辑  收藏  举报

导航