⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sony-laptop.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		}		val8 &= 0x07;		if (copy_to_user(argp, &val8, sizeof(val8)))			ret = -EFAULT;		break;	case SONYPI_IOCGBLUE:		val8 = spic_dev.bluetooth_power;		if (copy_to_user(argp, &val8, sizeof(val8)))			ret = -EFAULT;		break;	case SONYPI_IOCSBLUE:		if (copy_from_user(&val8, argp, sizeof(val8))) {			ret = -EFAULT;			break;		}		__sony_pic_set_bluetoothpower(val8);		break;	/* FAN Controls */	case SONYPI_IOCGFAN:		if (sony_pic_get_fanspeed(&val8)) {			ret = -EIO;			break;		}		if (copy_to_user(argp, &val8, sizeof(val8)))			ret = -EFAULT;		break;	case SONYPI_IOCSFAN:		if (copy_from_user(&val8, argp, sizeof(val8))) {			ret = -EFAULT;			break;		}		if (sony_pic_set_fanspeed(val8))			ret = -EIO;		break;	/* GET Temperature (useful under APM) */	case SONYPI_IOCGTEMP:		if (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(&spic_dev.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_compat_report_event(u8 event){	kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event));	kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);	wake_up_interruptible(&sonypi_compat.fifo_proc_list);}static int sonypi_compat_init(void){	int error;	spin_lock_init(&sonypi_compat.fifo_lock);	sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,					 &sonypi_compat.fifo_lock);	if (IS_ERR(sonypi_compat.fifo)) {		printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");		return PTR_ERR(sonypi_compat.fifo);	}	init_waitqueue_head(&sonypi_compat.fifo_proc_list);	if (minor != -1)		sonypi_misc_device.minor = minor;	error = misc_register(&sonypi_misc_device);	if (error) {		printk(KERN_ERR DRV_PFX "misc_register failed\n");		goto err_free_kfifo;	}	if (minor == -1)		printk(KERN_INFO DRV_PFX "device allocated minor is %d\n",		       sonypi_misc_device.minor);	return 0;err_free_kfifo:	kfifo_free(sonypi_compat.fifo);	return error;}static void sonypi_compat_exit(void){	misc_deregister(&sonypi_misc_device);	kfifo_free(sonypi_compat.fifo);}#elsestatic int sonypi_compat_init(void) { return 0; }static void sonypi_compat_exit(void) { }static void sonypi_compat_report_event(u8 event) { }#endif /* CONFIG_SONYPI_COMPAT *//* * ACPI callbacks */static acpi_statussony_pic_read_possible_resource(struct acpi_resource *resource, void *context){	u32 i;	struct sony_pic_dev *dev = (struct sony_pic_dev *)context;	switch (resource->type) {	case ACPI_RESOURCE_TYPE_START_DEPENDENT:		{			/* start IO enumeration */			struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);			if (!ioport)				return AE_ERROR;			list_add(&ioport->list, &dev->ioports);			return AE_OK;		}	case ACPI_RESOURCE_TYPE_END_DEPENDENT:		/* end IO enumeration */		return AE_OK;	case ACPI_RESOURCE_TYPE_IRQ:		{			struct acpi_resource_irq *p = &resource->data.irq;			struct sony_pic_irq *interrupt = NULL;			if (!p || !p->interrupt_count) {				/*				 * IRQ descriptors may have no IRQ# bits set,				 * particularly those those w/ _STA disabled				 */				dprintk("Blank IRQ resource\n");				return AE_OK;			}			for (i = 0; i < p->interrupt_count; i++) {				if (!p->interrupts[i]) {					printk(KERN_WARNING DRV_PFX							"Invalid IRQ %d\n",							p->interrupts[i]);					continue;				}				interrupt = kzalloc(sizeof(*interrupt),						GFP_KERNEL);				if (!interrupt)					return AE_ERROR;				list_add(&interrupt->list, &dev->interrupts);				interrupt->irq.triggering = p->triggering;				interrupt->irq.polarity = p->polarity;				interrupt->irq.sharable = p->sharable;				interrupt->irq.interrupt_count = 1;				interrupt->irq.interrupts[0] = p->interrupts[i];			}			return AE_OK;		}	case ACPI_RESOURCE_TYPE_IO:		{			struct acpi_resource_io *io = &resource->data.io;			struct sony_pic_ioport *ioport =				list_first_entry(&dev->ioports, struct sony_pic_ioport, list);			if (!io) {				dprintk("Blank IO resource\n");				return AE_OK;			}			if (!ioport->io1.minimum) {				memcpy(&ioport->io1, io, sizeof(*io));				dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,						ioport->io1.address_length);			}			else if (!ioport->io2.minimum) {				memcpy(&ioport->io2, io, sizeof(*io));				dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,						ioport->io2.address_length);			}			else {				printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n");				return AE_ERROR;			}			return AE_OK;		}	default:		dprintk("Resource %d isn't an IRQ nor an IO port\n",				resource->type);	case ACPI_RESOURCE_TYPE_END_TAG:		return AE_OK;	}	return AE_CTRL_TERMINATE;}static int sony_pic_possible_resources(struct acpi_device *device){	int result = 0;	acpi_status status = AE_OK;	if (!device)		return -EINVAL;	/* get device status */	/* see acpi_pci_link_get_current acpi_pci_link_get_possible */	dprintk("Evaluating _STA\n");	result = acpi_bus_get_status(device);	if (result) {		printk(KERN_WARNING DRV_PFX "Unable to read status\n");		goto end;	}	if (!device->status.enabled)		dprintk("Device disabled\n");	else		dprintk("Device enabled\n");	/*	 * Query and parse 'method'	 */	dprintk("Evaluating %s\n", METHOD_NAME__PRS);	status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,			sony_pic_read_possible_resource, &spic_dev);	if (ACPI_FAILURE(status)) {		printk(KERN_WARNING DRV_PFX				"Failure evaluating %s\n",				METHOD_NAME__PRS);		result = -ENODEV;	}end:	return result;}/* *  Disable the spic device by calling its _DIS method */static int sony_pic_disable(struct acpi_device *device){	if (ACPI_FAILURE(acpi_evaluate_object(device->handle,			"_DIS", NULL, NULL)))		return -ENXIO;	dprintk("Device disabled\n");	return 0;}/* *  Based on drivers/acpi/pci_link.c:acpi_pci_link_set * *  Call _SRS to set current resources */static int sony_pic_enable(struct acpi_device *device,		struct sony_pic_ioport *ioport, struct sony_pic_irq *irq){	acpi_status status;	int result = 0;	/* Type 1 resource layout is:	 *    IO	 *    IO	 *    IRQNoFlags	 *    End	 *	 * Type 2 and 3 resource layout is:	 *    IO	 *    IRQNoFlags	 *    End	 */	struct {		struct acpi_resource res1;		struct acpi_resource res2;		struct acpi_resource res3;		struct acpi_resource res4;	} *resource;	struct acpi_buffer buffer = { 0, NULL };	if (!ioport || !irq)		return -EINVAL;	/* init acpi_buffer */	resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);	if (!resource)		return -ENOMEM;	buffer.length = sizeof(*resource) + 1;	buffer.pointer = resource;	/* setup Type 1 resources */	if (spic_dev.model == SONYPI_DEVICE_TYPE1) {		/* setup io resources */		resource->res1.type = ACPI_RESOURCE_TYPE_IO;		resource->res1.length = sizeof(struct acpi_resource);		memcpy(&resource->res1.data.io, &ioport->io1,				sizeof(struct acpi_resource_io));		resource->res2.type = ACPI_RESOURCE_TYPE_IO;		resource->res2.length = sizeof(struct acpi_resource);		memcpy(&resource->res2.data.io, &ioport->io2,				sizeof(struct acpi_resource_io));		/* setup irq resource */		resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;		resource->res3.length = sizeof(struct acpi_resource);		memcpy(&resource->res3.data.irq, &irq->irq,				sizeof(struct acpi_resource_irq));		/* we requested a shared irq */		resource->res3.data.irq.sharable = ACPI_SHARED;		resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;	}	/* setup Type 2/3 resources */	else {		/* setup io resource */		resource->res1.type = ACPI_RESOURCE_TYPE_IO;		resource->res1.length = sizeof(struct acpi_resource);		memcpy(&resource->res1.data.io, &ioport->io1,				sizeof(struct acpi_resource_io));		/* setup irq resource */		resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;		resource->res2.length = sizeof(struct acpi_resource);		memcpy(&resource->res2.data.irq, &irq->irq,				sizeof(struct acpi_resource_irq));		/* we requested a shared irq */		resource->res2.data.irq.sharable = ACPI_SHARED;		resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;	}	/* Attempt to set the resource */	dprintk("Evaluating _SRS\n");	status = acpi_set_current_resources(device->handle, &buffer);	/* check for total failure */	if (ACPI_FAILURE(status)) {		printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n");		result = -ENODEV;		goto end;	}	/* Necessary device initializations calls (from sonypi) */	sony_pic_call1(0x82);	sony_pic_call2(0x81, 0xff);	sony_pic_call1(compat ? 0x92 : 0x82);end:	kfree(resource);	return result;}/***************** * * ISR: some event is available * *****************/static irqreturn_t sony_pic_irq(int irq, void *dev_id){	int i, j;	u8 ev = 0;	u8 data_mask = 0;	u8 device_event = 0;	struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;	ev = inb_p(dev->cur_ioport->io1.minimum);	if (dev->cur_ioport->io2.minimum)		data_mask = inb_p(dev->cur_ioport->io2.minimum);	else		data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset);	dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",			ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset);	if (ev == 0x00 || ev == 0xff)		return IRQ_HANDLED;	for (i = 0; sony_pic_eventtypes[i].model; i++) {		if (spic_dev.model != sony_pic_eventtypes[i].model)			continue;		if ((data_mask & sony_pic_eventtypes[i].data) !=		    sony_pic_eventtypes[i].data)			continue;		if (!(mask & sony_pic_eventtypes[i].mask))			continue;		for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) {			if (ev == sony_pic_eventtypes[i].events[j].data) {				device_event =					sony_pic_eventtypes[i].events[j].event;				goto found;			}		}	}	return IRQ_HANDLED;found:	sony_laptop_report_input_event(device_event);	acpi_bus_generate_proc_event(spic_dev.acpi_dev, 1, device_event);	sonypi_compat_report_event(device_event);	return IRQ_HANDLED;}/***************** * *  ACPI driver * *****************/static int sony_pic_remove(struct acpi_device *device, int type){	struct sony_pic_ioport *io, *tmp_io;	struct sony_pic_irq *irq, *tmp_irq;	if (sony_pic_disable(device)) {		printk(KERN_ERR DRV_PFX "Couldn't disable device.\n");		return -ENXIO;	}	free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);	release_region(spic_dev.cur_ioport->io1.minimum,			spic_dev.cur_ioport->io1.address_length);	if (spic_dev.cur_ioport->io2.minimum)		release_region(spic_dev.cur_ioport->io2.minimum,				spic_dev.cur_ioport->io2.address_length);	sonypi_compat_exit();	sony_laptop_remove_input();	/* pf attrs */	sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);	sony_pf_remove();	list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {		list_del(&io->list);		kfree(io);	}	list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {		list_del(&irq->list);		kfree(irq);	}	spic_dev.cur_ioport = NULL;	spic_dev.cur_irq = NULL;	dprintk(SONY_PIC_DRIVER_NAME " removed.\n");	return 0;}static int sony_pic_add(struct acpi_device *device){	int result;	struct sony_pic_ioport *io, *tmp_io;	struct sony_pic_irq *irq, *tmp_irq;	printk(KERN_INFO DRV_PFX "%s v%s.\n",		SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);	spic_dev.acpi_dev = device;	strcpy(acpi_device_class(device), "sony/hotkey");	spic_dev.model = sony_pic_detect_device_type();	mutex_init(&spic_dev.lock);	/* model specific characteristics */	switch(spic_dev.model) {		case SONYPI_DEVICE_TYPE1:			spic_dev.evport_offset = SONYPI_TYPE1_OFFSET;			break;		case SONYPI_DEVICE_TYP

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -