atkbd.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,002 行 · 第 1/2 页

C
1,002
字号
/* * AT and PS/2 keyboard driver * * Copyright (c) 1999-2002 Vojtech Pavlik *//* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. *//* * This driver can handle standard AT keyboards and PS/2 keyboards in * Translated and Raw Set 2 and Set 3, as well as AT keyboards on dumb * input-only controllers and AT keyboards connected over a one way RS232 * converter. */#include <linux/delay.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/input.h>#include <linux/serio.h>#include <linux/workqueue.h>#define DRIVER_DESC	"AT and PS/2 keyboard driver"MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");static int atkbd_set = 2;module_param_named(set, atkbd_set, int, 0);MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)");#if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)static int atkbd_reset;#elsestatic int atkbd_reset = 1;#endifmodule_param_named(reset, atkbd_reset, bool, 0);MODULE_PARM_DESC(reset, "Reset keyboard during initialization");static int atkbd_softrepeat;module_param_named(softrepeat, atkbd_softrepeat, bool, 0);MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");static int atkbd_softraw = 1;module_param_named(softraw, atkbd_softraw, bool, 0);MODULE_PARM_DESC(softraw, "Use software generated rawmode");static int atkbd_scroll;module_param_named(scroll, atkbd_scroll, bool, 0);MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");static int atkbd_extra;module_param_named(extra, atkbd_extra, bool, 0);MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");__obsolete_setup("atkbd_set=");__obsolete_setup("atkbd_reset");__obsolete_setup("atkbd_softrepeat=");/* * Scancode to keycode tables. These are just the default setting, and * are loadable via an userland utility. */#if defined(__hppa__)#include "hpps2atkbd.h"#elsestatic unsigned char atkbd_set2_keycode[512] = {	  0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,	  0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,	  0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,	  0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,	  0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,	  0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,	  0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,	 82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,	217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,	173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,	159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,	157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,	226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,	  0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,	110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,	  0,  0,  0, 65, 99,};#endifstatic unsigned char atkbd_set3_keycode[512] = {	  0,  0,  0,  0,  0,  0,  0, 59,  1,138,128,129,130, 15, 41, 60,	131, 29, 42, 86, 58, 16,  2, 61,133, 56, 44, 31, 30, 17,  3, 62,	134, 46, 45, 32, 18,  5,  4, 63,135, 57, 47, 33, 20, 19,  6, 64,	136, 49, 48, 35, 34, 21,  7, 65,137,100, 50, 36, 22,  8,  9, 66,	125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68,	113,114, 40, 43, 26, 13, 87, 99, 97, 54, 28, 27, 43, 43, 88, 70,	108,105,119,103,111,107, 14,110,  0, 79,106, 75, 71,109,102,104,	 82, 83, 80, 76, 77, 72, 69, 98,  0, 96, 81,  0, 78, 73, 55,183,	184,185,186,187, 74, 94, 92, 93,  0,  0,  0,125,126,127,112,  0,	  0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168,	148,149,147,140};static unsigned char atkbd_unxlate_table[128] = {          0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,         21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,         35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,         50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,         11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,        114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,         71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,         19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110};#define ATKBD_CMD_SETLEDS	0x10ed#define ATKBD_CMD_GSCANSET	0x11f0#define ATKBD_CMD_SSCANSET	0x10f0#define ATKBD_CMD_GETID		0x02f2#define ATKBD_CMD_SETREP	0x10f3#define ATKBD_CMD_ENABLE	0x00f4#define ATKBD_CMD_RESET_DIS	0x00f5#define ATKBD_CMD_SETALL_MBR	0x00fa#define ATKBD_CMD_RESET_BAT	0x02ff#define ATKBD_CMD_RESEND	0x00fe#define ATKBD_CMD_EX_ENABLE	0x10ea#define ATKBD_CMD_EX_SETLEDS	0x20eb#define ATKBD_CMD_OK_GETID	0x02e8#define ATKBD_RET_ACK		0xfa#define ATKBD_RET_NAK		0xfe#define ATKBD_RET_BAT		0xaa#define ATKBD_RET_EMUL0		0xe0#define ATKBD_RET_EMUL1		0xe1#define ATKBD_RET_RELEASE	0xf0#define ATKBD_RET_HANGUEL	0xf1#define ATKBD_RET_HANJA		0xf2#define ATKBD_RET_ERR		0xff#define ATKBD_KEY_UNKNOWN	  0#define ATKBD_KEY_NULL		255#define ATKBD_SCR_1		254#define ATKBD_SCR_2		253#define ATKBD_SCR_4		252#define ATKBD_SCR_8		251#define ATKBD_SCR_CLICK		250#define ATKBD_SPECIAL		250static unsigned char atkbd_scroll_keys[5][2] = {	{ ATKBD_SCR_1,     0x45 },	{ ATKBD_SCR_2,     0x29 },	{ ATKBD_SCR_4,     0x36 },	{ ATKBD_SCR_8,     0x27 },	{ ATKBD_SCR_CLICK, 0x60 },};#define ATKBD_FLAG_ACK		0	/* Waiting for ACK/NAK */#define ATKBD_FLAG_CMD		1	/* Waiting for command to finish */#define ATKBD_FLAG_CMD1		2	/* First byte of command response */#define ATKBD_FLAG_ENABLED	3	/* Waining for init to finish *//* * The atkbd control structure */struct atkbd {	/* Written only during init */	char name[64];	char phys[32];	struct serio *serio;	struct input_dev dev;	unsigned char set;	unsigned short id;	unsigned char keycode[512];	unsigned char translated;	unsigned char extra;	unsigned char write;	/* Protected by FLAG_ACK */	unsigned char nak;	/* Protected by FLAG_CMD */	unsigned char cmdbuf[4];	unsigned char cmdcnt;	/* Accessed only from interrupt */	unsigned char emul;	unsigned char resend;	unsigned char release;	unsigned char bat_xl;	unsigned int last;	unsigned long time;	/* Ensures that only one command is executing at a time */	struct semaphore cmd_sem;	/* Used to signal completion from interrupt handler */	wait_queue_head_t wait;	/* Flags */	unsigned long flags;};/* Work structure to schedule execution of a command */struct atkbd_work {	struct work_struct work;	struct atkbd *atkbd;	int command;	unsigned char param[0];};static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value){	input_regs(dev, regs);	if (value == 3) {		input_report_key(dev, code, 1);		input_report_key(dev, code, 0);	} else		input_event(dev, EV_KEY, code, value);	input_sync(dev);}/* * atkbd_interrupt(). Here takes place processing of data received from * the keyboard into events. */static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,			unsigned int flags, struct pt_regs *regs){	struct atkbd *atkbd = serio->private;	unsigned int code = data;	int scroll = 0, click = -1;	int value;#ifdef ATKBD_DEBUG	printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);#endif#if !defined(__i386__) && !defined (__x86_64__)	if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {		printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags);		serio_write(serio, ATKBD_CMD_RESEND);		atkbd->resend = 1;		goto out;	}	if (!flags && data == ATKBD_RET_ACK)		atkbd->resend = 0;#endif	if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags)) {		switch (code) {			case ATKBD_RET_ACK:				atkbd->nak = 0;				if (atkbd->cmdcnt) {					set_bit(ATKBD_FLAG_CMD, &atkbd->flags);					set_bit(ATKBD_FLAG_CMD1, &atkbd->flags);				}				clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);				wake_up_interruptible(&atkbd->wait);				break;			case ATKBD_RET_NAK:				atkbd->nak = 1;				clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);				wake_up_interruptible(&atkbd->wait);				break;		}		goto out;	}	if (test_bit(ATKBD_FLAG_CMD, &atkbd->flags)) {		if (atkbd->cmdcnt)			atkbd->cmdbuf[--atkbd->cmdcnt] = code;		if (test_and_clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags) && atkbd->cmdcnt)			wake_up_interruptible(&atkbd->wait);		if (!atkbd->cmdcnt) {			clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);			wake_up_interruptible(&atkbd->wait);		}		goto out;	}	if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags))		goto out;	input_event(&atkbd->dev, EV_MSC, MSC_RAW, code);	if (atkbd->translated) {		if (atkbd->emul ||		    !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 ||		      code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA ||		      code == ATKBD_RET_ERR ||	             (code == ATKBD_RET_BAT && !atkbd->bat_xl))) {			atkbd->release = code >> 7;			code &= 0x7f;		}		if (!atkbd->emul &&		     (code & 0x7f) == (ATKBD_RET_BAT & 0x7f))			atkbd->bat_xl = !atkbd->release;	}	switch (code) {		case ATKBD_RET_BAT:			clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);			serio_rescan(atkbd->serio);			goto out;		case ATKBD_RET_EMUL0:			atkbd->emul = 1;			goto out;		case ATKBD_RET_EMUL1:			atkbd->emul = 2;			goto out;		case ATKBD_RET_RELEASE:			atkbd->release = 1;			goto out;		case ATKBD_RET_HANGUEL:			atkbd_report_key(&atkbd->dev, regs, KEY_HANGUEL, 3);			goto out;		case ATKBD_RET_HANJA:			atkbd_report_key(&atkbd->dev, regs, KEY_HANJA, 3);			goto out;		case ATKBD_RET_ERR:			printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);			goto out;	}	if (atkbd->set != 3)		code = (code & 0x7f) | ((code & 0x80) << 1);	if (atkbd->emul) {		if (--atkbd->emul)			goto out;		code |= (atkbd->set != 3) ? 0x80 : 0x100;	}	if (atkbd->keycode[code] != ATKBD_KEY_NULL)		input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code);	switch (atkbd->keycode[code]) {		case ATKBD_KEY_NULL:			break;		case ATKBD_KEY_UNKNOWN:			if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) {				printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, "				       "like XFree86, might be trying access hardware directly.\n",				       data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);			} else {				printk(KERN_WARNING "atkbd.c: Unknown key %s "				       "(%s set %d, code %#x on %s).\n",				       atkbd->release ? "released" : "pressed",				       atkbd->translated ? "translated" : "raw",				       atkbd->set, code, serio->phys);				printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' "				       "to make it known.\n",				       code & 0x80 ? "e0" : "", code & 0x7f);			}			break;		case ATKBD_SCR_1:			scroll = 1 - atkbd->release * 2;			break;		case ATKBD_SCR_2:			scroll = 2 - atkbd->release * 4;			break;		case ATKBD_SCR_4:			scroll = 4 - atkbd->release * 8;			break;		case ATKBD_SCR_8:			scroll = 8 - atkbd->release * 16;			break;		case ATKBD_SCR_CLICK:			click = !atkbd->release;			break;		default:			value = atkbd->release ? 0 :				(1 + (!atkbd_softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));			switch (value) { 	/* Workaround Toshiba laptop multiple keypress */				case 0:					atkbd->last = 0;					break;				case 1:					atkbd->last = code;					atkbd->time = jiffies + (atkbd->dev.rep[REP_DELAY] * HZ + 500) / 1000 / 2;					break;				case 2:					if (!time_after(jiffies, atkbd->time) && atkbd->last == code)						value = 1;					break;			}			atkbd_report_key(&atkbd->dev, regs, atkbd->keycode[code], value);	}	if (scroll || click != -1) {		input_regs(&atkbd->dev, regs);		input_report_key(&atkbd->dev, BTN_MIDDLE, click);		input_report_rel(&atkbd->dev, REL_WHEEL, scroll);		input_sync(&atkbd->dev);	}	atkbd->release = 0;out:	return IRQ_HANDLED;}/* * atkbd_sendbyte() sends a byte to the keyboard, and waits for * acknowledge. It doesn't handle resends according to the keyboard * protocol specs, because if these are needed, the keyboard needs * replacement anyway, and they only make a mess in the protocol. * * atkbd_sendbyte() can only be called from a process context */static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte){#ifdef ATKBD_DEBUG	printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);#endif	atkbd->nak = 1;	set_bit(ATKBD_FLAG_ACK, &atkbd->flags);	if (serio_write(atkbd->serio, byte) == 0)		wait_event_interruptible_timeout(atkbd->wait,				!test_bit(ATKBD_FLAG_ACK, &atkbd->flags),				msecs_to_jiffies(200));	clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);	return -atkbd->nak;}/* * atkbd_command() sends a command, and its parameters to the keyboard, * then waits for the response and puts it in the param array. * * atkbd_command() can only be called from a process context */static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command){	int timeout;	int send = (command >> 12) & 0xf;	int receive = (command >> 8) & 0xf;	int rc = -1;	int i;	timeout = msecs_to_jiffies(command == ATKBD_CMD_RESET_BAT ? 4000 : 500);	down(&atkbd->cmd_sem);	clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);	if (receive && param)		for (i = 0; i < receive; i++)			atkbd->cmdbuf[(receive - 1) - i] = param[i];	atkbd->cmdcnt = receive;	if (command & 0xff)		if (atkbd_sendbyte(atkbd, command & 0xff))			goto out;	for (i = 0; i < send; i++)		if (atkbd_sendbyte(atkbd, param[i]))			goto out;	timeout = wait_event_interruptible_timeout(atkbd->wait,				!test_bit(ATKBD_FLAG_CMD1, &atkbd->flags), timeout);	if (atkbd->cmdcnt && timeout > 0) {		if (command == ATKBD_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100)			timeout = msecs_to_jiffies(100);		if (command == ATKBD_CMD_GETID &&		    atkbd->cmdbuf[receive - 1] != 0xab && atkbd->cmdbuf[receive - 1] != 0xac) {			/*			 * Device behind the port is not a keyboard			 * so we don't need to wait for the 2nd byte

⌨️ 快捷键说明

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