Pull acpi_bus_register_driver into release branch
[pandora-kernel.git] / drivers / char / sonypi.c
index d05067d..43dfd86 100644 (file)
@@ -471,7 +471,6 @@ struct sonypi_keypress {
 
 static struct sonypi_device {
        struct pci_dev *dev;
-       struct platform_device *pdev;
        u16 irq;
        u16 bits;
        u16 ioport1;
@@ -511,6 +510,11 @@ static struct sonypi_device {
 #define SONYPI_ACPI_ACTIVE 0
 #endif                         /* CONFIG_ACPI */
 
+#ifdef CONFIG_ACPI
+static struct acpi_device *sonypi_acpi_device;
+static int acpi_driver_registered;
+#endif
+
 static int sonypi_ec_write(u8 addr, u8 value)
 {
 #ifdef CONFIG_ACPI_EC
@@ -864,6 +868,11 @@ found:
        if (useinput)
                sonypi_report_input_event(event);
 
+#ifdef CONFIG_ACPI
+       if (sonypi_acpi_device)
+               acpi_bus_generate_event(sonypi_acpi_device, 1, event);
+#endif
+
        kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event));
        kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
        wake_up_interruptible(&sonypi_device.fifo_proc_list);
@@ -1165,44 +1174,38 @@ static int sonypi_disable(void)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int old_camera_power;
-
-static int sonypi_suspend(struct device *dev, pm_message_t state)
+#ifdef CONFIG_ACPI
+static int sonypi_acpi_add(struct acpi_device *device)
 {
-       old_camera_power = sonypi_device.camera_power;
-       sonypi_disable();
-
+       sonypi_acpi_device = device;
+       strcpy(acpi_device_name(device), "Sony laptop hotkeys");
+       strcpy(acpi_device_class(device), "sony/hotkey");
        return 0;
 }
 
-static int sonypi_resume(struct device *dev)
+static int sonypi_acpi_remove(struct acpi_device *device, int type)
 {
-       sonypi_enable(old_camera_power);
+       sonypi_acpi_device = NULL;
        return 0;
 }
-#endif
-
-static void sonypi_shutdown(struct device *dev)
-{
-       sonypi_disable();
-}
 
-static struct device_driver sonypi_driver = {
-       .name           = "sonypi",
-       .bus            = &platform_bus_type,
-#ifdef CONFIG_PM
-       .suspend        = sonypi_suspend,
-       .resume         = sonypi_resume,
-#endif
-       .shutdown       = sonypi_shutdown,
+static struct acpi_driver sonypi_acpi_driver = {
+       .name           = "sonypi",
+       .class          = "hkey",
+       .ids            = "SNY6001",
+       .ops            = {
+                          .add = sonypi_acpi_add,
+                          .remove = sonypi_acpi_remove,
+       },
 };
+#endif
 
 static int __devinit sonypi_create_input_devices(void)
 {
        struct input_dev *jog_dev;
        struct input_dev *key_dev;
        int i;
+       int error;
 
        sonypi_device.input_jog_dev = jog_dev = input_allocate_device();
        if (!jog_dev)
@@ -1218,9 +1221,8 @@ static int __devinit sonypi_create_input_devices(void)
 
        sonypi_device.input_key_dev = key_dev = input_allocate_device();
        if (!key_dev) {
-               input_free_device(jog_dev);
-               sonypi_device.input_jog_dev = NULL;
-               return -ENOMEM;
+               error = -ENOMEM;
+               goto err_free_jogdev;
        }
 
        key_dev->name = "Sony Vaio Keys";
@@ -1233,56 +1235,125 @@ static int __devinit sonypi_create_input_devices(void)
                if (sonypi_inputkeys[i].inputev)
                        set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit);
 
-       input_register_device(jog_dev);
-       input_register_device(key_dev);
+       error = input_register_device(jog_dev);
+       if (error)
+               goto err_free_keydev;
+
+       error = input_register_device(key_dev);
+       if (error)
+               goto err_unregister_jogdev;
 
        return 0;
+
+ err_unregister_jogdev:
+       input_unregister_device(jog_dev);
+       /* Set to NULL so we don't free it again below */
+       jog_dev = NULL;
+ err_free_keydev:
+       input_free_device(key_dev);
+       sonypi_device.input_key_dev = NULL;
+ err_free_jogdev:
+       input_free_device(jog_dev);
+       sonypi_device.input_jog_dev = NULL;
+
+       return error;
 }
 
-static int __devinit sonypi_probe(void)
+static int __devinit sonypi_setup_ioports(struct sonypi_device *dev,
+                               const struct sonypi_ioport_list *ioport_list)
 {
-       int i, ret;
-       struct sonypi_ioport_list *ioport_list;
-       struct sonypi_irq_list *irq_list;
-       struct pci_dev *pcidev;
+       while (ioport_list->port1) {
 
-       if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                    PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
-               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
-       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                         PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
-               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
-       else
-               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
+               if (request_region(ioport_list->port1,
+                                  sonypi_device.region_size,
+                                  "Sony Programable I/O Device")) {
+                       dev->ioport1 = ioport_list->port1;
+                       dev->ioport2 = ioport_list->port2;
+                       return 0;
+               }
+               ioport_list++;
+       }
 
-       sonypi_device.dev = pcidev;
+       return -EBUSY;
+}
+
+static int __devinit sonypi_setup_irq(struct sonypi_device *dev,
+                                     const struct sonypi_irq_list *irq_list)
+{
+       while (irq_list->irq) {
+
+               if (!request_irq(irq_list->irq, sonypi_irq,
+                                SA_SHIRQ, "sonypi", sonypi_irq)) {
+                       dev->irq = irq_list->irq;
+                       dev->bits = irq_list->bits;
+                       return 0;
+               }
+               irq_list++;
+       }
+
+       return -EBUSY;
+}
+
+static void __devinit sonypi_display_info(void)
+{
+       printk(KERN_INFO "sonypi: detected type%d model, "
+              "verbose = %d, fnkeyinit = %s, camera = %s, "
+              "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
+              sonypi_device.model,
+              verbose,
+              fnkeyinit ? "on" : "off",
+              camera ? "on" : "off",
+              compat ? "on" : "off",
+              mask,
+              useinput ? "on" : "off",
+              SONYPI_ACPI_ACTIVE ? "on" : "off");
+       printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
+              sonypi_device.irq,
+              sonypi_device.ioport1, sonypi_device.ioport2);
+
+       if (minor == -1)
+               printk(KERN_INFO "sonypi: device allocated minor is %d\n",
+                      sonypi_misc_device.minor);
+}
+
+static int __devinit sonypi_probe(struct platform_device *dev)
+{
+       const struct sonypi_ioport_list *ioport_list;
+       const struct sonypi_irq_list *irq_list;
+       struct pci_dev *pcidev;
+       int error;
 
        spin_lock_init(&sonypi_device.fifo_lock);
        sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
                                         &sonypi_device.fifo_lock);
        if (IS_ERR(sonypi_device.fifo)) {
                printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
-               ret = PTR_ERR(sonypi_device.fifo);
-               goto out_fifo;
+               return PTR_ERR(sonypi_device.fifo);
        }
 
        init_waitqueue_head(&sonypi_device.fifo_proc_list);
        init_MUTEX(&sonypi_device.lock);
        sonypi_device.bluetooth_power = -1;
 
+       if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                    PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
+               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
+       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                         PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
+               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
+       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                         PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
+               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
+       else
+               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
+
        if (pcidev && pci_enable_device(pcidev)) {
                printk(KERN_ERR "sonypi: pci_enable_device failed\n");
-               ret = -EIO;
-               goto out_pcienable;
-       }
-
-       if (minor != -1)
-               sonypi_misc_device.minor = minor;
-       if ((ret = misc_register(&sonypi_misc_device))) {
-               printk(KERN_ERR "sonypi: misc_register failed\n");
-               goto out_miscreg;
+               error = -EIO;
+               goto err_put_pcidev;
        }
 
+       sonypi_device.dev = pcidev;
 
        if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) {
                ioport_list = sonypi_type1_ioport_list;
@@ -1301,43 +1372,36 @@ static int __devinit sonypi_probe(void)
                irq_list = sonypi_type3_irq_list;
        }
 
