* Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
* Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
* Copyright (C) 2002,2003 NEC Corporation
+ * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
+ * Copyright (C) 2003-2005 Hewlett Packard
*
* All rights reserved.
*
/* local variables */
static int num_slots;
+static struct acpiphp_attention_info *attention_info;
-#define DRIVER_VERSION "0.4"
-#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>"
+#define DRIVER_VERSION "0.5"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>, Matthew Wilcox <willy@hp.com>"
#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
-module_param(debug, bool, 644);
+module_param(debug, bool, 0644);
+
+/* export the attention callback registration methods */
+EXPORT_SYMBOL_GPL(acpiphp_register_attention);
+EXPORT_SYMBOL_GPL(acpiphp_unregister_attention);
static int enable_slot (struct hotplug_slot *slot);
static int disable_slot (struct hotplug_slot *slot);
static int set_attention_status (struct hotplug_slot *slot, u8 value);
static int get_power_status (struct hotplug_slot *slot, u8 *value);
+static int get_attention_status (struct hotplug_slot *slot, u8 *value);
static int get_address (struct hotplug_slot *slot, u32 *value);
static int get_latch_status (struct hotplug_slot *slot, u8 *value);
static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
.disable_slot = disable_slot,
.set_attention_status = set_attention_status,
.get_power_status = get_power_status,
+ .get_attention_status = get_attention_status,
.get_latch_status = get_latch_status,
.get_adapter_status = get_adapter_status,
.get_address = get_address,
};
+
+/**
+ * acpiphp_register_attention - set attention LED callback
+ * @info: must be completely filled with LED callbacks
+ *
+ * Description: this is used to register a hardware specific ACPI
+ * driver that manipulates the attention LED. All the fields in
+ * info must be set.
+ **/
+int acpiphp_register_attention(struct acpiphp_attention_info *info)
+{
+ int retval = -EINVAL;
+
+ if (info && info->owner && info->set_attn &&
+ info->get_attn && !attention_info) {
+ retval = 0;
+ attention_info = info;
+ }
+ return retval;
+}
+
+
+/**
+ * acpiphp_unregister_attention - unset attention LED callback
+ * @info: must match the pointer used to register
+ *
+ * Description: this is used to un-register a hardware specific acpi
+ * driver that manipulates the attention LED. The pointer to the
+ * info struct must be the same as the one used to set it.
+ **/
+int acpiphp_unregister_attention(struct acpiphp_attention_info *info)
+{
+ int retval = -EINVAL;
+
+ if (info && attention_info == info) {
+ attention_info = NULL;
+ retval = 0;
+ }
+ return retval;
+}
+
+
/**
* enable_slot - power on and enable a slot
* @hotplug_slot: slot to enable
}
-/**
- * set_attention_status - set attention LED
+ /**
+ * set_attention_status - set attention LED
+ * @hotplug_slot: slot to set attention LED on
+ * @status: value to set attention LED to (0 or 1)
*
- * TBD:
- * ACPI doesn't have known method to manipulate
- * attention status LED.
- *
- */
-static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
-{
- dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-
- switch (status) {
- case 0:
- /* FIXME turn light off */
- hotplug_slot->info->attention_status = 0;
- break;
-
- case 1:
- default:
- /* FIXME turn light on */
- hotplug_slot->info->attention_status = 1;
- break;
- }
-
- return 0;
-}
+ * attention status LED, so we use a callback that
+ * was registered with us. This allows hardware specific
+ * ACPI implementations to blink the light for us.
+ **/
+ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
+ {
+ int retval = -ENODEV;
+
+ dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+ if (attention_info && try_module_get(attention_info->owner)) {
+ retval = attention_info->set_attn(hotplug_slot, status);
+ module_put(attention_info->owner);
+ } else
+ attention_info = NULL;
+ return retval;
+ }
+
/**
* get_power_status - get power status of a slot
return 0;
}
+
+ /**
+ * get_attention_status - get attention LED status
+ * @hotplug_slot: slot to get status from
+ * @value: returns with value of attention LED
+ *
+ * ACPI doesn't have known method to determine the state
+ * of the attention status LED, so we use a callback that
+ * was registered with us. This allows hardware specific
+ * ACPI implementations to determine its state
+ **/
+static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+ int retval = -EINVAL;
+
+ dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+ if (attention_info && try_module_get(attention_info->owner)) {
+ retval = attention_info->get_attn(hotplug_slot, value);
+ module_put(attention_info->owner);
+ } else
+ attention_info = NULL;
+ return retval;
+}
+
+
/**
* get_latch_status - get latch status of a slot
* @hotplug_slot: slot to get status
/**
* get_address - get pci address of a slot
* @hotplug_slot: slot to get status
- * @busdev: pointer to struct pci_busdev (seg, bus, dev)
- *
+ * @value: pointer to struct pci_busdev (seg, bus, dev)
*/
static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
{
slot->acpi_slot = get_slot_from_id(i);
slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
- slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot);
+ slot->hotplug_slot->info->attention_status = 0;
slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;