fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / pci / hotplug / acpiphp_ibm.c
index fe7866c..7f03881 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/moduleparam.h>
 
 #include "acpiphp.h"
-#include "pci_hotplug.h"
 
 #define DRIVER_VERSION "1.0.1"
 #define DRIVER_AUTHOR  "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"
@@ -47,7 +46,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRIVER_VERSION);
-module_param(debug, bool, 644);
+module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, " Debugging mode enabled or not");
 #define MY_NAME "acpiphp_ibm"
 
@@ -64,6 +63,8 @@ do {                                                  \
 #define IBM_HARDWARE_ID1 "IBM37D0"
 #define IBM_HARDWARE_ID2 "IBM37D4"
 
+#define hpslot_to_sun(A) (((struct slot *)((A)->private))->acpi_slot->sun)
+
 /* union apci_descriptor - allows access to the
  * various device descriptors that are embedded in the
  * aPCI table
@@ -84,6 +85,7 @@ union apci_descriptor {
                u8  attn;
                u8  status[2];
                u8  sun;
+               u8  res[3];
        } slot;
        struct {
                u8 type;
@@ -128,6 +130,43 @@ static struct acpiphp_attention_info ibm_attention_info =
        .owner = THIS_MODULE,
 };
 
+/**
+ * ibm_slot_from_id - workaround for bad ibm hardware
+ * @id: the slot number that linux refers to the slot by
+ *
+ * Description: this method returns the aCPI slot descriptor
+ * corresponding to the Linux slot number.  This descriptor
+ * has info about the aPCI slot id and attention status.
+ * This descriptor must be freed using kfree when done.
+ **/
+static union apci_descriptor *ibm_slot_from_id(int id)
+{
+       int ind = 0, size;
+       union apci_descriptor *ret = NULL, *des;
+       char *table;
+
+       size = ibm_get_table_from_acpi(&table);
+       des = (union apci_descriptor *)table;
+       if (memcmp(des->header.sig, "aPCI", 4) != 0)
+               goto ibm_slot_done;
+
+       des = (union apci_descriptor *)&table[ind += des->header.len];
+       while (ind < size && (des->generic.type != 0x82 ||
+                       des->slot.slot_num != id)) {
+               des = (union apci_descriptor *)&table[ind += des->generic.len];
+       }
+
+       if (ind < size && des->slot.slot_num == id)
+               ret = des;
+
+ibm_slot_done:
+       if (ret) {
+               ret = kmalloc(sizeof(union apci_descriptor), GFP_KERNEL);
+               memcpy(ret, des, sizeof(union apci_descriptor));
+       }
+       kfree(table);
+       return ret;
+}
 
 /**
  * ibm_set_attention_status - callback method to set the attention LED
@@ -139,32 +178,34 @@ static struct acpiphp_attention_info ibm_attention_info =
  **/
 static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status)
 {
-       int retval = 0;
        union acpi_object args[2]; 
        struct acpi_object_list params = { .pointer = args, .count = 2 };
        acpi_status stat; 
-       unsigned long rc = 0;
-       struct acpiphp_slot *acpi_slot;
+       unsigned long rc;
+       union apci_descriptor *ibm_slot;
 
-       acpi_slot = ((struct slot *)(slot->private))->acpi_slot;
+       ibm_slot = ibm_slot_from_id(hpslot_to_sun(slot));
 
-       dbg("%s: set slot %d attention status to %d\n", __FUNCTION__,
-                       acpi_slot->sun, (status ? 1 : 0));
+       dbg("%s: set slot %d (%d) attention status to %d\n", __FUNCTION__,
+                       ibm_slot->slot.slot_num, ibm_slot->slot.slot_id,
+                       (status ? 1 : 0));
 
        args[0].type = ACPI_TYPE_INTEGER;
-       args[0].integer.value = acpi_slot->sun;
+       args[0].integer.value = ibm_slot->slot.slot_id;
        args[1].type = ACPI_TYPE_INTEGER;
        args[1].integer.value = (status) ? 1 : 0;
 
+       kfree(ibm_slot);
+
        stat = acpi_evaluate_integer(ibm_acpi_handle, "APLS", &params, &rc);
        if (ACPI_FAILURE(stat)) {
-               retval = -ENODEV;
                err("APLS evaluation failed:  0x%08x\n", stat);
+               return -ENODEV;
        } else if (!rc) {
-               retval = -ERANGE;
                err("APLS method failed:  0x%08lx\n", rc);
+               return -ERANGE;
        }
-       return retval;
+       return 0;
 }
 
 /**
@@ -181,38 +222,21 @@ static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status)
  **/
 static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status)
 {
-       int retval = -EINVAL, ind = 0, size;
-       char *table = NULL;
-       struct acpiphp_slot *acpi_slot;
-       union apci_descriptor *des;
+       union apci_descriptor *ibm_slot;
 
-       acpi_slot = ((struct slot *)(slot->private))->acpi_slot;
+       ibm_slot = ibm_slot_from_id(hpslot_to_sun(slot));
 
-       size = ibm_get_table_from_acpi(&table);
-       if (size <= 0 || !table)
-               goto get_attn_done;
-       // read the header
-       des = (union apci_descriptor *)&table[ind];
-       if (memcmp(des->header.sig, "aPCI", 4) != 0)
-               goto get_attn_done;
-       des = (union apci_descriptor *)&table[ind += des->header.len];
-       while (ind < size && (des->generic.type != 0x82 ||
-                       des->slot.slot_id != acpi_slot->sun))
-               des = (union apci_descriptor *)&table[ind += des->generic.len];
-       if (ind < size && des->slot.slot_id == acpi_slot->sun) {
-               retval = 0;
-               if (des->slot.attn & 0xa0 || des->slot.status[1] & 0x08)
-                       *status = 1;
-               else
-                       *status = 0;
-       }
+       if (ibm_slot->slot.attn & 0xa0 || ibm_slot->slot.status[1] & 0x08)
+               *status = 1;
+       else
+               *status = 0;
 
-       dbg("%s: get slot %d attention status is %d retval=%x\n",
-                       __FUNCTION__, acpi_slot->sun, *status, retval);
+       dbg("%s: get slot %d (%d) attention status is %d\n", __FUNCTION__,
+                       ibm_slot->slot.slot_num, ibm_slot->slot.slot_id,
+                       *status);
 
-get_attn_done:
-       kfree(table);
-       return retval;
+       kfree(ibm_slot);
+       return 0;
 }
 
 /**
@@ -277,7 +301,7 @@ static int ibm_get_table_from_acpi(char **bufp)
        }
 
        package = (union acpi_object *) buffer.pointer;
-       if(!(package) ||
+       if (!(package) ||
                        (package->type != ACPI_TYPE_PACKAGE) ||
                        !(package->package.elements)) {
                err("%s:  Invalid APCI object\n", __FUNCTION__);
@@ -295,13 +319,12 @@ static int ibm_get_table_from_acpi(char **bufp)
        if (bufp == NULL)
                goto read_table_done;
 
-       lbuf = kmalloc(size, GFP_KERNEL);
+       lbuf = kzalloc(size, GFP_KERNEL);
        dbg("%s: element count: %i, ASL table size: %i, &table = 0x%p\n",
                        __FUNCTION__, package->package.count, size, lbuf);
 
        if (lbuf) {
                *bufp = lbuf;
-               memset(lbuf, 0, size);
        } else {
                size = -ENOMEM;
                goto read_table_done;
@@ -380,7 +403,7 @@ static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
        }
        info.hardware_id.value[sizeof(info.hardware_id.value) - 1] = '\0';
 
-       if(info.current_status && (info.valid & ACPI_VALID_HID) &&
+       if (info.current_status && (info.valid & ACPI_VALID_HID) &&
                        (!strcmp(info.hardware_id.value, IBM_HARDWARE_ID1) ||
                        !strcmp(info.hardware_id.value, IBM_HARDWARE_ID2))) {
                dbg("found hardware: %s, handle: %p\n", info.hardware_id.value,
@@ -424,13 +447,11 @@ static int __init ibm_acpiphp_init(void)
        }
 
        ibm_note.device = device;
-       status = acpi_install_notify_handler(
-                       ibm_acpi_handle,
-                       ACPI_DEVICE_NOTIFY,
-                       ibm_handle_events,
+       status = acpi_install_notify_handler(ibm_acpi_handle,
+                       ACPI_DEVICE_NOTIFY, ibm_handle_events,
                        &ibm_note);
        if (ACPI_FAILURE(status)) {
-               err("%s:  Failed to register notification handler\n",
+               err("%s: Failed to register notification handler\n",
                                __FUNCTION__);
                retval = -EBUSY;
                goto init_cleanup;
@@ -457,17 +478,14 @@ static void __exit ibm_acpiphp_exit(void)
        if (acpiphp_unregister_attention(&ibm_attention_info))
                err("%s: attention info deregistration failed", __FUNCTION__);
 
-          status = acpi_remove_notify_handler(
+       status = acpi_remove_notify_handler(
                           ibm_acpi_handle,
                           ACPI_DEVICE_NOTIFY,
                           ibm_handle_events);
-          if (ACPI_FAILURE(status))
-                  err("%s:  Notification handler removal failed\n",
-                                  __FUNCTION__);
-       // remove the /sys entries
-       if (sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr))
-               err("%s: removal of sysfs file apci_table failed\n",
-                               __FUNCTION__);
+       if (ACPI_FAILURE(status))
+               err("%s: Notification handler removal failed\n", __FUNCTION__);
+       /* remove the /sys entries */
+       sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr);
 }
 
 module_init(ibm_acpiphp_init);