blob: fb6e2c7b49c3683860819619cd8f167d00c43b28 [file] [log] [blame]
/*
* linux/fs/devices.c
*
* (C) 1993 Matthias Urlichs -- collected common code and tables.
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/fs.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/ext_fs.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
struct device_struct {
const char * name;
struct file_operations * fops;
};
static struct device_struct chrdevs[MAX_CHRDEV] = {
{ NULL, NULL },
};
static struct device_struct blkdevs[MAX_BLKDEV] = {
{ NULL, NULL },
};
struct file_operations * get_blkfops(unsigned int major)
{
if (major >= MAX_BLKDEV)
return NULL;
return blkdevs[major].fops;
}
struct file_operations * get_chrfops(unsigned int major)
{
if (major >= MAX_CHRDEV)
return NULL;
return chrdevs[major].fops;
}
int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
{
if (major >= MAX_CHRDEV)
return -EINVAL;
if (chrdevs[major].fops)
return -EBUSY;
chrdevs[major].name = name;
chrdevs[major].fops = fops;
return 0;
}
int register_blkdev(unsigned int major, const char * name, struct file_operations *fops)
{
if (major >= MAX_BLKDEV)
return -EINVAL;
if (blkdevs[major].fops)
return -EBUSY;
blkdevs[major].name = name;
blkdevs[major].fops = fops;
return 0;
}
int unregister_chrdev(unsigned int major, const char * name)
{
if (major >= MAX_CHRDEV)
return -EINVAL;
if (!chrdevs[major].fops)
return -EINVAL;
if (strcmp(chrdevs[major].name, name))
return -EINVAL;
chrdevs[major].name = NULL;
chrdevs[major].fops = NULL;
return 0;
}
int unregister_blkdev(unsigned int major, const char * name)
{
if (major >= MAX_BLKDEV)
return -EINVAL;
if (!blkdevs[major].fops)
return -EINVAL;
if (strcmp(blkdevs[major].name, name))
return -EINVAL;
blkdevs[major].name = NULL;
blkdevs[major].fops = NULL;
return 0;
}
/*
* Called every time a block special file is opened
*/
int blkdev_open(struct inode * inode, struct file * filp)
{
int i;
i = MAJOR(inode->i_rdev);
if (i >= MAX_BLKDEV || !blkdevs[i].fops)
return -ENODEV;
filp->f_op = blkdevs[i].fops;
if (filp->f_op->open)
return filp->f_op->open(inode,filp);
return 0;
}
/*
* Dummy default file-operations: the only thing this does
* is contain the open that then fills in the correct operations
* depending on the special file...
*/
struct file_operations def_blk_fops = {
NULL, /* lseek */
NULL, /* read */
NULL, /* write */
NULL, /* readdir */
NULL, /* select */
NULL, /* ioctl */
NULL, /* mmap */
blkdev_open, /* open */
NULL, /* release */
};
struct inode_operations blkdev_inode_operations = {
&def_blk_fops, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
/*
* Called every time a character special file is opened
*/
int chrdev_open(struct inode * inode, struct file * filp)
{
int i;
i = MAJOR(inode->i_rdev);
if (i >= MAX_CHRDEV || !chrdevs[i].fops)
return -ENODEV;
filp->f_op = chrdevs[i].fops;
if (filp->f_op->open)
return filp->f_op->open(inode,filp);
return 0;
}
/*
* Dummy default file-operations: the only thing this does
* is contain the open that then fills in the correct operations
* depending on the special file...
*/
struct file_operations def_chr_fops = {
NULL, /* lseek */
NULL, /* read */
NULL, /* write */
NULL, /* readdir */
NULL, /* select */
NULL, /* ioctl */
NULL, /* mmap */
chrdev_open, /* open */
NULL, /* release */
};
struct inode_operations chrdev_inode_operations = {
&def_chr_fops, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};