Commit 8d6a7478 authored by Ben Collins's avatar Ben Collins

[IEEE1394]: Convert to cdev API.

  Retire our char device dispatching logic.  With the 2.6 cdev API we
  can register much smaller device number regions, so we use that instead.
parent d58ab3e9
......@@ -82,6 +82,7 @@
#include <linux/poll.h>
#include <linux/ioctl32.h>
#include <linux/compat.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
......@@ -1196,6 +1197,7 @@ static int amdtp_release(struct inode *inode, struct file *file)
return 0;
}
static struct cdev amdtp_cdev;
static struct file_operations amdtp_fops =
{
.owner = THIS_MODULE,
......@@ -1262,12 +1264,11 @@ MODULE_LICENSE("GPL");
static int __init amdtp_init_module (void)
{
int ret;
ret = ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_AMDTP,
THIS_MODULE, &amdtp_fops);
if (ret) {
HPSB_ERR("amdtp: unable to get minor device block");
cdev_init(&amdtp_cdev, &amdtp_fops);
amdtp_cdev.owner = THIS_MODULE;
kobject_set_name(&amdtp_cdev.kobj, "amdtp");
if (cdev_add(&amdtp_cdev, IEEE1394_AMDTP_DEV, 16)) {
HPSB_ERR("amdtp: unable to add char device");
return -EIO;
}
......@@ -1304,10 +1305,12 @@ static void __exit amdtp_exit_module (void)
hpsb_unregister_highlevel(&amdtp_highlevel);
devfs_remove("amdtp");
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
cdev_unmap(IEEE1394_AMDTP_DEV, 16);
cdev_del(&amdtp_cdev);
HPSB_INFO("Unloaded AMDTP driver");
}
module_init(amdtp_init_module);
module_exit(amdtp_exit_module);
MODULE_ALIAS_CHARDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_AMDTP * 16);
......@@ -110,6 +110,7 @@
#include <linux/string.h>
#include <linux/ioctl32.h>
#include <linux/compat.h>
#include <linux/cdev.h>
#include "ieee1394.h"
#include "ieee1394_types.h"
......@@ -2165,6 +2166,7 @@ static void ir_tasklet_func(unsigned long data)
spin_unlock(&video->spinlock);
}
static struct cdev dv1394_cdev;
static struct file_operations dv1394_fops=
{
.owner = THIS_MODULE,
......@@ -2607,17 +2609,17 @@ static void __exit dv1394_exit_module(void)
hpsb_unregister_protocol(&dv1394_driver);
hpsb_unregister_highlevel(&dv1394_highlevel);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
cdev_unmap(IEEE1394_DV1394_DEV, 16);
cdev_del(&dv1394_cdev);
devfs_remove("ieee1394/dv");
}
static int __init dv1394_init_module(void)
{
int ret;
ret = ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_DV1394,
THIS_MODULE, &dv1394_fops);
if (ret) {
cdev_init(&dv1394_cdev, &dv1394_fops);
dv1394_cdev.owner = THIS_MODULE;
kobject_set_name(&dv1394_cdev.kobj, "dv1394");
if (cdev_add(&dv1394_cdev, IEEE1394_DV1394_DEV, 16)) {
printk(KERN_ERR "dv1394: unable to register character device\n");
return -EIO;
}
......@@ -2648,3 +2650,4 @@ static int __init dv1394_init_module(void)
module_init(dv1394_init_module);
module_exit(dv1394_exit_module);
MODULE_ALIAS_CHARDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16);
......@@ -993,186 +993,11 @@ void abort_timedouts(unsigned long __opaque)
}
/*
* character device dispatching (see ieee1394_core.h)
* Dan Maas <dmaas@dcine.com>
*/
static struct {
struct file_operations *file_ops;
struct module *module;
} ieee1394_chardevs[16];
static rwlock_t ieee1394_chardevs_lock = RW_LOCK_UNLOCKED;
static int ieee1394_dispatch_open(struct inode *inode, struct file *file);
static struct file_operations ieee1394_chardev_ops = {
.owner =THIS_MODULE,
.open = ieee1394_dispatch_open,
};
/* claim a block of minor numbers */
int ieee1394_register_chardev(int blocknum,
struct module *module,
struct file_operations *file_ops)
{
int retval;
if ( (blocknum < 0) || (blocknum > 15) )
return -EINVAL;
write_lock(&ieee1394_chardevs_lock);
if (ieee1394_chardevs[blocknum].file_ops == NULL) {
/* grab the minor block */
ieee1394_chardevs[blocknum].file_ops = file_ops;
ieee1394_chardevs[blocknum].module = module;
retval = 0;
} else {
/* block already taken */
retval = -EBUSY;
}
write_unlock(&ieee1394_chardevs_lock);
return retval;
}
/* release a block of minor numbers */
void ieee1394_unregister_chardev(int blocknum)
{
if ( (blocknum < 0) || (blocknum > 15) )
return;
write_lock(&ieee1394_chardevs_lock);
if (ieee1394_chardevs[blocknum].file_ops) {
ieee1394_chardevs[blocknum].file_ops = NULL;
ieee1394_chardevs[blocknum].module = NULL;
}
write_unlock(&ieee1394_chardevs_lock);
}
/*
ieee1394_get_chardev() - look up and acquire a character device
driver that has previously registered using ieee1394_register_chardev()
On success, returns 1 and sets module and file_ops to the driver.
The module will have an incremented reference count.
On failure, returns 0.
The module will NOT have an incremented reference count.
*/
static int ieee1394_get_chardev(int blocknum,
struct module **module,
struct file_operations **file_ops)
{
int ret = 0;
if ((blocknum < 0) || (blocknum > 15))
return ret;
read_lock(&ieee1394_chardevs_lock);
*module = ieee1394_chardevs[blocknum].module;
*file_ops = ieee1394_chardevs[blocknum].file_ops;
if (*file_ops == NULL)
goto out;
if (!try_module_get(*module))
goto out;
/* success! */
ret = 1;
out:
read_unlock(&ieee1394_chardevs_lock);
return ret;
}
/* the point of entry for open() on any ieee1394 character device */
static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
{
struct file_operations *file_ops;
struct module *module;
int blocknum;
int retval;
/*
Maintaining correct module reference counts is tricky here!
The key thing to remember is that the VFS increments the
reference count of ieee1394 before it calls
ieee1394_dispatch_open().
If the open() succeeds, then we need to transfer this extra
reference to the task-specific driver module (e.g. raw1394).
The VFS will deref the driver module automatically when the
file is later released.
If the open() fails, then the VFS will drop the
reference count of whatever module file->f_op->owner points
to, immediately after this function returns.
*/
/* shift away lower four bits of the minor
to get the index of the ieee1394_driver
we want */
blocknum = (iminor(inode) >> 4) & 0xF;
/* look up the driver */
if (ieee1394_get_chardev(blocknum, &module, &file_ops) == 0)
return -ENODEV;
/* redirect all subsequent requests to the driver's
own file_operations */
file->f_op = file_ops;
/* at this point BOTH ieee1394 and the task-specific driver have
an extra reference */
/* follow through with the open() */
retval = file_ops->open(inode, file);
if (retval == 0) {
/* If the open() succeeded, then ieee1394 will be left
* with an extra module reference, so we discard it here.
*
* The task-specific driver still has the extra reference
* given to it by ieee1394_get_chardev(). This extra
* reference prevents the module from unloading while the
* file is open, and will be dropped by the VFS when the
* file is released. */
module_put(THIS_MODULE);
} else {
/* point the file's f_ops back to ieee1394. The VFS will then
decrement ieee1394's reference count immediately after this
function returns. */
file->f_op = &ieee1394_chardev_ops;
/* If the open() failed, then we need to drop the extra
* reference we gave to the task-specific driver. */
module_put(module);
}
return retval;
}
static int __init ieee1394_init(void)
{
devfs_mk_dir("ieee1394");
if (register_chrdev(IEEE1394_MAJOR, "ieee1394", &ieee1394_chardev_ops)) {
if (register_chrdev_region(IEEE1394_CORE_DEV, 256, "ieee1394")) {
HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
return -ENODEV;
}
......@@ -1206,7 +1031,7 @@ static void __exit ieee1394_cleanup(void)
kmem_cache_destroy(hpsb_packet_cache);
unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
devfs_remove("ieee1394");
}
......@@ -1234,8 +1059,6 @@ EXPORT_SYMBOL(hpsb_selfid_received);
EXPORT_SYMBOL(hpsb_selfid_complete);
EXPORT_SYMBOL(hpsb_packet_sent);
EXPORT_SYMBOL(hpsb_packet_received);
EXPORT_SYMBOL(ieee1394_register_chardev);
EXPORT_SYMBOL(ieee1394_unregister_chardev);
/** ieee1394_transactions.c **/
EXPORT_SYMBOL(hpsb_get_tlabel);
......
......@@ -176,9 +176,9 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
* task-specific interfaces (raw1394, video1394, dv1394, etc) in
* blocks of 16.
*
* The core ieee1394.o modules handles the initial open() for all
* character devices on major 171; it then dispatches to the
* appropriate task-specific driver.
* The core ieee1394.o module allocates the device number region
* 171:0-255, the various drivers must then cdev_add() their cdev
* objects to handle their respective sub-regions.
*
* Minor device number block allocations:
*
......@@ -199,29 +199,19 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
#define IEEE1394_MINOR_BLOCK_AMDTP 3
#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
#define IEEE1394_CORE_DEV MKDEV(IEEE1394_MAJOR, 0)
#define IEEE1394_RAW1394_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16)
#define IEEE1394_VIDEO1394_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
#define IEEE1394_DV1394_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16)
#define IEEE1394_AMDTP_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_AMDTP * 16)
#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
/* return the index (within a minor number block) of a file */
static inline unsigned char ieee1394_file_to_instance(struct file *file)
{
unsigned char minor = iminor(file->f_dentry->d_inode);
/* return lower 4 bits */
return minor & 0xF;
return file->f_dentry->d_inode->i_cindex;
}
/*
* Task-specific drivers should call ieee1394_register_chardev() to
* request a block of 16 minor numbers.
*
* Returns 0 if the request was successful, -EBUSY if the block was
* already taken.
*/
int ieee1394_register_chardev(int blocknum, /* 0-15 */
struct module *module, /* THIS_MODULE */
struct file_operations *file_ops);
/* release a block of minor numbers */
void ieee1394_unregister_chardev(int blocknum);
/* Our sysfs bus entry */
extern struct bus_type ieee1394_bus_type;
......
......@@ -38,6 +38,7 @@
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/devfs_fs_kernel.h>
......@@ -2464,10 +2465,6 @@ static int raw1394_open(struct inode *inode, struct file *file)
{
struct file_info *fi;
if (ieee1394_file_to_instance(file) > 0) {
return -ENXIO;
}
fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL);
if (fi == NULL)
return -ENOMEM;
......@@ -2646,7 +2643,8 @@ static struct hpsb_highlevel raw1394_highlevel = {
.fcp_request = fcp_request,
};
static struct file_operations file_ops = {
static struct cdev raw1394_cdev;
static struct file_operations raw1394_fops = {
.owner = THIS_MODULE,
.read = raw1394_read,
.write = raw1394_write,
......@@ -2664,8 +2662,10 @@ static int __init init_raw1394(void)
devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16),
S_IFCHR | S_IRUSR | S_IWUSR, RAW1394_DEVICE_NAME);
if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394,
THIS_MODULE, &file_ops)) {
cdev_init(&raw1394_cdev, &raw1394_fops);
raw1394_cdev.owner = THIS_MODULE;
kobject_set_name(&raw1394_cdev.kobj, RAW1394_DEVICE_NAME);
if (cdev_add(&raw1394_cdev, IEEE1394_RAW1394_DEV, 1)) {
HPSB_ERR("raw1394 failed to register minor device block");
devfs_remove(RAW1394_DEVICE_NAME);
hpsb_unregister_highlevel(&raw1394_highlevel);
......@@ -2682,7 +2682,8 @@ static int __init init_raw1394(void)
static void __exit cleanup_raw1394(void)
{
hpsb_unregister_protocol(&raw1394_driver);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
cdev_unmap(IEEE1394_RAW1394_DEV, 16);
cdev_del(&raw1394_cdev);
devfs_remove(RAW1394_DEVICE_NAME);
hpsb_unregister_highlevel(&raw1394_highlevel);
}
......@@ -2690,3 +2691,4 @@ static void __exit cleanup_raw1394(void)
module_init(init_raw1394);
module_exit(cleanup_raw1394);
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16);
......@@ -46,6 +46,7 @@
#include <linux/mm.h>
#include <linux/ioctl32.h>
#include <linux/compat.h>
#include <linux/cdev.h>
#include "ieee1394.h"
#include "ieee1394_types.h"
......@@ -1231,6 +1232,7 @@ static int video1394_release(struct inode *inode, struct file *file)
return 0;
}
static struct cdev video1394_cdev;
static struct file_operations video1394_fops=
{
.owner = THIS_MODULE,
......@@ -1445,18 +1447,18 @@ static void __exit video1394_exit_module (void)
hpsb_unregister_highlevel(&video1394_highlevel);
devfs_remove(VIDEO1394_DRIVER_NAME);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
cdev_unmap(IEEE1394_VIDEO1394_DEV, 16);
cdev_del(&video1394_cdev);
PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
}
static int __init video1394_init_module (void)
{
int ret;
ret = ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394,
THIS_MODULE, &video1394_fops);
if (ret) {
cdev_init(&video1394_cdev, &video1394_fops);
video1394_cdev.owner = THIS_MODULE;
kobject_set_name(&video1394_cdev.kobj, VIDEO1394_DRIVER_NAME);
if (cdev_add(&video1394_cdev, IEEE1394_VIDEO1394_DEV, 16)) {
PRINT_G(KERN_ERR, "video1394: unable to get minor device block");
return -EIO;
}
......@@ -1496,3 +1498,4 @@ static int __init video1394_init_module (void)
module_init(video1394_init_module);
module_exit(video1394_exit_module);
MODULE_ALIAS_CHARDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_VIDEO1394 * 16);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment