ps2kbd.c

来自「适合KS8695X」· C语言 代码 · 共 691 行 · 第 1/2 页

C
691
字号
			return;
	}
	/* special cntrl keys */
	switch(scancode)
	{
	case 0x48:
	    kbd_put_queue(27);
	    kbd_put_queue(91);
	    kbd_put_queue('A');
	    return;
	case 0x50:
	    kbd_put_queue(27);
	    kbd_put_queue(91);
	    kbd_put_queue('B');
	    return;
	case 0x4b:
	    kbd_put_queue(27);
	    kbd_put_queue(91);
	    kbd_put_queue('D');
	    return;
	case 0x4D:
	    kbd_put_queue(27);
	    kbd_put_queue(91);
	    kbd_put_queue('C');
	    return;
	case 0x58: /* F12 key */
	    if (ctrl == 1)
	    {
		extern int console_changed;
		setenv("stdin", DEVNAME);
		setenv("stdout", "vga");
		console_changed = 1;
	    }
	    return;
	case 0x2A:
		case 0x36: /* shift pressed */
			shift=1;
			return; /* do nothing else */
		case 0xAA:
		case 0xB6: /* shift released */
			shift=0;
			return; /* do nothing else */
		case 0x38: /* alt pressed */
			alt=1;
			return; /* do nothing else */
		case 0xB8: /* alt released */
			alt=0;
			return; /* do nothing else */
		case 0x1d: /* ctrl pressed */
			ctrl=1;
			return; /* do nothing else */
		case 0x9d: /* ctrl released */
			ctrl=0;
			return; /* do nothing else */
		case 0x46: /* scrollock pressed */
			scroll_lock=~scroll_lock;
			kbd_set_leds();
			return; /* do nothing else */
		case 0x3A: /* capslock pressed */
			caps_lock=~caps_lock;
			kbd_set_leds();
			return;
		case 0x45: /* numlock pressed */
			num_lock=~num_lock;
			kbd_set_leds();
			return;
		case 0xC6: /* scroll lock released */
		case 0xC5: /* num lock released */
		case 0xBA: /* caps lock released */
			return; /* just swallow */
	}
	if((scancode&0x80)==0x80) /* key released */
		return;
	/* now, decide which table we need */
	if(scancode > (sizeof(kbd_plain_xlate)/sizeof(kbd_plain_xlate[0]))) { /* scancode not in list */
		PRINTF("unkown scancode %X\n",scancode);
		return; /* swallow it */
	}
	/* setup plain code first */
	keycode=kbd_plain_xlate[scancode];
	if(caps_lock==1) { /* caps_lock is pressed, overwrite plain code */
		if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
			PRINTF("unkown caps-locked scancode %X\n",scancode);
			return; /* swallow it */
		}
		keycode=kbd_shift_xlate[scancode];
		if(keycode<'A') { /* we only want the alphas capital */
			keycode=kbd_plain_xlate[scancode];
		}
	}
	if(shift==1) { /* shift overwrites caps_lock */
		if(scancode > (sizeof(kbd_shift_xlate)/sizeof(kbd_shift_xlate[0]))) { /* scancode not in list */
			PRINTF("unkown shifted scancode %X\n",scancode);
			return; /* swallow it */
		}
		keycode=kbd_shift_xlate[scancode];
	}
	if(ctrl==1) { /* ctrl overwrites caps_lock and shift */
		if(scancode > (sizeof(kbd_ctrl_xlate)/sizeof(kbd_ctrl_xlate[0]))) { /* scancode not in list */
			PRINTF("unkown ctrl scancode %X\n",scancode);
			return; /* swallow it */
		}
		keycode=kbd_ctrl_xlate[scancode];
	}
	/* check if valid keycode */
	if(keycode==0xff) {
		PRINTF("unkown scancode %X\n",scancode);
		return; /* swallow unknown codes */
	}

	kbd_put_queue(keycode);
	PRINTF("%x\n",keycode);
}

/*
 * This reads the keyboard status port, and does the
 * appropriate action.
 *
 */
unsigned char handle_kbd_event(void)
{
	unsigned char status = kbd_read_status();
	unsigned int work = 10000;

	while ((--work > 0) && (status & KBD_STAT_OBF)) {
		unsigned char scancode;

		scancode = kbd_read_input();

		/* Error bytes must be ignored to make the
		   Synaptics touchpads compaq use work */
		/* Ignore error bytes */
		if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR)))
		{
			if (status & KBD_STAT_MOUSE_OBF)
				; /* not supported: handle_mouse_event(scancode); */
			else
				handle_keyboard_event(scancode);
		}
		status = kbd_read_status();
	}
	if (!work)
		PRINTF("pc_keyb: controller jammed (0x%02X).\n", status);
	return status;
}


/******************************************************************************
 * Lowlevel Part of keyboard section
 */
unsigned char kbd_read_status(void)
{
	return(in8(CFG_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT));
}

unsigned char kbd_read_input(void)
{
	return(in8(CFG_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT));
}

void kbd_write_command(unsigned char cmd)
{
	out8(CFG_ISA_IO_BASE_ADDRESS + KDB_COMMAND_PORT,cmd);
}

