0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #define pr_fmt(fmt) "acpiphp: " fmt
0021
0022 #include <linux/init.h>
0023 #include <linux/module.h>
0024 #include <linux/moduleparam.h>
0025
0026 #include <linux/kernel.h>
0027 #include <linux/pci.h>
0028 #include <linux/pci-acpi.h>
0029 #include <linux/pci_hotplug.h>
0030 #include <linux/slab.h>
0031 #include <linux/smp.h>
0032 #include "acpiphp.h"
0033
0034
0035 #define SLOT_NAME_SIZE 21
0036
0037 bool acpiphp_disabled;
0038
0039
0040 static struct acpiphp_attention_info *attention_info;
0041
0042 #define DRIVER_VERSION "0.5"
0043 #define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>, Matthew Wilcox <willy@infradead.org>"
0044 #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver"
0045
0046 MODULE_AUTHOR(DRIVER_AUTHOR);
0047 MODULE_DESCRIPTION(DRIVER_DESC);
0048 MODULE_LICENSE("GPL");
0049 MODULE_PARM_DESC(disable, "disable acpiphp driver");
0050 module_param_named(disable, acpiphp_disabled, bool, 0444);
0051
0052 static int enable_slot(struct hotplug_slot *slot);
0053 static int disable_slot(struct hotplug_slot *slot);
0054 static int set_attention_status(struct hotplug_slot *slot, u8 value);
0055 static int get_power_status(struct hotplug_slot *slot, u8 *value);
0056 static int get_attention_status(struct hotplug_slot *slot, u8 *value);
0057 static int get_latch_status(struct hotplug_slot *slot, u8 *value);
0058 static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
0059
0060 static const struct hotplug_slot_ops acpi_hotplug_slot_ops = {
0061 .enable_slot = enable_slot,
0062 .disable_slot = disable_slot,
0063 .set_attention_status = set_attention_status,
0064 .get_power_status = get_power_status,
0065 .get_attention_status = get_attention_status,
0066 .get_latch_status = get_latch_status,
0067 .get_adapter_status = get_adapter_status,
0068 };
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078 int acpiphp_register_attention(struct acpiphp_attention_info *info)
0079 {
0080 int retval = -EINVAL;
0081
0082 if (info && info->owner && info->set_attn &&
0083 info->get_attn && !attention_info) {
0084 retval = 0;
0085 attention_info = info;
0086 }
0087 return retval;
0088 }
0089 EXPORT_SYMBOL_GPL(acpiphp_register_attention);
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 int acpiphp_unregister_attention(struct acpiphp_attention_info *info)
0101 {
0102 int retval = -EINVAL;
0103
0104 if (info && attention_info == info) {
0105 attention_info = NULL;
0106 retval = 0;
0107 }
0108 return retval;
0109 }
0110 EXPORT_SYMBOL_GPL(acpiphp_unregister_attention);
0111
0112
0113
0114
0115
0116
0117
0118
0119 static int enable_slot(struct hotplug_slot *hotplug_slot)
0120 {
0121 struct slot *slot = to_slot(hotplug_slot);
0122
0123 pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
0124
0125
0126 return acpiphp_enable_slot(slot->acpi_slot);
0127 }
0128
0129
0130
0131
0132
0133
0134
0135
0136 static int disable_slot(struct hotplug_slot *hotplug_slot)
0137 {
0138 struct slot *slot = to_slot(hotplug_slot);
0139
0140 pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
0141
0142
0143 return acpiphp_disable_slot(slot->acpi_slot);
0144 }
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156 static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
0157 {
0158 int retval = -ENODEV;
0159
0160 pr_debug("%s - physical_slot = %s\n", __func__,
0161 hotplug_slot_name(hotplug_slot));
0162
0163 if (attention_info && try_module_get(attention_info->owner)) {
0164 retval = attention_info->set_attn(hotplug_slot, status);
0165 module_put(attention_info->owner);
0166 } else
0167 attention_info = NULL;
0168 return retval;
0169 }
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
0181 {
0182 struct slot *slot = to_slot(hotplug_slot);
0183
0184 pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
0185
0186 *value = acpiphp_get_power_status(slot->acpi_slot);
0187
0188 return 0;
0189 }
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202 static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
0203 {
0204 int retval = -EINVAL;
0205
0206 pr_debug("%s - physical_slot = %s\n", __func__,
0207 hotplug_slot_name(hotplug_slot));
0208
0209 if (attention_info && try_module_get(attention_info->owner)) {
0210 retval = attention_info->get_attn(hotplug_slot, value);
0211 module_put(attention_info->owner);
0212 } else
0213 attention_info = NULL;
0214 return retval;
0215 }
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226 static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
0227 {
0228 struct slot *slot = to_slot(hotplug_slot);
0229
0230 pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
0231
0232 *value = acpiphp_get_latch_status(slot->acpi_slot);
0233
0234 return 0;
0235 }
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246 static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
0247 {
0248 struct slot *slot = to_slot(hotplug_slot);
0249
0250 pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
0251
0252 *value = acpiphp_get_adapter_status(slot->acpi_slot);
0253
0254 return 0;
0255 }
0256
0257
0258 int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
0259 unsigned int sun)
0260 {
0261 struct slot *slot;
0262 int retval = -ENOMEM;
0263 char name[SLOT_NAME_SIZE];
0264
0265 slot = kzalloc(sizeof(*slot), GFP_KERNEL);
0266 if (!slot)
0267 goto error;
0268
0269 slot->hotplug_slot.ops = &acpi_hotplug_slot_ops;
0270
0271 slot->acpi_slot = acpiphp_slot;
0272
0273 acpiphp_slot->slot = slot;
0274 slot->sun = sun;
0275 snprintf(name, SLOT_NAME_SIZE, "%u", sun);
0276
0277 retval = pci_hp_register(&slot->hotplug_slot, acpiphp_slot->bus,
0278 acpiphp_slot->device, name);
0279 if (retval == -EBUSY)
0280 goto error_slot;
0281 if (retval) {
0282 pr_err("pci_hp_register failed with error %d\n", retval);
0283 goto error_slot;
0284 }
0285
0286 pr_info("Slot [%s] registered\n", slot_name(slot));
0287
0288 return 0;
0289 error_slot:
0290 kfree(slot);
0291 error:
0292 return retval;
0293 }
0294
0295
0296 void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
0297 {
0298 struct slot *slot = acpiphp_slot->slot;
0299
0300 pr_info("Slot [%s] unregistered\n", slot_name(slot));
0301
0302 pci_hp_deregister(&slot->hotplug_slot);
0303 kfree(slot);
0304 }
0305
0306
0307 void __init acpiphp_init(void)
0308 {
0309 pr_info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n",
0310 acpiphp_disabled ? ", disabled by user; please report a bug"
0311 : "");
0312 }