patch-2.4.19 linux-2.4.19/drivers/ieee1394/ieee1394_core.c
Next file: linux-2.4.19/drivers/ieee1394/ieee1394_core.h
Previous file: linux-2.4.19/drivers/ieee1394/ieee1394.h
Back to the patch index
Back to the overall index
- Lines: 424
- Date:
Fri Aug 2 17:39:44 2002
- Orig file:
linux-2.4.18/drivers/ieee1394/ieee1394_core.c
- Orig date:
Fri Dec 21 09:41:54 2001
diff -urN linux-2.4.18/drivers/ieee1394/ieee1394_core.c linux-2.4.19/drivers/ieee1394/ieee1394_core.c
@@ -18,9 +18,11 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/proc_fs.h>
#include <asm/bitops.h>
#include <asm/byteorder.h>
#include <asm/semaphore.h>
+#include <asm/smplock.h>
#include "ieee1394_types.h"
#include "ieee1394.h"
@@ -39,6 +41,10 @@
MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
static int disable_nodemgr = 0;
+MODULE_PARM(disable_hotplug, "i");
+MODULE_PARM_DESC(disable_hotplug, "Disable hotplug for detected nodes.");
+static int disable_hotplug = 0;
+
/* We are GPL, so treat us special */
MODULE_LICENSE("GPL");
@@ -106,7 +112,7 @@
packet->data_size = data_size;
}
- INIT_TQ_HEAD(packet->complete_tq);
+ INIT_LIST_HEAD(&packet->complete_tq);
INIT_LIST_HEAD(&packet->list);
sema_init(&packet->state_change, 0);
packet->state = hpsb_unused;
@@ -135,12 +141,8 @@
int hpsb_reset_bus(struct hpsb_host *host, int type)
{
- if (!host->initialized) {
- return 1;
- }
-
if (!host->in_bus_reset) {
- host->template->devctl(host, RESET_BUS, type);
+ host->ops->devctl(host, RESET_BUS, type);
return 0;
} else {
return 1;
@@ -151,8 +153,8 @@
int hpsb_bus_reset(struct hpsb_host *host)
{
if (host->in_bus_reset) {
- HPSB_NOTICE(__FUNCTION__
- " called while bus reset already in progress");
+ HPSB_NOTICE("%s called while bus reset already in progress",
+ __FUNCTION__);
return 1;
}
@@ -171,14 +173,16 @@
* Verify num_of_selfids SelfIDs and return number of nodes. Return zero in
* case verification failed.
*/
-static int check_selfids(struct hpsb_host *host, unsigned int num_of_selfids)
+static int check_selfids(struct hpsb_host *host)
{
int nodeid = -1;
- int rest_of_selfids = num_of_selfids;
+ int rest_of_selfids = host->selfid_count;
struct selfid *sid = (struct selfid *)host->topology_map;
struct ext_selfid *esid;
int esid_seq = 23;
+ host->nodes_active = 0;
+
while (rest_of_selfids--) {
if (!sid->extended) {
nodeid++;
@@ -190,9 +194,11 @@
return 0;
}
- if (sid->contender && sid->link_active) {
- host->irm_id = LOCAL_BUS | sid->phy_id;
- }
+ if (sid->link_active) {
+ host->nodes_active++;
+ if (sid->contender)
+ host->irm_id = LOCAL_BUS | sid->phy_id;
+ }
} else {
esid = (struct ext_selfid *)sid;
@@ -226,7 +232,8 @@
return 0;
}
- return nodeid + 1;
+ host->node_count = nodeid + 1;
+ return 1;
}
static void build_speed_map(struct hpsb_host *host, int nodecount)
@@ -318,15 +325,17 @@
void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
{
+ if (!host->in_bus_reset)
+ HPSB_NOTICE("SelfID completion called outside of bus reset!");
+
host->node_id = LOCAL_BUS | phyid;
- host->in_bus_reset = 0;
host->is_root = isroot;
- host->node_count = check_selfids(host, host->selfid_count);
- if (!host->node_count) {
+ if (!check_selfids(host)) {
if (host->reset_retries++ < 20) {
/* selfid stage did not complete without error */
HPSB_NOTICE("Error in SelfID stage, resetting");
+ host->in_bus_reset = 0;
hpsb_reset_bus(host, LONG_RESET);
return;
} else {
@@ -346,8 +355,9 @@
}
host->reset_retries = 0;
- atomic_inc(&host->generation);
- if (isroot) host->template->devctl(host, ACT_CYCLE_MASTER, 1);
+ if (isroot) host->ops->devctl(host, ACT_CYCLE_MASTER, 1);
+ atomic_inc(&host->generation);
+ host->in_bus_reset = 0;
highlevel_host_reset(host);
}
@@ -402,7 +412,7 @@
{
struct hpsb_host *host = packet->host;
- if (!host->initialized || host->in_bus_reset
+ if (host->is_shutdown || host->in_bus_reset
|| (packet->generation != get_hpsb_generation(host))) {
return 0;
}
@@ -431,7 +441,7 @@
}
#endif
- return host->template->transmit_packet(host, packet);
+ return host->ops->transmit_packet(host, packet);
}
static void send_packet_nocare(struct hpsb_packet *packet)
@@ -727,7 +737,7 @@
struct list_head *lh;
LIST_HEAD(llist);
- host->template->devctl(host, CANCEL_REQUESTS, 0);
+ host->ops->devctl(host, CANCEL_REQUESTS, 0);
spin_lock_irqsave(&host->pending_pkt_lock, flags);
list_splice(&host->pending_packets, &llist);
@@ -786,14 +796,209 @@
}
+/*
+ * 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,
+};
+
+devfs_handle_t ieee1394_devfs_handle;
+
+
+/* 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);
+}
+
+/* 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 = -ENODEV;
+
+ /*
+ Maintaining correct module reference counts is tricky here!
+
+ For Linux v2.4 and later:
+
+ 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.
+
+ The comments below refer to the 2.4 case, since the 2.2
+ case is trivial.
+
+ */
+
+#define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \
+ if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0)
+#define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \
+ if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0)
+
+ /* shift away lower four bits of the minor
+ to get the index of the ieee1394_driver
+ we want */
+
+ blocknum = (minor(inode->i_rdev) >> 4) & 0xF;
+
+ /* printk("ieee1394_dispatch_open(%d)", blocknum); */
+
+ read_lock(&ieee1394_chardevs_lock);
+ module = ieee1394_chardevs[blocknum].module;
+ /* bump the reference count of the driver that
+ will receive the open() */
+ INCREF(module);
+ file_ops = ieee1394_chardevs[blocknum].file_ops;
+ read_unlock(&ieee1394_chardevs_lock);
+
+ if(file_ops == NULL) {
+ DECREF(module);
+ goto out_fail;
+ }
+
+ /* 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) {
+
+ /* if the open() failed, then we need to drop the
+ extra reference we gave to the task-specific
+ driver */
+
+ DECREF(module);
+ goto out_fail;
+
+ } else {
+
+ /* if the open() succeeded, then ieee1394 will be left
+ with an extra module reference, so we discard it here.*/
+
+ DECREF(THIS_MODULE);
+
+ /* the task-specific driver still has the extra
+ reference we gave it. 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. */
+
+ return 0;
+ }
+
+out_fail:
+ /* 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;
+ return retval;
+
+#undef INCREF
+#undef DECREF
+
+}
+
+struct proc_dir_entry *ieee1394_procfs_entry;
+
static int __init ieee1394_init(void)
{
hpsb_packet_cache = kmem_cache_create("hpsb_packet", sizeof(struct hpsb_packet),
0, 0, NULL, NULL);
+
+ ieee1394_devfs_handle = devfs_mk_dir(NULL, "ieee1394", NULL);
+
+ if (register_chrdev(IEEE1394_MAJOR, "ieee1394", &ieee1394_chardev_ops)) {
+ HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
+ devfs_unregister(ieee1394_devfs_handle);
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_PROC_FS
+ /* Must be done before we start everything else, since the drivers
+ * may use it. */
+ ieee1394_procfs_entry = proc_mkdir( "ieee1394", proc_bus);
+ if (ieee1394_procfs_entry == NULL) {
+ HPSB_ERR("unable to create /proc/bus/ieee1394\n");
+ unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
+ devfs_unregister(ieee1394_devfs_handle);
+ return -ENOMEM;
+ }
+ ieee1394_procfs_entry->owner = THIS_MODULE;
+#endif
+
init_hpsb_highlevel();
init_csr();
if (!disable_nodemgr)
- init_ieee1394_nodemgr();
+ init_ieee1394_nodemgr(disable_hotplug);
else
HPSB_INFO("nodemgr functionality disabled");
@@ -807,6 +1012,13 @@
cleanup_csr();
kmem_cache_destroy(hpsb_packet_cache);
+
+ unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
+
+ /* it's ok to pass a NULL devfs_handle to devfs_unregister */
+ devfs_unregister(ieee1394_devfs_handle);
+
+ remove_proc_entry("ieee1394", proc_bus);
}
module_init(ieee1394_init);
@@ -815,9 +1027,11 @@
/* Exported symbols */
EXPORT_SYMBOL(hpsb_register_lowlevel);
EXPORT_SYMBOL(hpsb_unregister_lowlevel);
-EXPORT_SYMBOL(hpsb_get_host);
-EXPORT_SYMBOL(hpsb_inc_host_usage);
-EXPORT_SYMBOL(hpsb_dec_host_usage);
+EXPORT_SYMBOL(hpsb_alloc_host);
+EXPORT_SYMBOL(hpsb_add_host);
+EXPORT_SYMBOL(hpsb_remove_host);
+EXPORT_SYMBOL(hpsb_ref_host);
+EXPORT_SYMBOL(hpsb_unref_host);
EXPORT_SYMBOL(hpsb_speedto_str);
EXPORT_SYMBOL(alloc_hpsb_packet);
@@ -867,12 +1081,19 @@
EXPORT_SYMBOL(highlevel_add_host);
EXPORT_SYMBOL(highlevel_remove_host);
EXPORT_SYMBOL(highlevel_host_reset);
-EXPORT_SYMBOL(highlevel_add_one_host);
EXPORT_SYMBOL(hpsb_guid_get_entry);
EXPORT_SYMBOL(hpsb_nodeid_get_entry);
-EXPORT_SYMBOL(hpsb_get_host_by_ne);
-EXPORT_SYMBOL(hpsb_guid_fill_packet);
+EXPORT_SYMBOL(hpsb_node_fill_packet);
+EXPORT_SYMBOL(hpsb_node_read);
+EXPORT_SYMBOL(hpsb_node_write);
+EXPORT_SYMBOL(hpsb_node_lock);
EXPORT_SYMBOL(hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol);
EXPORT_SYMBOL(hpsb_release_unit_directory);
+
+EXPORT_SYMBOL(ieee1394_register_chardev);
+EXPORT_SYMBOL(ieee1394_unregister_chardev);
+EXPORT_SYMBOL(ieee1394_devfs_handle);
+
+EXPORT_SYMBOL(ieee1394_procfs_entry);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)