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

📄 i8042.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
 * used it for a PCI card or somethig else. */	if (i8042_noloop || aux_loop_broken) {/* * Without LOOP command we can't test AUX IRQ delivery. Assume the port * is working and hope we are right. */		retval = 0;		goto out;	}	if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED,			"i8042", i8042_platform_device))		goto out;	irq_registered = 1;	if (i8042_enable_aux_port())		goto out;	spin_lock_irqsave(&i8042_lock, flags);	init_completion(&i8042_aux_irq_delivered);	i8042_irq_being_tested = 1;	param = 0xa5;	retval = __i8042_command(&param, I8042_CMD_AUX_LOOP & 0xf0ff);	spin_unlock_irqrestore(&i8042_lock, flags);	if (retval)		goto out;	if (wait_for_completion_timeout(&i8042_aux_irq_delivered,					msecs_to_jiffies(250)) == 0) {/* * AUX IRQ was never delivered so we need to flush the controller to * get rid of the byte we put there; otherwise keyboard may not work. */		i8042_flush();		retval = -1;	} out:/* * Disable the interface. */	i8042_ctr |= I8042_CTR_AUXDIS;	i8042_ctr &= ~I8042_CTR_AUXINT;	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))		retval = -1;	if (irq_registered)		free_irq(I8042_AUX_IRQ, i8042_platform_device);	return retval;}static int i8042_controller_check(void){	if (i8042_flush() == I8042_BUFFER_SIZE) {		printk(KERN_ERR "i8042.c: No controller found.\n");		return -ENODEV;	}	return 0;}static int i8042_controller_selftest(void){	unsigned char param;	if (!i8042_reset)		return 0;	if (i8042_command(&param, I8042_CMD_CTL_TEST)) {		printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");		return -ENODEV;	}	if (param != I8042_RET_CTL_TEST) {		printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",			 param, I8042_RET_CTL_TEST);		return -EIO;	}	return 0;}/* * i8042_controller init initializes the i8042 controller, and, * most importantly, sets it into non-xlated mode if that's * desired. */static int i8042_controller_init(void){	unsigned long flags;/* * Save the CTR for restoral on unload / reboot. */	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {		printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n");		return -EIO;	}	i8042_initial_ctr = i8042_ctr;/* * Disable the keyboard interface and interrupt. */	i8042_ctr |= I8042_CTR_KBDDIS;	i8042_ctr &= ~I8042_CTR_KBDINT;/* * Handle keylock. */	spin_lock_irqsave(&i8042_lock, flags);	if (~i8042_read_status() & I8042_STR_KEYLOCK) {		if (i8042_unlock)			i8042_ctr |= I8042_CTR_IGNKEYLOCK;		else			printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");	}	spin_unlock_irqrestore(&i8042_lock, flags);/* * If the chip is configured into nontranslated mode by the BIOS, don't * bother enabling translating and be happy. */	if (~i8042_ctr & I8042_CTR_XLATE)		i8042_direct = 1;/* * Set nontranslated mode for the kbd interface if requested by an option. * After this the kbd interface becomes a simple serial in/out, like the aux * interface is. We don't do this by default, since it can confuse notebook * BIOSes. */	if (i8042_direct)		i8042_ctr &= ~I8042_CTR_XLATE;/* * Write CTR back. */	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {		printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n");		return -EIO;	}	return 0;}/* * Reset the controller and reset CRT to the original value set by BIOS. */static void i8042_controller_reset(void){	i8042_flush();/* * Disable both KBD and AUX interfaces so they don't get in the way */	i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;	i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);/* * Disable MUX mode if present. */	if (i8042_mux_present)		i8042_set_mux_mode(0, NULL);/* * Reset the controller if requested. */	i8042_controller_selftest();/* * Restore the original control register setting. */	if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))		printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");}/* * i8042_panic_blink() will flash the keyboard LEDs and is called when * kernel panics. Flashing LEDs is useful for users running X who may * not see the console and will help distingushing panics from "real" * lockups. * * Note that DELAY has a limit of 10ms so we will not get stuck here * waiting for KBC to free up even if KBD interrupt is off */#define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)static long i8042_panic_blink(long count){	long delay = 0;	static long last_blink;	static char led;	/*	 * We expect frequency to be about 1/2s. KDB uses about 1s.	 * Make sure they are different.	 */	if (!i8042_blink_frequency)		return 0;	if (count - last_blink < i8042_blink_frequency)		return 0;	led ^= 0x01 | 0x04;	while (i8042_read_status() & I8042_STR_IBF)		DELAY;	dbg("%02x -> i8042 (panic blink)", 0xed);	i8042_suppress_kbd_ack = 2;	i8042_write_data(0xed); /* set leds */	DELAY;	while (i8042_read_status() & I8042_STR_IBF)		DELAY;	DELAY;	dbg("%02x -> i8042 (panic blink)", led);	i8042_write_data(led);	DELAY;	last_blink = count;	return delay;}#undef DELAY#ifdef CONFIG_PM/* * Here we try to restore the original BIOS settings. We only want to * do that once, when we really suspend, not when we taking memory * snapshot for swsusp (in this case we'll perform required cleanup * as part of shutdown process). */static int i8042_suspend(struct platform_device *dev, pm_message_t state){	if (dev->dev.power.power_state.event != state.event) {		if (state.event == PM_EVENT_SUSPEND)			i8042_controller_reset();		dev->dev.power.power_state = state;	}	return 0;}/* * Here we try to reset everything back to a state in which suspended */static int i8042_resume(struct platform_device *dev){	int error;/* * Do not bother with restoring state if we haven't suspened yet */	if (dev->dev.power.power_state.event == PM_EVENT_ON)		return 0;	error = i8042_controller_check();	if (error)		return error;	error = i8042_controller_selftest();	if (error)		return error;/* * Restore original CTR value and disable all ports */	i8042_ctr = i8042_initial_ctr;	if (i8042_direct)		i8042_ctr &= ~I8042_CTR_XLATE;	i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;	i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {		printk(KERN_ERR "i8042: Can't write CTR to resume\n");		return -EIO;	}	if (i8042_mux_present) {		if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports())			printk(KERN_WARNING				"i8042: failed to resume active multiplexor, "				"mouse won't work.\n");	} else if (i8042_ports[I8042_AUX_PORT_NO].serio)		i8042_enable_aux_port();	if (i8042_ports[I8042_KBD_PORT_NO].serio)		i8042_enable_kbd_port();	i8042_interrupt(0, NULL);	dev->dev.power.power_state = PMSG_ON;	return 0;}#endif /* CONFIG_PM *//* * We need to reset the 8042 back to original mode on system shutdown, * because otherwise BIOSes will be confused. */static void i8042_shutdown(struct platform_device *dev){	i8042_controller_reset();}static int __devinit i8042_create_kbd_port(void){	struct serio *serio;	struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);	if (!serio)		return -ENOMEM;	serio->id.type		= i8042_direct ? SERIO_8042 : SERIO_8042_XL;	serio->write		= i8042_dumbkbd ? NULL : i8042_kbd_write;	serio->start		= i8042_start;	serio->stop		= i8042_stop;	serio->port_data	= port;	serio->dev.parent	= &i8042_platform_device->dev;	strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));	strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));	port->serio = serio;	port->irq = I8042_KBD_IRQ;	return 0;}static int __devinit i8042_create_aux_port(int idx){	struct serio *serio;	int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;	struct i8042_port *port = &i8042_ports[port_no];	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);	if (!serio)		return -ENOMEM;	serio->id.type		= SERIO_8042;	serio->write		= i8042_aux_write;	serio->start		= i8042_start;	serio->stop		= i8042_stop;	serio->port_data	= port;	serio->dev.parent	= &i8042_platform_device->dev;	if (idx < 0) {		strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name));		strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));	} else {		snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx);		snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1);	}	port->serio = serio;	port->mux = idx;	port->irq = I8042_AUX_IRQ;	return 0;}static void __devinit i8042_free_kbd_port(void){	kfree(i8042_ports[I8042_KBD_PORT_NO].serio);	i8042_ports[I8042_KBD_PORT_NO].serio = NULL;}static void __devinit i8042_free_aux_ports(void){	int i;	for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) {		kfree(i8042_ports[i].serio);		i8042_ports[i].serio = NULL;	}}static void __devinit i8042_register_ports(void){	int i;	for (i = 0; i < I8042_NUM_PORTS; i++) {		if (i8042_ports[i].serio) {			printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n",				i8042_ports[i].serio->name,				(unsigned long) I8042_DATA_REG,				(unsigned long) I8042_COMMAND_REG,				i8042_ports[i].irq);			serio_register_port(i8042_ports[i].serio);		}	}}static void __devexit i8042_unregister_ports(void){	int i;	for (i = 0; i < I8042_NUM_PORTS; i++) {		if (i8042_ports[i].serio) {			serio_unregister_port(i8042_ports[i].serio);			i8042_ports[i].serio = NULL;		}	}}static void i8042_free_irqs(void){	if (i8042_aux_irq_registered)		free_irq(I8042_AUX_IRQ, i8042_platform_device);	if (i8042_kbd_irq_registered)		free_irq(I8042_KBD_IRQ, i8042_platform_device);	i8042_aux_irq_registered = i8042_kbd_irq_registered = 0;}static int __devinit i8042_setup_aux(void){	int (*aux_enable)(void);	int error;	int i;	if (i8042_check_aux())		return -ENODEV;	if (i8042_nomux || i8042_check_mux()) {		error = i8042_create_aux_port(-1);		if (error)			goto err_free_ports;		aux_enable = i8042_enable_aux_port;	} else {		for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {			error = i8042_create_aux_port(i);			if (error)				goto err_free_ports;		}		aux_enable = i8042_enable_mux_ports;	}	error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED,			    "i8042", i8042_platform_device);	if (error)		goto err_free_ports;	if (aux_enable())		goto err_free_irq;	i8042_aux_irq_registered = 1;	return 0; err_free_irq:	free_irq(I8042_AUX_IRQ, i8042_platform_device); err_free_ports:	i8042_free_aux_ports();	return error;}static int __devinit i8042_setup_kbd(void){	int error;	error = i8042_create_kbd_port();	if (error)		return error;	error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,			    "i8042", i8042_platform_device);	if (error)		goto err_free_port;	error = i8042_enable_kbd_port();	if (error)		goto err_free_irq;	i8042_kbd_irq_registered = 1;	return 0; err_free_irq:	free_irq(I8042_KBD_IRQ, i8042_platform_device); err_free_port:	i8042_free_kbd_port();	return error;}static int __devinit i8042_probe(struct platform_device *dev){	int error;	error = i8042_controller_selftest();	if (error)		return error;	error = i8042_controller_init();	if (error)		return error;	if (!i8042_noaux) {		error = i8042_setup_aux();		if (error && error != -ENODEV && error != -EBUSY)			goto out_fail;	}	if (!i8042_nokbd) {		error = i8042_setup_kbd();		if (error)			goto out_fail;	}/* * Ok, everything is ready, let's register all serio ports */	i8042_register_ports();	return 0; out_fail:	i8042_free_aux_ports();	/* in case KBD failed but AUX not */	i8042_free_irqs();	i8042_controller_reset();	return error;}static int __devexit i8042_remove(struct platform_device *dev){	i8042_unregister_ports();	i8042_free_irqs();	i8042_controller_reset();	return 0;}static struct platform_driver i8042_driver = {	.driver		= {		.name	= "i8042",		.owner	= THIS_MODULE,	},	.probe		= i8042_probe,	.remove		= __devexit_p(i8042_remove),	.shutdown	= i8042_shutdown,#ifdef CONFIG_PM	.suspend	= i8042_suspend,	.resume		= i8042_resume,#endif};static int __init i8042_init(void){	int err;	dbg_init();	err = i8042_platform_init();	if (err)		return err;	err = i8042_controller_check();	if (err)		goto err_platform_exit;	err = platform_driver_register(&i8042_driver);	if (err)		goto err_platform_exit;	i8042_platform_device = platform_device_alloc("i8042", -1);	if (!i8042_platform_device) {		err = -ENOMEM;		goto err_unregister_driver;	}	err = platform_device_add(i8042_platform_device);	if (err)		goto err_free_device;	panic_blink = i8042_panic_blink;	return 0; err_free_device:	platform_device_put(i8042_platform_device); err_unregister_driver:	platform_driver_unregister(&i8042_driver); err_platform_exit:	i8042_platform_exit();	return err;}static void __exit i8042_exit(void){	platform_device_unregister(i8042_platform_device);	platform_driver_unregister(&i8042_driver);	i8042_platform_exit();	panic_blink = NULL;}module_init(i8042_init);module_exit(i8042_exit);

⌨️ 快捷键说明

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