diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 51a07370e636..6a9e23dc4897 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -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; @@ -1165,45 +1164,12 @@ static int sonypi_disable(void) 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; -} -#endif - -static void sonypi_shutdown(struct platform_device *dev) -{ - sonypi_disable(); -} - -static struct platform_driver sonypi_driver = { -#ifdef CONFIG_PM - .suspend = sonypi_suspend, - .resume = sonypi_resume, -#endif - .shutdown = sonypi_shutdown, - .driver = { - .name = "sonypi", - }, -}; - 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) @@ -1219,9 +1185,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"; @@ -1234,136 +1199,67 @@ 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; - - sonypi_device.dev = pcidev; - - 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; - } - - init_waitqueue_head(&sonypi_device.fifo_proc_list); - init_MUTEX(&sonypi_device.lock); - sonypi_device.bluetooth_power = -1; - - 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; - } - - - if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) { - ioport_list = sonypi_type1_ioport_list; - sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE; - sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET; - irq_list = sonypi_type1_irq_list; - } else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) { - ioport_list = sonypi_type2_ioport_list; - sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE; - sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET; - irq_list = sonypi_type2_irq_list; - } else { - ioport_list = sonypi_type3_ioport_list; - sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE; - sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET; - irq_list = sonypi_type3_irq_list; - } - - for (i = 0; ioport_list[i].port1; i++) { - if (request_region(ioport_list[i].port1, + if (request_region(ioport_list->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; + dev->ioport1 = ioport_list->port1; + dev->ioport2 = ioport_list->port2; + return 0; } - } - if (!sonypi_device.ioport1) { - printk(KERN_ERR "sonypi: request_region failed\n"); - ret = -ENODEV; - goto out_reqreg; + ioport_list++; } - for (i = 0; irq_list[i].irq; i++) { + return -EBUSY; +} - sonypi_device.irq = irq_list[i].irq; - sonypi_device.bits = irq_list[i].bits; +static int __devinit sonypi_setup_irq(struct sonypi_device *dev, + const struct sonypi_irq_list *irq_list) +{ + while (irq_list->irq) { - if (!request_irq(sonypi_device.irq, sonypi_irq, - SA_SHIRQ, "sonypi", sonypi_irq)) - break; - } - - if (!irq_list[i].irq) { - printk(KERN_ERR "sonypi: request_irq failed\n"); - ret = -ENODEV; - goto out_reqirq; - } - - if (useinput) { - - ret = sonypi_create_input_devices(); - if (ret) - goto out_inputdevices; - - spin_lock_init(&sonypi_device.input_fifo_lock); - sonypi_device.input_fifo = - kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL, - &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; + 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; } - - INIT_WORK(&sonypi_device.input_work, input_keyrelease, NULL); + irq_list++; } - 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; - } + return -EBUSY; +} - sonypi_enable(0); - - printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver" - "v%s.\n", SONYPI_DRIVER_VERSION); +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", @@ -1382,55 +1278,196 @@ static int __devinit sonypi_probe(void) 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"); + 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 + sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2; + + if (pcidev && pci_enable_device(pcidev)) { + printk(KERN_ERR "sonypi: pci_enable_device failed\n"); + error = -EIO; + goto err_put_pcidev; + } + + sonypi_device.dev = pcidev; + + if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) { + ioport_list = sonypi_type1_ioport_list; + sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE; + sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET; + irq_list = sonypi_type1_irq_list; + } else if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) { + ioport_list = sonypi_type2_ioport_list; + sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE; + sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET; + irq_list = sonypi_type2_irq_list; + } else { + ioport_list = sonypi_type3_ioport_list; + sonypi_device.region_size = SONYPI_TYPE3_REGION_SIZE; + sonypi_device.evtype_offset = SONYPI_TYPE3_EVTYPE_OFFSET; + irq_list = sonypi_type3_irq_list; + } + + error = sonypi_setup_ioports(&sonypi_device, ioport_list); + if (error) { + printk(KERN_ERR "sonypi: failed to request ioports\n"); + goto err_disable_pcidev; + } + + error = sonypi_setup_irq(&sonypi_device, irq_list); + if (error) { + printk(KERN_ERR "sonypi: request_irq failed\n"); + goto err_free_ioports; + } + + 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) { + + 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 = + kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL, + &sonypi_device.input_fifo_lock); + if (IS_ERR(sonypi_device.input_fifo)) { + printk(KERN_ERR "sonypi: kfifo_alloc failed\n"); + error = PTR_ERR(sonypi_device.input_fifo); + goto err_inpdev_unregister; + } + + INIT_WORK(&sonypi_device.input_work, input_keyrelease, NULL); + } + + sonypi_enable(0); 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: - free_irq(sonypi_device.irq, sonypi_irq); -out_reqirq: - release_region(sonypi_device.ioport1, sonypi_device.region_size); -out_reqreg: + err_miscdev_unregister: misc_deregister(&sonypi_misc_device); -out_miscreg: + err_free_irq: + free_irq(sonypi_device.irq, sonypi_irq); + err_free_ioports: + release_region(sonypi_device.ioport1, sonypi_device.region_size); + 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", @@ -1451,26 +1488,43 @@ 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 = platform_driver_register(&sonypi_driver); - if (ret) - return ret; + error = platform_driver_register(&sonypi_driver); + if (error) + return error; - ret = sonypi_probe(); - if (ret) - platform_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; + + 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) { + platform_device_unregister(sonypi_platform_device); platform_driver_unregister(&sonypi_driver); - sonypi_remove(); + printk(KERN_INFO "sonypi: removed.\n"); } module_init(sonypi_init);