vserver 1.9.5.x5
[linux-2.6.git] / drivers / pci / hotplug / acpiphp_ibm.c
index fe7866c..7e7f913 100644 (file)
@@ -47,7 +47,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 +64,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 +86,7 @@ union apci_descriptor {
                u8  attn;
                u8  status[2];
                u8  sun;
+               u8  res[3];
        } slot;
        struct {
                u8 type;
@@ -128,6 +131,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 +179,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 +223,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;
 }
 
 /**