mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-10 01:21:49 +00:00
Merge "Fix the missing IRQ problem."
This commit is contained in:
@@ -37,6 +37,30 @@ static void configure_gpio(void)
|
||||
}
|
||||
|
||||
|
||||
/* Manually generates an IRQ to host (edge-trigger).
|
||||
*
|
||||
* For SERIRQ quite mode, we need to set LM4_LPC_LPCIRQCTL twice.
|
||||
* The first one is to assert IRQ (pull low), and then the second one is
|
||||
* to de-assert it. This generates a pulse (high-low-high) for an IRQ.
|
||||
*
|
||||
* Note that the irq_num == 0 would set the AH bit (Active High).
|
||||
*/
|
||||
void lpc_manual_irq(int irq_num) {
|
||||
uint32_t common_bits =
|
||||
0x00000004 | /* PULSE */
|
||||
0x00000002 | /* ONCHG - for quiet mode */
|
||||
0x00000001; /* SND - send immediately */
|
||||
|
||||
while (LM4_LPC_LPCIRQCTL & 1); /* wait until SND is cleared */
|
||||
LM4_LPC_LPCIRQCTL = (1 << (irq_num + 16)) | common_bits;
|
||||
|
||||
while (LM4_LPC_LPCIRQCTL & 1); /* wait until SND is cleared */
|
||||
LM4_LPC_LPCIRQCTL = common_bits; /* generate a all-high frame to
|
||||
* simulate a rising edge. */
|
||||
while (LM4_LPC_LPCIRQCTL & 1); /* wait until SND is cleared */
|
||||
}
|
||||
|
||||
|
||||
int lpc_init(void)
|
||||
{
|
||||
volatile uint32_t scratch __attribute__((unused));
|
||||
@@ -47,6 +71,7 @@ int lpc_init(void)
|
||||
|
||||
LM4_LPC_LPCIM = 0;
|
||||
LM4_LPC_LPCCTL = 0;
|
||||
LM4_LPC_LPCIRQCTL = 0;
|
||||
|
||||
/* Configure GPIOs */
|
||||
configure_gpio();
|
||||
@@ -83,7 +108,7 @@ int lpc_init(void)
|
||||
* data writes, pool bytes 0(data)/1(cmd) */
|
||||
LM4_LPC_ADR(LPC_CH_KEYBOARD) = 0x60;
|
||||
LM4_LPC_CTL(LPC_CH_KEYBOARD) = (1 << 24/* IRQSEL1 */) |
|
||||
(1 << 18/* IRQEN1 */) | (LPC_POOL_OFFS_KEYBOARD << (5 - 1));
|
||||
(0 << 18/* IRQEN1 */) | (LPC_POOL_OFFS_KEYBOARD << (5 - 1));
|
||||
LM4_LPC_ST(LPC_CH_KEYBOARD) = 0;
|
||||
/* Unmask interrupt for host command/data writes and data reads */
|
||||
LM4_LPC_LPCIM |= LM4_LPC_INT_MASK(LPC_CH_KEYBOARD, 7);
|
||||
@@ -148,6 +173,19 @@ void lpc_send_host_response(int slot, int status)
|
||||
}
|
||||
|
||||
|
||||
/* Return true if the TOH is still set */
|
||||
int lpc_keyboard_has_char() {
|
||||
return (LM4_LPC_ST(LPC_CH_KEYBOARD) & (1 << 0 /* TOH */)) ? 1 : 0;
|
||||
}
|
||||
|
||||
void lpc_keyboard_put_char(uint8_t chr, int send_irq) {
|
||||
LPC_POOL_KEYBOARD[1] = chr;
|
||||
if (send_irq) {
|
||||
lpc_manual_irq(1); /* IRQ#1 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int lpc_comx_has_char(void)
|
||||
{
|
||||
return LM4_LPC_ST(LPC_CH_COMX) & 0x02;
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
#include "common.h"
|
||||
#include "i8042.h"
|
||||
#include "keyboard.h"
|
||||
/* TODO: Code in common.c should not directly access chip registers */
|
||||
#include "registers.h"
|
||||
#include "lpc.h"
|
||||
#include "task.h"
|
||||
#include "timer.h"
|
||||
#include "uart.h"
|
||||
@@ -32,14 +31,17 @@ static int tail_to_buffer = 0;
|
||||
#define HOST_BUFFER_SIZE (16)
|
||||
static uint8_t to_host_buffer[HOST_BUFFER_SIZE];
|
||||
|
||||
static int i8042_irq_enabled = 0;
|
||||
|
||||
|
||||
/* Reset all i8042 buffer */
|
||||
void i8042_init()
|
||||
{
|
||||
head_to_buffer = tail_to_buffer = 0;
|
||||
LM4_LPC_ST(LPC_CH_KEYBOARD) = 0; /* clear the TOH bit */
|
||||
}
|
||||
|
||||
|
||||
/* Called by the chip-specific code when host sedns a byte to port 0x60. */
|
||||
void i8042_receives_data(int data)
|
||||
{
|
||||
int ret_len;
|
||||
@@ -52,6 +54,7 @@ void i8042_receives_data(int data)
|
||||
}
|
||||
|
||||
|
||||
/* Called by the chip-specific code when host sedns a byte to port 0x64. */
|
||||
void i8042_receives_command(int cmd)
|
||||
{
|
||||
int ret_len;
|
||||
@@ -64,6 +67,7 @@ void i8042_receives_command(int cmd)
|
||||
}
|
||||
|
||||
|
||||
/* Called by EC common code to send bytes to host via port 0x60. */
|
||||
static void enq_to_host(int len, uint8_t *to_host)
|
||||
{
|
||||
int from, to;
|
||||
@@ -80,6 +84,18 @@ static void enq_to_host(int len, uint8_t *to_host)
|
||||
}
|
||||
|
||||
|
||||
/* Called by common/keyboard.c when the host wants to receive keyboard IRQ
|
||||
* (or not).
|
||||
*/
|
||||
void i8042_enable_keyboard_irq(void) {
|
||||
i8042_irq_enabled = 1;
|
||||
}
|
||||
|
||||
void i8042_disable_keyboard_irq(void) {
|
||||
i8042_irq_enabled = 0;
|
||||
}
|
||||
|
||||
|
||||
void i8042_command_task(void)
|
||||
{
|
||||
while (1) {
|
||||
@@ -99,10 +115,11 @@ void i8042_command_task(void)
|
||||
|
||||
/* if the host still didn't read that away,
|
||||
try next time. */
|
||||
if (LM4_LPC_ST(LPC_CH_KEYBOARD) & (1 << 0 /* TOH */)) {
|
||||
if (lpc_keyboard_has_char()) {
|
||||
#if I8042_DEBUG >= 5
|
||||
uart_printf("[%d] i8042_command_task() "
|
||||
"cannot send to host due to TOH\n",
|
||||
"cannot send to host due to host "
|
||||
"havn't taken away.\n",
|
||||
get_time().le.lo);
|
||||
#endif
|
||||
break;
|
||||
@@ -114,8 +131,8 @@ void i8042_command_task(void)
|
||||
(head_to_buffer + 1) % HOST_BUFFER_SIZE;
|
||||
/* end of atomic protection */
|
||||
|
||||
/* Write to host. TOH is set automatically. */
|
||||
LPC_POOL_KEYBOARD[1] = chr;
|
||||
/* Write to host. */
|
||||
lpc_keyboard_put_char(chr, i8042_irq_enabled);
|
||||
#if I8042_DEBUG >= 4
|
||||
uart_printf("[%d] i8042_command_task() "
|
||||
"sends to host: 0x%02x\n",
|
||||
|
||||
@@ -27,13 +27,14 @@
|
||||
/*
|
||||
* i8042 global settings.
|
||||
*/
|
||||
static int i8042_enabled = 0; /* default the keyboard is disabled. */
|
||||
static int keyboard_enabled = 0; /* default the keyboard is disabled. */
|
||||
static uint8_t resend_command[MAX_SCAN_CODE_LEN];
|
||||
static uint8_t resend_command_len = 0;
|
||||
static uint8_t controller_ram_address;
|
||||
static uint8_t controller_ram[0x20] = {
|
||||
I8042_AUX_DIS, /* the so called "command byte" */
|
||||
/* 0x01 - 0x1f are controller RAM */
|
||||
/* the so called "command byte" */
|
||||
I8042_XLATE | I8042_AUX_DIS | I8042_KBD_DIS,
|
||||
/* 0x01 - 0x1f are controller RAM */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -121,6 +122,12 @@ static enum ec_error_list matrix_callback(
|
||||
|
||||
*len = 0;
|
||||
|
||||
if (controller_ram[0] & I8042_XLATE) {
|
||||
/* If the keyboard translation is enabled,
|
||||
* then always generates set 1. */
|
||||
code_set = SCANCODE_SET_1;
|
||||
}
|
||||
|
||||
switch (code_set) {
|
||||
case SCANCODE_SET_1:
|
||||
make_code = scancode_set1[row][col];
|
||||
@@ -215,6 +222,53 @@ void keyboard_state_changed(int row, int col, int is_pressed) {
|
||||
}
|
||||
|
||||
|
||||
void keyboard_enable(int enable) {
|
||||
if (!keyboard_enabled && enable) {
|
||||
/* enable */
|
||||
} else if (keyboard_enabled && !enable) {
|
||||
/* disable */
|
||||
reset_rate_and_delay();
|
||||
clean_underlying_buffer();
|
||||
}
|
||||
keyboard_enabled = enable;
|
||||
}
|
||||
|
||||
|
||||
uint8_t read_ctl_ram(uint8_t addr) {
|
||||
ASSERT(addr < 0x20); // Controller RAM is only 32 bytes.
|
||||
|
||||
return controller_ram[addr];
|
||||
}
|
||||
|
||||
|
||||
/* Manipulates the controller_ram[]. Some bits change may trigger internal
|
||||
* state change.
|
||||
*/
|
||||
void update_ctl_ram(uint8_t addr, uint8_t data) {
|
||||
uint8_t orig;
|
||||
|
||||
ASSERT(addr < 0x20); // Controller RAM is only 32 bytes.
|
||||
orig = controller_ram[addr];
|
||||
controller_ram[addr] = data;
|
||||
#if KEYBOARD_DEBUG >= 5
|
||||
uart_printf("Set CTR_RAM[0x%02x]=0x%02x (old:0x%02x)\n",
|
||||
addr, data, orig);
|
||||
#endif
|
||||
|
||||
if (addr == 0x00) { /* the controller RAM */
|
||||
/* Handle the I8042_KBD_DIS bit */
|
||||
keyboard_enable(!(data & I8042_KBD_DIS));
|
||||
|
||||
/* Handle the I8042_ENIRQ1 bit */
|
||||
if (!(orig & I8042_ENIRQ1) && (data & I8042_ENIRQ1)) {
|
||||
i8042_enable_keyboard_irq();
|
||||
} else if ((orig & I8042_ENIRQ1) && !(data & I8042_ENIRQ1)) {
|
||||
i8042_disable_keyboard_irq();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum {
|
||||
STATE_NORMAL = 0,
|
||||
STATE_SCANCODE,
|
||||
@@ -237,7 +291,7 @@ int handle_keyboard_data(uint8_t data, uint8_t *output) {
|
||||
switch (data_port_state) {
|
||||
case STATE_SCANCODE:
|
||||
#if KEYBOARD_DEBUG >= 5
|
||||
uart_printf("Eaten by STATE_SCANCODE\n");
|
||||
uart_printf("Eaten by STATE_SCANCODE: 0x%02x\n", data);
|
||||
#endif
|
||||
if (data == SCANCODE_GET_SET) {
|
||||
output[out_len++] = I8042_RET_ACK;
|
||||
@@ -261,22 +315,27 @@ int handle_keyboard_data(uint8_t data, uint8_t *output) {
|
||||
break;
|
||||
|
||||
case STATE_WRITE_CMD_BYTE:
|
||||
controller_ram[controller_ram_address] = data;
|
||||
#if KEYBOARD_DEBUG >= 5
|
||||
uart_printf("Set command_bytes[0x%02x]=0x%02x\n",
|
||||
controller_ram_address,
|
||||
controller_ram[controller_ram_address]);
|
||||
uart_printf("Eaten by STATE_WRITE_CMD_BYTE: 0x%02x\n", data);
|
||||
#endif
|
||||
update_ctl_ram(controller_ram_address, data);
|
||||
output[out_len++] = I8042_RET_ACK;
|
||||
data_port_state = STATE_NORMAL;
|
||||
break;
|
||||
|
||||
case STATE_ECHO_MOUSE:
|
||||
#if KEYBOARD_DEBUG >= 5
|
||||
uart_printf("Eaten by STATE_ECHO_MOUSE: 0x%02x\n", data);
|
||||
#endif
|
||||
output[out_len++] = I8042_RET_ACK;
|
||||
output[out_len++] = data;
|
||||
data_port_state = STATE_NORMAL;
|
||||
break;
|
||||
|
||||
case STATE_SEND_TO_MOUSE:
|
||||
#if KEYBOARD_DEBUG >= 5
|
||||
uart_printf("Eaten by STATE_SEND_TO_MOUSE: 0x%02x\n", data);
|
||||
#endif
|
||||
data_port_state = STATE_NORMAL;
|
||||
break;
|
||||
|
||||
@@ -294,6 +353,11 @@ int handle_keyboard_data(uint8_t data, uint8_t *output) {
|
||||
data_port_state = STATE_SETLEDS;
|
||||
break;
|
||||
|
||||
case I8042_CMD_DIAG_ECHO:
|
||||
output[out_len++] = I8042_RET_ACK;
|
||||
output[out_len++] = I8042_CMD_DIAG_ECHO;
|
||||
break;
|
||||
|
||||
case I8042_CMD_GETID: /* fall-thru */
|
||||
case I8042_CMD_OK_GETID:
|
||||
output[out_len++] = I8042_RET_ACK;
|
||||
@@ -314,13 +378,12 @@ int handle_keyboard_data(uint8_t data, uint8_t *output) {
|
||||
|
||||
case I8042_CMD_ENABLE:
|
||||
output[out_len++] = I8042_RET_ACK;
|
||||
i8042_enabled = 1;
|
||||
clean_underlying_buffer();
|
||||
keyboard_enable(1);
|
||||
break;
|
||||
|
||||
case I8042_CMD_RESET_DIS:
|
||||
output[out_len++] = I8042_RET_ACK;
|
||||
i8042_enabled = 0;
|
||||
keyboard_enable(0);
|
||||
reset_rate_and_delay();
|
||||
clean_underlying_buffer();
|
||||
break;
|
||||
@@ -333,7 +396,7 @@ int handle_keyboard_data(uint8_t data, uint8_t *output) {
|
||||
|
||||
case I8042_CMD_RESET_BAT:
|
||||
output[out_len++] = I8042_RET_ACK;
|
||||
i8042_enabled = 0;
|
||||
keyboard_enable(0);
|
||||
output[out_len++] = I8042_RET_BAT;
|
||||
output[out_len++] = I8042_RET_BAT;
|
||||
break;
|
||||
@@ -357,9 +420,6 @@ int handle_keyboard_data(uint8_t data, uint8_t *output) {
|
||||
case I8042_CMD_EX_ENABLE:
|
||||
default:
|
||||
output[out_len++] = I8042_RET_NAK;
|
||||
i8042_enabled = 0;
|
||||
reset_rate_and_delay();
|
||||
clean_underlying_buffer();
|
||||
#if KEYBOARD_DEBUG >= 1
|
||||
uart_printf("Unsupported i8042 data 0x%02x.\n", data);
|
||||
#endif
|
||||
@@ -389,7 +449,7 @@ int handle_keyboard_command(uint8_t command, uint8_t *output) {
|
||||
#endif
|
||||
switch (command) {
|
||||
case I8042_READ_CMD_BYTE:
|
||||
output[out_len++] = controller_ram[0];
|
||||
output[out_len++] = read_ctl_ram(0);
|
||||
break;
|
||||
|
||||
case I8042_WRITE_CMD_BYTE:
|
||||
@@ -398,19 +458,27 @@ int handle_keyboard_command(uint8_t command, uint8_t *output) {
|
||||
break;
|
||||
|
||||
case I8042_DIS_KB:
|
||||
i8042_enabled = 0;
|
||||
keyboard_enable(0);
|
||||
break;
|
||||
|
||||
case I8042_ENA_KB:
|
||||
i8042_enabled = 1;
|
||||
keyboard_enable(1);
|
||||
break;
|
||||
|
||||
case I8042_RESET_SELF_TEST:
|
||||
output[out_len++] = 0x55; // Self test success.
|
||||
break;
|
||||
|
||||
case I8042_DIS_MOUSE:
|
||||
controller_ram[0] |= I8042_AUX_DIS;
|
||||
update_ctl_ram(0, read_ctl_ram(0) | I8042_AUX_DIS);
|
||||
break;
|
||||
|
||||
case I8042_ENA_MOUSE:
|
||||
controller_ram[0] &= ~I8042_AUX_DIS;
|
||||
update_ctl_ram(0, read_ctl_ram(0) & ~I8042_AUX_DIS);
|
||||
break;
|
||||
|
||||
case I8042_TEST_MOUSE:
|
||||
output[out_len++] = 0; // no error detected
|
||||
break;
|
||||
|
||||
case I8042_ECHO_MOUSE:
|
||||
@@ -424,19 +492,22 @@ int handle_keyboard_command(uint8_t command, uint8_t *output) {
|
||||
default:
|
||||
if (command >= I8042_READ_CTL_RAM &&
|
||||
command <= I8042_READ_CTL_RAM_END) {
|
||||
output[out_len++] = controller_ram[command - 0x20];
|
||||
output[out_len++] = read_ctl_ram(command - 0x20);
|
||||
} else if (command >= I8042_WRITE_CTL_RAM &&
|
||||
command <= I8042_WRITE_CTL_RAM_END) {
|
||||
data_port_state = STATE_WRITE_CMD_BYTE;
|
||||
controller_ram_address = command - 0x60;
|
||||
} else if (command >= I8042_PULSE_START &&
|
||||
command <= I8042_PULSE_END) {
|
||||
/* Pulse Output Bit. Not implemented. Ignore it. */
|
||||
} else {
|
||||
#if KEYBOARD_DEBUG >= 1
|
||||
uart_printf("Unsupported cmd:[0x%02x]\n", command);
|
||||
#endif
|
||||
i8042_enabled = 0;
|
||||
reset_rate_and_delay();
|
||||
clean_underlying_buffer();
|
||||
output[out_len++] = I8042_RET_NAK;
|
||||
data_port_state = STATE_NORMAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -451,6 +522,8 @@ static int command_codeset(int argc, char **argv)
|
||||
|
||||
if (argc == 1) {
|
||||
uart_printf("Current scancode set: %d\n", scancode_set);
|
||||
uart_printf("I8042_XLATE: %d\n",
|
||||
controller_ram[0] & I8042_XLATE ? 1 : 0);
|
||||
} else if (argc == 2) {
|
||||
set = strtoi(argv[1], NULL, 0);
|
||||
switch (set) {
|
||||
|
||||
@@ -63,6 +63,9 @@
|
||||
#define I8042_ENA_KB 0xae
|
||||
#define I8042_ECHO_MOUSE 0xd3 /* expect a byte on port 0x60 */
|
||||
#define I8042_SEND_TO_MOUSE 0xd4 /* expect a byte on port 0x60 */
|
||||
#define I8042_PULSE_START 0xf0
|
||||
#define I8042_PULSE_END 0xfd
|
||||
#define I8042_SYSTEM_RESET 0xfe
|
||||
|
||||
/* port 0x60 return value */
|
||||
#define I8042_RET_BAT 0xaa
|
||||
@@ -79,9 +82,12 @@
|
||||
#define I8042_RET_ERR 0xff
|
||||
|
||||
/* port 64 - command byte bits */
|
||||
#define I8042_XLATE (1 << 6)
|
||||
#define I8042_AUX_DIS (1 << 5)
|
||||
#define I8042_KBD_DIS (1 << 4)
|
||||
#define I8042_SYS_FLAG (1 << 2)
|
||||
#define I8042_ENIRQ12 (1 << 1)
|
||||
#define I8042_ENIRQ1 (1 << 0)
|
||||
|
||||
|
||||
void i8042_init(void);
|
||||
@@ -98,6 +104,13 @@ void i8042_receives_data(int data);
|
||||
void i8042_receives_command(int cmd);
|
||||
|
||||
|
||||
/* Called by common/keyboard.c when the host doesn't want to receive
|
||||
* keyboard IRQ.
|
||||
*/
|
||||
void i8042_enable_keyboard_irq(void);
|
||||
void i8042_disable_keyboard_irq(void);
|
||||
|
||||
|
||||
/* Send the scan code to the host. The EC lib will push the scan code bytes
|
||||
* to host via port 0x60 and assert the IBF flag to trigger an interrupt.
|
||||
* The EC lib must queue them if the host cannot read the previous byte away
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
/* Manually generates an IRQ to host.
|
||||
* Note that the irq_num == 0 would set the AH bit (Active High).
|
||||
*/
|
||||
void lpc_manual_irq(int irq_num);
|
||||
|
||||
|
||||
/* Initializes the LPC module. */
|
||||
int lpc_init(void);
|
||||
|
||||
@@ -25,6 +32,12 @@ uint8_t *lpc_get_host_range(int slot);
|
||||
* commands, 1 for usermode-originated commands. */
|
||||
void lpc_send_host_response(int slot, int status);
|
||||
|
||||
/* Return true if the TOH is still set */
|
||||
int lpc_keyboard_has_char(void);
|
||||
|
||||
/* Send a byte to host via port 0x60 and asserts IRQ if specified. */
|
||||
void lpc_keyboard_put_char(uint8_t chr, int send_irq);
|
||||
|
||||
/* Returns non-zero if the COMx interface has received a character. */
|
||||
int lpc_comx_has_char(void);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user