X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fpci%2Fhotplug%2Facpiphp_core.c;h=40c79b03c7ef983b14e44532ddd35110dfa22d3a;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=51860a03f12fb71433ee354b8b777d6e89b0fb9a;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 51860a03f..40c79b03c 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -7,6 +7,8 @@ * 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. * @@ -25,106 +27,105 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to , - * + * Send feedback to * */ #include #include +#include #include #include +#include #include #include #include -#include "pci_hotplug.h" #include "acpiphp.h" -static LIST_HEAD(slot_list); - -#if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE) - #define MY_NAME "acpiphp" -#else - #define MY_NAME THIS_MODULE->name -#endif +#define MY_NAME "acpiphp" static int debug; int acpiphp_debug; /* local variables */ static int num_slots; +static struct acpiphp_attention_info *attention_info; -#define DRIVER_VERSION "0.4" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " +#define DRIVER_VERSION "0.5" +#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi , Matthew Wilcox " #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); +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 hardware_test (struct hotplug_slot *slot, u32 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_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); -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); static struct hotplug_slot_ops acpi_hotplug_slot_ops = { .owner = THIS_MODULE, .enable_slot = enable_slot, .disable_slot = disable_slot, .set_attention_status = set_attention_status, - .hardware_test = hardware_test, .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, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, }; -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int slot_paranoia_check (struct slot *slot, const char *function) +/** + * 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) { - if (!slot) { - dbg("%s - slot == NULL\n", function); - return -1; - } - if (slot->magic != SLOT_MAGIC) { - dbg("%s - bad magic number for slot\n", function); - return -1; - } - if (!slot->hotplug_slot) { - dbg("%s - slot->hotplug_slot == NULL!\n", function); - return -1; + int retval = -EINVAL; + + if (info && info->owner && info->set_attn && + info->get_attn && !attention_info) { + retval = 0; + attention_info = info; } - return 0; + return retval; } -static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +/** + * 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) { - struct slot *slot; + int retval = -EINVAL; - if (!hotplug_slot) { - dbg("%s - hotplug_slot == NULL\n", function); - return NULL; + if (info && attention_info == info) { + attention_info = NULL; + retval = 0; } - - slot = (struct slot *)hotplug_slot->private; - if (slot_paranoia_check(slot, function)) - return NULL; - return slot; + return retval; } @@ -135,20 +136,14 @@ static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const ch * Actual tasks are done in acpiphp_enable_slot() * */ -static int enable_slot (struct hotplug_slot *hotplug_slot) +static int enable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; + struct slot *slot = hotplug_slot->private; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); /* enable the specified slot */ - retval = acpiphp_enable_slot(slot->acpi_slot); - - return retval; + return acpiphp_enable_slot(slot->acpi_slot); } @@ -159,76 +154,40 @@ static int enable_slot (struct hotplug_slot *hotplug_slot) * Actual tasks are done in acpiphp_disable_slot() * */ -static int disable_slot (struct hotplug_slot *hotplug_slot) +static int disable_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; + struct slot *slot = hotplug_slot->private; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); /* disable the specified slot */ - retval = acpiphp_disable_slot(slot->acpi_slot); - - return retval; -} - - -/** - * set_attention_status - set attention LED - * - * TBD: - * ACPI doesn't have known method to manipulate - * attention status LED. - * - */ -static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) -{ - int retval = 0; - - 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 retval; + return acpiphp_disable_slot(slot->acpi_slot); } -/** - * hardware_test - hardware test + /** + * set_attention_status - set attention LED + * @hotplug_slot: slot to set attention LED on + * @status: value to set attention LED to (0 or 1) * - * We have nothing to do for now... - * - */ -static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - err("No hardware tests are defined for this driver\n"); - retval = -ENODEV; - + * 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 @@ -239,37 +198,39 @@ static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) * In that case, the value returned may not be reliable. * */ -static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; + struct slot *slot = hotplug_slot->private; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); *value = acpiphp_get_power_status(slot->acpi_slot); - return retval; + return 0; } -/** + /** * get_attention_status - get attention LED status + * @hotplug_slot: slot to get status from + * @value: returns with value of attention LED * - * TBD: - * ACPI doesn't provide any formal means to access attention LED status. - * - */ -static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) + * 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 = 0; + int retval = -EINVAL; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - *value = hotplug_slot->info->attention_status; - + 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; } @@ -283,19 +244,15 @@ static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) * Instead, we fake latch status from _STA * */ -static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; + struct slot *slot = hotplug_slot->private; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); *value = acpiphp_get_latch_status(slot->acpi_slot); - return retval; + return 0; } @@ -308,73 +265,35 @@ static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) * Instead, we fake adapter status from _STA * */ -static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; + struct slot *slot = hotplug_slot->private; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); *value = acpiphp_get_adapter_status(slot->acpi_slot); - return retval; + return 0; } /** * 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) +static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; + struct slot *slot = hotplug_slot->private; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); *value = acpiphp_get_address(slot->acpi_slot); - return retval; -} - - -/* return dummy value because ACPI doesn't provide any method... */ -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if (slot == NULL) - return -ENODEV; - - *value = PCI_SPEED_UNKNOWN; - return 0; } - -/* return dummy value because ACPI doesn't provide any method... */ -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if (slot == NULL) - return -ENODEV; - - *value = PCI_SPEED_UNKNOWN; - - return 0; -} - - -static int __init init_acpi (void) +static int __init init_acpi(void) { int retval; @@ -384,154 +303,106 @@ static int __init init_acpi (void) /* read initial number of slots */ if (!retval) { num_slots = acpiphp_get_num_slots(); - if (num_slots == 0) + if (num_slots == 0) { + acpiphp_glue_exit(); retval = -ENODEV; + } } return retval; } - -/** - * make_slot_name - make a slot name that appears in pcihpfs - * @slot: slot to name - * - */ -static void make_slot_name (struct slot *slot) -{ - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%u", - slot->acpi_slot->sun); -} - /** * release_slot - free up the memory used by a slot * @hotplug_slot: slot to free */ static void release_slot(struct hotplug_slot *hotplug_slot) { - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if (slot == NULL) - return; + struct slot *slot = hotplug_slot->private; dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); kfree(slot); } -/** - * init_slots - initialize 'struct slot' structures for each slot - * - */ -static int __init init_slots (void) +/* callback routine to initialize 'struct slot' for each slot */ +int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) { struct slot *slot; - int retval = 0; - int i; - - for (i = 0; i < num_slots; ++i) { - slot = kmalloc(sizeof(struct slot), GFP_KERNEL); - if (!slot) - return -ENOMEM; - memset(slot, 0, sizeof(struct slot)); - - slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL); - if (!slot->hotplug_slot) { - kfree(slot); - return -ENOMEM; - } - memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); + int retval = -ENOMEM; - slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); - if (!slot->hotplug_slot->info) { - kfree(slot->hotplug_slot); - kfree(slot); - return -ENOMEM; - } - memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info)); - - slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if (!slot->hotplug_slot->name) { - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot); - kfree(slot); - return -ENOMEM; - } + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) + goto error; - slot->magic = SLOT_MAGIC; - slot->number = i; + slot->hotplug_slot = kzalloc(sizeof(*slot->hotplug_slot), GFP_KERNEL); + if (!slot->hotplug_slot) + goto error_slot; - slot->hotplug_slot->private = slot; - slot->hotplug_slot->release = &release_slot; - slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; + slot->hotplug_slot->info = &slot->info; - 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->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->name = slot->name; - make_slot_name(slot); + slot->hotplug_slot->private = slot; + slot->hotplug_slot->release = &release_slot; + slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; - retval = pci_hp_register(slot->hotplug_slot); - if (retval) { - err("pci_hp_register failed with error %d\n", retval); - release_slot(slot->hotplug_slot); - return retval; - } + slot->acpi_slot = acpiphp_slot; + slot->hotplug_slot->info->power_status = acpiphp_get_power_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; + slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; - /* add slot to our internal list */ - list_add(&slot->slot_list, &slot_list); - info("Slot [%s] registered\n", slot->hotplug_slot->name); - } + acpiphp_slot->slot = slot; + snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun); + + retval = pci_hp_register(slot->hotplug_slot); + if (retval) { + err("pci_hp_register failed with error %d\n", retval); + goto error_hpslot; + } + info("Slot [%s] registered\n", slot->hotplug_slot->name); + + return 0; +error_hpslot: + kfree(slot->hotplug_slot); +error_slot: + kfree(slot); +error: return retval; } -static void __exit cleanup_slots (void) +void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot) { - struct list_head *tmp, *n; - struct slot *slot; + struct slot *slot = acpiphp_slot->slot; + int retval = 0; - list_for_each_safe (tmp, n, &slot_list) { - /* memory will be freed in release_slot callback */ - slot = list_entry(tmp, struct slot, slot_list); - list_del(&slot->slot_list); - pci_hp_deregister(slot->hotplug_slot); - } + info ("Slot [%s] unregistered\n", slot->hotplug_slot->name); - return; + retval = pci_hp_deregister(slot->hotplug_slot); + if (retval) + err("pci_hp_deregister failed with error %d\n", retval); } static int __init acpiphp_init(void) { - int retval; - info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); acpiphp_debug = debug; /* read all the ACPI info from the system */ - retval = init_acpi(); - if (retval) - return retval; - - retval = init_slots(); - if (retval) - return retval; - - return 0; + return init_acpi(); } static void __exit acpiphp_exit(void) { - cleanup_slots(); /* deallocate internal data structures etc. */ acpiphp_glue_exit(); }