mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
Merge i8042.c into keyboard_8042.c
This is in preparation for cleaning up the 8042 protocol stack and merging the typematic and i8042cmd tasks. No functionality change, just shuffling code and renaming functions. BUG=chrome-os-partner:18360 BRANCH=none TEST=boot link and type on its keyboard Change-Id: Iefc41cd5b8d18ac87830bff3080cfff92e9d10d2 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/46805 Reviewed-by: Bill Richardson <wfrichar@chromium.org>
This commit is contained in:
committed by
ChromeBot
parent
fe3ccdf70a
commit
95a3a4107a
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
|
||||
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "gpio.h"
|
||||
#include "hooks.h"
|
||||
#include "host_command.h"
|
||||
#include "i8042.h"
|
||||
#include "keyboard_protocol.h"
|
||||
#include "lpc.h"
|
||||
#include "port80.h"
|
||||
#include "pwm.h"
|
||||
@@ -560,7 +560,7 @@ static void lpc_interrupt(void)
|
||||
/* Handle keyboard interface writes */
|
||||
st = LM4_LPC_ST(LPC_CH_KEYBOARD);
|
||||
if (st & LM4_LPC_ST_FRMH)
|
||||
i8042_receive(LPC_POOL_KEYBOARD[0], st & LM4_LPC_ST_CMD);
|
||||
keyboard_host_write(LPC_POOL_KEYBOARD[0], st & LM4_LPC_ST_CMD);
|
||||
|
||||
if (mis & LM4_LPC_INT_MASK(LPC_CH_KEYBOARD, 1)) {
|
||||
/* Host read data; wake up task to send remaining bytes */
|
||||
|
||||
@@ -31,7 +31,7 @@ common-$(CONFIG_SMART_BATTERY)+=smart_battery.o smart_battery_stub.o
|
||||
common-$(CONFIG_TASK_CHARGER)+=charge_state.o battery_precharge.o
|
||||
common-$(CONFIG_TASK_CONSOLE)+=console.o
|
||||
common-$(CONFIG_TASK_HOSTCMD)+=host_command.o host_event_commands.o
|
||||
common-$(CONFIG_TASK_I8042CMD)+=i8042.o keyboard_8042.o
|
||||
common-$(CONFIG_TASK_I8042CMD)+=keyboard_8042.o
|
||||
common-$(CONFIG_TASK_KEYSCAN)+=keyboard_scan.o
|
||||
common-$(CONFIG_TASK_LIGHTBAR)+=lightbar.o
|
||||
common-$(CONFIG_TASK_THERMAL)+=thermal.o
|
||||
|
||||
146
common/i8042.c
146
common/i8042.c
@@ -1,146 +0,0 @@
|
||||
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* i8042 interface to host
|
||||
*
|
||||
* i8042 commands are processed by keyboard.c.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "console.h"
|
||||
#include "i8042.h"
|
||||
#include "keyboard_protocol.h"
|
||||
#include "lpc.h"
|
||||
#include "queue.h"
|
||||
#include "task.h"
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Console output macros */
|
||||
#define CPRINTF(format, args...) cprintf(CC_KEYBOARD, format, ## args)
|
||||
|
||||
static int i8042_irq_enabled;
|
||||
|
||||
/*
|
||||
* Mutex to control write access to the to-host buffer head. Don't need to
|
||||
* mutex the tail because reads are only done in one place.
|
||||
*/
|
||||
static struct mutex to_host_mutex;
|
||||
|
||||
static uint8_t to_host_buffer[16];
|
||||
static struct queue to_host = {
|
||||
.buf_bytes = sizeof(to_host_buffer),
|
||||
.unit_bytes = sizeof(uint8_t),
|
||||
.buf = to_host_buffer,
|
||||
};
|
||||
|
||||
/* Queue command/data from the host */
|
||||
enum {
|
||||
HOST_COMMAND = 0,
|
||||
HOST_DATA,
|
||||
};
|
||||
struct host_byte {
|
||||
uint8_t type;
|
||||
uint8_t byte;
|
||||
};
|
||||
|
||||
/* 4 is big enough for all i8042 commands */
|
||||
static uint8_t from_host_buffer[4 * sizeof(struct host_byte)];
|
||||
static struct queue from_host = {
|
||||
.buf_bytes = sizeof(from_host_buffer),
|
||||
.unit_bytes = sizeof(struct host_byte),
|
||||
.buf = from_host_buffer,
|
||||
};
|
||||
|
||||
void i8042_flush_buffer()
|
||||
{
|
||||
mutex_lock(&to_host_mutex);
|
||||
queue_reset(&to_host);
|
||||
mutex_unlock(&to_host_mutex);
|
||||
lpc_keyboard_clear_buffer();
|
||||
}
|
||||
|
||||
void i8042_receive(int data, int is_cmd)
|
||||
{
|
||||
struct host_byte h;
|
||||
|
||||
h.type = is_cmd ? HOST_COMMAND : HOST_DATA;
|
||||
h.byte = data;
|
||||
queue_add_units(&from_host, &h, 1);
|
||||
task_wake(TASK_ID_I8042CMD);
|
||||
}
|
||||
|
||||
void i8042_enable_keyboard_irq(int enable)
|
||||
{
|
||||
i8042_irq_enabled = enable;
|
||||
if (enable)
|
||||
lpc_keyboard_resume_irq();
|
||||
}
|
||||
|
||||
static void i8042_handle_from_host(void)
|
||||
{
|
||||
struct host_byte h;
|
||||
int ret_len;
|
||||
uint8_t output[MAX_SCAN_CODE_LEN];
|
||||
|
||||
while (queue_remove_unit(&from_host, &h)) {
|
||||
if (h.type == HOST_COMMAND)
|
||||
ret_len = handle_keyboard_command(h.byte, output);
|
||||
else
|
||||
ret_len = handle_keyboard_data(h.byte, output);
|
||||
|
||||
i8042_send_to_host(ret_len, output);
|
||||
}
|
||||
}
|
||||
|
||||
void i8042_command_task(void)
|
||||
{
|
||||
while (1) {
|
||||
/* Wait for next host read/write */
|
||||
task_wait_event(-1);
|
||||
|
||||
while (1) {
|
||||
uint8_t chr;
|
||||
|
||||
/* Handle command/data write from host */
|
||||
i8042_handle_from_host();
|
||||
|
||||
/* Check if we have data to send to host */
|
||||
if (queue_is_empty(&to_host))
|
||||
break;
|
||||
|
||||
/* Host interface must have space */
|
||||
if (lpc_keyboard_has_char())
|
||||
break;
|
||||
|
||||
/* Get a char from buffer. */
|
||||
kblog_put('k', to_host.head);
|
||||
queue_remove_unit(&to_host, &chr);
|
||||
kblog_put('K', chr);
|
||||
|
||||
/* Write to host. */
|
||||
lpc_keyboard_put_char(chr, i8042_irq_enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void i8042_send_to_host(int len, const uint8_t *bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
kblog_put('s', bytes[i]);
|
||||
|
||||
/* Enqueue output data if there's space */
|
||||
mutex_lock(&to_host_mutex);
|
||||
if (queue_has_space(&to_host, len)) {
|
||||
kblog_put('t', to_host.tail);
|
||||
queue_add_units(&to_host, bytes, len);
|
||||
}
|
||||
mutex_unlock(&to_host_mutex);
|
||||
|
||||
/* Wake up the task to move from queue to host */
|
||||
task_wake(TASK_ID_I8042CMD);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Chrome OS EC keyboard common code.
|
||||
* 8042 keyboard protocol
|
||||
*/
|
||||
|
||||
#include "chipset.h"
|
||||
@@ -10,12 +10,12 @@
|
||||
#include "console.h"
|
||||
#include "hooks.h"
|
||||
#include "host_command.h"
|
||||
#include "i8042.h"
|
||||
#include "i8042_protocol.h"
|
||||
#include "keyboard_config.h"
|
||||
#include "keyboard_protocol.h"
|
||||
#include "lightbar.h"
|
||||
#include "lpc.h"
|
||||
#include "queue.h"
|
||||
#include "registers.h"
|
||||
#include "shared_mem.h"
|
||||
#include "system.h"
|
||||
@@ -23,18 +23,11 @@
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
|
||||
#define KEYBOARD_DEBUG 1
|
||||
|
||||
/* Console output macros */
|
||||
#if KEYBOARD_DEBUG >= 1
|
||||
#define CPUTS(outstr) cputs(CC_KEYBOARD, outstr)
|
||||
#define CPRINTF(format, args...) cprintf(CC_KEYBOARD, format, ## args)
|
||||
#else
|
||||
#define CPUTS(outstr)
|
||||
#define CPRINTF(format, args...)
|
||||
#endif
|
||||
|
||||
#if KEYBOARD_DEBUG >= 5
|
||||
#ifdef CONFIG_KEYBOARD_DEBUG_MORE
|
||||
#define CPUTS5(outstr) cputs(CC_KEYBOARD, outstr)
|
||||
#define CPRINTF5(format, args...) cprintf(CC_KEYBOARD, format, ## args)
|
||||
#else
|
||||
@@ -42,6 +35,19 @@
|
||||
#define CPRINTF5(format, args...)
|
||||
#endif
|
||||
|
||||
static enum {
|
||||
STATE_NORMAL = 0,
|
||||
STATE_SCANCODE,
|
||||
STATE_SETLEDS,
|
||||
STATE_EX_SETLEDS_1, /* Expect 2-byte parameter */
|
||||
STATE_EX_SETLEDS_2,
|
||||
STATE_WRITE_CMD_BYTE,
|
||||
STATE_WRITE_OUTPUT_PORT,
|
||||
STATE_ECHO_MOUSE,
|
||||
STATE_SETREP,
|
||||
STATE_SEND_TO_MOUSE,
|
||||
} data_port_state = STATE_NORMAL;
|
||||
|
||||
enum scancode_set_list {
|
||||
SCANCODE_GET_SET = 0,
|
||||
SCANCODE_SET_1,
|
||||
@@ -50,10 +56,42 @@ enum scancode_set_list {
|
||||
SCANCODE_MAX = SCANCODE_SET_3,
|
||||
};
|
||||
|
||||
#define MAX_SCAN_CODE_LEN 4
|
||||
|
||||
/*
|
||||
* i8042 global settings.
|
||||
* Mutex to control write access to the to-host buffer head. Don't need to
|
||||
* mutex the tail because reads are only done in one place.
|
||||
*/
|
||||
static struct mutex to_host_mutex;
|
||||
|
||||
static uint8_t to_host_buffer[16];
|
||||
static struct queue to_host = {
|
||||
.buf_bytes = sizeof(to_host_buffer),
|
||||
.unit_bytes = sizeof(uint8_t),
|
||||
.buf = to_host_buffer,
|
||||
};
|
||||
|
||||
/* Queue command/data from the host */
|
||||
enum {
|
||||
HOST_COMMAND = 0,
|
||||
HOST_DATA,
|
||||
};
|
||||
struct host_byte {
|
||||
uint8_t type;
|
||||
uint8_t byte;
|
||||
};
|
||||
|
||||
/* 4 is big enough for all i8042 commands */
|
||||
static uint8_t from_host_buffer[4 * sizeof(struct host_byte)];
|
||||
static struct queue from_host = {
|
||||
.buf_bytes = sizeof(from_host_buffer),
|
||||
.unit_bytes = sizeof(struct host_byte),
|
||||
.buf = from_host_buffer,
|
||||
};
|
||||
|
||||
static int i8042_irq_enabled;
|
||||
|
||||
/* i8042 global settings */
|
||||
static int keyboard_enabled; /* default the keyboard is disabled. */
|
||||
static int keystroke_enabled; /* output keystrokes */
|
||||
static uint8_t resend_command[MAX_SCAN_CODE_LEN];
|
||||
@@ -88,7 +126,7 @@ static enum scancode_set_list scancode_set = SCANCODE_SET_2;
|
||||
#define DEFAULT_TYPEMATIC_VALUE ((1 << 5) || (1 << 3) || (3 << 0))
|
||||
#define DEFAULT_FIRST_DELAY 500
|
||||
#define DEFAULT_INTER_DELAY 91
|
||||
#define TYPEMATIC_DELAY_UNIT 1000 /* 1ms = 1000us */
|
||||
#define TYPEMATIC_DELAY_UNIT MSEC
|
||||
static uint8_t typematic_value_from_host = DEFAULT_TYPEMATIC_VALUE;
|
||||
static int refill_first_delay = DEFAULT_FIRST_DELAY; /* unit: ms */
|
||||
static int refill_inter_delay = DEFAULT_INTER_DELAY; /* unit: ms */
|
||||
@@ -96,7 +134,6 @@ static int typematic_delay; /* unit: us */
|
||||
static int typematic_len; /* length of typematic_scan_code */
|
||||
static uint8_t typematic_scan_code[MAX_SCAN_CODE_LEN];
|
||||
|
||||
|
||||
#define KB_SYSJUMP_TAG 0x4b42 /* "KB" */
|
||||
#define KB_HOOK_VERSION 1
|
||||
/* the previous keyboard state before reboot_ec. */
|
||||
@@ -106,7 +143,6 @@ struct kb_state {
|
||||
uint8_t pad[2]; /* Pad to 4 bytes for system_add_jump_tag(). */
|
||||
};
|
||||
|
||||
|
||||
/* The standard Chrome OS keyboard matrix table. */
|
||||
static const uint16_t scancode_set1[KEYBOARD_ROWS][KEYBOARD_COLS] = {
|
||||
{0x0000, 0xe05b, 0x003b, 0x0030, 0x0044, 0x0073, 0x0031, 0x0000, 0x000d,
|
||||
@@ -146,15 +182,107 @@ static const uint16_t scancode_set2[KEYBOARD_ROWS][KEYBOARD_COLS] = {
|
||||
0x0044, 0x0000, 0xe075, 0xe06b},
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Keyboard event log */
|
||||
|
||||
/* Log the traffic between EC and host -- for debug only */
|
||||
#define MAX_KBLOG 512 /* Max events in keyboard log */
|
||||
|
||||
struct kblog_t {
|
||||
/*
|
||||
* Type:
|
||||
*
|
||||
* s = byte enqueued to send to host
|
||||
* t = to-host queue tail pointer before type='s' bytes enqueued
|
||||
*
|
||||
* d = data byte from host
|
||||
* c = command byte from host
|
||||
*
|
||||
* k = to-host queue head pointer before byte dequeued
|
||||
* K = byte actually sent to host via LPC
|
||||
*/
|
||||
uint8_t type;
|
||||
uint8_t byte;
|
||||
};
|
||||
static struct kblog_t *kblog; /* Log buffer, or NULL if not logging */
|
||||
static int kblog_len; /* Current log length */
|
||||
|
||||
static struct kblog_t *kblog_buf; /* Log buffer; NULL if not logging */
|
||||
static int kblog_len; /* Current log length */
|
||||
|
||||
/**
|
||||
* Add event to keyboard log.
|
||||
*/
|
||||
static void kblog_put(char type, uint8_t byte)
|
||||
{
|
||||
if (kblog_buf && kblog_len < MAX_KBLOG) {
|
||||
kblog_buf[kblog_len].type = type;
|
||||
kblog_buf[kblog_len].byte = byte;
|
||||
kblog_len++;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* Flush and reset all i8042 keyboard buffers.
|
||||
*/
|
||||
static void i8042_flush_buffer(void)
|
||||
{
|
||||
mutex_lock(&to_host_mutex);
|
||||
queue_reset(&to_host);
|
||||
mutex_unlock(&to_host_mutex);
|
||||
lpc_keyboard_clear_buffer();
|
||||
}
|
||||
|
||||
void keyboard_host_write(int data, int is_cmd)
|
||||
{
|
||||
struct host_byte h;
|
||||
|
||||
h.type = is_cmd ? HOST_COMMAND : HOST_DATA;
|
||||
h.byte = data;
|
||||
queue_add_units(&from_host, &h, 1);
|
||||
task_wake(TASK_ID_I8042CMD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable keyboard IRQ generation.
|
||||
*
|
||||
* @param enable Enable (!=0) or disable (0) IRQ generation.
|
||||
*/
|
||||
static void keyboard_enable_irq(int enable)
|
||||
{
|
||||
i8042_irq_enabled = enable;
|
||||
if (enable)
|
||||
lpc_keyboard_resume_irq();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a 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 in time.
|
||||
*
|
||||
* @param len Number of bytes to send to the host
|
||||
* @param to_host Data to send
|
||||
*/
|
||||
static void i8042_send_to_host(int len, const uint8_t *bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
kblog_put('s', bytes[i]);
|
||||
|
||||
/* Enqueue output data if there's space */
|
||||
mutex_lock(&to_host_mutex);
|
||||
if (queue_has_space(&to_host, len)) {
|
||||
kblog_put('t', to_host.tail);
|
||||
queue_add_units(&to_host, bytes, len);
|
||||
}
|
||||
mutex_unlock(&to_host_mutex);
|
||||
|
||||
/* Wake up the task to move from queue to host */
|
||||
task_wake(TASK_ID_I8042CMD);
|
||||
}
|
||||
|
||||
/* Change to set 1 if the I8042_XLATE flag is set. */
|
||||
static enum scancode_set_list acting_code_set(enum scancode_set_list set)
|
||||
@@ -167,11 +295,10 @@ static enum scancode_set_list acting_code_set(enum scancode_set_list set)
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
static enum ec_error_list matrix_callback(int8_t row, int8_t col,
|
||||
int8_t pressed,
|
||||
enum scancode_set_list code_set,
|
||||
uint8_t *scan_code, int32_t* len)
|
||||
uint8_t *scan_code, int32_t *len)
|
||||
{
|
||||
uint16_t make_code;
|
||||
|
||||
@@ -227,12 +354,14 @@ static enum ec_error_list matrix_callback(int8_t row, int8_t col,
|
||||
break;
|
||||
|
||||
case SCANCODE_SET_2:
|
||||
/* insert the break byte, move back the last byte and insert a
|
||||
* 0xf0 byte before that. */
|
||||
/*
|
||||
* Insert the break byte, move back the last byte and insert a
|
||||
* 0xf0 byte before that.
|
||||
*/
|
||||
if (!pressed) {
|
||||
ASSERT(*len >= 1);
|
||||
scan_code[*len] = scan_code[*len - 1];
|
||||
scan_code[*len - 1] = 0xF0;
|
||||
scan_code[*len - 1] = 0xf0;
|
||||
*len += 1;
|
||||
}
|
||||
break;
|
||||
@@ -243,7 +372,6 @@ static enum ec_error_list matrix_callback(int8_t row, int8_t col,
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void reset_rate_and_delay(void)
|
||||
{
|
||||
typematic_value_from_host = DEFAULT_TYPEMATIC_VALUE;
|
||||
@@ -251,7 +379,6 @@ static void reset_rate_and_delay(void)
|
||||
refill_inter_delay = DEFAULT_INTER_DELAY;
|
||||
}
|
||||
|
||||
|
||||
void keyboard_clear_buffer(void)
|
||||
{
|
||||
i8042_flush_buffer();
|
||||
@@ -268,8 +395,7 @@ void keyboard_state_changed(int row, int col, int is_pressed)
|
||||
int32_t len;
|
||||
enum ec_error_list ret;
|
||||
|
||||
CPRINTF5("[%T KB %s(): row=%d col=%d is_pressed=%d]\n",
|
||||
__func__, row, col, is_pressed);
|
||||
CPRINTF5("[%T KB (%d,%d)=%d]\n", row, col, is_pressed);
|
||||
|
||||
ret = matrix_callback(row, col, is_pressed, scancode_set, scan_code,
|
||||
&len);
|
||||
@@ -282,7 +408,7 @@ void keyboard_state_changed(int row, int col, int is_pressed)
|
||||
if (is_pressed) {
|
||||
keyboard_wakeup();
|
||||
|
||||
typematic_delay = refill_first_delay * 1000;
|
||||
typematic_delay = refill_first_delay * MSEC;
|
||||
memcpy(typematic_scan_code, scan_code, len);
|
||||
typematic_len = len;
|
||||
task_wake(TASK_ID_TYPEMATIC);
|
||||
@@ -291,7 +417,6 @@ void keyboard_state_changed(int row, int col, int is_pressed)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void keyboard_enable(int enable)
|
||||
{
|
||||
if (!keyboard_enabled && enable) {
|
||||
@@ -314,7 +439,6 @@ static void keystroke_enable(int enable)
|
||||
keystroke_enabled = enable;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t read_ctl_ram(uint8_t addr)
|
||||
{
|
||||
if (addr < ARRAY_SIZE(controller_ram))
|
||||
@@ -323,9 +447,11 @@ static uint8_t read_ctl_ram(uint8_t addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Manipulate the controller_ram[]. Some bits change may trigger internal
|
||||
* state change. */
|
||||
/**
|
||||
* Manipulate the controller_ram[].
|
||||
*
|
||||
* Some bits change may trigger internal state change.
|
||||
*/
|
||||
static void update_ctl_ram(uint8_t addr, uint8_t data)
|
||||
{
|
||||
uint8_t orig;
|
||||
@@ -338,37 +464,31 @@ static void update_ctl_ram(uint8_t addr, uint8_t data)
|
||||
CPRINTF5("[%T KB set CTR_RAM(0x%02x)=0x%02x (old:0x%02x)]\n",
|
||||
addr, data, orig);
|
||||
|
||||
if (addr == 0x00) { /* the controller RAM */
|
||||
if (addr == 0x00) {
|
||||
/* Keyboard enable/disable */
|
||||
|
||||
/* Enable IRQ before enable keyboard (queue chars to host) */
|
||||
if (!(orig & I8042_ENIRQ1) && (data & I8042_ENIRQ1))
|
||||
i8042_enable_keyboard_irq(1);
|
||||
keyboard_enable_irq(1);
|
||||
|
||||
/* Handle the I8042_KBD_DIS bit */
|
||||
keyboard_enable(!(data & I8042_KBD_DIS));
|
||||
|
||||
/* Disable IRQ after disable keyboard so that every char
|
||||
* must have informed the host. */
|
||||
/*
|
||||
* Disable IRQ after disable keyboard so that every char must
|
||||
* have informed the host.
|
||||
*/
|
||||
if ((orig & I8042_ENIRQ1) && !(data & I8042_ENIRQ1))
|
||||
i8042_enable_keyboard_irq(0);
|
||||
keyboard_enable_irq(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static enum {
|
||||
STATE_NORMAL = 0,
|
||||
STATE_SCANCODE,
|
||||
STATE_SETLEDS,
|
||||
STATE_EX_SETLEDS_1, /* expect 2-byte parameter coming */
|
||||
STATE_EX_SETLEDS_2,
|
||||
STATE_WRITE_CMD_BYTE,
|
||||
STATE_WRITE_OUTPUT_PORT,
|
||||
STATE_ECHO_MOUSE,
|
||||
STATE_SETREP,
|
||||
STATE_SEND_TO_MOUSE,
|
||||
} data_port_state = STATE_NORMAL;
|
||||
|
||||
|
||||
int handle_keyboard_data(uint8_t data, uint8_t *output)
|
||||
/**
|
||||
* Handle the port 0x60 writes from host.
|
||||
*
|
||||
* This functions returns the number of bytes stored in *output buffer.
|
||||
*/
|
||||
static int handle_keyboard_data(uint8_t data, uint8_t *output)
|
||||
{
|
||||
int out_len = 0;
|
||||
int save_for_resend = 1;
|
||||
@@ -434,7 +554,7 @@ int handle_keyboard_data(uint8_t data, uint8_t *output)
|
||||
typematic_value_from_host = data;
|
||||
refill_first_delay =
|
||||
(((typematic_value_from_host & 0x60) >> 5) + 1) * 250;
|
||||
refill_inter_delay = 1000 * /* ms */
|
||||
refill_inter_delay = MSEC *
|
||||
(1 << ((typematic_value_from_host & 0x18) >> 3)) *
|
||||
((typematic_value_from_host & 0x7) + 8) /
|
||||
240;
|
||||
@@ -457,8 +577,7 @@ int handle_keyboard_data(uint8_t data, uint8_t *output)
|
||||
break;
|
||||
|
||||
case I8042_CMD_SETLEDS:
|
||||
/* We use screen indicator. Do nothing in keyboard
|
||||
* controller. */
|
||||
/* Chrome OS doesn't have keyboard LEDs, so ignore */
|
||||
output[out_len++] = I8042_RET_ACK;
|
||||
data_port_state = STATE_SETLEDS;
|
||||
break;
|
||||
@@ -518,13 +637,16 @@ int handle_keyboard_data(uint8_t data, uint8_t *output)
|
||||
output[out_len++] = resend_command[i];
|
||||
break;
|
||||
|
||||
/* u-boot hack */
|
||||
case 0x60: /* see CONFIG_USE_CPCIDVI in */
|
||||
case 0x45: /* third_party/u-boot/files/drivers/input/i8042.c */
|
||||
/* just ignore, don't reply anything. */
|
||||
case 0x60: /* fall-thru */
|
||||
case 0x45:
|
||||
/*
|
||||
* U-boot hack. See CONFIG_USE_CPCIDVI in
|
||||
* third_party/u-boot/files/drivers/input/i8042.c.
|
||||
* Just ignore; don't reply.
|
||||
*/
|
||||
break;
|
||||
|
||||
case I8042_CMD_SETALL_MB: /* fall-thru below */
|
||||
case I8042_CMD_SETALL_MB: /* fall-thru */
|
||||
case I8042_CMD_SETALL_MBR:
|
||||
case I8042_CMD_EX_ENABLE:
|
||||
default:
|
||||
@@ -547,8 +669,13 @@ int handle_keyboard_data(uint8_t data, uint8_t *output)
|
||||
return out_len;
|
||||
}
|
||||
|
||||
|
||||
int handle_keyboard_command(uint8_t command, uint8_t *output)
|
||||
/**
|
||||
* Handle the port 0x64 writes from host.
|
||||
*
|
||||
* This functions returns the number of bytes stored in *output buffer.
|
||||
* BUT those bytes will appear at port 0x60.
|
||||
*/
|
||||
static int handle_keyboard_command(uint8_t command, uint8_t *output)
|
||||
{
|
||||
int out_len = 0;
|
||||
|
||||
@@ -649,6 +776,21 @@ int handle_keyboard_command(uint8_t command, uint8_t *output)
|
||||
return out_len;
|
||||
}
|
||||
|
||||
static void i8042_handle_from_host(void)
|
||||
{
|
||||
struct host_byte h;
|
||||
int ret_len;
|
||||
uint8_t output[MAX_SCAN_CODE_LEN];
|
||||
|
||||
while (queue_remove_unit(&from_host, &h)) {
|
||||
if (h.type == HOST_COMMAND)
|
||||
ret_len = handle_keyboard_command(h.byte, output);
|
||||
else
|
||||
ret_len = handle_keyboard_data(h.byte, output);
|
||||
|
||||
i8042_send_to_host(ret_len, output);
|
||||
}
|
||||
}
|
||||
|
||||
/* U U D D L R L R b a */
|
||||
static void keyboard_special(uint16_t k)
|
||||
@@ -723,17 +865,37 @@ void keyboard_set_power_button(int pressed)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void kblog_put(char type, uint8_t byte)
|
||||
void i8042_command_task(void)
|
||||
{
|
||||
if (kblog && kblog_len < MAX_KBLOG) {
|
||||
kblog[kblog_len].type = type;
|
||||
kblog[kblog_len].byte = byte;
|
||||
kblog_len++;
|
||||
while (1) {
|
||||
/* Wait for next host read/write */
|
||||
task_wait_event(-1);
|
||||
|
||||
while (1) {
|
||||
uint8_t chr;
|
||||
|
||||
/* Handle command/data write from host */
|
||||
i8042_handle_from_host();
|
||||
|
||||
/* Check if we have data to send to host */
|
||||
if (queue_is_empty(&to_host))
|
||||
break;
|
||||
|
||||
/* Host interface must have space */
|
||||
if (lpc_keyboard_has_char())
|
||||
break;
|
||||
|
||||
/* Get a char from buffer. */
|
||||
kblog_put('k', to_host.head);
|
||||
queue_remove_unit(&to_host, &chr);
|
||||
kblog_put('K', chr);
|
||||
|
||||
/* Write to host. */
|
||||
lpc_keyboard_put_char(chr, i8042_irq_enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void keyboard_typematic_task(void)
|
||||
{
|
||||
while (1) {
|
||||
@@ -748,7 +910,7 @@ void keyboard_typematic_task(void)
|
||||
if (keystroke_enabled)
|
||||
i8042_send_to_host(typematic_len,
|
||||
typematic_scan_code);
|
||||
typematic_delay = refill_inter_delay * 1000;
|
||||
typematic_delay = refill_inter_delay * MSEC;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -835,8 +997,9 @@ static int command_keyboard_log(int argc, char **argv)
|
||||
|
||||
if (argc == 1) {
|
||||
ccprintf("KBC log (len=%d):\n", kblog_len);
|
||||
for (i = 0; kblog && i < kblog_len; ++i) {
|
||||
ccprintf("%c.%02x ", kblog[i].type, kblog[i].byte);
|
||||
for (i = 0; kblog_buf && i < kblog_len; ++i) {
|
||||
ccprintf("%c.%02x ",
|
||||
kblog_buf[i].type, kblog_buf[i].byte);
|
||||
if ((i & 15) == 15) {
|
||||
ccputs("\n");
|
||||
cflush();
|
||||
@@ -844,21 +1007,23 @@ static int command_keyboard_log(int argc, char **argv)
|
||||
}
|
||||
ccputs("\n");
|
||||
} else if (argc == 2 && !strcasecmp("on", argv[1])) {
|
||||
if (!kblog) {
|
||||
int rv = shared_mem_acquire(sizeof(*kblog) * MAX_KBLOG,
|
||||
(char **)&kblog);
|
||||
if (!kblog_buf) {
|
||||
int rv = shared_mem_acquire(
|
||||
sizeof(*kblog_buf) * MAX_KBLOG,
|
||||
(char **)&kblog_buf);
|
||||
if (rv != EC_SUCCESS)
|
||||
kblog = NULL;
|
||||
kblog_buf = NULL;
|
||||
kblog_len = 0;
|
||||
return rv;
|
||||
}
|
||||
} else if (argc == 2 && !strcasecmp("off", argv[1])) {
|
||||
kblog_len = 0;
|
||||
if (kblog)
|
||||
shared_mem_release(kblog);
|
||||
kblog = NULL;
|
||||
} else
|
||||
if (kblog_buf)
|
||||
shared_mem_release(kblog_buf);
|
||||
kblog_buf = NULL;
|
||||
} else {
|
||||
return EC_ERROR_PARAM1;
|
||||
}
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
|
||||
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Mock EC i8042 interface code.
|
||||
*/
|
||||
|
||||
#include "i8042.h"
|
||||
#include "keyboard_i8042.h"
|
||||
#include "timer.h"
|
||||
#include "uart.h"
|
||||
|
||||
void i8042_receive(int data, int is_cmd)
|
||||
void keyboard_receive(int data, int is_cmd)
|
||||
{
|
||||
/* Not implemented */
|
||||
return;
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* i8042 keyboard protocol
|
||||
*/
|
||||
|
||||
#ifndef __CROS_EC_I8042_H
|
||||
#define __CROS_EC_I8042_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
* Flush and reset all i8042 keyboard buffers.
|
||||
*/
|
||||
void i8042_flush_buffer(void);
|
||||
|
||||
/**
|
||||
* Notify the i8042 module when a byte is written by the host.
|
||||
*
|
||||
* Note: This is called in interrupt context by the LPC interrupt handler.
|
||||
*
|
||||
* @param data Byte written by host
|
||||
* @param is_cmd Is byte command (!=0) or data (0)
|
||||
*/
|
||||
void i8042_receive(int data, int is_cmd);
|
||||
|
||||
/**
|
||||
* Enable keyboard IRQ generation.
|
||||
*
|
||||
* @param enable Enable (!=0) or disable (0) IRQ generation.
|
||||
*/
|
||||
void i8042_enable_keyboard_irq(int enable);
|
||||
|
||||
/**
|
||||
* Send a 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 in time.
|
||||
*
|
||||
* @param len Number of bytes to send to the host
|
||||
* @param to_host Data to send
|
||||
*/
|
||||
void i8042_send_to_host(int len, const uint8_t *to_host);
|
||||
|
||||
#endif /* __CROS_EC_I8042_H */
|
||||
@@ -10,22 +10,15 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define MAX_SCAN_CODE_LEN 4
|
||||
|
||||
/**
|
||||
* Handle the port 0x60 writes from host.
|
||||
* Notify the keyboard module when a byte is written by the host.
|
||||
*
|
||||
* This functions returns the number of bytes stored in *output buffer.
|
||||
*/
|
||||
int handle_keyboard_data(uint8_t data, uint8_t *output);
|
||||
|
||||
/**
|
||||
* Handle the port 0x64 writes from host.
|
||||
* Note: This is called in interrupt context by the LPC interrupt handler.
|
||||
*
|
||||
* This functions returns the number of bytes stored in *output buffer.
|
||||
* BUT theose bytes will appear at port 0x60.
|
||||
* @param data Byte written by host
|
||||
* @param is_cmd Is byte command (!=0) or data (0)
|
||||
*/
|
||||
int handle_keyboard_command(uint8_t command, uint8_t *output);
|
||||
void keyboard_host_write(int data, int is_cmd);
|
||||
|
||||
/**
|
||||
* Called by keyboard scan code once any key state change (after de-bounce),
|
||||
@@ -39,9 +32,4 @@ void keyboard_state_changed(int row, int col, int is_pressed);
|
||||
*/
|
||||
void keyboard_set_power_button(int pressed);
|
||||
|
||||
/**
|
||||
* Log the keyboard-related information
|
||||
*/
|
||||
void kblog_put(char type, uint8_t byte);
|
||||
|
||||
#endif /* __CROS_EC_KEYBOARD_8042_H */
|
||||
|
||||
Reference in New Issue
Block a user