Link keyboard-related code together.

Added i8042 interface and matrix code. Demonstrate a key is pressed and passed
to host through the board-dependent matrix code.

BUG=None
TEST=make && make runtests

Change-Id: I6a9f5e621d9e93e5c16384afebf4d665000e81a6
This commit is contained in:
Louis Yung-Chieh Lo
2011-10-27 16:31:08 +08:00
parent aa8ecb2b65
commit 79a661d00c
19 changed files with 455 additions and 49 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,3 @@
board/
board/*/
build/
vendor/

View File

@@ -30,6 +30,7 @@ endif
export TOP = $(shell pwd)
export CROS_EC_DIR=$(TOP)/cros_ec
export CHIP_STUB_DIR=$(CROS_EC_DIR)/chip_stub
export BOARD_DIR=$(TOP)/board
INCLUDES = -I$(TOP)/chip_interface -I$(CROS_EC_DIR)/include
@@ -42,11 +43,12 @@ export INCLUDES
export BUILD = ${TOP}/build
export CROS_EC_LIB = ${BUILD}/cros_ec.a
export CHIP_STUB_LIB = ${BUILD}/chip_stub.a
export BOARD_LIB = ${BUILD}/board.a
ifeq ($(FIRMWARE_ARCH),)
SUBDIRS = cros_ec cros_ec/test utility
SUBDIRS = board cros_ec cros_ec/test utility
else
SUBDIRS = cros_ec
SUBDIRS = board cros_ec
endif
all:

30
board/Makefile Normal file
View File

@@ -0,0 +1,30 @@
# Copyright (c) 2011 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.
CROS_EC_TOP := $(shell pwd)
BUILD_ROOT := ${BUILD}/$(shell basename ${CROS_EC_TOP})
INCLUDES += \
-I$(TOP)
ifeq ($(FIRMWARE_ARCH),)
INCLUDES += -I$(STUBDIR)/include
else
INCLUDES += -I$(FWDIR)/arch/$(FIRMWARE_ARCH)/include
endif
BOARD_SRCS = \
board.c
BOARD_OBJS = $(BOARD_SRCS:%.c=${BUILD_ROOT}/%.o)
ALL_SRCS = ${BOARD_SRCS}
all : $(BOARD_LIB)
include ../common.mk
$(BOARD_LIB) : $(BOARD_OBJS)
rm -f $@
ar qc $@ $^

56
board/board.c Normal file
View File

@@ -0,0 +1,56 @@
/* Copyright (c) 2011 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.
*
* main.c -- the main function of board-specific code.
*/
#include "cros_ec/include/ec_common.h"
#include "board/board_interface.h"
#include "cros_ec/include/ec_keyboard.h"
#define CROS_ROW_NUM 8 /* TODO: +1 for power button. */
#define CROS_COL_NUM 13
/* The standard Chrome OS keyboard matrix table. */
static uint8_t maxtri_table[CROS_ROW_NUM][CROS_COL_NUM] = {
/* FIXME: waiting for approval to open-source this table. */
};
static EcError MatrixCallback(
int8_t row, int8_t col, int8_t pressed,
uint8_t *scan_code, int32_t* len) {
uint8_t make_code;
EC_ASSERT(scan_code);
EC_ASSERT(len);
if (row > CROS_ROW_NUM ||
col > CROS_COL_NUM) {
return EC_ERROR_INVALID_PARAMETER;
}
make_code = maxtri_table[row][col];
make_code = row * 13 + col; /* FIXME: remove this after we can open-source
* the matrix table. */
if (pressed) {
*scan_code = make_code;
*len = 1;
} else {
*scan_code = make_code | 0x80;
*len = 1;
}
return EC_SUCCESS;
}
EcError BoardInit() {
EC_ASSERT(EC_SUCCESS ==
EcKeyboardMatrixRegisterCallback(
CROS_ROW_NUM, CROS_COL_NUM, MatrixCallback));
return EC_SUCCESS;
}

