summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile72
-rw-r--r--README3
-rw-r--r--chip_interface/ec_gpio.h37
-rw-r--r--chip_interface/ec_system.h59
-rw-r--r--chip_interface/ec_uart.h (renamed from cros_ec/include/ec_uart.h)10
-rw-r--r--common.mk20
-rw-r--r--cros_ec/Makefile51
-rw-r--r--cros_ec/chip_stub/ec_os.c516
-rw-r--r--cros_ec/chip_stub/ec_uart.c41
-rw-r--r--cros_ec/chip_stub/include/ec_os_types.h93
-rw-r--r--cros_ec/include/ec_common.h2
-rw-r--r--cros_ec/include/ec_os.h119
-rw-r--r--cros_ec/lib/ec_console.c2
-rw-r--r--cros_ec/test/Makefile45
-rw-r--r--cros_ec/test/ec_os_test.c128
-rw-r--r--host_interface/ec_command.h112
-rw-r--r--utility/Makefile28
-rw-r--r--utility/ec_uartd.c185
19 files changed, 1510 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..598dd8d7cb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+board/
+build/
+vendor/
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000..58696c285f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,72 @@
+# 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.
+
+export FIRMWARE_ARCH
+
+export CC ?= gcc
+export CXX ?= g++
+export CFLAGS = -Wall -Werror
+
+ifeq (${DEBUG},)
+CFLAGS += -O3
+else
+CFLAGS += -O0 -g
+endif
+
+# Fix compiling directly on host (outside of emake)
+ifeq ($(ARCH),)
+export ARCH=amd64
+endif
+
+ifneq (${DEBUG},)
+CFLAGS += -DVBOOT_DEBUG
+endif
+
+ifeq (${DISABLE_NDEBUG},)
+CFLAGS += -DNDEBUG
+endif
+
+export TOP = $(shell pwd)
+export CROS_EC_DIR=$(TOP)/cros_ec
+export CHIP_STUB_DIR=$(CROS_EC_DIR)/chip_stub
+
+INCLUDES = -I$(TOP)/chip_interface -I$(CROS_EC_DIR)/include
+
+ifeq ($(FIRMWARE_ARCH),)
+INCLUDES += -I$(CHIP_STUB_DIR)/include
+endif
+
+export INCLUDES
+
+export BUILD = ${TOP}/build
+export CROS_EC_LIB = ${BUILD}/cros_ec.a
+export CHIP_STUB_LIB = ${BUILD}/chip_stub.a
+
+ifeq ($(FIRMWARE_ARCH),)
+SUBDIRS = cros_ec cros_ec/test utility
+else
+SUBDIRS = cros_ec
+endif
+
+all:
+ set -e; \
+ for d in $(shell find ${SUBDIRS} -name '*.c' -exec dirname {} \; |\
+ sort -u); do \
+ newdir=${BUILD}/$$d; \
+ if [ ! -d $$newdir ]; then \
+ mkdir -p $$newdir; \
+ fi; \
+ done; \
+ for i in $(SUBDIRS); do \
+ make -C $$i; \
+ done
+
+clean:
+ /bin/rm -rf ${BUILD}
+
+install:
+ $(MAKE) -C utility install
+
+runtests:
+ $(MAKE) -C cros_ec/test runtests
diff --git a/README b/README
new file mode 100644
index 0000000000..d208014a7d
--- /dev/null
+++ b/README
@@ -0,0 +1,3 @@
+
+Google Coding Style:
+ http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
diff --git a/chip_interface/ec_gpio.h b/chip_interface/ec_gpio.h
new file mode 100644
index 0000000000..9f4f5ba81f
--- /dev/null
+++ b/chip_interface/ec_gpio.h
@@ -0,0 +1,37 @@
+/* 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.
+ */
+
+/* GPIO module for Chrome EC */
+
+#ifndef __CROS_EC_GPIO_H
+#define __CROS_EC_GPIO_H
+
+#include "ec_common.h"
+
+/* GPIO signal definitions. */
+typedef enum EcGpioSignal {
+ /* Firmware write protect */
+ EC_GPIO_WRITE_PROTECT = 0,
+ /* Recovery switch */
+ EC_GPIO_RECOVERY_SWITCH,
+ /* Debug LED */
+ EC_GPIO_DEBUG_LED
+} EcGpioSignal;
+
+
+/* Initializes the GPIO module. */
+EcError EcGpioInit(void);
+
+/* Functions should return an error if the requested signal is not
+ * supported / not present on the board. */
+
+/* Gets the current value of a signal (0=low, 1=hi). */
+EcError EcGpioGet(EcGpioSignal signal, int* value_ptr);
+
+/* Sets the current value of a signal. Returns error if the signal is
+ * not supported or is an input signal. */
+EcError EcGpioSet(EcGpioSignal signal, int value);
+
+#endif /* __CROS_EC_GPIO_H */
diff --git a/chip_interface/ec_system.h b/chip_interface/ec_system.h
new file mode 100644
index 0000000000..da3874d8c1
--- /dev/null
+++ b/chip_interface/ec_system.h
@@ -0,0 +1,59 @@
+/* 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.
+ */
+
+/* System module for Chrome EC */
+
+#ifndef __CROS_EC_SYSTEM_H
+#define __CROS_EC_SYSTEM_H
+
+#include "ec_common.h"
+
+/* Reset causes */
+typedef enum EcSystemResetCause {
+ /* Unknown reset cause */
+ EC_SYSTEM_RESET_UNKNOWN = 0,
+ /* System reset cause is known, but not one of the causes listed below */
+ EC_SYSTEM_RESET_OTHER,
+ /* Brownout */
+ EC_SYSTEM_RESET_BROWNOUT,
+ /* Power-on reset */
+ EC_SYSTEM_RESET_POWER_ON,
+ /* Reset caused by asserting reset (RST#) pin */
+ EC_SYSTEM_RESET_RESET_PIN,
+ /* Software requested cold reset */
+ EC_SYSTEM_RESET_SOFT_COLD,
+ /* Software requested warm reset */
+ EC_SYSTEM_RESET_SOFT_WARM,
+ /* Watchdog timer reset */
+ EC_SYSTEM_RESET_WATCHDOG,
+} EcSystemResetCause;
+
+
+/* Initializes the system module. */
+EcError EcSystemInit(void);
+
+/* Returns the cause of the last reset, or EC_SYSTEM_RESET_UNKNOWN if
+ * the cause is not known. */
+EcSystemResetCause EcSystemGetResetCause(void);
+
+/* Resets the system. If is_cold!=0, performs a cold reset (which
+ * resets on-chip peripherals); else performs a warm reset (which does
+ * not reset on-chip peripherals). If successful, does not return.
+ * Returns error if the reboot type cannot be requested (e.g. brownout
+ * or reset pin). */
+EcError EcSystemReset(int is_cold);
+
+/* Sets a scratchpad register to the specified value. The scratchpad
+ * register must maintain its contents across a software-requested
+ * warm reset. */
+EcError EcSystemSetScratchpad(uint32_t value);
+
+/* Stores the current scratchpad register value into <value_ptr>. */
+EcError EcSystemGetScratchpad(uint32_t* value_ptr);
+
+/* TODO: request sleep. How do we want to handle transitioning
+ * to/from low-power states? */
+
+#endif /* __CROS_EC_SYSTEM_H */
diff --git a/cros_ec/include/ec_uart.h b/chip_interface/ec_uart.h
index 8f49d43cce..4fdb273ba7 100644
--- a/cros_ec/include/ec_uart.h
+++ b/chip_interface/ec_uart.h
@@ -42,6 +42,16 @@ EcError EcUartPrintf(const char* format, ...);
* Returns error if output was truncated. */
EcError EcUartPuts(const char* outstr);
+/* Put a null-terminated string to the UART using polling mode, like puts().
+ *
+ * Writes directly to the UART, bypassing any buffering or resource
+ * locks, blocking until the entire string has been passed to the
+ * UART. This can be used for ensuring debug output when the system
+ * is in a questionable state such as when a fault occurs.
+ *
+ * Do not use during normal operation; use EcUartPuts() instead. */
+void EcUartPutsPolled(const char* outstr);
+
/* Flushes output. Blocks until UART has transmitted all output. */
void EcUartFlushOutput(void);
diff --git a/common.mk b/common.mk
new file mode 100644
index 0000000000..f0de87987c
--- /dev/null
+++ b/common.mk
@@ -0,0 +1,20 @@
+# Copyright (c) 2010 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.
+
+ALL_OBJS = $(ALL_SRCS:%.c=${BUILD_ROOT}/%.o)
+ALL_DEPS = $(ALL_OBJS:%.o=%.o.d)
+
+#
+# For this target (all) to be built by default, the including file must not
+# define any other targets above the line including this file.
+#
+# This all: rule must be above the %.o: %.c rule below, otherwise the
+# rule below becomes the default target.
+#
+all: ${ALL_OBJS}
+
+${BUILD_ROOT}/%.o : %.c
+ $(CC) $(CFLAGS) $(INCLUDES) -MMD -MF $@.d -c -o $@ $<
+
+-include ${ALL_DEPS}
diff --git a/cros_ec/Makefile b/cros_ec/Makefile
index ff59ee3b50..33433fd1f1 100644
--- a/cros_ec/Makefile
+++ b/cros_ec/Makefile
@@ -2,17 +2,48 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-LIB_SRCS=\
- lib/ec_console.c
+CROS_EC_TOP := $(shell pwd)
+LIBDIR = $(CROS_EC_TOP)/lib
+STUBDIR = $(CROS_EC_TOP)/chip_stub
+TESTDIR = $(CROS_EC_TOP)/test
+BUILD_ROOT := ${BUILD}/$(shell basename ${CROS_EC_TOP})
+LIBS = $(CROS_EC_LIB) # Firmware library must be self-contained
-STUB_SRCS=\
- chip_stub/ec_uart.c
+INCLUDES += -I$(LIBDIR)/include
-all: fakemain
+ifeq ($(FIRMWARE_ARCH),)
+INCLUDES += -I$(STUBDIR)/include
+else
+INCLUDES += -I$(FWDIR)/arch/$(FIRMWARE_ARCH)/include
+endif
-clean:
- rm -f fakemain
+# find ./lib -iname '*.c' | sort
+LIB_SRCS = \
+ ./lib/ec_console.c \
+ ./lib/ec_host_command.c
-fakemain: test/fakemain.c $(LIB_SRCS) $(STUB_SRCS)
- gcc -Wall -I include -o fakemain test/fakemain.c \
- $(LIB_SRCS) $(STUB_SRCS)
+LIB_OBJS = $(LIB_SRCS:%.c=${BUILD_ROOT}/%.o)
+
+STUB_SRCS = \
+ ./chip_stub/ec_os.c \
+ ./chip_stub/ec_uart.c
+
+STUB_OBJS = $(STUB_SRCS:%.c=${BUILD_ROOT}/%.o)
+
+ALL_SRCS = ${LIB_SRCS} ${STUB_SRCS}
+
+ifeq ($(FIRMWARE_ARCH),)
+all : $(CROS_EC_LIB) $(CHIP_STUB_LIB)
+else
+all : $(CROS_EC_LIB)
+endif
+
+include ../common.mk
+
+$(CROS_EC_LIB) : $(LIB_OBJS)
+ rm -f $@
+ ar qc $@ $^
+
+$(CHIP_STUB_LIB) : $(STUB_OBJS)
+ rm -f $@
+ ar qc $@ $^
diff --git a/cros_ec/chip_stub/ec_os.c b/cros_ec/chip_stub/ec_os.c
new file mode 100644
index 0000000000..ff48a5bf0b
--- /dev/null
+++ b/cros_ec/chip_stub/ec_os.c
@@ -0,0 +1,516 @@
+/* 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.
+ */
+
+/* Operating system library EC */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "ec_common.h"
+#include "ec_os.h"
+
+
+static int os_has_started = 0;
+static pthread_mutex_t os_start_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t os_start_cond = PTHREAD_COND_INITIALIZER;
+
+
+/* Waits for OS to start */
+static void WaitForOsStart(void) {
+ pthread_mutex_lock(&os_start_mutex);
+ if (!os_has_started)
+ pthread_cond_wait(&os_start_cond, &os_start_mutex);
+ pthread_mutex_unlock(&os_start_mutex);
+}
+
+static void UsecToTimespec(int usec, struct timespec* ts) {
+ ts->tv_sec = usec / 1000000;
+ ts->tv_nsec = 1000 * (long)(usec % 1000000);
+}
+
+/*****************************************************************************/
+/* Tasks */
+
+/* Internal data for a task */
+typedef struct EcTaskInternal {
+ pthread_t thread;
+ void (*task_func)(void*);
+ void* param;
+ struct EcTaskInternal* next;
+} EcTaskInternal;
+
+
+static EcTaskInternal* task_list = NULL;
+static pthread_mutex_t task_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+/* Task wrapper. Waits for OS to start, then runs the task function. */
+static void* EcTaskWrapper(void* param) {
+ EcTaskInternal* ti = (EcTaskInternal*)param;
+
+ WaitForOsStart();
+
+ /* Chain to the task function */
+ ti->task_func(ti->param);
+
+ return NULL;
+}
+
+
+EcError EcTaskCreate(EcTask* task, int priority, int stack_size,
+ void (*task_func)(void*), void* param) {
+ EcTaskInternal* ti = (EcTaskInternal*)task;
+ pthread_attr_t attr;
+
+ /* TODO: priority */
+
+ /* Initialize task data */
+ ti->task_func = task_func;
+ ti->param = param;
+
+ /* Add it to the task list */
+ pthread_mutex_lock(&task_list_mutex);
+ ti->next = task_list;
+ task_list = ti;
+ pthread_mutex_unlock(&task_list_mutex);
+
+ /* Mark thread as joinable */
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ /* Create the thread */
+ if (pthread_create(&ti->thread, &attr, EcTaskWrapper, ti) != 0)
+ return EC_ERROR_UNKNOWN;
+
+ return EC_SUCCESS;
+}
+
+
+void EcTaskSleep(int usec) {
+ usleep(usec);
+}
+
+
+void EcTaskExit(void) {
+ pthread_exit(NULL);
+}
+
+
+/*****************************************************************************/
+/* Software interrupts (SWI)
+ *
+ * SWIs don't exist in pthreads. Simulate them with a thread which waits
+ * on a semaphore and calls the SWI function when it wakes. */
+
+typedef struct EcSwiInternal {
+ pthread_t thread;
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
+ uint32_t pending_bits;
+ void (*swi_func)(void *, uint32_t);
+ void* param;
+} EcSwiInternal;
+
+
+/* SWI wrapper. Loops and calls SWI function when semaphore is signalled. */
+static void* EcSwiWrapper(void* param) {
+ EcSwiInternal* si = (EcSwiInternal*)param;
+
+ WaitForOsStart();
+
+ while (1) {
+ int bits;
+
+ pthread_mutex_lock(&si->mutex);
+ pthread_cond_wait(&si->cond, &si->mutex);
+ bits = si->pending_bits;
+ si->pending_bits = 0;
+ pthread_mutex_unlock(&si->mutex);
+
+ if (bits)
+ si->swi_func(si->param, bits);
+ }
+
+ return NULL;
+}
+
+
+EcError EcSwiCreate(EcSwi* swi, int priority,
+ void (*swi_func)(void*, uint32_t), void* param) {
+ EcSwiInternal* si = (EcSwiInternal*)swi;
+
+ /* TODO: priority */
+
+ /* Init internal data */
+ si->pending_bits = 0;
+ si->swi_func = swi_func;
+ si->param = param;
+
+ /* Allocate pthreads objects for the swi */
+ if (pthread_mutex_init(&si->mutex, NULL) != 0)
+ return EC_ERROR_UNKNOWN;
+ if (pthread_cond_init(&si->cond, NULL) != 0)
+ return EC_ERROR_UNKNOWN;
+ if (pthread_create(&si->thread, NULL, EcSwiWrapper, si) != 0)
+ return EC_ERROR_UNKNOWN;
+
+ return EC_SUCCESS;
+}
+
+
+/* Sets the specified bits in the SWI. */
+EcError EcSwiPost(EcSwi* swi, uint32_t bits) {
+ EcSwiInternal* si = (EcSwiInternal*)swi;
+ int prev_bits;
+
+ pthread_mutex_lock(&si->mutex);
+
+ prev_bits = si->pending_bits;
+ si->pending_bits |= bits;
+
+ if (!prev_bits)
+ pthread_cond_signal(&si->cond);
+
+ pthread_mutex_unlock(&si->mutex);
+
+ return EC_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/* Timers */
+
+
+typedef struct EcTimerInternal {
+ pthread_t thread;
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
+ int interval_usec;
+ int flags;
+ void (*timer_func)(void *);
+ void* param;
+} EcTimerInternal;
+
+/* Timer flags */
+/* Timer is periodic; if not present, timer is one-shot. */
+#define EC_TIMER_FLAG_PERIODIC 0x01
+#define EC_TIMER_FLAG_STARTED 0x02
+
+
+/* Timer wrapper. Loops and calls timer function. */
+static void* EcTimerWrapper(void* param) {
+ EcTimerInternal* ti = (EcTimerInternal*)param;
+
+ WaitForOsStart();
+
+ while (1) {
+
+ /* Wait for timer to be enabled */
+ pthread_mutex_lock(&ti->mutex);
+ if (!(ti->flags & EC_TIMER_FLAG_STARTED))
+ pthread_cond_wait(&ti->cond, &ti->mutex);
+ pthread_mutex_unlock(&ti->mutex);
+
+ /* TODO: should really sleep for interval, less the time used by
+ * the previous call. Or we could use a second thread to
+ * pthread_cond_signal() and then immediately go back to sleep. */
+ usleep(ti->interval_usec);
+
+ /* Only call the timer func if the flag is still started */
+ if (ti->flags & EC_TIMER_FLAG_STARTED)
+ ti->timer_func(ti->param);
+
+ if (!(ti->flags & EC_TIMER_FLAG_PERIODIC))
+ break; /* One-shot timer */
+ }
+
+ return NULL;
+}
+
+
+/* Creates a timer which will call timer_func(param) after the
+ * specified interval. See EC_TIMER_FLAG_* for valid flags. Fills
+ * <timer>. */
+EcError EcTimerCreate(EcTimer* timer, int interval_usec, int priority,
+ uint32_t flags, void (*timer_func)(void*), void* param) {
+ EcTimerInternal* ti = (EcTimerInternal*)timer;
+
+ /* TODO: priority */
+
+ /* Init internal data */
+ ti->interval_usec = interval_usec;
+ ti->flags = flags;
+ ti->timer_func = timer_func;
+ ti->param = param;
+
+ /* Create thread to call timer func */
+ if (pthread_mutex_init(&ti->mutex, NULL) != 0)
+ return EC_ERROR_UNKNOWN;
+ if (pthread_cond_init(&ti->cond, NULL) != 0)
+ return EC_ERROR_UNKNOWN;
+ if (pthread_create(&ti->thread, NULL, EcTimerWrapper, ti) != 0)
+ return EC_ERROR_UNKNOWN;
+
+ return EC_SUCCESS;
+}
+
+
+/* Stops a timer. */
+EcError EcTimerStop(EcTimer* timer) {
+ EcTimerInternal* ti = (EcTimerInternal*)timer;
+
+ pthread_mutex_lock(&ti->mutex);
+ ti->flags &= ~EC_TIMER_FLAG_STARTED;
+ pthread_mutex_unlock(&ti->mutex);
+ return EC_SUCCESS;
+}
+
+
+/* Starts a timer. */
+EcError EcTimerStart(EcTimer* timer) {
+ EcTimerInternal* ti = (EcTimerInternal*)timer;
+
+ pthread_mutex_lock(&ti->mutex);
+ ti->flags |= EC_TIMER_FLAG_STARTED;
+ pthread_cond_signal(&ti->cond);
+ pthread_mutex_unlock(&ti->mutex);
+ return EC_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/* Semaphores */
+
+typedef struct EcSemaphoreInternal {
+ sem_t sem;
+} EcSemaphoreInternal;
+
+
+EcError EcSemaphoreCreate(EcSemaphore* semaphore, int initial_count) {
+ EcSemaphoreInternal* si = (EcSemaphoreInternal*)semaphore;
+
+ if (sem_init(&si->sem, 0, initial_count) != 0)
+ return EC_ERROR_UNKNOWN;
+
+ return EC_SUCCESS;
+}
+
+
+EcError EcSemaphorePost(EcSemaphore* semaphore) {
+ EcSemaphoreInternal* si = (EcSemaphoreInternal*)semaphore;
+
+ if (sem_post(&si->sem) != 0)
+ return EC_ERROR_UNKNOWN;
+
+ return EC_SUCCESS;
+}
+
+
+EcError EcSemaphoreWait(EcSemaphore* semaphore, int timeout_usec) {
+ EcSemaphoreInternal* si = (EcSemaphoreInternal*)semaphore;
+ int rv;
+
+ if (timeout_usec == 0) {
+ rv = sem_trywait(&si->sem);
+
+ } else if (timeout_usec == EC_OS_FOREVER) {
+ rv = sem_wait(&si->sem);
+ if (errno == EAGAIN)
+ return EC_ERROR_TIMEOUT;
+
+ } else {
+ struct timespec ts;
+ UsecToTimespec(timeout_usec, &ts);
+ rv = sem_timedwait(&si->sem, &ts);
+ if (errno == ETIMEDOUT)
+ return EC_ERROR_TIMEOUT;
+ }
+
+ return (rv == 0 ? EC_SUCCESS : EC_ERROR_UNKNOWN);
+}
+
+
+EcError EcSemaphoreGetCount(EcSemaphore* semaphore, int* count_ptr) {
+ EcSemaphoreInternal* si = (EcSemaphoreInternal*)semaphore;
+
+ if (sem_getvalue(&si->sem, count_ptr) != 0)
+ return EC_ERROR_UNKNOWN;
+
+ return EC_SUCCESS;
+}
+
+/*****************************************************************************/
+/* Events */
+
+typedef struct EcEventInternal {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ uint32_t bits_set;
+ uint32_t bits_or;
+ uint32_t bits_and;
+} EcEventInternal;
+
+EcError EcEventCreate(EcEvent* event, uint32_t initial_bits) {
+ EcEventInternal* ei = (EcEventInternal*)event;
+
+ /* Init internal data */
+ ei->bits_set = initial_bits;
+ ei->bits_or = ei->bits_and = 0;
+ if (pthread_mutex_init(&ei->mutex, NULL) != 0)
+ return EC_ERROR_UNKNOWN;
+ if (pthread_cond_init(&ei->cond, NULL) != 0)
+ return EC_ERROR_UNKNOWN;
+
+ return EC_SUCCESS;
+}
+
+/* Turns on the specified bits in the event. */
+EcError EcEventPost(EcEvent* event, uint32_t bits) {
+ EcEventInternal* ei = (EcEventInternal*)event;
+
+ pthread_mutex_lock(&ei->mutex);
+
+ ei->bits_set |= bits;
+
+ /* See if that's enough bits to release the thread waiting on us */
+ if (ei->bits_or & ei->bits_set) {
+ ei->bits_or = 0;
+ pthread_cond_signal(&ei->cond);
+
+ } else if (ei->bits_and && (ei->bits_and & ei->bits_set) == ei->bits_and) {
+ ei->bits_and = 0;
+ pthread_cond_signal(&ei->cond);
+ }
+
+ pthread_mutex_unlock(&ei->mutex);
+ return EC_SUCCESS;
+}
+
+
+EcError EcEventWaitAll(EcEvent* event, uint32_t bits, int timeout_usec) {
+ EcEventInternal* ei = (EcEventInternal*)event;
+ int rv = 0;
+
+ pthread_mutex_lock(&ei->mutex);
+
+ /* Only wait if we don't have the bits we need */
+ if ((ei->bits_set & bits) != bits) {
+ ei->bits_and = bits;
+
+ if (timeout_usec == EC_OS_FOREVER) {
+ rv = pthread_cond_wait(&ei->cond, &ei->mutex);
+ } else {
+ struct timespec ts;
+ UsecToTimespec(timeout_usec, &ts);
+ rv = pthread_cond_timedwait(&ei->cond, &ei->mutex, &ts);
+ }
+ }
+
+ /* If we succeeded, consume all the bits we waited for */
+ if (!rv)
+ ei->bits_set &= ~bits;
+
+ pthread_mutex_unlock(&ei->mutex);
+
+ if (rv == ETIMEDOUT)
+ return EC_ERROR_TIMEOUT;
+ else
+ return (rv == 0 ? EC_SUCCESS : EC_ERROR_UNKNOWN);
+}
+
+
+EcError EcEventWaitAny(EcEvent* event, uint32_t bits, uint32_t* got_bits_ptr,
+ int timeout_usec) {
+ EcEventInternal* ei = (EcEventInternal*)event;
+ int rv = 0;
+
+ pthread_mutex_lock(&ei->mutex);
+
+ /* Only wait if we don't have the bits we need */
+ if (!(ei->bits_set & bits)) {
+ ei->bits_or = bits;
+
+ if (timeout_usec == EC_OS_FOREVER) {
+ rv = pthread_cond_wait(&ei->cond, &ei->mutex);
+ } else {
+ struct timespec ts;
+ UsecToTimespec(timeout_usec, &ts);
+ rv = pthread_cond_timedwait(&ei->cond, &ei->mutex, &ts);
+ }
+ }
+
+ /* If we succeeded, consume all the bits we waited for */
+ if (!rv) {
+ if (got_bits_ptr)
+ *got_bits_ptr = ei->bits_set & bits;
+ ei->bits_set &= ~bits;
+ }
+
+ pthread_mutex_unlock(&ei->mutex);
+
+ if (rv == ETIMEDOUT)
+ return EC_ERROR_TIMEOUT;
+ else
+ return (rv == 0 ? EC_SUCCESS : EC_ERROR_UNKNOWN);
+}
+
+/*****************************************************************************/
+/* Other functions */
+
+
+void EcOsInit(void) {
+
+ /* Make sure struct sizes are correct */
+ //printf("%ld", sizeof(EcTimerInternal));
+ assert(EC_TASK_STRUCT_SIZE == sizeof(EcTaskInternal));
+ assert(EC_SWI_STRUCT_SIZE == sizeof(EcSwiInternal));
+ assert(EC_TIMER_STRUCT_SIZE == sizeof(EcTimerInternal));
+ assert(EC_SEMAPHORE_STRUCT_SIZE == sizeof(EcSemaphoreInternal));
+ assert(EC_EVENT_STRUCT_SIZE == sizeof(EcEventInternal));
+}
+
+
+void EcOsStart(void) {
+ EcTaskInternal* ti;
+
+ /* Kick off threads */
+ pthread_mutex_lock(&os_start_mutex);
+ os_has_started = 1;
+ pthread_cond_broadcast(&os_start_cond);
+ pthread_mutex_unlock(&os_start_mutex);
+
+ /* Wait for all task threads to run */
+ while (1) {
+ EcTaskInternal* ti_wait;
+
+ /* Find the next task */
+ pthread_mutex_lock(&task_list_mutex);
+ ti_wait = task_list;
+ pthread_mutex_unlock(&task_list_mutex);
+ if (!ti_wait)
+ break; /* No tasks left */
+
+ /* Wait for it to die */
+ pthread_join(ti_wait->thread, NULL);
+
+ /* Remove the dead thread from the list */
+ pthread_mutex_lock(&task_list_mutex);
+ if (task_list == ti_wait)
+ task_list = ti_wait->next;
+ else {
+ for (ti = task_list; ti->next == ti_wait; ti = ti->next);
+ if (ti)
+ ti->next = ti_wait->next;
+ }
+ pthread_mutex_unlock(&task_list_mutex);
+ }
+
+ /* The remaining tasks for SWIs, etc, will die when the process exits */
+}
diff --git a/cros_ec/chip_stub/ec_uart.c b/cros_ec/chip_stub/ec_uart.c
index f76691169a..744e964f4a 100644
--- a/cros_ec/chip_stub/ec_uart.c
+++ b/cros_ec/chip_stub/ec_uart.c
@@ -3,39 +3,70 @@
* found in the LICENSE file.
*/
-/* UART module for Chrome EC, empty implementation */
+/* UART module for Chrome EC, emulated/linux implementation */
+
+#include <stdio.h>
+#include <stdarg.h>
#include "ec_uart.h"
+static void (*uart_input_callback)(void) = NULL;
+static int uart_input_callback_char = -1;
+static FILE *uart_stream = NULL;
+
+
+EcError EcUartInit(void) {
+ uart_stream = stdout;
+ return EC_SUCCESS;
+}
+
+
EcError EcUartPrintf(const char* format, ...) {
- return EC_ERROR_UNIMPLEMENTED;
+ va_list args;
+
+ va_start(args, format);
+ /* TODO; for now, printf() will be pretty close */
+ /* TODO: fixed-sizes for integers won't work because int is 64-bit
+ * by default on desktop Linux. I don't distinguish between %d
+ * (int) and %d (int32_t). */
+ /* TODO: support for pointers (%p) */
+ vfprintf(uart_stream, format, args);
+ va_end(args);
+
+ return EC_SUCCESS;
}
EcError EcUartPuts(const char* outstr) {
- return EC_ERROR_UNIMPLEMENTED;
+ fputs(outstr, uart_stream);
+ return EC_SUCCESS;
}
-void EcUartFlush(void) {
+void EcUartFlushOutput(void) {
+ fflush(uart_stream);
}
void EcUartFlushInput(void) {
+ /* TODO */
}
int EcUartPeek(int c) {
+ /* TODO */
return -1;
}
int EcUartGets(char* dest, int size) {
- *dest = 0;
+ /* TODO */
return 0;
}
void EcUartRegisterHasInputCallback(UartHasInputCallback callback, int c) {
+ uart_input_callback = callback;
+ uart_input_callback_char = c;
}
diff --git a/cros_ec/chip_stub/include/ec_os_types.h b/cros_ec/chip_stub/include/ec_os_types.h
new file mode 100644
index 0000000000..f9c4a263e0
--- /dev/null
+++ b/cros_ec/chip_stub/include/ec_os_types.h
@@ -0,0 +1,93 @@
+/* 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.
+ */
+
+/* Operating system object types for EC. These are
+ * implementation-dependent; this file should come from the
+ * implementation include directory. */
+
+#ifndef __CROS_EC_OS_TYPES_H
+#define __CROS_EC_OS_TYPES_H
+
+#include "ec_common.h"
+
+/* Structure sizes depend on the underlying implementation. These
+ * sizes are correct for the pthreads implementation. */
+#define EC_TASK_STRUCT_SIZE 32
+#define EC_SWI_STRUCT_SIZE 120
+#define EC_TIMER_STRUCT_SIZE 120
+#define EC_SEMAPHORE_STRUCT_SIZE 32
+#define EC_EVENT_STRUCT_SIZE 104
+
+/*****************************************************************************/
+/* Tasks */
+
+/* Task priority range */
+#define EC_TASK_PRIORITY_LOWEST 0
+#define EC_TASK_PRIORITY_DEFAULT 3
+#define EC_TASK_PRIORITY_HIGHEST 7
+
+/* Task instance. Treat this as an opaque identifier. */
+typedef struct EcTask {
+ union {
+ uint64_t align; /* Align on something big */
+ uint8_t data[EC_TASK_STRUCT_SIZE];
+ };
+} EcTask;
+
+/*****************************************************************************/
+/* Software interrupts (SWI) */
+
+/* SWI priority range */
+#define EC_SWI_PRIORITY_LOWEST 0
+#define EC_SWI_PRIORITY_DEFAULT 3
+#define EC_SWI_PRIORITY_HIGHEST 7
+
+/* SWI instance. Treat this as an opaque identifier. */
+typedef struct EcSwi {
+ union {
+ uint64_t align; /* Align on something big */
+ uint8_t data[EC_SWI_STRUCT_SIZE];
+ };
+} EcSwi;
+
+/*****************************************************************************/
+/* Timers */
+
+/* Timer priority range */
+#define EC_TIMER_PRIORITY_LOWEST 0
+#define EC_TIMER_PRIORITY_DEFAULT 3
+#define EC_TIMER_PRIORITY_HIGHEST 7
+
+/* Timer instance. Treat this as an opaque identifier. */
+typedef struct EcTimer {
+ union {
+ uint64_t align; /* Align on something big */
+ uint8_t data[EC_TIMER_STRUCT_SIZE];
+ };
+} EcTimer;
+
+/*****************************************************************************/
+/* Semaphores */
+
+/* Semaphore instance. Treat this as an opaque identifier. */
+typedef struct EcSemaphore {
+ union {
+ uint64_t align; /* Align on something big */
+ uint8_t data[EC_SEMAPHORE_STRUCT_SIZE];
+ };
+} EcSemaphore;
+
+/*****************************************************************************/
+/* Events */
+
+/* Event instance. Treat this as an opaque identifier. */
+typedef struct EcEvent {
+ union {
+ uint64_t align; /* Align on something big */
+ uint8_t data[EC_EVENT_STRUCT_SIZE];
+ };
+} EcEvent;
+
+#endif
diff --git a/cros_ec/include/ec_common.h b/cros_ec/include/ec_common.h
index 615a88adcf..d5adb4e280 100644
--- a/cros_ec/include/ec_common.h
+++ b/cros_ec/include/ec_common.h
@@ -25,6 +25,8 @@ enum EcErrorList {
EC_ERROR_UNIMPLEMENTED = 2,
/* Overflow error; too much input provided. */
EC_ERROR_OVERFLOW = 3,
+ /* Timeout */
+ EC_ERROR_TIMEOUT = 4,
/* Module-internal error codes may use this range. */
EC_ERROR_INTERNAL_FIRST = 0x10000,
diff --git a/cros_ec/include/ec_os.h b/cros_ec/include/ec_os.h
new file mode 100644
index 0000000000..b21e4772cd
--- /dev/null
+++ b/cros_ec/include/ec_os.h
@@ -0,0 +1,119 @@
+/* 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.
+ */
+
+/* Operating system objects for EC */
+
+#ifndef __CROS_EC_OS_H
+#define __CROS_EC_OS_H
+
+#include "ec_common.h"
+#include "ec_os_types.h"
+
+/* Timeout value which means "wait forever". */
+#define EC_OS_FOREVER -1
+
+/*****************************************************************************/
+/* Tasks */
+
+/* Creates a task of the specified priority and stack size. If
+ * stack_size=0, uses the default stack size. The task will call
+ * task_func(param). Fills <task>. */
+EcError EcTaskCreate(EcTask* task, int priority, int stack_size,
+ void (*task_func)(void*), void* param);
+
+/* Sleep for the specified number of microseconds. */
+void EcTaskSleep(int usec);
+
+/* Exits the current task. */
+void EcTaskExit(void);
+
+/*****************************************************************************/
+/* Software interrupts (SWI) */
+
+/* Creates a SWI of the specified priority. When the SWI is
+ * triggered, it will call swi_func(param, bits), where <bits> is the
+ * accumulated bits value from all preceding calls to EcSwiPost().
+ * Fills <swi>. */
+EcError EcSwiCreate(EcSwi* swi, int priority,
+ void (*swi_func)(void*, uint32_t), void* param);
+
+/* Sets the specified bits in the SWI. */
+EcError EcSwiPost(EcSwi* swi, uint32_t bits);
+
+/*****************************************************************************/
+/* Timers */
+
+/* Timer flags */
+/* Timer is periodic; if not present, timer is one-shot. */
+#define EC_TIMER_FLAG_PERIODIC 0x01
+#define EC_TIMER_FLAG_STARTED 0x02
+
+/* Creates a timer which will call timer_func(param) after the
+ * specified interval. See EC_TIMER_FLAG_* for valid flags. Fills
+ * <timer>. */
+EcError EcTimerCreate(EcTimer* timer, int interval_usec, int priority,
+ uint32_t flags, void (*timer_func)(void*), void* param);
+
+/* Stops a timer. */
+EcError EcTimerStop(EcTimer* timer);
+
+/* Starts a timer. */
+EcError EcTimerStart(EcTimer* timer);
+
+/*****************************************************************************/
+/* Semaphores */
+
+/* Creates a semaphore with the specified initial count. Fills <semaphore>. */
+EcError EcSemaphoreCreate(EcSemaphore* semaphore, int initial_count);
+
+/* Posts the semaphore, incrementing its count by one. If count>0,
+ * this will allow the next task pending on the semaphore to run. */
+EcError EcSemaphorePost(EcSemaphore* semaphore);
+
+/* Waits up to <timeout_usec> microseconds (or forever, if
+ * timeout_usec==EC_OS_FOREVER) for the semaphore. If it's unable to
+ * acquire the semaphore before the timeout, returns
+ * EC_ERROR_TIMEOUT. */
+EcError EcSemaphoreWait(EcSemaphore* semaphore, int timeout_usec);
+
+/* Stores the current semaphore count into <count_ptr>. */
+EcError EcSemaphoreGetCount(EcSemaphore* semaphore, int* count_ptr);
+
+/*****************************************************************************/
+/* Events
+ *
+ * To be compatible with all platforms, only one task at a time may
+ * wait on an event. */
+
+/* Creates an event with the specified initial bits. Fills <event>. */
+EcError EcEventCreate(EcEvent* event, uint32_t initial_bits);
+
+/* Turns on the specified bits in the event. */
+EcError EcEventPost(EcEvent* event, uint32_t bits);
+
+/* Waits up to <timeout_usec> microseconds (or forever, if
+ * timeout_usec==EC_OS_FOREVER) for all of the requested bits to be
+ * set in the event. Returns EC_ERROR_TIMEOUT on timeout. */
+EcError EcEventWaitAll(EcEvent* event, uint32_t bits, int timeout_usec);
+
+/* Waits up to <timeout_usec> microseconds (or forever, if
+ * timeout_usec==EC_OS_FOREVER) for any of the requested bits to be
+ * set in the event. If got_bits_ptr!=NULL, sets it to the bits which
+ * were posted, and clears those bits. Returns EC_ERROR_TIMEOUT on timeout. */
+EcError EcEventWaitAny(EcEvent* event, uint32_t bits, uint32_t* got_bits_ptr,
+ int timeout_usec);
+
+/*****************************************************************************/
+/* Other OS functions */
+
+/* Initializes the OS. Must be called before any of the functions above. */
+void EcOsInit(void);
+
+/* Starts OS task management. Returns when all threads have exited.
+ * This function should be called by main(). */
+void EcOsStart(void);
+
+
+#endif
diff --git a/cros_ec/lib/ec_console.c b/cros_ec/lib/ec_console.c
index 0196f84a92..1b87f3577c 100644
--- a/cros_ec/lib/ec_console.c
+++ b/cros_ec/lib/ec_console.c
@@ -129,7 +129,7 @@ const EcConsoleCommand* FindCommand(char* name) {
EcError ConsoleHandleCommand(char* input) {
char* argv[MAX_ARGS_PER_COMMAND];
const EcConsoleCommand *cmd;
- int argc;
+ int argc = 0;
/* Split input into words. Ignore words past our limit. */
SplitWords(input, MAX_ARGS_PER_COMMAND, &argc, argv);
diff --git a/cros_ec/test/Makefile b/cros_ec/test/Makefile
new file mode 100644
index 0000000000..035a3f825c
--- /dev/null
+++ b/cros_ec/test/Makefile
@@ -0,0 +1,45 @@
+# 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.
+
+INCLUDES += -I./include \
+ -I$(CROS_EC_DIR)/lib/include
+BUILD_ROOT = ${BUILD}/cros_ec/test
+
+TEST_NAMES = ec_os_test
+
+TEST_BINS = $(addprefix ${BUILD_ROOT}/,$(TEST_NAMES))
+
+# TODO: port over test lib from vboot_reference
+# TEST_LIB = ${BUILD_ROOT}/test.a
+# TEST_LIB_SRCS = test_common.c timer_utils.c
+# TEST_LIB_OBJS = $(TEST_LIB_SRCS:%.c=${BUILD_ROOT}/%.o)
+# ALL_DEPS = $(addsuffix .d,${TEST_BINS} ${TEST_LIB_OBJS})
+
+# 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)
+
+ifneq (${RUNTESTS},)
+EXTRA_TARGET = runtests
+endif
+
+all: $(TEST_BINS) ${EXTRA_TARGET}
+
+# ${TEST_LIB}: ${TEST_LIB_OBJS}
+# rm -f $@
+# ar qc $@ $^
+
+${BUILD_ROOT}/%.o : %.c
+ $(CC) $(CFLAGS) $(INCLUDES) -MMD -MF $@.d -c -o $@ $<
+
+${BUILD_ROOT}/% : %.c ${LIBS}
+ $(CC) $(CFLAGS) $(INCLUDES) $< ${LIBS} -o $@ -lrt
+
+ALLTESTS = ec_os_test
+
+runtests:
+ ${BUILD_ROOT}/ec_os_test
+
+-include ${ALL_DEPS}
diff --git a/cros_ec/test/ec_os_test.c b/cros_ec/test/ec_os_test.c
new file mode 100644
index 0000000000..6eda412b04
--- /dev/null
+++ b/cros_ec/test/ec_os_test.c
@@ -0,0 +1,128 @@
+/* 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.
+ */
+
+/* Basic test for EcOs objects */
+
+#include "ec_os.h"
+#include "ec_uart.h"
+
+EcTask t1, t2, t3, t4;
+EcSemaphore sem;
+EcSwi swi;
+EcTimer timer1, timer2;
+EcEvent ev1, ev2;
+
+
+void Thread1(void* arg) {
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ EcSemaphoreWait(&sem, EC_OS_FOREVER);
+ /* Do some work */
+ EcTaskSleep(5000);
+ EcUartPrintf("Hello from thread1: %s\n", (char*)arg);
+ EcSemaphorePost(&sem);
+
+ /* Two rapid posts to SWI, to see that they merge */
+ EcSwiPost(&swi, 1 << i);
+ EcSwiPost(&swi, 0x100 << i);
+
+ EcTaskSleep(100);
+ }
+
+ EcTaskSleep(500000);
+ EcUartPrintf("Goodbye from thread1\n");
+}
+
+
+void Thread2(void* arg) {
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ EcSemaphoreWait(&sem, EC_OS_FOREVER);
+ /* Do some work */
+ EcTaskSleep(5000);
+ EcUartPrintf("Hello from thread2: %s\n", (char*)arg);
+ EcSemaphorePost(&sem);
+
+ /* Post events */
+ EcEventPost(&ev1, 1 << i);
+ EcEventPost(&ev2, 1 << i);
+
+ EcTaskSleep(100);
+ }
+
+ EcTaskSleep(50000);
+ EcUartPrintf("Goodbye from thread2\n");
+}
+
+
+void Thread3(void* arg) {
+ uint32_t got_bits = 0;
+
+ while(got_bits != 0x10) {
+ /* Wait for any of the bits to be set */
+
+ EcEventWaitAny(&ev1, 0x1c, &got_bits, EC_OS_FOREVER);
+ EcUartPrintf("Event thread 3 got bits: 0x%x\n", got_bits);
+ }
+ EcUartPrintf("Goodbye from event thread 3\n");
+}
+
+
+void Thread4(void* arg) {
+ /* Wait on event bit from creation and a few posted bits. */
+ EcEventWaitAll(&ev2, 0x10e, EC_OS_FOREVER);
+ EcUartPrintf("Event thread 4 got all bits\n");
+ EcUartPrintf("Goodbye from event thread 4\n");
+}
+
+
+void SwiFunc(void* arg, uint32_t bits) {
+ EcUartPrintf("Hello from SWI with bits=0x%x\n", bits);
+}
+
+
+void TimerFunc(void* arg) {
+ EcUartPrintf("Hello from timer: %s\n", (char*)arg);
+ /* Start the one-shot timer. */
+ EcTimerStart(&timer2);
+}
+
+
+void OneTimerFunc(void* arg) {
+ EcUartPrintf("Hello from one-shot timer: %s\n", (char*)arg);
+ /* Stop the periodic timer */
+ EcTimerStop(&timer1);
+}
+
+
+int main(void) {
+ EcOsInit();
+ EcUartInit();
+
+ EcUartPrintf("Hello, world.\n");
+
+ EcTaskCreate(&t1, EC_TASK_PRIORITY_DEFAULT, 0, Thread1, "Foo1");
+ EcTaskCreate(&t2, EC_TASK_PRIORITY_DEFAULT, 0, Thread2, "Foo2");
+ EcTaskCreate(&t3, EC_TASK_PRIORITY_DEFAULT, 0, Thread3, "EventTask1");
+ EcTaskCreate(&t4, EC_TASK_PRIORITY_DEFAULT, 0, Thread4, "EventTask2");
+
+ EcSwiCreate(&swi, EC_SWI_PRIORITY_DEFAULT, SwiFunc, "Swi1");
+ EcTimerCreate(&timer1, 100000, EC_TIMER_PRIORITY_DEFAULT,
+ EC_TIMER_FLAG_STARTED|EC_TIMER_FLAG_PERIODIC,
+ TimerFunc, "Timer1");
+ EcTimerCreate(&timer2, 150000, EC_TIMER_PRIORITY_DEFAULT,
+ 0, OneTimerFunc, "Timer2");
+ EcSemaphoreCreate(&sem, 1);
+ EcEventCreate(&ev1, 0);
+ EcEventCreate(&ev2, 0x100);
+
+ EcUartPrintf("EcOs objects created.\n");
+
+ EcOsStart();
+
+ return 0;
+}
diff --git a/host_interface/ec_command.h b/host_interface/ec_command.h
new file mode 100644
index 0000000000..c868918019
--- /dev/null
+++ b/host_interface/ec_command.h
@@ -0,0 +1,112 @@
+/* lid.h - handle lid open/close
+ *
+ * (Chromium license) */
+
+#ifndef __HOST_INTERFACE_EC_COMMAND_H
+#define __HOST_INTERFACE_EC_COMMAND_H
+
+#include <stdint.h>
+
+/* This file is included by BIOS/OS and EC firmware. */
+
+
+enum EcCommand {
+ /*------------------------------------------------------------------------*/
+ /* Version and boot information */
+ EC_COMMAND_INFO_CMD = 0x00,
+ EC_COMMAND_INFO_CMD_MASK = 0xf0,
+ EC_COMMAND_INFO_GET_CHIP_ID = 0x01,
+ EC_COMMAND_INFO_GET_ACTIVE_FIRMWARE = 0x02,
+ EC_COMMAND_INFO_GET_FIRMWARE_VERSION = 0x03,
+ EC_COMMAND_INFO_GET_RECOVERY_REASON = 0x04,
+ EC_COMMAND_INFO_SET_TRY_B_COUNT = 0x05,
+ EC_COMMAND_INFO_GET_TRY_B_COUNT = 0x06,
+ EC_COMMAND_INFO_REQUEST_REBOOT = 0x07,
+ EC_COMMAND_INFO_GET_VBOOT_INFO = 0x08,
+ EC_COMMAND_INFO_RESET_ROLLBACK_INDEX = 0x09,
+
+ /*------------------------------------------------------------------------*/
+ /* keyboard (not in 8042 protocol */
+ EC_COMMAND_KEYBOARD_CMD = 0x10,
+ EC_COMMAND_KEYBOARD_CMD_MASK = 0xf0,
+ EC_COMMAND_KEYBOARD_SET_BACKLIGHT = 0x11,
+ EC_COMMAND_KEYBOARD_GET_BACKLIGHT = 0x12,
+ EC_COMMAND_KEYBOARD_GET_KEY_DOWN_LIST = 0x13,
+ EC_COMMAND_KEYBOARD_GET_PWB_HOLD_TIME = 0x14,
+
+ /*------------------------------------------------------------------------*/
+ /* Thermal and fan */
+ EC_COMMAND_THERMAL_CMD = 0x20,
+ EC_COMMAND_THERMAL_CMD_MASK = 0xf0,
+ EC_COMMAND_THERMAL_GET_CURRENT_FAN_RPM = 0x21,
+ EC_COMMAND_THERMAL_GET_TARGET_FAN_RPM = 0x22,
+ EC_COMMAND_THERMAL_SET_TARGET_FAN_RPM = 0x23,
+ EC_COMMAND_THERMAL_READ_SENSOR = 0x24,
+ EC_COMMAND_THERMAL_SET_ALARM_RANGE = 0x25,
+ /* TODO: PECI? */
+
+ /*------------------------------------------------------------------------*/
+ /* Power */
+ EC_COMMAND_POWER_CMD = 0x30,
+ EC_COMMAND_POWER_CMD_MASK = 0xf0,
+ EC_COMMAND_POWER_SET_S3_WAKE_REASON = 0x31,
+ EC_COMMAND_POWER_GET_S3_WAKE_REASON = 0x32,
+ EC_COMMAND_POWER_SET_TARGET_POWER_STATE = 0x33,
+ EC_COMMAND_POWER_GET_TARGET_POWER_STATE = 0x34,
+ EC_COMMAND_POWER_GET_CURRENT_POWER_STATE = 0x35,
+
+ /*------------------------------------------------------------------------*/
+ /* BATTERYTERY */
+ EC_COMMAND_BATTERY_CMD = 0x40,
+ EC_COMMAND_BATTERY_CMD_MASK = 0xe0, /* 0x41 ~ 0x5f */
+ EC_COMMAND_BATTERY_GET_FLAGS = 0x41,
+ EC_COMMAND_BATTERY_GET_REMAIN_CAP_PERCENT = 0x42,
+ EC_COMMAND_BATTERY_GET_REMAIN_CAP_MAH = 0x43,
+ EC_COMMAND_BATTERY_GET_CURRENT_DRAIN_RATE = 0x44,
+ EC_COMMAND_BATTERY_GET_VOLTAGE = 0x45,
+ EC_COMMAND_BATTERY_GET_DESIGN_CAP = 0x46,
+ EC_COMMAND_BATTERY_GET_DESIGN_MIN_CAP = 0x47,
+ EC_COMMAND_BATTERY_GET_CURRENT_CAP = 0x48,
+ EC_COMMAND_BATTERY_GET_DESIGN_VOL = 0x49,
+ EC_COMMAND_BATTERY_GET_TEMPERATURE = 0x4a,
+ EC_COMMAND_BATTERY_GET_TYPE = 0x4b,
+ EC_COMMAND_BATTERY_GET_OEM_INFO = 0x4c,
+ EC_COMMAND_BATTERY_GET_TIME_REMAIN = 0x4d,
+ EC_COMMAND_BATTERY_SET_ENABLE_CHARGE = 0x50,
+ EC_COMMAND_BATTERY_SET_ENABLE_AC = 0x51,
+
+ /*------------------------------------------------------------------------*/
+ /* Lid */
+ EC_COMMAND_LID_CMD = 0x60,
+ EC_COMMAND_LID_CMD_MASK = 0xf0,
+ EC_COMMAND_LID_GET_FLAGS = 0x41,
+
+ /*------------------------------------------------------------------------*/
+ /* Flash */
+ EC_COMMAND_FLASH_CMD = 0x70,
+ EC_COMMAND_FLASH_CMD_MASK = 0xf0,
+ EC_COMMAND_FLASH_GET_INFO = 0x71,
+ EC_COMMAND_FLAHS_READ = 0x72,
+ EC_COMMAND_FLASH_WRITE = 0x73,
+ EC_COMMAND_FLASH_ERASE = 0x74,
+ EC_COMMAND_FLASH_SET_ENABLE_WRITE_PROTECT = 0x75,
+ EC_COMMAND_FLASH_GET_ENABLE_WRITE_PROTECT = 0x76,
+ EC_COMMAND_FLASH_SET_WRITE_PROTECT_RANGE = 0x77,
+ EC_COMMAND_FLASH_GET_WRITE_PROTECT_RANGE = 0x78,
+ EC_COMMAND_FLASH_GET_WRITE_PROTECT_GPIO = 0x79,
+ EC_COMMAND_FLASH_GET_FMAP_OFFSET = 0x7a,
+
+ /*------------------------------------------------------------------------*/
+ /* Debug */
+ EC_COMMAND_DEBUG_CMD = 0x80,
+ EC_COMMAND_DEBUG_CMD_MASK = 0xf0,
+ EC_COMMAND_DEBUG_GET_EC_BOOT_REASON = 0x81,
+ EC_COMMAND_DEBUG_GET_LAST_CRASH_INFO = 0x82,
+ EC_COMMAND_DEBUG_GET_GPIO_VALUE = 0x83,
+
+ /*------------------------------------------------------------------------*/
+ /* 0xe0~0xff are reserved for return value */
+};
+
+
+#endif /* __HOST_INTERFACE_EC_COMMAND_H */
diff --git a/utility/Makefile b/utility/Makefile
new file mode 100644
index 0000000000..660117744a
--- /dev/null
+++ b/utility/Makefile
@@ -0,0 +1,28 @@
+# 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.
+
+CFLAGS += $(INCLUDES)
+CFLAGS += -MMD -MF $@.d
+HOSTCC = cc
+
+BUILD_ROOT = ${BUILD}/utility
+
+DESTDIR ?= /usr/bin
+
+TARGET_NAMES = ec_uartd
+
+TARGET_BINS = $(addprefix ${BUILD_ROOT}/,$(TARGET_NAMES))
+ALL_DEPS = $(addsuffix .d,${TARGET_BINS})
+
+all: $(TARGET_BINS)
+
+${BUILD_ROOT}/ec_uartd: ec_uartd.c $(LIBS)
+ $(CC) $(CFLAGS) $< -o $@ $(LIBS) -lftdi
+
+install: $(TARGET_BINS)
+ mkdir -p $(DESTDIR)
+ cp -f $(TARGET_BINS) $(DESTDIR)
+ chmod a+rx $(patsubst %,$(DESTDIR)/%,$(TARGET_NAMES))
+
+-include ${ALL_DEPS}
diff --git a/utility/ec_uartd.c b/utility/ec_uartd.c
new file mode 100644
index 0000000000..8a4a89ae3c
--- /dev/null
+++ b/utility/ec_uartd.c
@@ -0,0 +1,185 @@
+/* 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.
+ */
+
+/* ec_uartd.c - UART daemon for serial output from a FTDI FT2232 chip
+ *
+ * based on chromeos_public/src/third_party/hdctools/src/ftdiuart.c
+ *
+ * compile with:
+ * gcc -o ec_uartd ec_uartd.c -lftdi
+ */
+
+#include <fcntl.h>
+#include <ftdi.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <unistd.h>
+
+int grantpt(int fd);
+int unlockpt(int fd);
+int ptsname_r(int fd, char *buf, size_t buflen);
+int posix_openpt(int flags);
+
+
+/* Create a pty. Returns the pty handle, which should be closed with
+ * close(), or -1 if error. */
+int openpty(const char* desc) {
+ char ptname[PATH_MAX];
+ struct termios tty_cfg;
+ int fd;
+
+ if ((fd = posix_openpt(O_RDWR | O_NOCTTY)) == -1) {
+ perror("opening pty master");
+ return -1;
+ }
+ if (grantpt(fd) == -1) {
+ perror("grantpt");
+ return -1;
+ }
+ if (unlockpt(fd) == -1) {
+ perror("unlockpt");
+ return -1;
+ }
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+ perror("fcntl setfl -> nonblock");
+ return -1;
+ }
+ if (ptsname_r(fd, ptname, PATH_MAX) != 0) {
+ perror("getting name of pty");
+ return -1;
+ }
+ fprintf(stderr, "%s pty name = %s\n", desc, ptname);
+ if (!isatty(fd)) {
+ perror("not a TTY device\n");
+ return -1;
+ }
+ cfmakeraw(&tty_cfg);
+ tcsetattr(fd, TCSANOW, &tty_cfg);
+ if (chmod(ptname, 0666) == -1) {
+ perror("setting pty attributes");
+ return -1;
+ }
+
+ return fd;
+}
+
+
+int main(int argc, char **argv) {
+ struct ftdi_context fcontext;
+ unsigned char buf[1024], buf_ec[1024], buf_x86[1024];
+ int fd_ec, fd_x86;
+ int rv, i;
+
+ // Init
+ if (ftdi_init(&fcontext) < 0)
+ {
+ fprintf(stderr, "ftdi_init failed\n");
+ return 1;
+ }
+
+ // Open interface B (UART) in the FTDI device and set 115kbaud
+ ftdi_set_interface(&fcontext, INTERFACE_B);
+ rv = ftdi_usb_open(&fcontext, 0x0403, 0xbcda);
+ if (rv < 0)
+ {
+ fprintf(stderr, "error opening ftdi device: %d (%s)\n",
+ rv, ftdi_get_error_string(&fcontext));
+ return 2;
+ }
+ rv = ftdi_set_baudrate(&fcontext, 115200);
+ if (rv < 0)
+ {
+ fprintf(stderr, "error setting baudrate: %d (%s)\n",
+ rv, ftdi_get_error_string(&fcontext));
+ return 2;
+ }
+ // Set DTR; this muxes RX on the ICDI board
+ ftdi_setdtr(&fcontext, 1);
+
+ // Open the ptys
+ fd_ec = openpty("EC");
+ fd_x86 = openpty("x86");
+ if (fd_ec == -1 || fd_x86 == -1)
+ return 3;
+
+ // Read and write data forever
+ while (1) {
+ int bytes;
+ int bytes_ec = 0;
+ int bytes_x86 = 0;
+
+ // Copy data from EC pty, turning high bit on
+ if ((bytes = read(fd_ec, buf, sizeof(buf))) > 0) {
+ for (i = 0; i < bytes; i++)
+ buf[i] |= 0x80;
+
+ rv = ftdi_write_data(&fcontext, buf, bytes);
+ if (rv != bytes) {
+ perror("writing to uart");
+ break;
+ }
+ }
+
+ // Copy data from x86 pty, turning high bit off
+ if ((bytes = read(fd_x86, buf, sizeof(buf))) > 0) {
+ for (i = 0; i < bytes; i++)
+ buf[i] &= ~0x80;
+
+ rv = ftdi_write_data(&fcontext, buf, bytes);
+ if (rv != bytes) {
+ perror("writing to uart");
+ break;
+ }
+ }
+
+ usleep(1000);
+
+ // Get output from UART
+ bytes = ftdi_read_data(&fcontext, buf, sizeof(buf));
+ if (bytes < 0) {
+ perror("failed ftdi_read_data");
+ break;
+ }
+
+ // Split into EC and x86 buffers
+ for (i = 0; i < bytes; i++) {
+ if (buf[i] & 0x80)
+ buf_ec[bytes_ec++] = buf[i] & ~0x80;
+ else
+ buf_x86[bytes_x86++] = buf[i];
+ }
+
+ // Copy data to EC pty
+ if (bytes_ec > 0) {
+ int bytes_remaining = bytes_ec;
+ while ((bytes = write(fd_ec, buf_ec, bytes_remaining)) > 0) {
+ bytes_remaining -= bytes;
+ }
+ if (bytes == -1) {
+ perror("writing ftdi data to EC pty");
+ }
+ }
+
+ // Copy data to x86 pty
+ if (bytes_x86 > 0) {
+ int bytes_remaining = bytes_x86;
+ while ((bytes = write(fd_x86, buf_x86, bytes_remaining)) > 0) {
+ bytes_remaining -= bytes;
+ }
+ if (bytes == -1) {
+ perror("writing ftdi data to x86 pty");
+ }
+ }
+ }
+
+ // Cleanup
+ close(fd_ec);
+ close(fd_x86);
+ ftdi_usb_close(&fcontext);
+ ftdi_deinit(&fcontext);
+ return 0;
+}