-       for (i = 0; ioport_list[i].port1; i++) {
-               if (request_region(ioport_list[i].port1,
-                                  sonypi_device.region_size,
-                                  "Sony Programable I/O Device")) {
-                       /* get the ioport */
-                       sonypi_device.ioport1 = ioport_list[i].port1;
-                       sonypi_device.ioport2 = ioport_list[i].port2;
-                       break;
-               }
-       }
-       if (!sonypi_device.ioport1) {
-               printk(KERN_ERR "sonypi: request_region failed\n");
-               ret = -ENODEV;
-               goto out_reqreg;
+       error = sonypi_setup_ioports(&sonypi_device, ioport_list);
+       if (error) {
+               printk(KERN_ERR "sonypi: failed to request ioports\n");
+               goto err_disable_pcidev;
        }
 
-       for (i = 0; irq_list[i].irq; i++) {
-
-               sonypi_device.irq = irq_list[i].irq;
-               sonypi_device.bits = irq_list[i].bits;
-
-               if (!request_irq(sonypi_device.irq, sonypi_irq,
-                                SA_SHIRQ, "sonypi", sonypi_irq))
-                       break;
+       error = sonypi_setup_irq(&sonypi_device, irq_list);
+       if (error) {
+               printk(KERN_ERR "sonypi: request_irq failed\n");
+               goto err_free_ioports;
        }
 
-       if (!irq_list[i].irq) {
-               printk(KERN_ERR "sonypi: request_irq failed\n");
-               ret = -ENODEV;
-               goto out_reqirq;
+       if (minor != -1)
+               sonypi_misc_device.minor = minor;
+       error = misc_register(&sonypi_misc_device);
+       if (error) {
+               printk(KERN_ERR "sonypi: misc_register failed\n");
+               goto err_free_irq;
        }
 
+       sonypi_display_info();
+
        if (useinput) {
 
-               ret = sonypi_create_input_devices();
-               if (ret)
-                       goto out_inputdevices;
+               error = sonypi_create_input_devices();
+               if (error) {
+                       printk(KERN_ERR
+                               "sonypi: failed to create input devices\n");
+                       goto err_miscdev_unregister;
+               }
 
                spin_lock_init(&sonypi_device.input_fifo_lock);
                sonypi_device.input_fifo =
@@ -1345,91 +1409,104 @@ static int __devinit sonypi_probe(void)
                                    &sonypi_device.input_fifo_lock);
                if (IS_ERR(sonypi_device.input_fifo)) {
                        printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
-                       ret = PTR_ERR(sonypi_device.input_fifo);
-                       goto out_infifo;
+                       error = PTR_ERR(sonypi_device.input_fifo);
+                       goto err_inpdev_unregister;
                }
 
                INIT_WORK(&sonypi_device.input_work, input_keyrelease, NULL);
        }
 
-       sonypi_device.pdev = platform_device_register_simple("sonypi", -1,
-                                                            NULL, 0);
-       if (IS_ERR(sonypi_device.pdev)) {
-               ret = PTR_ERR(sonypi_device.pdev);
-               goto out_platformdev;
-       }
-
        sonypi_enable(0);
 
-       printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver"
-              "v%s.\n", SONYPI_DRIVER_VERSION);
-       printk(KERN_INFO "sonypi: detected type%d model, "
-              "verbose = %d, fnkeyinit = %s, camera = %s, "
-              "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
-              sonypi_device.model,
-              verbose,
-              fnkeyinit ? "on" : "off",
-              camera ? "on" : "off",
-              compat ? "on" : "off",
-              mask,
-              useinput ? "on" : "off",
-              SONYPI_ACPI_ACTIVE ? "on" : "off");
-       printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
-              sonypi_device.irq,
-              sonypi_device.ioport1, sonypi_device.ioport2);
-
-       if (minor == -1)
-               printk(KERN_INFO "sonypi: device allocated minor is %d\n",
-                      sonypi_misc_device.minor);
-
        return 0;
 
