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

📄 i8042.c

📁 QQ2440板子
💻 C
📖 第 1 页 / 共 2 页
字号:
 * i8042_check_mux() checks whether the controller supports the PS/2 Active * Multiplexing specification by Synaptics, Phoenix, Insyde and * LCS/Telegraphics. */static int __init i8042_check_mux(void){	unsigned char mux_version;	if (i8042_set_mux_mode(1, &mux_version))		return -1;	/* Workaround for interference with USB Legacy emulation */	/* that causes a v10.12 MUX to be found. */	if (mux_version == 0xAC)		return -1;	printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",		(mux_version >> 4) & 0xf, mux_version & 0xf);	if (i8042_enable_mux_ports())		return -1;	i8042_mux_present = 1;	return 0;}/* * i8042_check_aux() applies as much paranoia as it can at detecting * the presence of an AUX interface. */static int __init i8042_check_aux(void){	unsigned char param;	static int i8042_check_aux_cookie;/* * Check if AUX irq is available. If it isn't, then there is no point * in trying to detect AUX presence. */	if (request_irq(i8042_ports[I8042_AUX_PORT_NO].irq, i8042_interrupt,			SA_SHIRQ, "i8042", &i8042_check_aux_cookie))                return -1;	free_irq(i8042_ports[I8042_AUX_PORT_NO].irq, &i8042_check_aux_cookie);/* * Get rid of bytes in the queue. */	i8042_flush();/* * Internal loopback test - filters out AT-type i8042's. Unfortunately * SiS screwed up and their 5597 doesn't support the LOOP command even * though it has an AUX port. */	param = 0x5a;	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0x5a) {/* * External connection test - filters out AT-soldered PS/2 i8042's * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error * 0xfa - no error on some notebooks which ignore the spec * Because it's common for chipsets to return error on perfectly functioning * AUX ports, we test for this only when the LOOP command failed. */		if (i8042_command(&param, I8042_CMD_AUX_TEST)			|| (param && param != 0xfa && param != 0xff))				return -1;	}/* * Bit assignment test - filters out PS/2 i8042's in AT mode */	if (i8042_command(&param, I8042_CMD_AUX_DISABLE))		return -1;	if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS)) {		printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");		printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n");	}	if (i8042_command(&param, I8042_CMD_AUX_ENABLE))		return -1;	if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS))		return -1;/* * Disable the interface. */	i8042_ctr |= I8042_CTR_AUXDIS;	i8042_ctr &= ~I8042_CTR_AUXINT;	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))		return -1;	return 0;}/* * i8042_port_register() marks the device as existing, * registers it, and reports to the user. */static int __init i8042_port_register(struct i8042_port *port){	i8042_ctr &= ~port->disable;	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {		printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n");		kfree(port->serio);		port->serio = NULL;		i8042_ctr |= port->disable;		return -1;	}	printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n",	       port->name,	       (unsigned long) I8042_DATA_REG,	       (unsigned long) I8042_COMMAND_REG,	       port->irq);	serio_register_port(port->serio);	return 0;}static void i8042_timer_func(unsigned long data){	i8042_interrupt(0, NULL, NULL);}static int i8042_ctl_test(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 -1;	}	if (param != I8042_RET_CTL_TEST) {		printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",			 param, I8042_RET_CTL_TEST);		return -1;	}	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;/* * Test the i8042. We need to know if it thinks it's working correctly * before doing anything else. */	if (i8042_flush() == I8042_BUFFER_SIZE) {		printk(KERN_ERR "i8042.c: No controller found.\n");		return -1;	}	if (i8042_ctl_test())		return -1;/* * 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 -1;	}	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 -1;	}	return 0;}/* * Reset the controller. */static void i8042_controller_reset(void){/* * Reset the controller if requested. */	i8042_ctl_test();/* * Disable MUX mode if present. */	if (i8042_mux_present)		i8042_set_mux_mode(0, NULL);/* * Restore the original control register setting. */	i8042_ctr = i8042_initial_ctr;	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))		printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");}/* * Here we try to reset everything back to a state in which the BIOS will be * able to talk to the hardware when rebooting. */static void i8042_controller_cleanup(void){	int i;	i8042_flush();/* * Reset anything that is connected to the ports. */	for (i = 0; i < I8042_NUM_PORTS; i++)		if (i8042_ports[i].exists)			serio_cleanup(i8042_ports[i].serio);	i8042_controller_reset();}/* * 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;	i8042_write_data(0xed); /* set leds */	DELAY;	while (i8042_read_status() & I8042_STR_IBF)		DELAY;	DELAY;	i8042_write_data(led);	DELAY;	last_blink = count;	return delay;}#undef DELAY/* * Here we try to restore the original BIOS settings */static int i8042_suspend(struct device *dev, pm_message_t state, u32 level){	if (level == SUSPEND_DISABLE) {		del_timer_sync(&i8042_timer);		i8042_controller_reset();	}	return 0;}/* * Here we try to reset everything back to a state in which suspended */static int i8042_resume(struct device *dev, u32 level){	int i;	if (level != RESUME_ENABLE)		return 0;	if (i8042_ctl_test())		return -1;	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {		printk(KERN_ERR "i8042: Can't write CTR\n");		return -1;	}	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");/* * Activate all ports. */	for (i = 0; i < I8042_NUM_PORTS; i++)		i8042_activate_port(&i8042_ports[i]);/* * Restart timer (for polling "stuck" data) */	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);	panic_blink = i8042_panic_blink;	return 0;}/* * We need to reset the 8042 back to original mode on system shutdown, * because otherwise BIOSes will be confused. */static void i8042_shutdown(struct device *dev){	i8042_controller_cleanup();}static struct device_driver i8042_driver = {	.name		= "i8042",	.bus		= &platform_bus_type,	.suspend	= i8042_suspend,	.resume		= i8042_resume,	.shutdown	= i8042_shutdown,};static void __init i8042_create_kbd_port(void){	struct serio *serio;	struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);	if (serio) {		memset(serio, 0, sizeof(struct serio));		serio->id.type		= i8042_direct ? SERIO_8042 : SERIO_8042_XL;		serio->write		= i8042_dumbkbd ? NULL : i8042_kbd_write;		serio->open		= i8042_open;		serio->close		= i8042_close;		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;		i8042_port_register(port);	}}static void __init i8042_create_aux_port(void){	struct serio *serio;	struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO];	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);	if (serio) {		memset(serio, 0, sizeof(struct serio));		serio->id.type		= SERIO_8042;		serio->write		= i8042_aux_write;		serio->open		= i8042_open;		serio->close		= i8042_close;		serio->start		= i8042_start;		serio->stop		= i8042_stop;		serio->port_data	= port;		serio->dev.parent	= &i8042_platform_device->dev;		strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name));		strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));		port->serio = serio;		i8042_port_register(port);	}}static void __init i8042_create_mux_port(int index){	struct serio *serio;	struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index];	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);	if (serio) {		memset(serio, 0, sizeof(struct serio));		serio->id.type		= SERIO_8042;		serio->write		= i8042_aux_write;		serio->open		= i8042_open;		serio->close		= i8042_close;		serio->start		= i8042_start;		serio->stop		= i8042_stop;		serio->port_data	= port;		serio->dev.parent	= &i8042_platform_device->dev;		snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index);		snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1);		*port = i8042_ports[I8042_AUX_PORT_NO];		port->exists = 0;		snprintf(port->name, sizeof(port->name), "AUX%d", index);		port->mux = index;		port->serio = serio;		i8042_port_register(port);	}}static int __init i8042_init(void){	int i;	int err;	dbg_init();	init_timer(&i8042_timer);	i8042_timer.function = i8042_timer_func;	if (i8042_platform_init())		return -EBUSY;	i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ;	i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ;	if (i8042_controller_init()) {		i8042_platform_exit();		return -ENODEV;	}	err = driver_register(&i8042_driver);	if (err) {		i8042_platform_exit();		return err;	}	i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0);	if (IS_ERR(i8042_platform_device)) {		driver_unregister(&i8042_driver);		i8042_platform_exit();		return PTR_ERR(i8042_platform_device);	}	if (!i8042_noaux && !i8042_check_aux()) {		if (!i8042_nomux && !i8042_check_mux())			for (i = 0; i < I8042_NUM_MUX_PORTS; i++)				i8042_create_mux_port(i);		else			i8042_create_aux_port();	}	i8042_create_kbd_port();	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);	return 0;}static void __exit i8042_exit(void){	int i;	i8042_controller_cleanup();	for (i = 0; i < I8042_NUM_PORTS; i++)		if (i8042_ports[i].exists)			serio_unregister_port(i8042_ports[i].serio);	del_timer_sync(&i8042_timer);	platform_device_unregister(i8042_platform_device);	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 + -