void kbd_write_output(unsigned char data)
{
	out8(CFG_ISA_IO_BASE_ADDRESS + KDB_DATA_PORT, data);
}

int kbd_read_data(void)
{
	int val;
	unsigned char status;

	val=-1;
	status = kbd_read_status();
	if (status & KBD_STAT_OBF) {
		val = kbd_read_input();
		if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
			val = -2;
	}
	return val;
}

int kbd_wait_for_input(void)
{
	unsigned long timeout;
	int val;

	timeout = KBD_TIMEOUT;
	val=kbd_read_data();
	while(val < 0)
	{
		if(timeout--==0)
			return -1;
		udelay(1000);
		val=kbd_read_data();
	}
	return val;
}


int kb_wait(void)
{
	unsigned long timeout = KBC_TIMEOUT * 10;

	do {
		unsigned char status = handle_kbd_event();
		if (!(status & KBD_STAT_IBF))
			return 0; /* ok */
		udelay(1000);
		timeout--;
	} while (timeout);
	return 1;
}

void kbd_write_command_w(int data)
{
	if(kb_wait())
		PRINTF("timeout in kbd_write_command_w\n");
	kbd_write_command(data);
}

void kbd_write_output_w(int data)
{
	if(kb_wait())
		PRINTF("timeout in kbd_write_output_w\n");
	kbd_write_output(data);
}

void kbd_send_data(unsigned char data)
{
	unsigned char status;
	i8259_mask_irq(KBD_INTERRUPT); /* disable interrupt */
	kbd_write_output_w(data);
	status = kbd_wait_for_input();
	if (status == KBD_REPLY_ACK)
		i8259_unmask_irq(KBD_INTERRUPT); /* enable interrupt */
}


char * kbd_initialize(void)
{
	int status;

	in_pointer = 0; /* delete in Buffer */
	out_pointer = 0;
	/*
	 * Test the keyboard interface.
	 * This seems to be the only way to get it going.
	 * If the test is successful a x55 is placed in the input buffer.
	 */
	kbd_write_command_w(KBD_CCMD_SELF_TEST);
	if (kbd_wait_for_input() != 0x55)
		return "Kbd:   failed self test";
	/*
	 * Perform a keyboard interface test.  This causes the controller
	 * to test the keyboard clock and data lines.  The results of the
	 * test are placed in the input buffer.
	 */
	kbd_write_command_w(KBD_CCMD_KBD_TEST);
	if (kbd_wait_for_input() != 0x00)
		return "Kbd:   interface failed self test";
	/*
	 * Enable the keyboard by allowing the keyboard clock to run.
	 */
	kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
	status = kbd_wait_for_input();
	/*
	 * Reset keyboard. If the read times out
	 * then the assumption is that no keyboard is
	 * plugged into the machine.
	 * This defaults the keyboard to scan-code set 2.
	 *
	 * Set up to try again if the keyboard asks for RESEND.
	 */
	do {
		kbd_write_output_w(KBD_CMD_RESET);
		status = kbd_wait_for_input();
		if (status == KBD_REPLY_ACK)
			break;
		if (status != KBD_REPLY_RESEND)
		{
			PRINTF("status: %X\n",status);
			return "Kbd:   reset failed, no ACK";
		}
	} while (1);
	if (kbd_wait_for_input() != KBD_REPLY_POR)
		return "Kbd:   reset failed, no POR";

	/*
	 * Set keyboard controller mode. During this, the keyboard should be
	 * in the disabled state.
	 *
	 * Set up to try again if the keyboard asks for RESEND.
	 */
	do {
		kbd_write_output_w(KBD_CMD_DISABLE);
		status = kbd_wait_for_input();
		if (status == KBD_REPLY_ACK)
			break;
		if (status != KBD_REPLY_RESEND)
			return "Kbd:   disable keyboard: no ACK";
	} while (1);

	kbd_write_command_w(KBD_CCMD_WRITE_MODE);
	kbd_write_output_w(KBD_MODE_KBD_INT
			      | KBD_MODE_SYS
			      | KBD_MODE_DISABLE_MOUSE
			      | KBD_MODE_KCC);

	/* ibm powerpc portables need this to use scan-code set 1 -- Cort */
	kbd_write_command_w(KBD_CCMD_READ_MODE);
	if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
		/*
		 * If the controller does not support conversion,
		 * Set the keyboard to scan-code set 1.
		 */
		kbd_write_output_w(0xF0);
		kbd_wait_for_input();
		kbd_write_output_w(0x01);
		kbd_wait_for_input();
	}
	kbd_write_output_w(KBD_CMD_ENABLE);
	if (kbd_wait_for_input() != KBD_REPLY_ACK)
		return "Kbd:   enable keyboard: no ACK";

	/*
	 * Finally, set the typematic rate to maximum.
	 */
	kbd_write_output_w(KBD_CMD_SET_RATE);
	if (kbd_wait_for_input() != KBD_REPLY_ACK)
		return "Kbd:   Set rate: no ACK";
	kbd_write_output_w(0x00);
	if (kbd_wait_for_input() != KBD_REPLY_ACK)
		return "Kbd:   Set rate: no ACK";
	return NULL;
}

void kbd_interrupt(void)
{
	handle_kbd_event();
}

⌨️ 快捷键说明

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