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 + -
显示快捷键?