#ifndef __KERNEL_
#  define __KERNEL__
#endif
#ifndef MODULE
#  define MODULE
#endif

#define SBULL_MAJOR 0       /* dynamic major by default */
#define SBULL_DEVS 2        /* two disks */
#define SBULL_RAHEAD 2      /* two sectors */
#define SBULL_SIZE 2048     /* two megs each */
#define SBULL_BLKSIZE 1024  /* 1k blocks */
#define SBULL_HARDSECT 512  /* 2.2 and 2.4 can used different values */

#define SBULLR_MAJOR 0      /* Dynamic major for raw device */

#include <linux/fs.h>
#include <linux/config.h>
#include <linux/module.h>

#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/errno.h>  /* error codes */
#include <linux/types.h>  /* size_t */
#include <linux/fcntl.h>  /* O_ACCMODE */

static int major = SBULL_MAJOR;

#include <asm/system.h>   /* cli(), *_flags */
#include <linux/ioctl.h>

#include <linux/blk.h>

typedef struct Blkdev_Dev {
        int size;
        int usage;
        struct timer_list timer;
        spinlock_t lock;
        u8 *data;
        request_queue_t queue;
} Sbull_Dev;

struct block_device_operations sbull_bdops;

Sbull_Dev *sbull_devices = NULL;

int sbull_read_procmem(char *buf, char **start, off_t offset,
                int count, int *eof, void *data)
{
        int i, len = 0;
        int limit = count - 80; /* Don<92>t print more than this */
        for (i = 0; len <= limit; i++)
        {
                len += sprintf(buf+len,"\nSbull device proc test!");
        }
        *eof = 1;
        return len;
}

//request_queue_t *queue;
void sbull_request(request_queue_t *q)
{
    while(1)
    {
        INIT_REQUEST;
        printk("<1>request %p: cmd %i sec %li (nr. %li)\n", CURRENT,
                CURRENT->cmd,
                CURRENT->sector,
                CURRENT->current_nr_sectors);
        end_request(1);
    }
}

int sbull_init(void)
{
        int result;

        result = register_blkdev(major, "sbull", &sbull_bdops);
        if (result < 0)
        {
                printk(KERN_WARNING "sbull: can't get major %d\n", major);
                return result;
        }

        if (sbull_major == 0)
        {
                sbull_major = result; /* dynamic */
        }

        major = sbull_major;

        blk_init_queue(BLK_DEFAULT_QUEUE(major), sbull_request);
        sbull_devices = kmalloc(sizeof (Sbull_Dev), GFP_KERNEL);
        if (!sbull_devices)
        {
                printk("Can't init sbull!");
                return -1;
        }

        create_proc_read_entry("sbullmem",
                        0 /* default mode */,
                        NULL /* parent dir */,
                        sbull_read_procmem,
                        NULL /* client data */);


}

void sbull_cleanup(void)
{
        unregister_blkdev(major, "sbull");
        blk_cleanup_queue(BLK_DEFAULT_QUEUE(major));
        remove_proc_entry("sbullmem", NULL /* parent dir */);
}


int sbull_open (struct inode *inode, struct file *filp)
{
        Sbull_Dev *dev;
        int num = MINOR(inode->i_rdev);
        dev = sbull_devices + num;
        spin_lock(&dev->lock);

        if (!dev->usage)
        {
                check_disk_change(inode->i_rdev);
                if (!dev->data)
                {
                        spin_unlock (&dev->lock);
                        return -ENOMEM;
                }
        }

        dev->usage++;
        spin_unlock(&dev->lock);
        MOD_INC_USE_COUNT;
        return 0;          /* success */
}

int sbull_release (struct inode *inode, struct file *filp)
{
        Sbull_Dev *dev = sbull_devices + MINOR(inode->i_rdev);
        spin_lock(&dev->lock);
        dev->usage--;

        if (!dev->usage)
        {
                fsync_dev(inode->i_rdev);
                invalidate_buffers(inode->i_rdev);
        }

        MOD_DEC_USE_COUNT;
        spin_unlock(&dev->lock);
        return 0;
}

int sbull_ioctl (struct inode *inode, struct file *filp,
                 unsigned int cmd, unsigned long arg)
{
        long size;

        switch(cmd)
        {
                case BLKRRPART:
                        return -ENOTTY;

                default:
                        return blk_ioctl(inode->i_rdev, cmd, arg);

        }

        return -ENOTTY; /* unknown command */
}

 

int sbull_change(kdev_t i_rdev)
{
        int minor = MINOR(i_rdev);
        Sbull_Dev *dev = sbull_devices + minor;

        PDEBUG("check_change for dev %i\n",minor);

        if (dev->data)
        {
                return 0; /* still valid */
        }

        return 1; /* expired */
}

int sbull_revalidate(kdev_t i_rdev)
{
        Sbull_Dev *dev = sbull_devices + MINOR(i_rdev);
        PDEBUG("revalidate for dev %i\n",MINOR(i_rdev));

        if (dev->data)
        {
                return 0;
        }

        dev->data = vmalloc(dev->size);

        if (!dev->data)
        {
                return -ENOMEM;
        }

        return 0;
}

 

struct block_device_operations sbull_bdops =
{
        open: sbull_open,
        release: sbull_release,
        ioctl: sbull_ioctl,
        check_media_change: sbull_change,
        revalidate: sbull_revalidate
};

module_init(sbull_init);
module_exit(sbull_cleanup);

posted on 2005-04-21 20:41  default.aspx  阅读(877)  评论(0编辑  收藏  举报