
From: Corey Minyard <cminyard@mvista.com>

Here are some minor updates to the IPMI driver.  They fix the following:

    * A missing check for copy_to_user() in the watchdog driver.
    * Removal of unnecessary check_region() calls.
    * Fixes for the ACPI configuration. The previous one would only work
      with memory addresses, this will work with memory addresses,
      ports, and hadle checking that the type is correct.




 25-akpm/drivers/char/ipmi/ipmi_kcs_intf.c |  125 ++++++++++++++++++------------
 25-akpm/drivers/char/ipmi/ipmi_watchdog.c |    5 -
 2 files changed, 81 insertions(+), 49 deletions(-)

diff -puN drivers/char/ipmi/ipmi_kcs_intf.c~ipmi-update drivers/char/ipmi/ipmi_kcs_intf.c
--- 25/drivers/char/ipmi/ipmi_kcs_intf.c~ipmi-update	Mon Aug 11 13:54:40 2003
+++ 25-akpm/drivers/char/ipmi/ipmi_kcs_intf.c	Mon Aug 11 13:54:40 2003
@@ -1018,52 +1018,81 @@ static int init_one_kcs(int kcs_port, 
 
 #ifdef CONFIG_ACPI_INTERPRETER
 
-/* Retrieve the base physical address from ACPI tables.  Originally
-   from Hewlett-Packard simple bmc.c, a GPL KCS driver. */
-
 #include <linux/acpi.h>
 
 struct SPMITable {
-	s8	Signature[4];
-	u32	Length;
-	u8	Revision;
-	u8	Checksum;
-	s8	OEMID[6];
-	s8	OEMTableID[8];
-	s8	OEMRevision[4];
-	s8	CreatorID[4];
-	s8	CreatorRevision[4];
-	s16	InterfaceType;
-	s16	SpecificationRevision;
-	u8	InterruptType;
-	u8	GPE;
-	s16	Reserved;
-	u64	GlobalSystemInterrupt;
-	u8	BaseAddress[12];
-	u8	UID[4];
-} __attribute__ ((packed));
+	s8      Signature[4];
+	u32     Length;
+	u8      Revision;
+	u8      Checksum;
+	s8      OEMID[6];
+	s8      OEMTableID[8];
+	s8      OEMRevision[4];
+	s8      CreatorID[4];
+	s8      CreatorRevision[4];
+	u8      InterfaceType[2];
+	s16     SpecificationRevision;
+
+	/*
+	 * Bit 0 - SCI interrupt supported
+	 * Bit 1 - I/O APIC/SAPIC
+	 */
+	u8      InterruptType;
+
+	/* If bit 0 of InterruptType is set, then this is the SCI
+	   interrupt in the GPEx_STS register. */
+	u8      GPE;
+
+	s16     Reserved;
+
+	/* If bit 1 of InterruptType is set, then this is the I/O
+	   APIC/SAPIC interrupt. */
+	u32     GlobalSystemInterrupt;
+
+	/* The actual register address. */
+	struct acpi_generic_address addr;
 
-static unsigned long acpi_find_bmc(void)
-{
-	acpi_status status;
-	struct acpi_table_header *spmi;
-	static unsigned long io_base = 0;
+	u8      UID[4];
+
+	s8      spmi_id[1]; /* A '\0' terminated array starts here. */
+};
 
-	if (io_base != 0)
-		return io_base;
+static int acpi_find_bmc(unsigned long *physaddr, int *port)
+{
+	acpi_status          status;
+	struct SPMITable     *spmi;
 
 	status = acpi_get_firmware_table("SPMI", 1,
-			ACPI_LOGICAL_ADDRESSING, &spmi);
+					 ACPI_LOGICAL_ADDRESSING,
+					 (struct acpi_table_header **) &spmi);
+	if (status != AE_OK)
+		goto not_found;
+
+	if (spmi->InterfaceType[0] != 1)
+		/* Not IPMI. */
+		goto not_found;
+
+	if (spmi->InterfaceType[1] != 1)
+		/* Not KCS. */
+		goto not_found;
+
+	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+		*physaddr = spmi->addr.address;
+		printk("ipmi_kcs_intf: Found ACPI-specified state machine"
+		       " at memory address 0x%lx\n",
+		       (unsigned long) spmi->addr.address);
+	} else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+		*port = spmi->addr.address;
+		printk("ipmi_kcs_intf: Found ACPI-specified state machine"
+		       " at I/O address 0x%lx\n",
+		       (int) spmi->addr.address);
+	} else
+		goto not_found; /* Not an address type we recognise. */
 
-	if (status != AE_OK) {
-		printk(KERN_ERR "ipmi_kcs: SPMI table not found.\n");
-		return 0;
-	}
+	return 0;
 
-	memcpy(&io_base, ((struct SPMITable *)spmi)->BaseAddress,
-			sizeof(io_base));
-	
-	return io_base;
+ not_found:
+	return -ENODEV;
 }
 #endif
 
@@ -1074,6 +1103,7 @@ static __init int init_ipmi_kcs(void)
 	int		i = 0;
 #ifdef CONFIG_ACPI_INTERPRETER
 	unsigned long	physaddr = 0;
+	int             port = 0;
 #endif
 
 	if (initialized)
@@ -1101,20 +1131,19 @@ static __init int init_ipmi_kcs(void)
 	/* Only try the defaults if enabled and resources are available
 	   (because they weren't already specified above). */
 
-	if (kcs_trydefaults) {
+	if (kcs_trydefaults && (pos == 0)) {
+		rv = -EINVAL;
 #ifdef CONFIG_ACPI_INTERPRETER
-		if ((physaddr = acpi_find_bmc())) {
-			if (!check_mem_region(physaddr, 2)) {
-				rv = init_one_kcs(0, 
-						  0, 
-						  physaddr, 
-						  &(kcs_infos[pos]));
-				if (rv == 0)
-					pos++;
-			}
+		if (rv && (physaddr = acpi_find_bmc(&physaddr, &port) == 0)) {
+			rv = init_one_kcs(port,
+					  0,
+					  physaddr,
+					  &(kcs_infos[pos]));
+			if (rv == 0)
+				pos++;
 		}
 #endif
-		if (!check_region(DEFAULT_IO_PORT, 2)) {
+		if (rv) {
 			rv = init_one_kcs(DEFAULT_IO_PORT, 
 					  0, 
 					  0, 
diff -puN drivers/char/ipmi/ipmi_watchdog.c~ipmi-update drivers/char/ipmi/ipmi_watchdog.c
--- 25/drivers/char/ipmi/ipmi_watchdog.c~ipmi-update	Mon Aug 11 13:54:40 2003
+++ 25-akpm/drivers/char/ipmi/ipmi_watchdog.c	Mon Aug 11 13:54:40 2003
@@ -559,7 +559,10 @@ static int ipmi_ioctl(struct inode *inod
 
 	case WDIOC_GETSTATUS:
 		val = 0;
-		return copy_to_user((void *) arg, &val, sizeof(val));
+		i = copy_to_user((void *) arg, &val, sizeof(val));
+		if (i)
+			return -EFAULT;
+		return 0;
 
 	default:
 		return -ENOIOCTLCMD;

_
