Chinaunix首页 | 论坛 | 博客
  • 博客访问: 738381
  • 博文数量: 251
  • 博客积分: 10367
  • 博客等级: 上将
  • 技术积分: 2750
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-10 14:43
文章分类

全部博文(251)

文章存档

2009年(2)

2008年(86)

2007年(163)

分类: LINUX

2007-08-18 00:34:37

 
     对这个驱动世界报了个到后,一直没进去游览过,而时间过得好快,转眼一个暑假就快过完了,从明天开始应该把这个美丽的世界走一遍了,同行的还有余秋雨教授,所以一路上应该不会孤单,我会一直安静地走下去,直到...
/********************************************************
 *                     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
阅读(1187) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~