Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 57 additions & 29 deletions src/app/main/kbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,34 @@ bool kbc_scancode(uint16_t key, bool pressed) {
return kbc_buffer_push(scancodes, scancodes_len);
}

static uint8_t kbc_second_buffer[16] = { 0 };
static uint8_t kbc_second_buffer_head = 0;
static uint8_t kbc_second_buffer_tail = 0;

static bool kbc_second_buffer_pop(uint8_t *const scancode) {
if (kbc_second_buffer_head == kbc_second_buffer_tail) {
return false;
}
*scancode = kbc_second_buffer[kbc_second_buffer_head];
kbc_second_buffer_head = (kbc_second_buffer_head + 1U) % ARRAY_SIZE(kbc_second_buffer);
return true;
}

static bool kbc_second_buffer_push(uint8_t data) {
uint8_t next = (kbc_second_buffer_tail + 1U) % ARRAY_SIZE(kbc_second_buffer);
if (next == kbc_second_buffer_head) {
return false;
}
kbc_second_buffer[kbc_second_buffer_tail] = data;
kbc_second_buffer_tail = next;
return true;
}

static void kbc_second_buffer_clear(void) {
kbc_second_buffer_head = 0;
kbc_second_buffer_tail = 0;
}

enum KbcState {
// Input buffer states
KBC_STATE_NORMAL,
Expand All @@ -149,7 +177,6 @@ enum KbcState {
KBC_STATE_SECOND_PORT_INPUT,
// Output buffer states
KBC_STATE_KEYBOARD,
KBC_STATE_TOUCHPAD,
KBC_STATE_MOUSE,
// After output buffer states
KBC_STATE_IDENTIFY_0,
Expand Down Expand Up @@ -256,10 +283,6 @@ static void kbc_on_input_command(struct Kbc *const kbc, uint8_t data) {
static void kbc_on_input_data(struct Kbc *const kbc, uint8_t data) {
TRACE("kbc data: %02X\n", data);
switch (state) {
case KBC_STATE_TOUCHPAD:
// Interrupt touchpad command
state = KBC_STATE_NORMAL;
// Fall through
case KBC_STATE_NORMAL:
TRACE(" keyboard command\n");
// Keyboard commands clear output buffer
Expand Down Expand Up @@ -402,20 +425,35 @@ static void kbc_on_input_data(struct Kbc *const kbc, uint8_t data) {
TRACE(" write second port input\n");
state = KBC_STATE_NORMAL;
// Begin write
*(PS2_TOUCHPAD.control) = 0x1D;
*(PS2_TOUCHPAD.control) = PSCTL_DCEN | PSCTL_TRMS | PSCTL_PSHE | PSCTL_CDAT;
// Write the data
*(PS2_TOUCHPAD.data) = data;
// Pull data line low
*(PS2_TOUCHPAD.control) = 0x1C;
*(PS2_TOUCHPAD.control) = PSCTL_DCEN | PSCTL_TRMS | PSCTL_PSHE;
// Pull clock line high
*(PS2_TOUCHPAD.control) = 0x1E;
*(PS2_TOUCHPAD.control) = PSCTL_DCEN | PSCTL_TRMS | PSCTL_PSHE | PSCTL_CCLK;
// Set wait timeout of 100 cycles
kbc_second_wait = 100;

// Reset command should clear buffer
if (data == 0xFF) {
kbc_second_buffer_clear();
}

break;
}
}

static void kbc_on_output_empty(struct Kbc *const kbc) {
// Read from scancode or mouse buffer when possible
if (state == KBC_STATE_NORMAL) {
if (kbc_buffer_pop(&state_data)) {
state = KBC_STATE_KEYBOARD;
} else if (kbc_second_buffer_pop(&state_data)) {
state = KBC_STATE_MOUSE;
}
}

switch (state) {
case KBC_STATE_KEYBOARD:
TRACE("kbc keyboard: %02X\n", state_data);
Expand All @@ -424,9 +462,6 @@ static void kbc_on_output_empty(struct Kbc *const kbc) {
state_next = KBC_STATE_NORMAL;
}
break;
case KBC_STATE_TOUCHPAD:
state_data = *(PS2_TOUCHPAD.data);
// Fall through
case KBC_STATE_MOUSE:
TRACE("kbc mouse: %02X\n", state_data);
if (kbc_mouse(kbc, state_data, KBC_TIMEOUT)) {
Expand Down Expand Up @@ -460,22 +495,18 @@ static void kbc_on_output_empty(struct Kbc *const kbc) {
}

void kbc_event(struct Kbc *const kbc) {
uint8_t sts;

// Read from scancode buffer when possible
if (state == KBC_STATE_NORMAL && kbc_buffer_pop(&state_data)) {
state = KBC_STATE_KEYBOARD;
}
uint8_t sts, data;

// Read from touchpad when possible
if (kbc_second) {
if (kbc_second_wait > 0) {
// Wait for touchpad write transaction to finish
kbc_second_wait -= 1;
uint8_t sts = *(PS2_TOUCHPAD.status);
sts = *(PS2_TOUCHPAD.status);
*(PS2_TOUCHPAD.status) = sts;
// If transaction is done, stop waiting
if (sts & PSSTS_DONE) {
ps2_reset(&PS2_TOUCHPAD);
kbc_second_wait = 0;
}
// If an error happened, clear status, print error, and stop waiting
Expand All @@ -490,17 +521,14 @@ void kbc_event(struct Kbc *const kbc) {
TRACE(" write second port input TIMEOUT\n");
kbc_second_wait = 0;
}
}

if (kbc_second_wait == 0) {
} else if (kbc_second_wait == 0) {
// Attempt to read from touchpad
*(PS2_TOUCHPAD.control) = 0x17;
if (state == KBC_STATE_NORMAL) {
uint8_t sts = *(PS2_TOUCHPAD.status);
*(PS2_TOUCHPAD.status) = sts;
if (sts & PSSTS_DONE) {
state = KBC_STATE_TOUCHPAD;
}
*(PS2_TOUCHPAD.control) = PSCTL_DCEN | PSCTL_PSHE | PSCTL_CCLK | PSCTL_CDAT;
sts = *(PS2_TOUCHPAD.status);
*(PS2_TOUCHPAD.status) = sts;
if (sts & PSSTS_DONE) {
data = *(PS2_TOUCHPAD.data);
kbc_second_buffer_push(data);
}
}
} else {
Expand All @@ -510,7 +538,7 @@ void kbc_event(struct Kbc *const kbc) {
// Read command/data while available
sts = kbc_status(kbc);
if (sts & KBC_STS_IBF) {
uint8_t data = kbc_read(kbc);
data = kbc_read(kbc);
if (sts & KBC_STS_CMD) {
kbc_on_input_command(kbc, data);
} else {
Expand Down
12 changes: 12 additions & 0 deletions src/ec/ite/include/ec/ps2.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,20 @@
#ifndef _EC_PS2_H
#define _EC_PS2_H

#include <common/macro.h>
#include <stdint.h>

// Debounce circuit enable
#define PSCTL_DCEN BIT(4)
// Transmit/receive mode selection
#define PSCTL_TRMS BIT(3)
// PS/2 hardware enable
#define PSCTL_PSHE BIT(2)
// Control CLK line
#define PSCTL_CCLK BIT(1)
// Control DATA line
#define PSCTL_CDAT BIT(0)

#define PSSTS_TIMEOUT_ERR BIT(6)
#define PSSTS_FRAME_ERR BIT(5)
#define PSSTS_PARITY_ERR BIT(4)
Expand Down
2 changes: 1 addition & 1 deletion src/ec/ite/ps2.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct Ps2 __code PS2_3 = PS2(3);

void ps2_reset(struct Ps2 *const ps2) {
// Reset interface to defaults
*(ps2->control) = 1;
*(ps2->control) = PSCTL_CDAT;
// Clear status
*(ps2->status) = *(ps2->status);
}