20
board/board_interface.h Normal file
View File

@@ -0,0 +1,20 @@
/* Copyright (c) 2011 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.
*
* board.h -- defines the board interface. The implementation will be under
* board/your_board_name/main.c.
*/
#ifndef __BOARD_BOARD_INTERFACE_H
#define __BOARD_BOARD_INTERFACE_H
#include "cros_ec/include/ec_common.h"
/* The initialize function of a board. Called by the EC core at start.
* The main mission is to register its callback function to the EC core.
*/
EcError BoardInit();
#endif /* __BOARD_BOARD_INTERFACE_H */

View File

@@ -2,7 +2,9 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* keyboard.h - Keyboard interface between EC core and EC Lib.
* keyboard.h - Keyboard interface between EC core and EC Lib. Both would
* include this file. And, it is EC lib to provides the real implementation
* (wrapping the low-level driver).
*/
#ifndef __CHIP_INTERFACE_KEYBOARD_H
@@ -10,10 +12,10 @@
#include "cros_ec/include/ec_common.h"
#define MAX_KEYBOARD_MATRIX_COLS 16
#define MAX_KEYBOARD_MATRIX_ROWS 8
#define MAX_KEYBOARD_MATRIX_COLS 16
typedef void (*EcKeyboardCallback)(int col, int row, int is_pressed);
typedef void (*EcKeyboardCallback)(int row, int col, int is_pressed);
/* Registers a callback function to underlayer EC lib. So that any key state
* change would notify the upper EC main code.
@@ -25,7 +27,7 @@ EcError EcKeyboardRegisterCallback(EcKeyboardCallback cb);
/* Asks the underlayer EC lib what keys are pressed right now.
*
* Sets bit_array to a debounced array of which keys are currently pressed,
* where a 1-bit means the key is pressed. For example, if only col=2 row=3
* where a 1-bit means the key is pressed. For example, if only row=2 col=3
* is pressed, it would set bit_array to {0, 0, 0x08, 0, ...}
*
* bit_array must be at least MAX_KEYBOARD_MATRIX_COLS bytes long.

View File

@@ -35,7 +35,8 @@ LIB_OBJS = $(LIB_SRCS:%.c=${BUILD_ROOT}/%.o)
STUB_SRCS = \
./chip_stub/ec_os.c \
./chip_stub/ec_uart.c \
./chip_stub/keyboard.c
./chip_stub/keyboard.c \
./chip_stub/host.c
STUB_OBJS = $(STUB_SRCS:%.c=${BUILD_ROOT}/%.o)

83
cros_ec/chip_stub/host.c Normal file
View File

@@ -0,0 +1,83 @@
/* Copyright (c) 2011 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.
*
* host.c -- implements the LPC driver of EC lib and provides simulation
* functions.
*/
#include <string.h> /* FIXME: remove after we have our-own mem*(). */
#include "cros_ec/include/ec_common.h"
#include "cros_ec/chip_stub/include/keyboard.h"
#include "host_interface/ec_command.h"
#include "host_interface/i8042.h"
static EcAcpiCallback acpi_callback;
static EcI8042Callback i8042_callback;
#define SCAN_CODE_QUEUE_LEN 16
static int scan_code_queue_len = 0;
static uint8_t scan_code_queue[SCAN_CODE_QUEUE_LEN];
EcError EcAcpiRegisterCallback(EcAcpiCallback callback) {
acpi_callback = callback;
return EC_SUCCESS;
}
EcError EcI8042RegisterCallback(EcI8042Callback callback) {
i8042_callback = callback;
return EC_SUCCESS;
}
EcError EcI8042SendScanCode(int len, uint8_t *scan_code) {
if ((scan_code_queue_len + len) > SCAN_CODE_QUEUE_LEN) {
return EC_ERROR_BUFFER_FULL;
}
memcpy(&scan_code_queue[scan_code_queue_len], scan_code, len);
scan_code_queue_len += len;
return EC_SUCCESS;
}
/************* Simulation functions ***************/
int SimulateAcpiCommand(
uint8_t command,
uint8_t data,
uint8_t *mailbox,
uint8_t *output) {
EC_ASSERT(acpi_callback);
return acpi_callback(command, data, mailbox, output);
}
int SimulateI8042Command(
uint8_t command,
uint8_t data,
uint8_t *output) {
EC_ASSERT(i8042_callback);
return i8042_callback(command, data, output);
}
EcError PullI8042ScanCode(uint8_t *buf) {
EC_ASSERT(buf);
if (scan_code_queue_len <= 0) {
return EC_ERROR_BUFFER_EMPTY;
}
*buf = scan_code_queue[0];
memmove(&scan_code_queue[0], &scan_code_queue[1], --scan_code_queue_len);
return EC_SUCCESS;
}

