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

📄 atkbd.c

📁 at91_ps2_驱动~at91sam9261的IO口模拟PS2键盘驱动程序设计——最新
💻 C
📖 第 1 页 / 共 3 页
字号:
		case ATKBD_SCR_LEFT:			hscroll = -1;			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)		//LED设置{	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);	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);}/* * 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. * 返回来自输入模块,改变器件进程状态,如果功能 不能被中断环境下使用 * 则卸下atkbd_event_work */static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value){	struct atkbd *atkbd = dev->private;	if (!atkbd->write)		return -1;	switch (type) {		case EV_LED:			set_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask);			wmb();			schedule_work(&atkbd->event_work);			return 0;		case EV_REP:			if (!atkbd->softrepeat) {				set_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask);				wmb();				schedule_work(&atkbd->event_work);			}			return 0;	}	return -1;}/* * atkbd_enable() signals that interrupt handler is allowed to * generate input events. * 使能AT键盘信号,使中断被允许,产生输入事件 */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. * 禁止atkbd */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. * 关于有些系统的控制I/O口抖动把键盘弄乱,需要重启 */	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. * 键盘ID正常情况下是0xab83,有些会不同但是允许前面为ab或者ac, * 老式键盘不会返回任何值,如果接的是鼠标确定我们不要设置LED,否则会报错 */	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. * 若ID返回出错,检查键盘的LED,学习从LED状态来检测键盘 */		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) {		/*	ID 相等于(0xaca1 && 译码)*/		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;}/* atkbd激活  */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));//初始化键盘码映射表	//将keycode所指向的某一块内存中的每个字节的内容全部设置为0指定的ASCII值,	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));		//由src所指内存区域复制count个字节到dest所指内存区域。  	//src和dest所指内存区域不能重叠,函数返回指向dest的指针。	} 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->private = atkbd;	input_dev->cdev.dev = &atkbd->ps2dev.serio->dev;	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);	if (atkbd->write) {		input_dev->evbit[0] |= BIT(EV_LED);		input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);	}	if (atkbd->extra)		input_dev->ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) |					BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);		if (!atkbd->softrepeat) {		input_dev->rep[REP_DELAY] = 250;		input_dev->rep[REP_PERIOD] = 33;	}	input_dev->mscbit[0] = atkbd->softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN);	if (atkbd->scroll) {		input_dev->evbit[0] |= BIT(EV_REL);		input_dev->relbit[0] = BIT(REL_WHEEL) | BIT(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. * 当发现有键盘接入 调用atkbd_connect() */

⌨️ 快捷键说明

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