Files
OpenCellular/common/i8042.c
Randall Spangler a61d8db3d3 Change task messages to events
Signed-off-by: Randall Spangler <rspangler@chromium.org>

BUG=chrome-os-partner:7461
TEST=manual

make BOARD={bds,link,daisy}
make tests
flash link system and make sure it boots

Change-Id: I1241a1895c083e387e38ddab01ac346ca4474eb9
2012-04-06 09:06:53 -07:00

151 lines
3.3 KiB
C

/* 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.
*
* Chrome OS EC i8042 interface code.
*/
#include "board.h"
#include "common.h"
#include "i8042.h"
#include "keyboard.h"
#include "task.h"
#include "timer.h"
#include "uart.h"
#include "util.h"
#define I8042_DEBUG 1
#define MAX_QUEUED_KEY_PRESS 16
/* Circular buffer to host.
* head: next to dequeqe
* tail: next to enqueue
* head == tail: empty.
* tail + 1 == head: full
*/
static int head_to_buffer = 0;
static int tail_to_buffer = 0;
#define HOST_BUFFER_SIZE (16)
static uint8_t to_host_buffer[HOST_BUFFER_SIZE];
static int i8042_irq_enabled = 0;
/* Reset all i8042 buffer */
void i8042_init()
{
head_to_buffer = tail_to_buffer = 0;
}
/* Called by the chip-specific code when host sedns a byte to port 0x60. */
void i8042_receives_data(int data)
{
int ret_len;
uint8_t output[MAX_SCAN_CODE_LEN];
enum ec_error_list ret;
ret_len = handle_keyboard_data(data, output);
ret = i8042_send_to_host(ret_len, output);
ASSERT(ret == EC_SUCCESS);
}
/* Called by the chip-specific code when host sedns a byte to port 0x64. */
void i8042_receives_command(int cmd)
{
int ret_len;
uint8_t output[MAX_SCAN_CODE_LEN];
enum ec_error_list ret;
ret_len = handle_keyboard_command(cmd, output);
ret = i8042_send_to_host(ret_len, output);
ASSERT(ret == EC_SUCCESS);
}
/* Called by EC common code to send bytes to host via port 0x60. */
static void enq_to_host(int len, uint8_t *to_host)
{
int from, to;
/* Check if the buffer has enough space, then copy them to buffer. */
if ((tail_to_buffer + len) <= (head_to_buffer + HOST_BUFFER_SIZE - 1)) {
for (from = 0, to = tail_to_buffer; from < len;) {
to_host_buffer[to++] = to_host[from++];
to %= HOST_BUFFER_SIZE;
}
tail_to_buffer = (tail_to_buffer + len) % HOST_BUFFER_SIZE;
}
}
/* Called by common/keyboard.c when the host wants to receive keyboard IRQ
* (or not).
*/
void i8042_enable_keyboard_irq(void) {
i8042_irq_enabled = 1;
}
void i8042_disable_keyboard_irq(void) {
i8042_irq_enabled = 0;
}
void i8042_command_task(void)
{
while (1) {
/* Either a new byte to host or host picking up can un-block. */
task_wait_event(-1);
while (1) {
uint8_t chr;
int empty = 0;
/* Check if we have data in buffer to host. */
if (head_to_buffer == tail_to_buffer) {
empty = 1; /* nothing to host */
}
if (empty) break;
/* if the host still didn't read that away,
try next time. */
if (keyboard_has_char()) {
#if I8042_DEBUG >= 5
uart_printf("[%d] i8042_command_task() "
"cannot send to host due to host "
"havn't taken away.\n",
get_time().le.lo);
#endif
break;
}
/* Get a char from buffer. */
chr = to_host_buffer[head_to_buffer];
head_to_buffer =
(head_to_buffer + 1) % HOST_BUFFER_SIZE;
/* Write to host. */
keyboard_put_char(chr, i8042_irq_enabled);
#if I8042_DEBUG >= 4
uart_printf("[%d] i8042_command_task() "
"sends to host: 0x%02x\n",
get_time().le.lo, chr);
#endif
}
}
}
enum ec_error_list i8042_send_to_host(int len, uint8_t *to_host)
{
enq_to_host(len, to_host);
/* Wake up the task to handle the command */
task_wake(TASK_ID_I8042CMD);
return EC_SUCCESS;
}