sonypi.c
来自「linux 内核源代码」· C语言 代码 · 共 1,571 行 · 第 1/3 页
C
1,571 行
if (sonypi_ec_write(SONYPI_FAN0_STATUS, val8)) ret = -EIO; break; /* GET Temperature (useful under APM) */ case SONYPI_IOCGTEMP: if (sonypi_ec_read(SONYPI_TEMP_STATUS, &val8)) { ret = -EIO; break; } if (copy_to_user(argp, &val8, sizeof(val8))) ret = -EFAULT; break; default: ret = -EINVAL; } mutex_unlock(&sonypi_device.lock); return ret;}static const struct file_operations sonypi_misc_fops = { .owner = THIS_MODULE, .read = sonypi_misc_read, .poll = sonypi_misc_poll, .open = sonypi_misc_open, .release = sonypi_misc_release, .fasync = sonypi_misc_fasync, .ioctl = sonypi_misc_ioctl,};static struct miscdevice sonypi_misc_device = { .minor = MISC_DYNAMIC_MINOR, .name = "sonypi", .fops = &sonypi_misc_fops,};static void sonypi_enable(unsigned int camera_on){ switch (sonypi_device.model) { case SONYPI_DEVICE_MODEL_TYPE1: sonypi_type1_srs(); break; case SONYPI_DEVICE_MODEL_TYPE2: sonypi_type2_srs(); break; case SONYPI_DEVICE_MODEL_TYPE3: sonypi_type3_srs(); break; } sonypi_call1(0x82); sonypi_call2(0x81, 0xff); sonypi_call1(compat ? 0x92 : 0x82); /* Enable ACPI mode to get Fn key events */ if (!SONYPI_ACPI_ACTIVE && fnkeyinit) outb(0xf0, 0xb2); if (camera && camera_on) sonypi_camera_on();}static int sonypi_disable(void){ sonypi_call2(0x81, 0); /* make sure we don't get any more events */ if (camera) sonypi_camera_off(); /* disable ACPI mode */ if (!SONYPI_ACPI_ACTIVE && fnkeyinit) outb(0xf1, 0xb2); switch (sonypi_device.model) { case SONYPI_DEVICE_MODEL_TYPE1: sonypi_type1_dis(); break; case SONYPI_DEVICE_MODEL_TYPE2: sonypi_type2_dis(); break; case SONYPI_DEVICE_MODEL_TYPE3: sonypi_type3_dis(); break; } return 0;}#ifdef CONFIG_ACPIstatic int sonypi_acpi_add(struct acpi_device *device){ sonypi_acpi_device = device; strcpy(acpi_device_name(device), "Sony laptop hotkeys"); strcpy(acpi_device_class(device), "sony/hotkey"); return 0;}static int sonypi_acpi_remove(struct acpi_device *device, int type){ sonypi_acpi_device = NULL; return 0;}const static struct acpi_device_id sonypi_device_ids[] = { {"SNY6001", 0}, {"", 0},};static struct acpi_driver sonypi_acpi_driver = { .name = "sonypi", .class = "hkey", .ids = sonypi_device_ids, .ops = { .add = sonypi_acpi_add, .remove = sonypi_acpi_remove, },};#endifstatic int __devinit sonypi_create_input_devices(struct platform_device *pdev){ 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) return -ENOMEM; jog_dev->name = "Sony Vaio Jogdial"; jog_dev->id.bustype = BUS_ISA; jog_dev->id.vendor = PCI_VENDOR_ID_SONY; jog_dev->dev.parent = &pdev->dev; jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE); jog_dev->relbit[0] = BIT_MASK(REL_WHEEL); sonypi_device.input_key_dev = key_dev = input_allocate_device(); if (!key_dev) { error = -ENOMEM; goto err_free_jogdev; } key_dev->name = "Sony Vaio Keys"; key_dev->id.bustype = BUS_ISA; key_dev->id.vendor = PCI_VENDOR_ID_SONY; key_dev->dev.parent = &pdev->dev; /* Initialize the Input Drivers: special keys */ key_dev->evbit[0] = BIT_MASK(EV_KEY); for (i = 0; sonypi_inputkeys[i].sonypiev; i++) if (sonypi_inputkeys[i].inputev) set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit); 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_setup_ioports(struct sonypi_device *dev, const struct sonypi_ioport_list *ioport_list){ /* try to detect if sony-laptop is being used and thus * has already requested one of the known ioports. * As in the deprecated check_region this is racy has we have * multiple ioports available and one of them can be requested * between this check and the subsequent request. Anyway, as an * attempt to be some more user-friendly as we currently are, * this is enough. */ const struct sonypi_ioport_list *check = ioport_list; while (check_ioport && check->port1) { if (!request_region(check->port1, sonypi_device.region_size, "Sony Programable I/O Device Check")) { printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? " "if not use check_ioport=0\n", check->port1); return -EBUSY; } release_region(check->port1, sonypi_device.region_size); check++; } while (ioport_list->port1) { 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++; } 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, IRQF_SHARED, "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; printk(KERN_WARNING "sonypi: please try the sony-laptop module instead " "and report failures, see also " "http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n"); 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); mutex_init(&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"); 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(dev); 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); } sonypi_enable(0); return 0; err_inpdev_unregister: input_unregister_device(sonypi_device.input_key_dev); input_unregister_device(sonypi_device.input_jog_dev); err_miscdev_unregister: misc_deregister(&sonypi_misc_device); 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); err_put_pcidev: pci_dev_put(pcidev); kfifo_free(sonypi_device.fifo); return error;}static int __devexit sonypi_remove(struct platform_device *dev){ sonypi_disable(); synchronize_irq(sonypi_device.irq); flush_scheduled_work(); 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); if (sonypi_device.dev) { pci_disable_device(sonypi_device.dev); pci_dev_put(sonypi_device.dev); } kfifo_free(sonypi_device.fifo); return 0;}#ifdef CONFIG_PMstatic 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#endifstatic 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", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"), }, }, { .ident = "Sony Vaio", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"), }, }, { }};static int __init sonypi_init(void){ 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; error = platform_driver_register(&sonypi_driver); if (error) return error; sonypi_platform_device = platform_device_alloc("sonypi", -1); if (!sonypi_platform_device) { error = -ENOMEM; goto err_driver_unregister; } 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){#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);module_exit(sonypi_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?