atkbd.c

来自「linux 内核源代码」· C语言 代码 · 共 1,417 行 · 第 1/3 页

C
1,417
字号
			break;		case ATKBD_SCR_RIGHT:			hscroll = 1;			break;		default:			if (atkbd->release) {				value = 0;				atkbd->last = 0;			} else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {				/* Workaround Toshiba laptop multiple keypress */				value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;			} else {				value = 1;				atkbd->last = code;				atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;			}			input_event(dev, EV_KEY, keycode, value);			input_sync(dev);			if (value && add_release_event) {				input_report_key(dev, keycode, 0);				input_sync(dev);			}	}	if (atkbd->scroll) {		if (click != -1)			input_report_key(dev, BTN_MIDDLE, click);		input_report_rel(dev, REL_WHEEL, scroll);		input_report_rel(dev, REL_HWHEEL, hscroll);		input_sync(dev);	}	atkbd->release = 0;out:	return IRQ_HANDLED;}static int atkbd_set_repeat_rate(struct atkbd *atkbd){	const short period[32] =		{ 33,  37,  42,  46,  50,  54,  58,  63,  67,  75,  83,  92, 100, 109, 116, 125,		 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };	const short delay[4] =		{ 250, 500, 750, 1000 };	struct input_dev *dev = atkbd->dev;	unsigned char param;	int i = 0, j = 0;	while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD])		i++;	dev->rep[REP_PERIOD] = period[i];	while (j < ARRAY_SIZE(delay) - 1 && delay[j] < dev->rep[REP_DELAY])		j++;	dev->rep[REP_DELAY] = delay[j];	param = i | (j << 5);	return ps2_command(&atkbd->ps2dev, &param, ATKBD_CMD_SETREP);}static int atkbd_set_leds(struct atkbd *atkbd){	struct input_dev *dev = atkbd->dev;	unsigned char param[2];	param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)		 | (test_bit(LED_NUML,    dev->led) ? 2 : 0)		 | (test_bit(LED_CAPSL,   dev->led) ? 4 : 0);	if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))		return -1;	if (atkbd->extra) {		param[0] = 0;		param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)			 | (test_bit(LED_SLEEP,   dev->led) ? 0x02 : 0)			 | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)			 | (test_bit(LED_MISC,    dev->led) ? 0x10 : 0)			 | (test_bit(LED_MUTE,    dev->led) ? 0x20 : 0);		if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS))			return -1;	}	return 0;}/* * atkbd_event_work() is used to complete processing of events that * can not be processed by input_event() which is often called from * interrupt context. */static void atkbd_event_work(struct work_struct *work){	struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work);	mutex_lock(&atkbd->event_mutex);	if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))		atkbd_set_leds(atkbd);	if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))		atkbd_set_repeat_rate(atkbd);	mutex_unlock(&atkbd->event_mutex);}/* * Schedule switch for execution. We need to throttle requests, * otherwise keyboard may become unresponsive. */static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit){	unsigned long delay = msecs_to_jiffies(50);	if (time_after(jiffies, atkbd->event_jiffies + delay))		delay = 0;	atkbd->event_jiffies = jiffies;	set_bit(event_bit, &atkbd->event_mask);	wmb();	schedule_delayed_work(&atkbd->event_work, delay);}/* * Event callback from the input module. Events that change the state of * the hardware are processed here. If action can not be performed in * interrupt context it is offloaded to atkbd_event_work. */static int atkbd_event(struct input_dev *dev,			unsigned int type, unsigned int code, int value){	struct atkbd *atkbd = input_get_drvdata(dev);	if (!atkbd->write)		return -1;	switch (type) {		case EV_LED:			atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);			return 0;		case EV_REP:			if (!atkbd->softrepeat)				atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);			return 0;	}	return -1;}/* * atkbd_enable() signals that interrupt handler is allowed to * generate input events. */static inline void atkbd_enable(struct atkbd *atkbd){	serio_pause_rx(atkbd->ps2dev.serio);	atkbd->enabled = 1;	serio_continue_rx(atkbd->ps2dev.serio);}/* * atkbd_disable() tells input handler that all incoming data except * for ACKs and command response should be dropped. */static inline void atkbd_disable(struct atkbd *atkbd){	serio_pause_rx(atkbd->ps2dev.serio);	atkbd->enabled = 0;	serio_continue_rx(atkbd->ps2dev.serio);}/* * atkbd_probe() probes for an AT keyboard on a serio port. */static int atkbd_probe(struct atkbd *atkbd){	struct ps2dev *ps2dev = &atkbd->ps2dev;	unsigned char param[2];/* * Some systems, where the bit-twiddling when testing the io-lines of the * controller may confuse the keyboard need a full reset of the keyboard. On * these systems the BIOS also usually doesn't do it for us. */	if (atkbd_reset)		if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))			printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", ps2dev->serio->phys);/* * Then we check the keyboard ID. We should get 0xab83 under normal conditions. * Some keyboards report different values, but the first byte is always 0xab or * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this * should make sure we don't try to set the LEDs on it. */	param[0] = param[1] = 0xa5;	/* initialize with invalid values */	if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {/* * If the get ID command failed, we check if we can at least set the LEDs on * the keyboard. This should work on every keyboard out there. It also turns * the LEDs off, which we want anyway. */		param[0] = 0;		if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))			return -1;		atkbd->id = 0xabba;		return 0;	}	if (!ps2_is_keyboard_id(param[0]))		return -1;	atkbd->id = (param[0] << 8) | param[1];	if (atkbd->id == 0xaca1 && atkbd->translated) {		printk(KERN_ERR "atkbd.c: NCD terminal keyboards are only supported on non-translating\n");		printk(KERN_ERR "atkbd.c: controllers. Use i8042.direct=1 to disable translation.\n");		return -1;	}	return 0;}/* * atkbd_select_set checks if a keyboard has a working Set 3 support, and * sets it into that. Unfortunately there are keyboards that can be switched * to Set 3, but don't work well in that (BTC Multimedia ...) */static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra){	struct ps2dev *ps2dev = &atkbd->ps2dev;	unsigned char param[2];	atkbd->extra = 0;/* * For known special keyboards we can go ahead and set the correct set. * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards. */	if (atkbd->translated)		return 2;	if (atkbd->id == 0xaca1) {		param[0] = 3;		ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET);		return 3;	}	if (allow_extra) {		param[0] = 0x71;		if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {			atkbd->extra = 1;			return 2;		}	}	if (target_set != 3)		return 2;	if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) {		atkbd->id = param[0] << 8 | param[1];		return 2;	}	param[0] = 3;	if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))		return 2;	param[0] = 0;	if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET))		return 2;	if (param[0] != 3) {		param[0] = 2;		if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))		return 2;	}	ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);	return 3;}static int atkbd_activate(struct atkbd *atkbd){	struct ps2dev *ps2dev = &atkbd->ps2dev;	unsigned char param[1];/* * Set the LEDs to a defined state. */	param[0] = 0;	if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))		return -1;/* * Set autorepeat to fastest possible. */	param[0] = 0;	if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))		return -1;/* * Enable the keyboard to receive keystrokes. */	if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {		printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",			ps2dev->serio->phys);		return -1;	}	return 0;}/* * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a * reboot. */static void atkbd_cleanup(struct serio *serio){	struct atkbd *atkbd = serio_get_drvdata(serio);	ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT);}/* * atkbd_disconnect() closes and frees. */static void atkbd_disconnect(struct serio *serio){	struct atkbd *atkbd = serio_get_drvdata(serio);	atkbd_disable(atkbd);	/* make sure we don't have a command in flight */	synchronize_sched();  /* Allow atkbd_interrupt()s to complete. */	flush_scheduled_work();	sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);	input_unregister_device(atkbd->dev);	serio_close(serio);	serio_set_drvdata(serio, NULL);	kfree(atkbd);}/* * atkbd_set_keycode_table() initializes keyboard's keycode table * according to the selected scancode set */static void atkbd_set_keycode_table(struct atkbd *atkbd){	int i, j;	memset(atkbd->keycode, 0, sizeof(atkbd->keycode));	if (atkbd->translated) {		for (i = 0; i < 128; i++) {			atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];			atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];			if (atkbd->scroll)				for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)					if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j].set2)						atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;		}	} else if (atkbd->set == 3) {		memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));	} else {		memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));		if (atkbd->scroll)			for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)				atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode;	}	atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL)] = KEY_HANGUEL;	atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA)] = KEY_HANJA;}/* * atkbd_set_device_attrs() sets up keyboard's input device structure */static void atkbd_set_device_attrs(struct atkbd *atkbd){	struct input_dev *input_dev = atkbd->dev;	int i;	if (atkbd->extra)		snprintf(atkbd->name, sizeof(atkbd->name),			 "AT Set 2 Extra keyboard");	else		snprintf(atkbd->name, sizeof(atkbd->name),			 "AT %s Set %d keyboard",			 atkbd->translated ? "Translated" : "Raw", atkbd->set);	snprintf(atkbd->phys, sizeof(atkbd->phys),		 "%s/input0", atkbd->ps2dev.serio->phys);	input_dev->name = atkbd->name;	input_dev->phys = atkbd->phys;	input_dev->id.bustype = BUS_I8042;	input_dev->id.vendor = 0x0001;	input_dev->id.product = atkbd->translated ? 1 : atkbd->set;	input_dev->id.version = atkbd->id;	input_dev->event = atkbd_event;	input_dev->dev.parent = &atkbd->ps2dev.serio->dev;	input_set_drvdata(input_dev, atkbd);	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |		BIT_MASK(EV_MSC);	if (atkbd->write) {		input_dev->evbit[0] |= BIT_MASK(EV_LED);		input_dev->ledbit[0] = BIT_MASK(LED_NUML) |			BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL);	}	if (atkbd->extra)		input_dev->ledbit[0] |= BIT_MASK(LED_COMPOSE) |			BIT_MASK(LED_SUSPEND) | BIT_MASK(LED_SLEEP) |			BIT_MASK(LED_MUTE) | BIT_MASK(LED_MISC);	if (!atkbd->softrepeat) {		input_dev->rep[REP_DELAY] = 250;		input_dev->rep[REP_PERIOD] = 33;	}	input_dev->mscbit[0] = atkbd->softraw ? BIT_MASK(MSC_SCAN) :		BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN);	if (atkbd->scroll) {		input_dev->evbit[0] |= BIT_MASK(EV_REL);		input_dev->relbit[0] = BIT_MASK(REL_WHEEL) |			BIT_MASK(REL_HWHEEL);		set_bit(BTN_MIDDLE, input_dev->keybit);	}	input_dev->keycode = atkbd->keycode;	input_dev->keycodesize = sizeof(unsigned char);	input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);	for (i = 0; i < 512; i++)		if (atkbd->keycode[i] && atkbd->keycode[i] < ATKBD_SPECIAL)			set_bit(atkbd->keycode[i], input_dev->keybit);}/* * atkbd_connect() is called when the serio module finds an interface * that isn't handled yet by an appropriate device driver. We check if * there is an AT keyboard out there and if yes, we register ourselves * to the input module. */

⌨️ 快捷键说明

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