# This is a BitKeeper generated patch for the following project:
# Project Name: greg k-h's linux 2.4 USB kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.783   -> 1.787  
#	drivers/hotplug/pci_hotplug.h	1.1     -> 1.2    
#	      kernel/ksyms.c	1.51    -> 1.52   
#	drivers/hotplug/pci_hotplug_core.c	1.8     -> 1.10   
#	drivers/hotplug/ibmphp_core.c	1.9     -> 1.10   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/09/17	scottm@somanetworks.com	1.784
# [PATCH] Small pcihpfs dnotify fix
# 
# I've been working on a userspace daemon to go with my CompactPCI driver,
# and yesterday I discovered an oversight in pci_hp_change_slot_info - it
# doesn't call dnotify_parent, so dnotify based clients basically don't
# work against pcihpfs.  The following patch (against 2.5 BK) reworks
# things to just update the mtime (since we're modifying the file after
# all), and then call dnotify_parent.
# --------------------------------------------
# 02/09/17	greg@kroah.com	1.785
# add __inode_dir_notify to ksyms.c so that dnotify can be used by filesystems
# in modules.
# --------------------------------------------
# 02/09/17	greg@kroah.com	1.786
# added max bus speed and current bus speed files to the pci hotplug core.
#   
# Patch based on work done by Irene Zubarev <zubarev@us.ibm.com>
# --------------------------------------------
# 02/09/17	greg@kroah.com	1.787
# uncommented max bus speed and current bus speed functions from the ibm pci hotplug driver
# --------------------------------------------
#
diff -Nru a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c
--- a/drivers/hotplug/ibmphp_core.c	Tue Sep 17 17:52:29 2002
+++ b/drivers/hotplug/ibmphp_core.c	Tue Sep 17 17:52:29 2002
@@ -384,14 +384,15 @@
 	debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
 	return rc;
 }
-/*
-static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value)
+
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
 	int rc = -ENODEV;
 	struct slot *pslot;
 	u8 mode = 0;
 
-	debug ("get_max_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+	debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__,
+		hotplug_slot, value);
 
 	ibmphp_lock_operations ();
 
@@ -413,25 +414,26 @@
 				*value = pslot->supported_speed + 0x01;
 				break;
 			default:
-*/				/* Note (will need to change): there would be soon 256, 512 also */
-/*				rc = -ENODEV;
+				/* Note (will need to change): there would be soon 256, 512 also */
+				rc = -ENODEV;
 			}
 		}
 	} else
 		rc = -ENODEV;
 
 	ibmphp_unlock_operations ();
-	debug ("get_max_bus_speed - Exit rc[%d] value[%x]\n", rc, *value);
+	debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value);
 	return rc;
 }
 
-static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value)
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
 	int rc = -ENODEV;
 	struct slot *pslot;
 	u8 mode = 0;
 
-	debug ("get_cur_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+	debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__,
+		hotplug_slot, value);
 
 	ibmphp_lock_operations ();
 
@@ -458,8 +460,8 @@
 					*value += 0x01;
 					break;
 				default:
-*/					/* Note of change: there would also be 256, 512 soon */
-/*					rc = -ENODEV;
+					/* Note of change: there would also be 256, 512 soon */
+					rc = -ENODEV;
 				}
 			}
 		}
@@ -467,10 +469,10 @@
 		rc = -ENODEV;
 
 	ibmphp_unlock_operations ();
-	debug ("get_cur_bus_speed - Exit rc[%d] value[%x]\n", rc, *value);
+	debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value);
 	return rc;
 }
-
+/*
 static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag)
 {
 	int rc = -ENODEV;
@@ -1579,9 +1581,9 @@
 	.get_attention_status =		get_attention_status,
 	.get_latch_status =		get_latch_status,
 	.get_adapter_status =		get_adapter_present,
-/*	.get_max_bus_speed_status =	get_max_bus_speed,
-	.get_max_adapter_speed_status =	get_max_adapter_speed,
+	.get_max_bus_speed_status =	get_max_bus_speed,
 	.get_cur_bus_speed_status =	get_cur_bus_speed,
+/*	.get_max_adapter_speed_status =	get_max_adapter_speed,
 	.get_bus_name_status =		get_bus_name,
 */
 };
diff -Nru a/drivers/hotplug/pci_hotplug.h b/drivers/hotplug/pci_hotplug.h
--- a/drivers/hotplug/pci_hotplug.h	Tue Sep 17 17:52:29 2002
+++ b/drivers/hotplug/pci_hotplug.h	Tue Sep 17 17:52:29 2002
@@ -29,6 +29,22 @@
 #define _PCI_HOTPLUG_H
 
 
+/* These values come from the PCI Hotplug Spec */
+enum pci_bus_speed {
+	PCI_SPEED_33MHz			= 0x00,
+	PCI_SPEED_66MHz			= 0x01,
+	PCI_SPEED_66MHz_PCIX		= 0x02,
+	PCI_SPEED_100MHz_PCIX		= 0x03,
+	PCI_SPEED_133MHz_PCIX		= 0x04,
+	PCI_SPEED_66MHz_PCIX_266	= 0x09,
+	PCI_SPEED_100MHz_PCIX_266	= 0x0a,
+	PCI_SPEED_133MHz_PCIX_266	= 0x0b,
+	PCI_SPEED_66MHz_PCIX_533	= 0x11,
+	PCI_SPEED_100MHz_PCIX_533	= 0X12,
+	PCI_SPEED_133MHz_PCIX_533	= 0x13,
+	PCI_SPEED_UNKNOWN		= 0xff,
+};
+
 struct hotplug_slot;
 struct hotplug_slot_core;
 
@@ -50,7 +66,13 @@
  * @get_latch_status: Called to get the current latch status of a slot.
  *	If this field is NULL, the value passed in the struct hotplug_slot_info
  *	will be used when this value is requested by a user.
- * @get_adapter_present: Called to get see if an adapter is present in the slot or not.
+ * @get_adapter_status: Called to get see if an adapter is present in the slot or not.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_max_bus_speed_status: Called to get the max bus speed for a slot.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_cur_bus_speed_status: Called to get the current bus speed for a slot.
  *	If this field is NULL, the value passed in the struct hotplug_slot_info
  *	will be used when this value is requested by a user.
  *
@@ -69,6 +91,8 @@
 	int (*get_attention_status)	(struct hotplug_slot *slot, u8 *value);
 	int (*get_latch_status)		(struct hotplug_slot *slot, u8 *value);
 	int (*get_adapter_status)	(struct hotplug_slot *slot, u8 *value);
+	int (*get_max_bus_speed_status)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+	int (*get_cur_bus_speed_status)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
 };
 
 /**
@@ -85,6 +109,8 @@
 	u8	attention_status;
 	u8	latch_status;
 	u8	adapter_status;
+	enum pci_bus_speed	max_bus_speed_status;
+	enum pci_bus_speed	cur_bus_speed_status;
 };
 
 /**
diff -Nru a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c
--- a/drivers/hotplug/pci_hotplug_core.c	Tue Sep 17 17:52:29 2002
+++ b/drivers/hotplug/pci_hotplug_core.c	Tue Sep 17 17:52:29 2002
@@ -37,6 +37,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/dnotify.h>
 #include <asm/uaccess.h>
 #include "pci_hotplug.h"
 
@@ -73,6 +74,8 @@
 	struct dentry	*latch_dentry;
 	struct dentry	*adapter_dentry;
 	struct dentry	*test_dentry;
+	struct dentry	*max_bus_speed_dentry;
+	struct dentry	*cur_bus_speed_dentry;
 };
 
 static struct super_operations pcihpfs_ops;
@@ -85,6 +88,29 @@
 
 LIST_HEAD(pci_hotplug_slot_list);
 
+/* these strings match up with the values in pci_bus_speed */
+static char *pci_bus_speed_strings[] = {
+	"33 MHz PCI",		/* 0x00 */
+	"66 MHz PCI",		/* 0x01 */
+	"66 MHz PCIX", 		/* 0x02 */
+	"100 MHz PCIX",		/* 0x03 */
+	"133 MHz PCIX",		/* 0x04 */
+	NULL,			/* 0x05 */
+	NULL,			/* 0x06 */
+	NULL,			/* 0x07 */
+	NULL,			/* 0x08 */
+	"66 MHz PCIX 266",	/* 0x09 */
+	"100 MHz PCIX 266",	/* 0x0a */
+	"133 MHz PCIX 266",	/* 0x0b */
+	NULL,			/* 0x0c */
+	NULL,			/* 0x0d */
+	NULL,			/* 0x0e */
+	NULL,			/* 0x0f */
+	NULL,			/* 0x10 */
+	"66 MHz PCIX 533",	/* 0x11 */
+	"100 MHz PCIX 533",	/* 0x12 */
+	"133 MHz PCIX 533",	/* 0x13 */
+};
 
 static int pcihpfs_statfs (struct super_block *sb, struct statfs *buf)
 {
@@ -279,6 +305,24 @@
 	llseek:		default_file_lseek,
 };
 
+/* file ops for the "max bus speed" files */
+static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
+static struct file_operations max_bus_speed_file_operations = {
+	read:		max_bus_speed_read_file,
+	write:		default_write_file,
+	open:		default_open,
+	llseek:		default_file_lseek,
+};
+
+/* file ops for the "current bus speed" files */
+static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
+static struct file_operations cur_bus_speed_file_operations = {
+	read:		cur_bus_speed_read_file,
+	write:		default_write_file,
+	open:		default_open,
+	llseek:		default_file_lseek,
+};
+
 /* file ops for the "test" files */
 static ssize_t test_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos);
 static struct file_operations test_file_operations = {
@@ -495,8 +539,8 @@
 	up(&parent->d_inode->i_sem);
 }
 
-#define GET_STATUS(name)	\
-static int get_##name##_status (struct hotplug_slot *slot, u8 *value)	\
+#define GET_STATUS(name,type)	\
+static int get_##name##_status (struct hotplug_slot *slot, type *value)	\
 {									\
 	struct hotplug_slot_ops *ops = slot->ops;			\
 	int retval = 0;							\
@@ -511,10 +555,12 @@
 	return retval;							\
 }
 
-GET_STATUS(power)
-GET_STATUS(attention)
-GET_STATUS(latch)
-GET_STATUS(adapter)
+GET_STATUS(power, u8)
+GET_STATUS(attention, u8)
+GET_STATUS(latch, u8)
+GET_STATUS(adapter, u8)
+GET_STATUS(max_bus_speed, enum pci_bus_speed)
+GET_STATUS(cur_bus_speed, enum pci_bus_speed)
 
 static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
 {
@@ -763,7 +809,6 @@
 	return retval;
 }
 
-
 static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
 {
 	struct hotplug_slot *slot = file->private_data;
@@ -807,6 +852,108 @@
 	return retval;
 }
 
+static char *unknown_speed = "Unknown bus speed";
+
+static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	struct hotplug_slot *slot = file->private_data;
+	unsigned char *page;
+	char *speed_string;
+	int retval;
+	int len = 0;
+	enum pci_bus_speed value;
+	
+	dbg ("count = %d, offset = %lld\n", count, *offset);
+
+	if (*offset < 0)
+		return -EINVAL;
+	if (count <= 0)
+		return 0;
+	if (*offset != 0)
+		return 0;
+
+	if (slot == NULL) {
+		dbg("slot == NULL???\n");
+		return -ENODEV;
+	}
+
+	page = (unsigned char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	retval = get_max_bus_speed_status (slot, &value);
+	if (retval)
+		goto exit;
+
+	if (value == PCI_SPEED_UNKNOWN)
+		speed_string = unknown_speed;
+	else
+		speed_string = pci_bus_speed_strings[value];
+	
+	len = sprintf (page, "%s\n", speed_string);
+
+	if (copy_to_user (buf, page, len)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+	*offset += len;
+	retval = len;
+
+exit:
+	free_page((unsigned long)page);
+	return retval;
+}
+
+static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	struct hotplug_slot *slot = file->private_data;
+	unsigned char *page;
+	char *speed_string;
+	int retval;
+	int len = 0;
+	enum pci_bus_speed value;
+
+	dbg ("count = %d, offset = %lld\n", count, *offset);
+
+	if (*offset < 0)
+		return -EINVAL;
+	if (count <= 0)
+		return 0;
+	if (*offset != 0)
+		return 0;
+
+	if (slot == NULL) {
+		dbg("slot == NULL???\n");
+		return -ENODEV;
+	}
+
+	page = (unsigned char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	retval = get_cur_bus_speed_status (slot, &value);
+	if (retval)
+		goto exit;
+
+	if (value == PCI_SPEED_UNKNOWN)
+		speed_string = unknown_speed;
+	else
+		speed_string = pci_bus_speed_strings[value];
+	
+	len = sprintf (page, "%s\n", speed_string);
+
+	if (copy_to_user (buf, page, len)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+	*offset += len;
+	retval = len;
+
+exit:
+	free_page((unsigned long)page);
+	return retval;
+}
+
 static ssize_t test_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
 {
 	struct hotplug_slot *slot = file->private_data;
@@ -870,30 +1017,57 @@
 					   S_IFDIR | S_IXUGO | S_IRUGO,
 					   NULL, NULL, NULL);
 	if (core->dir_dentry != NULL) {
-		core->power_dentry = fs_create_file ("power",
-						     S_IFREG | S_IRUGO | S_IWUSR,
-						     core->dir_dentry, slot,
-						     &power_file_operations);
-
-		core->attention_dentry = fs_create_file ("attention",
-							 S_IFREG | S_IRUGO | S_IWUSR,
-							 core->dir_dentry, slot,
-							 &attention_file_operations);
-
-		core->latch_dentry = fs_create_file ("latch",
-						     S_IFREG | S_IRUGO,
-						     core->dir_dentry, slot,
-						     &latch_file_operations);
-
-		core->adapter_dentry = fs_create_file ("adapter",
-						       S_IFREG | S_IRUGO,
-						       core->dir_dentry, slot,
-						       &presence_file_operations);
-
-		core->test_dentry = fs_create_file ("test",
-						    S_IFREG | S_IRUGO | S_IWUSR,
-						    core->dir_dentry, slot,
-						    &test_file_operations);
+		if ((slot->ops->enable_slot) ||
+		    (slot->ops->disable_slot) ||
+		    (slot->ops->get_power_status))
+			core->power_dentry = 
+				fs_create_file ("power",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						core->dir_dentry, slot,
+						&power_file_operations);
+
+		if ((slot->ops->set_attention_status) ||
+		    (slot->ops->get_attention_status))
+			core->attention_dentry =
+				fs_create_file ("attention",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						core->dir_dentry, slot,
+						&attention_file_operations);
+
+		if (slot->ops->get_latch_status)
+			core->latch_dentry = 
+				fs_create_file ("latch",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&latch_file_operations);
+
+		if (slot->ops->get_adapter_status)
+			core->adapter_dentry = 
+				fs_create_file ("adapter",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&presence_file_operations);
+
+		if (slot->ops->get_max_bus_speed_status)
+			core->max_bus_speed_dentry = 
+				fs_create_file ("max_bus_speed",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&max_bus_speed_file_operations);
+
+		if (slot->ops->get_cur_bus_speed_status)
+			core->cur_bus_speed_dentry =
+				fs_create_file ("cur_bus_speed",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&cur_bus_speed_file_operations);
+
+		if (slot->ops->hardware_test)
+			core->test_dentry =
+				fs_create_file ("test",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						core->dir_dentry, slot,
+						&test_file_operations);
 	}
 	return 0;
 }
@@ -911,6 +1085,10 @@
 			fs_remove_file (core->latch_dentry);
 		if (core->adapter_dentry)
 			fs_remove_file (core->adapter_dentry);
+		if (core->max_bus_speed_dentry)
+			fs_remove_file (core->max_bus_speed_dentry);
+		if (core->cur_bus_speed_dentry)
+			fs_remove_file (core->cur_bus_speed_dentry);
 		if (core->test_dentry)
 			fs_remove_file (core->test_dentry);
 		fs_remove_file (core->dir_dentry);
@@ -963,6 +1141,7 @@
 		return -EEXIST;
 	}
 
+	memset (core, 0, sizeof (struct hotplug_slot_core));
 	slot->core_priv = core;
 
 	list_add (&slot->slot_list, &pci_hotplug_slot_list);
@@ -1006,10 +1185,13 @@
 	return 0;
 }
 
-static inline void update_inode_time (struct inode *inode)
+static inline void update_dentry_inode_time (struct dentry *dentry)
 {
-	if (inode)
-		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	struct inode *inode = dentry->d_inode;
+	if (inode) {
+		inode->i_mtime = CURRENT_TIME;
+		dnotify_parent(dentry, DN_MODIFY);
+	}
 }
 
 /**
@@ -1044,16 +1226,19 @@
 	core = temp->core_priv;
 	if ((core->power_dentry) &&
 	    (temp->info->power_status != info->power_status))
-		update_inode_time (core->power_dentry->d_inode);
+		update_dentry_inode_time (core->power_dentry);
 	if ((core->attention_dentry) &&
 	    (temp->info->attention_status != info->attention_status))
-		update_inode_time (core->attention_dentry->d_inode);
+		update_dentry_inode_time (core->attention_dentry);
 	if ((core->latch_dentry) &&
 	    (temp->info->latch_status != info->latch_status))
-		update_inode_time (core->latch_dentry->d_inode);
+		update_dentry_inode_time (core->latch_dentry);
 	if ((core->adapter_dentry) &&
 	    (temp->info->adapter_status != info->adapter_status))
-		update_inode_time (core->adapter_dentry->d_inode);
+		update_dentry_inode_time (core->adapter_dentry);
+	if ((core->cur_bus_speed_dentry) &&
+	    (temp->info->cur_bus_speed_status != info->cur_bus_speed_status))
+		update_dentry_inode_time (core->cur_bus_speed_dentry);
 
 	memcpy (temp->info, info, sizeof (struct hotplug_slot_info));
 	spin_unlock (&list_lock);
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Tue Sep 17 17:52:29 2002
+++ b/kernel/ksyms.c	Tue Sep 17 17:52:29 2002
@@ -47,6 +47,7 @@
 #include <linux/in6.h>
 #include <linux/completion.h>
 #include <linux/seq_file.h>
+#include <linux/dnotify.h>
 #include <asm/checksum.h>
 
 #if defined(CONFIG_PROC_FS)
@@ -531,6 +532,7 @@
 EXPORT_SYMBOL(is_bad_inode);
 EXPORT_SYMBOL(event);
 EXPORT_SYMBOL(brw_page);
+EXPORT_SYMBOL(__inode_dir_notify);
 
 #ifdef CONFIG_UID16
 EXPORT_SYMBOL(overflowuid);