View File

@@ -0,0 +1,26 @@
/* Copyright (c) 2011 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.
*
* host.h -- defines the API provided by chip_stub/host.c.
*/
#ifndef __CROS_EC_CHIP_STUB_INCLUDE_HOST_H
#define __CROS_EC_CHIP_STUB_INCLUDE_HOST_H
#include "cros_ec/include/ec_common.h"
int SimulateAcpiCommand(
uint8_t command,
uint8_t data,
uint8_t *mailbox,
uint8_t *output);
int SimulateI8042Command(
uint8_t command,
uint8_t data,
uint8_t *output);
EcError PullI8042ScanCode(uint8_t *buf);
#endif /* __CROS_EC_CHIP_STUB_INCLUDE_HOST_H */

View File

@@ -9,6 +9,6 @@
#ifndef __EC_CHIP_STUB_KEYBOARD_H_
#define __EC_CHIP_STUB_KEYBOARD_H_
EcError SimulateKeyStateChange(int col, int row, int state);
EcError SimulateKeyStateChange(int row, int col, int state);
#endif /* __EC_CHIP_STUB_KEYBOARD_H_ */

View File

@@ -26,9 +26,9 @@ EcError EcKeyboardGetState(uint8_t *bit_array) {
/* Called by test code. This simulates a key press or release.
* Usually, the test code would expect a scan code is received at host side.
*/
EcError SimulateKeyStateChange(int col, int row, int state) {
ASSERT(col < MAX_KEYBOARD_MATRIX_COLS);
ASSERT(row < MAX_KEYBOARD_MATRIX_ROWS);
EcError SimulateKeyStateChange(int row, int col, int state) {
EC_ASSERT(row < MAX_KEYBOARD_MATRIX_ROWS);
EC_ASSERT(col < MAX_KEYBOARD_MATRIX_COLS);
if (!core_keyboard_callback) return EC_ERROR_UNKNOWN;
@@ -38,10 +38,10 @@ EcError SimulateKeyStateChange(int col, int row, int state) {
if (state && !current_state) {
/* key is just pressed down */
virtual_matrix[col] |= 1 << row;
core_keyboard_callback(col, row, state);
core_keyboard_callback(row, col, state);
} else if (!state && current_state) {
virtual_matrix[col] &= ~(1 << row);
core_keyboard_callback(col, row, state);
core_keyboard_callback(row, col, state);
} else {
/* Nothing happens if a key has been pressed or released. */
}

View File

@@ -28,6 +28,12 @@ enum EcErrorList {
EC_ERROR_OVERFLOW = 3,
/* Timeout */
EC_ERROR_TIMEOUT = 4,
/* Invalid parameter */
EC_ERROR_INVALID_PARAMETER,
/* Buffer is full, for output. */
EC_ERROR_BUFFER_FULL,
/* Buffer is empty, for input. */
EC_ERROR_BUFFER_EMPTY,
/* Module-internal error codes may use this range. */
EC_ERROR_INTERNAL_FIRST = 0x10000,
@@ -39,10 +45,11 @@ enum EcErrorList {
#define PRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
/* TODO: move to a proper .h file */
#define ASSERT(expr) do { \
#define EC_ASSERT(expr) do { \
if (!(expr)) { \
PRINTF("ASSERT(%s) failed at file %s:%d.\n", \
PRINTF("\n*** EC_ASSERT(%s) failed at file %s:%d.\n", \
#expr, __FILE__, __LINE__); \
while (1); \
} \
} while (0)

View File

@@ -1,13 +1,14 @@
/* Copyright (c) 2011 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.
*
* The functions implemented by keyboard component of EC core.
*/
/* Keyboard emulation */
#ifndef __CROS_EC_KEYBOARD_H
#define __CROS_EC_KEYBOARD_H
#ifndef __CROS_INCLUDE_EC_KEYBOARD_H
#define __CROS_INCLUDE_EC_KEYBOARD_H
#include "cros_ec/include/ec_common.h"
/* The initialize code of keyboard lib. Called by core main. */
EcError EcKeyboardInit();
@@ -15,12 +16,19 @@ EcError EcKeyboardInit();
/* Register the board-specific keyboard matrix translation function.
* The callback function accepts col/row and returns the scan code.
*
* Note that *scan_code must be at least 4 bytes long to store maximum
* possible sequence.
*/
EcError EcKeyboardMatrixRegister(
int8_t col_num, int8_t row_num,
EcError (*callback)(
int8_t column, int8_t row, int8_t pressed,
uint8_t *scan_code, int32_t* len));
typedef EcError (*EcKeyboardMatrixCallback)(
int8_t row, int8_t col, int8_t pressed,
uint8_t *scan_code, int32_t* len);
EcError EcKeyboardMatrixRegisterCallback(
int8_t row_num, int8_t col_num,
EcKeyboardMatrixCallback callback);
#define MAX_SCAN_CODE_LEN 4
#endif /* __CROS_EC_KEYBOARD_H */
#endif /* __CROS_INCLUDE_EC_KEYBOARD_H */

View File

@@ -6,11 +6,43 @@
*/
#include "cros_ec/include/ec_common.h"
#include "cros_ec/include/ec_keyboard.h"
#include "chip_interface/keyboard.h"
#include "host_interface/i8042.h"
static void KeyboardStateChanged(int col, int row, int is_pressed) {
PRINTF("File %s:%s(): col=%d row=%d is_pressed=%d\n",
__FILE__, __FUNCTION__, col, row, is_pressed);
static EcKeyboardMatrixCallback matrix_callback;
static void KeyboardStateChanged(int row, int col, int is_pressed) {
uint8_t scan_code[MAX_SCAN_CODE_LEN];
int len;
EcError ret;
PRINTF("File %s:%s(): row=%d col=%d is_pressed=%d\n",
__FILE__, __FUNCTION__, row, col, is_pressed);
EC_ASSERT(matrix_callback);
ret = matrix_callback(row, col, is_pressed, scan_code, &len);
if (ret == EC_SUCCESS) {
EC_ASSERT(len > 0);
EcI8042SendScanCode(len, scan_code);
} else {
/* FIXME: long-term solution is to ignore this key. However, keep
* assertion in the debug stage. */
EC_ASSERT(ret == EC_SUCCESS);
}
}
EcError EcKeyboardMatrixRegisterCallback(
int8_t row_num, int8_t col_num,
EcKeyboardMatrixCallback callback) {
matrix_callback = callback;
return EC_SUCCESS;
}

View File

@@ -9,16 +9,24 @@
#include "cros_ec/include/core.h"
#include "cros_ec/include/ec_common.h"
#include "cros_ec/include/ec_keyboard.h"
#include "board/board_interface.h"
#define ReturnIfInitFailed(func) \
do { \
EcError ret; \
ret = func(); \
if (ret != EC_SUCCESS) { \
printf("%s() failed at %s:%d: %d\n", #func, __FILE__, __LINE__, ret); \
return ret; \
} \
} while (0)
EcError CoreMain() {
EcError ret;
ret = EcKeyboardInit();
if (ret != EC_SUCCESS) {
printf("EcKeyboardInit() failed: %d\n", ret);
return ret;
}
ReturnIfInitFailed(EcKeyboardInit);
ReturnIfInitFailed(BoardInit);
return EC_SUCCESS;
}

View File

@@ -20,7 +20,7 @@ TEST_BINS = $(addprefix ${BUILD_ROOT}/,$(TEST_NAMES))
# Allow multiple definitions, so tests can mock functions from other libraries
CFLAGS += -MMD -MF $@.d -Xlinker --allow-multiple-definition
LIBS := ${TEST_LIB} $(CROS_EC_LIB) $(CHIP_STUB_LIB)
LIBS := ${TEST_LIB} $(CROS_EC_LIB) $(CHIP_STUB_LIB) $(BOARD_LIB)
.SUFFIXES:
.SUFFIXES: .o .c

View File

@@ -5,21 +5,63 @@
* Testing code. Running at Linux environment.
*/
#include "cros_ec/include/ec_common.h"
#include "chip_interface/ec_uart.h"
#include "cros_ec/include/core.h"
#include "cros_ec/chip_stub/keyboard.h"
#include "cros_ec/chip_stub/include/host.h"
#include "cros_ec/chip_stub/include/keyboard.h"
#define RUN_TEST(func) do { \
int ret; \
ret = func(); \
if (ret != EC_SUCCESS) { \
EcUartPrintf("Test %s() failed, retval = %d\n", #func, ret); \
return ret; \
} \
} while (0)
EcError testKeyMade() {
uint8_t buf;
SimulateKeyStateChange(2, 3, 1);
EC_ASSERT(EC_SUCCESS == PullI8042ScanCode(&buf));
EC_ASSERT(buf == 2 * 13 + 3);
/* The duplicate press event will be ignored. */
SimulateKeyStateChange(2, 3, 1);
EC_ASSERT(EC_ERROR_BUFFER_EMPTY == PullI8042ScanCode(&buf));
return EC_SUCCESS;
}
EcError testKeyReleased() {
uint8_t buf;
/* The key is not pressed yet. A release event doesn't send out a code. */
SimulateKeyStateChange(7, 12, 0);
EC_ASSERT(EC_ERROR_BUFFER_EMPTY == PullI8042ScanCode(&buf));
/* Press and release it. Expect a release code. */
SimulateKeyStateChange(7, 12, 1);
SimulateKeyStateChange(7, 12, 0);
EC_ASSERT(EC_SUCCESS == PullI8042ScanCode(&buf));
EC_ASSERT(buf == 7 * 13 + 12);
EC_ASSERT(EC_SUCCESS == PullI8042ScanCode(&buf));
EC_ASSERT(buf == 7 * 13 + 12 + 0x80);
return EC_SUCCESS;
}
int run_test_cases() {
/* Just a simple test */
SimulateKeyStateChange(2, 3, 1);
/* Expect KeyboardStateChanged() in cros_ec/keyboard.c shows something. */
RUN_TEST(testKeyMade);
RUN_TEST(testKeyReleased);
return 0;
return EC_SUCCESS;
}
int main(int argc, char **argv) {
EcError ret;
/* Call Google EC core initial code. */

View File

@@ -2,9 +2,8 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* This file defines the EC commands used in mailbox between host and EC.
*
* This file is included by both BIOS/OS and EC firmware.
* This file defines the EC commands used in mailbox between host and EC, and
* is included by both BIOS/OS and EC firmware.
*/
#ifndef __HOST_INTERFACE_EC_COMMAND_H
@@ -13,6 +12,29 @@
#include "cros_ec/include/ec_common.h"
/*
* Register ACPI callback to EC lib. The EC lib would then invoke this callback
* when port ACPI command is written by the host.
*
* The command would contain the value just written in 0x66 while the data would
* hold the value in 0x62.
*
* The callback function would return an integer to indicate how many bytes
* contain in output (max len is MAX_ACPI_OUTPUT_LEN defined below).
* Then the EC lib would output those bytes via port 0x62 one-by-one.
*
* Registering a NULL pointer can remove any registered callback.
*/
typedef int (*EcAcpiCallback)(
uint8_t command, /* just written in port 0x66 */
uint8_t data, /* just written in port 0x62 */
uint8_t *mailbox,
uint8_t* output);
EcError EcAcpiRegisterCallback(EcAcpiCallback callback);
#define MAX_ACPI_OUTPUT_LEN 4
enum EcCommand {
/*------------------------------------------------------------------------*/
/* Version and boot information */
@@ -127,7 +149,6 @@ enum EcCommand {
* - host gets the return value and reads parameters from to_host range.
*/
/* When host writes this value to port 0x66 (ACPI command port),
* the EC firmware would read the EcCommand in port 0x62 and execute
* the corresponding function.
@@ -152,15 +173,35 @@ enum EcMailboxError {
EC_MAILBOX_ERROR_UNIMPLEMENTED = 2,
};
/* The callback function can return a value which will be put at port 0x62. */
/* FIXME: move to EC core internal. */
#if 0
/* This function is implemented by EC lib, which communicates with low level
* LPC driver. The EC core would register a callback function to handle
* the EC commands from host.
*
* When the callback function is invoked, the ec_command would store the
* value that was just written to port 0x62. In addition, the to_ec would
* point to the starting address of mailbox. If the mailbox is not direct-
* accessible, the EC lib needs copying to a buffer and prepare a buffer
* for to_host too. to_ec and to_host can be overlapped in memory.
*
* At final, the callback function can return a value which will be put at
* port 0x62. The EC lib (or the underlying hardware) needs to handle the
* IBF flags in port 0x66 so that the host knows the EC has completed the
* command.
*
* Registering a NULL pointer can remove any registered callback.
*/
typedef enum EcMailboxError (*EcMailboxCallback)(
uint8_t ec_command,
uint8_t *to_ec, /* pointer to input parameter */
uint8_t *to_host /* pointer to output buffer */);
/* Registering NULL can remove any registered callback. */
EcError EcMailboxRegisterCallback(EcMailboxCallback callback);
#endif
#endif /* __HOST_INTERFACE_EC_COMMAND_H */

48
host_interface/i8042.h Normal file
View File

@@ -0,0 +1,48 @@
/* Copyright (c) 2011 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.h -- defines the interface between EC core and the EC lib, which
* talks to the LPC driver (on the EC side) peering to the keyboard driver
* (on the host side).
*
* The EC lib implements this interface.
*/
#ifndef __HOST_INTERFACE_I8042_H
#define __HOST_INTERFACE_I8042_H
#include "cros_ec/include/ec_common.h"
/*
* Register the i8042 callback to EC lib.
*
* The callback function would return an integer to indicate how many bytes
* contain in output (max len is MAX_I8042_OUTPUT_LEN defined below).
* Then the EC lib would output those bytes via port 0x60 one-by-one.
*
* Registering a NULL pointer can remove any registered callback.
*/
typedef int (*EcI8042Callback) (
uint8_t command,
uint8_t data,
uint8_t *output);
EcError EcI8042RegisterCallback(EcI8042Callback callback);
#define MAX_I8042_OUTPUT_LEN 4
/* 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
* in time.
*
* Return:
* EC_ERROR_BUFFER_FULL -- the queue to host is full. Try again?
*/
EcError EcI8042SendScanCode(int len, uint8_t *scan_code);
#endif /* __HOST_INTERFACE_I8042_H */