-out_platformdev:
-       kfifo_free(sonypi_device.input_fifo);
-out_infifo:
+ err_inpdev_unregister:
        input_unregister_device(sonypi_device.input_key_dev);
        input_unregister_device(sonypi_device.input_jog_dev);
-out_inputdevices:
+ err_miscdev_unregister:
+       misc_deregister(&sonypi_misc_device);
+ err_free_irq:
        free_irq(sonypi_device.irq, sonypi_irq);
-out_reqirq:
+ err_free_ioports:
        release_region(sonypi_device.ioport1, sonypi_device.region_size);
-out_reqreg:
-       misc_deregister(&sonypi_misc_device);
-out_miscreg:
+ err_disable_pcidev:
        if (pcidev)
                pci_disable_device(pcidev);
-out_pcienable:
+ err_put_pcidev:
+       pci_dev_put(pcidev);
        kfifo_free(sonypi_device.fifo);
-out_fifo:
-       pci_dev_put(sonypi_device.dev);
-       return ret;
+
+       return error;
 }
 
-static void __devexit sonypi_remove(void)
+static int __devexit sonypi_remove(struct platform_device *dev)
 {
        sonypi_disable();
 
        synchronize_sched();  /* Allow sonypi interrupt to complete. */
        flush_scheduled_work();
 
-       platform_device_unregister(sonypi_device.pdev);
-
        if (useinput) {
                input_unregister_device(sonypi_device.input_key_dev);
                input_unregister_device(sonypi_device.input_jog_dev);
                kfifo_free(sonypi_device.input_fifo);
        }
 
+       misc_deregister(&sonypi_misc_device);
+
        free_irq(sonypi_device.irq, sonypi_irq);
        release_region(sonypi_device.ioport1, sonypi_device.region_size);
-       misc_deregister(&sonypi_misc_device);
-       if (sonypi_device.dev)
+
+       if (sonypi_device.dev) {
                pci_disable_device(sonypi_device.dev);
+               pci_dev_put(sonypi_device.dev);
+       }
+
        kfifo_free(sonypi_device.fifo);
-       pci_dev_put(sonypi_device.dev);
-       printk(KERN_INFO "sonypi: removed.\n");
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int old_camera_power;
+
+static int sonypi_suspend(struct platform_device *dev, pm_message_t state)
+{
+       old_camera_power = sonypi_device.camera_power;
+       sonypi_disable();
+
+       return 0;
+}
+
+static int sonypi_resume(struct platform_device *dev)
+{
+       sonypi_enable(old_camera_power);
+       return 0;
+}
+#else
+#define sonypi_suspend NULL
+#define sonypi_resume  NULL
+#endif
+
+static void sonypi_shutdown(struct platform_device *dev)
+{
+       sonypi_disable();
 }
 
+static struct platform_driver sonypi_driver = {
+       .driver         = {
+               .name   = "sonypi",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = sonypi_probe,
+       .remove         = __devexit_p(sonypi_remove),
+       .shutdown       = sonypi_shutdown,
+       .suspend        = sonypi_suspend,
+       .resume         = sonypi_resume,
+};
+
+static struct platform_device *sonypi_platform_device;
+
 static struct dmi_system_id __initdata sonypi_dmi_table[] = {
        {
                .ident = "Sony Vaio",
@@ -1450,26 +1527,52 @@ static struct dmi_system_id __initdata sonypi_dmi_table[] = {
 
 static int __init sonypi_init(void)
 {
-       int ret;
+       int error;
+
+       printk(KERN_INFO
+               "sonypi: Sony Programmable I/O Controller Driver v%s.\n",
+               SONYPI_DRIVER_VERSION);
 
        if (!dmi_check_system(sonypi_dmi_table))
                return -ENODEV;
 
-       ret = driver_register(&sonypi_driver);
-       if (ret)
-               return ret;
+       error = platform_driver_register(&sonypi_driver);
+       if (error)
+               return error;
 
-       ret = sonypi_probe();
-       if (ret)
-               driver_unregister(&sonypi_driver);
+       sonypi_platform_device = platform_device_alloc("sonypi", -1);
+       if (!sonypi_platform_device) {
+               error = -ENOMEM;
+               goto err_driver_unregister;
+       }
 
-       return ret;
+       error = platform_device_add(sonypi_platform_device);
+       if (error)
+               goto err_free_device;
+
+#ifdef CONFIG_ACPI
+       if (acpi_bus_register_driver(&sonypi_acpi_driver) >= 0)
+               acpi_driver_registered = 1;
+#endif
+
+       return 0;
+
+ err_free_device:
+       platform_device_put(sonypi_platform_device);
+ err_driver_unregister:
+       platform_driver_unregister(&sonypi_driver);
+       return error;
 }
 
 static void __exit sonypi_exit(void)
 {
-       driver_unregister(&sonypi_driver);
-       sonypi_remove();
+#ifdef CONFIG_ACPI
+       if (acpi_driver_registered)
+               acpi_bus_unregister_driver(&sonypi_acpi_driver);
+#endif
+       platform_device_unregister(sonypi_platform_device);
+       platform_driver_unregister(&sonypi_driver);
+       printk(KERN_INFO "sonypi: removed.\n");
 }
 
 module_init(sonypi_init);