#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>"
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"
#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
u8 attn;
u8 status[2];
u8 sun;
+ u8 res[3];
} slot;
struct {
u8 type;
.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
**/
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", ¶ms, &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;
}
/**
**/
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;
}
/**
}
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__);
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;
}
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,
}
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;
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);