|
@@ -64,6 +64,7 @@
|
|
|
#include <linux/dmi.h>
|
|
|
#include <linux/string.h>
|
|
|
#include <linux/ctype.h>
|
|
|
+#include <linux/pnp.h>
|
|
|
|
|
|
#ifdef CONFIG_PPC_OF
|
|
|
#include <linux/of_device.h>
|
|
@@ -2023,6 +2024,103 @@ static __devinit void spmi_find_bmc(void)
|
|
|
try_init_spmi(spmi);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
|
|
|
+ const struct pnp_device_id *dev_id)
|
|
|
+{
|
|
|
+ struct acpi_device *acpi_dev;
|
|
|
+ struct smi_info *info;
|
|
|
+ acpi_handle handle;
|
|
|
+ acpi_status status;
|
|
|
+ unsigned long long tmp;
|
|
|
+
|
|
|
+ acpi_dev = pnp_acpi_device(dev);
|
|
|
+ if (!acpi_dev)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
|
|
|
+ if (!info)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ info->addr_source = "ACPI";
|
|
|
+
|
|
|
+ handle = acpi_dev->handle;
|
|
|
+
|
|
|
+ /* _IFT tells us the interface type: KCS, BT, etc */
|
|
|
+ status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp);
|
|
|
+ if (ACPI_FAILURE(status))
|
|
|
+ goto err_free;
|
|
|
+
|
|
|
+ switch (tmp) {
|
|
|
+ case 1:
|
|
|
+ info->si_type = SI_KCS;
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ info->si_type = SI_SMIC;
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ info->si_type = SI_BT;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ dev_info(&dev->dev, "unknown interface type %lld\n", tmp);
|
|
|
+ goto err_free;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pnp_port_valid(dev, 0)) {
|
|
|
+ info->io_setup = port_setup;
|
|
|
+ info->io.addr_type = IPMI_IO_ADDR_SPACE;
|
|
|
+ info->io.addr_data = pnp_port_start(dev, 0);
|
|
|
+ } else if (pnp_mem_valid(dev, 0)) {
|
|
|
+ info->io_setup = mem_setup;
|
|
|
+ info->io.addr_type = IPMI_MEM_ADDR_SPACE;
|
|
|
+ info->io.addr_data = pnp_mem_start(dev, 0);
|
|
|
+ } else {
|
|
|
+ dev_err(&dev->dev, "no I/O or memory address\n");
|
|
|
+ goto err_free;
|
|
|
+ }
|
|
|
+
|
|
|
+ info->io.regspacing = DEFAULT_REGSPACING;
|
|
|
+ info->io.regsize = DEFAULT_REGSPACING;
|
|
|
+ info->io.regshift = 0;
|
|
|
+
|
|
|
+ /* If _GPE exists, use it; otherwise use standard interrupts */
|
|
|
+ status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
|
|
|
+ if (ACPI_SUCCESS(status)) {
|
|
|
+ info->irq = tmp;
|
|
|
+ info->irq_setup = acpi_gpe_irq_setup;
|
|
|
+ } else if (pnp_irq_valid(dev, 0)) {
|
|
|
+ info->irq = pnp_irq(dev, 0);
|
|
|
+ info->irq_setup = std_irq_setup;
|
|
|
+ }
|
|
|
+
|
|
|
+ info->dev = &acpi_dev->dev;
|
|
|
+ pnp_set_drvdata(dev, info);
|
|
|
+
|
|
|
+ return try_smi_init(info);
|
|
|
+
|
|
|
+err_free:
|
|
|
+ kfree(info);
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+static void __devexit ipmi_pnp_remove(struct pnp_dev *dev)
|
|
|
+{
|
|
|
+ struct smi_info *info = pnp_get_drvdata(dev);
|
|
|
+
|
|
|
+ cleanup_one_si(info);
|
|
|
+}
|
|
|
+
|
|
|
+static const struct pnp_device_id pnp_dev_table[] = {
|
|
|
+ {"IPI0001", 0},
|
|
|
+ {"", 0},
|
|
|
+};
|
|
|
+
|
|
|
+static struct pnp_driver ipmi_pnp_driver = {
|
|
|
+ .name = DEVICE_NAME,
|
|
|
+ .probe = ipmi_pnp_probe,
|
|
|
+ .remove = __devexit_p(ipmi_pnp_remove),
|
|
|
+ .id_table = pnp_dev_table,
|
|
|
+};
|
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_DMI
|
|
@@ -3106,6 +3204,9 @@ static __devinit int init_ipmi_si(void)
|
|
|
#ifdef CONFIG_ACPI
|
|
|
spmi_find_bmc();
|
|
|
#endif
|
|
|
+#ifdef CONFIG_PNP
|
|
|
+ pnp_register_driver(&ipmi_pnp_driver);
|
|
|
+#endif
|
|
|
|
|
|
#ifdef CONFIG_PCI
|
|
|
rv = pci_register_driver(&ipmi_pci_driver);
|
|
@@ -3229,6 +3330,9 @@ static __exit void cleanup_ipmi_si(void)
|
|
|
#ifdef CONFIG_PCI
|
|
|
pci_unregister_driver(&ipmi_pci_driver);
|
|
|
#endif
|
|
|
+#ifdef CONFIG_PNP
|
|
|
+ pnp_unregister_driver(&ipmi_pnp_driver);
|
|
|
+#endif
|
|
|
|
|
|
#ifdef CONFIG_PPC_OF
|
|
|
of_unregister_platform_driver(&ipmi_of_platform_driver);
|