2  * ACPI PCI Hot Plug Controller Driver
 
   4  * Copyright (C) 1995,2001 Compaq Computer Corporation
 
   5  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
 
   6  * Copyright (C) 2001 IBM Corp.
 
   7  * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
 
   8  * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
 
   9  * Copyright (C) 2002,2003 NEC Corporation
 
  10  * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
 
  11  * Copyright (C) 2003-2005 Hewlett Packard
 
  13  * All rights reserved.
 
  15  * This program is free software; you can redistribute it and/or modify
 
  16  * it under the terms of the GNU General Public License as published by
 
  17  * the Free Software Foundation; either version 2 of the License, or (at
 
  18  * your option) any later version.
 
  20  * This program is distributed in the hope that it will be useful, but
 
  21  * WITHOUT ANY WARRANTY; without even the implied warranty of
 
  22  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
 
  23  * NON INFRINGEMENT.  See the GNU General Public License for more
 
  26  * You should have received a copy of the GNU General Public License
 
  27  * along with this program; if not, write to the Free Software
 
  28  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
  30  * Send feedback to <kristen.c.accardi@intel.com>
 
  34 #include <linux/init.h>
 
  35 #include <linux/module.h>
 
  36 #include <linux/moduleparam.h>
 
  38 #include <linux/kernel.h>
 
  39 #include <linux/pci.h>
 
  40 #include <linux/pci_hotplug.h>
 
  41 #include <linux/slab.h>
 
  42 #include <linux/smp.h>
 
  45 #define MY_NAME "acpiphp"
 
  47 /* name size which is used for entries in pcihpfs */
 
  48 #define SLOT_NAME_SIZE  21              /* {_SUN} */
 
  55 static struct acpiphp_attention_info *attention_info;
 
  57 #define DRIVER_VERSION  "0.5"
 
  58 #define DRIVER_AUTHOR   "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>, Matthew Wilcox <willy@hp.com>"
 
  59 #define DRIVER_DESC     "ACPI Hot Plug PCI Controller Driver"
 
  61 MODULE_AUTHOR(DRIVER_AUTHOR);
 
  62 MODULE_DESCRIPTION(DRIVER_DESC);
 
  63 MODULE_LICENSE("GPL");
 
  64 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
 
  65 module_param(debug, bool, 0644);
 
  67 /* export the attention callback registration methods */
 
  68 EXPORT_SYMBOL_GPL(acpiphp_register_attention);
 
  69 EXPORT_SYMBOL_GPL(acpiphp_unregister_attention);
 
  71 static int enable_slot          (struct hotplug_slot *slot);
 
  72 static int disable_slot         (struct hotplug_slot *slot);
 
  73 static int set_attention_status (struct hotplug_slot *slot, u8 value);
 
  74 static int get_power_status     (struct hotplug_slot *slot, u8 *value);
 
  75 static int get_attention_status (struct hotplug_slot *slot, u8 *value);
 
  76 static int get_latch_status     (struct hotplug_slot *slot, u8 *value);
 
  77 static int get_adapter_status   (struct hotplug_slot *slot, u8 *value);
 
  79 static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
 
  81         .enable_slot            = enable_slot,
 
  82         .disable_slot           = disable_slot,
 
  83         .set_attention_status   = set_attention_status,
 
  84         .get_power_status       = get_power_status,
 
  85         .get_attention_status   = get_attention_status,
 
  86         .get_latch_status       = get_latch_status,
 
  87         .get_adapter_status     = get_adapter_status,
 
  91  * acpiphp_register_attention - set attention LED callback
 
  92  * @info: must be completely filled with LED callbacks
 
  94  * Description: This is used to register a hardware specific ACPI
 
  95  * driver that manipulates the attention LED.  All the fields in
 
  98 int acpiphp_register_attention(struct acpiphp_attention_info *info)
 
 100         int retval = -EINVAL;
 
 102         if (info && info->owner && info->set_attn &&
 
 103                         info->get_attn && !attention_info) {
 
 105                 attention_info = info;
 
 112  * acpiphp_unregister_attention - unset attention LED callback
 
 113  * @info: must match the pointer used to register
 
 115  * Description: This is used to un-register a hardware specific acpi
 
 116  * driver that manipulates the attention LED.  The pointer to the 
 
 117  * info struct must be the same as the one used to set it.
 
 119 int acpiphp_unregister_attention(struct acpiphp_attention_info *info)
 
 121         int retval = -EINVAL;
 
 123         if (info && attention_info == info) {
 
 124                 attention_info = NULL;
 
 132  * enable_slot - power on and enable a slot
 
 133  * @hotplug_slot: slot to enable
 
 135  * Actual tasks are done in acpiphp_enable_slot()
 
 137 static int enable_slot(struct hotplug_slot *hotplug_slot)
 
 139         struct slot *slot = hotplug_slot->private;
 
 141         dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
 
 143         /* enable the specified slot */
 
 144         return acpiphp_enable_slot(slot->acpi_slot);
 
 149  * disable_slot - disable and power off a slot
 
 150  * @hotplug_slot: slot to disable
 
 152  * Actual tasks are done in acpiphp_disable_slot()
 
 154 static int disable_slot(struct hotplug_slot *hotplug_slot)
 
 156         struct slot *slot = hotplug_slot->private;
 
 159         dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
 
 161         /* disable the specified slot */
 
 162         retval = acpiphp_disable_slot(slot->acpi_slot);
 
 164                 retval = acpiphp_eject_slot(slot->acpi_slot);
 
 170  * set_attention_status - set attention LED
 
 171  * @hotplug_slot: slot to set attention LED on
 
 172  * @status: value to set attention LED to (0 or 1)
 
 174  * attention status LED, so we use a callback that
 
 175  * was registered with us.  This allows hardware specific
 
 176  * ACPI implementations to blink the light for us.
 
 178  static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
 
 180         int retval = -ENODEV;
 
 182         dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot));
 
 184         if (attention_info && try_module_get(attention_info->owner)) {
 
 185                 retval = attention_info->set_attn(hotplug_slot, status);
 
 186                 module_put(attention_info->owner);
 
 188                 attention_info = NULL;
 
 194  * get_power_status - get power status of a slot
 
 195  * @hotplug_slot: slot to get status
 
 196  * @value: pointer to store status
 
 198  * Some platforms may not implement _STA method properly.
 
 199  * In that case, the value returned may not be reliable.
 
 201 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
 
 203         struct slot *slot = hotplug_slot->private;
 
 205         dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
 
 207         *value = acpiphp_get_power_status(slot->acpi_slot);
 
 214  * get_attention_status - get attention LED status
 
 215  * @hotplug_slot: slot to get status from
 
 216  * @value: returns with value of attention LED
 
 218  * ACPI doesn't have known method to determine the state
 
 219  * of the attention status LED, so we use a callback that
 
 220  * was registered with us.  This allows hardware specific
 
 221  * ACPI implementations to determine its state.
 
 223 static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
 
 225         int retval = -EINVAL;
 
 227         dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot));
 
 229         if (attention_info && try_module_get(attention_info->owner)) {
 
 230                 retval = attention_info->get_attn(hotplug_slot, value);
 
 231                 module_put(attention_info->owner);
 
 233                 attention_info = NULL;
 
 239  * get_latch_status - get latch status of a slot
 
 240  * @hotplug_slot: slot to get status
 
 241  * @value: pointer to store status
 
 243  * ACPI doesn't provide any formal means to access latch status.
 
 244  * Instead, we fake latch status from _STA.
 
 246 static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
 
 248         struct slot *slot = hotplug_slot->private;
 
 250         dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
 
 252         *value = acpiphp_get_latch_status(slot->acpi_slot);
 
 259  * get_adapter_status - get adapter status of a slot
 
 260  * @hotplug_slot: slot to get status
 
 261  * @value: pointer to store status
 
 263  * ACPI doesn't provide any formal means to access adapter status.
 
 264  * Instead, we fake adapter status from _STA.
 
 266 static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
 
 268         struct slot *slot = hotplug_slot->private;
 
 270         dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
 
 272         *value = acpiphp_get_adapter_status(slot->acpi_slot);
 
 277 static int __init init_acpi(void)
 
 281         /* initialize internal data structure etc. */
 
 282         retval = acpiphp_glue_init();
 
 284         /* read initial number of slots */
 
 286                 num_slots = acpiphp_get_num_slots();
 
 287                 if (num_slots == 0) {
 
 297  * release_slot - free up the memory used by a slot
 
 298  * @hotplug_slot: slot to free
 
 300 static void release_slot(struct hotplug_slot *hotplug_slot)
 
 302         struct slot *slot = hotplug_slot->private;
 
 304         dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
 
 306         kfree(slot->hotplug_slot);
 
 310 /* callback routine to initialize 'struct slot' for each slot */
 
 311 int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
 
 314         int retval = -ENOMEM;
 
 315         char name[SLOT_NAME_SIZE];
 
 317         slot = kzalloc(sizeof(*slot), GFP_KERNEL);
 
 321         slot->hotplug_slot = kzalloc(sizeof(*slot->hotplug_slot), GFP_KERNEL);
 
 322         if (!slot->hotplug_slot)
 
 325         slot->hotplug_slot->info = &slot->info;
 
 327         slot->hotplug_slot->private = slot;
 
 328         slot->hotplug_slot->release = &release_slot;
 
 329         slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
 
 331         slot->acpi_slot = acpiphp_slot;
 
 332         slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
 
 333         slot->hotplug_slot->info->attention_status = 0;
 
 334         slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
 
 335         slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
 
 336         slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
 
 337         slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
 
 339         acpiphp_slot->slot = slot;
 
 340         snprintf(name, SLOT_NAME_SIZE, "%llu", slot->acpi_slot->sun);
 
 342         retval = pci_hp_register(slot->hotplug_slot,
 
 343                                         acpiphp_slot->bridge->pci_bus,
 
 344                                         acpiphp_slot->device,
 
 346         if (retval == -EBUSY)
 
 349                 err("pci_hp_register failed with error %d\n", retval);
 
 353         info("Slot [%s] registered\n", slot_name(slot));
 
 357         kfree(slot->hotplug_slot);
 
 365 void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
 
 367         struct slot *slot = acpiphp_slot->slot;
 
 370         info("Slot [%s] unregistered\n", slot_name(slot));
 
 372         retval = pci_hp_deregister(slot->hotplug_slot);
 
 374                 err("pci_hp_deregister failed with error %d\n", retval);
 
 378 static int __init acpiphp_init(void)
 
 380         info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
 
 382         if (acpi_pci_disabled)
 
 385         acpiphp_debug = debug;
 
 387         /* read all the ACPI info from the system */
 
 392 static void __exit acpiphp_exit(void)
 
 394         if (acpi_pci_disabled)
 
 397         /* deallocate internal data structures etc. */
 
 401 module_init(acpiphp_init);
 
 402 module_exit(acpiphp_exit);