#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);