diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile | 72 | ||||
-rw-r--r-- | README | 3 | ||||
-rw-r--r-- | chip_interface/ec_gpio.h | 37 | ||||
-rw-r--r-- | chip_interface/ec_system.h | 59 | ||||
-rw-r--r-- | chip_interface/ec_uart.h (renamed from cros_ec/include/ec_uart.h) | 10 | ||||
-rw-r--r-- | common.mk | 20 | ||||
-rw-r--r-- | cros_ec/Makefile | 51 | ||||
-rw-r--r-- | cros_ec/chip_stub/ec_os.c | 516 | ||||
-rw-r--r-- | cros_ec/chip_stub/ec_uart.c | 41 | ||||
-rw-r--r-- | cros_ec/chip_stub/include/ec_os_types.h | 93 | ||||
-rw-r--r-- | cros_ec/include/ec_common.h | 2 | ||||
-rw-r--r-- | cros_ec/include/ec_os.h | 119 | ||||
-rw-r--r-- | cros_ec/lib/ec_console.c | 2 | ||||
-rw-r--r-- | cros_ec/test/Makefile | 45 | ||||
-rw-r--r-- | cros_ec/test/ec_os_test.c | 128 | ||||
-rw-r--r-- | host_interface/ec_command.h | 112 | ||||
-rw-r--r-- | utility/Makefile | 28 | ||||
-rw-r--r-- | utility/ec_uartd.c | 185 |
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; +} |