Make touchpad access non-blocking

This commit is contained in:
Jeremy Soller 2021-05-24 10:42:26 -06:00 committed by Jeremy Soller
parent 532219c3f8
commit 1b539e1206
5 changed files with 55 additions and 138 deletions

View File

@ -24,10 +24,12 @@ void kbc_init(void) {
#define KBC_TIMEOUT 1000
// Enable first port - TODO
// Enable first port
static bool kbc_first = false;
// Enable second port - TODO
// Enable second port
static bool kbc_second = false;
// Second port input timeout
static uint8_t kbc_second_wait = 0;
// Translate from scancode set 2 to scancode set 1
// for basically no good reason
static bool kbc_translate = true;
@ -359,7 +361,15 @@ static void kbc_on_input_data(struct Kbc * kbc, uint8_t data) {
case KBC_STATE_SECOND_PORT_INPUT:
TRACE(" write second port input\n");
state = KBC_STATE_NORMAL;
ps2_write(&PS2_TOUCHPAD, &data, 1);
// Begin write
*(PS2_TOUCHPAD.control) = 0x0D;
*(PS2_TOUCHPAD.data) = data;
// Pull data line low
*(PS2_TOUCHPAD.control) = 0x0C;
// Pull clock line high
*(PS2_TOUCHPAD.control) = 0x0E;
// Set wait timeout of 100 cycles
kbc_second_wait = 100;
break;
}
}
@ -408,12 +418,37 @@ void kbc_event(struct Kbc * kbc) {
// Read from touchpad when possible
if (kbc_second) {
*(PS2_TOUCHPAD.control) = 0x07;
if (state == KBC_STATE_NORMAL) {
if (kbc_second_wait > 0) {
// Wait for touchpad write transaction to finish
kbc_second_wait -= 1;
uint8_t sts = *(PS2_TOUCHPAD.status);
*(PS2_TOUCHPAD.status) = sts;
if (sts & BIT(3)) {
state = KBC_STATE_TOUCHPAD;
// If transaction is done, stop waiting
if (sts & PSSTS_DONE) {
kbc_second_wait = 0;
}
// If an error happened, clear status, print error, and stop waiting
else if (sts & PSSTS_ALL_ERR) {
ps2_reset(&PS2_TOUCHPAD);
TRACE(" write second port input ERROR %02X\n", sts);
kbc_second_wait = 0;
}
// If a timeout occurs, clear status, print error, and stop waiting
else if (kbc_second_wait == 0) {
ps2_reset(&PS2_TOUCHPAD);
TRACE(" write second port input TIMEOUT\n");
kbc_second_wait = 0;
}
}
if (kbc_second_wait == 0) {
// Attempt to read from touchpad
*(PS2_TOUCHPAD.control) = 0x07;
if (state == KBC_STATE_NORMAL) {
uint8_t sts = *(PS2_TOUCHPAD.status);
*(PS2_TOUCHPAD.status) = sts;
if (sts & PSSTS_DONE) {
state = KBC_STATE_TOUCHPAD;
}
}
}
} else {

View File

@ -5,6 +5,12 @@
#include <stdint.h>
#define PSSTS_TIMEOUT_ERR BIT(6)
#define PSSTS_FRAME_ERR BIT(5)
#define PSSTS_PARITY_ERR BIT(4)
#define PSSTS_ALL_ERR (PSSTS_TIMEOUT_ERR | PSSTS_FRAME_ERR | PSSTS_PARITY_ERR)
#define PSSTS_DONE BIT(3)
struct Ps2 {
volatile uint8_t * control;
volatile uint8_t * interrupt;
@ -17,8 +23,6 @@ extern struct Ps2 __code PS2_2;
extern struct Ps2 __code PS2_3;
void ps2_reset(struct Ps2 * ps2);
int ps2_read(struct Ps2 * ps2, uint8_t * data, int length);
int ps2_write(struct Ps2 * ps2, uint8_t * data, int length);
volatile uint8_t __xdata __at(0x1700) PSCTL1;
volatile uint8_t __xdata __at(0x1701) PSCTL2;

View File

@ -1,8 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-only
#include <stdbool.h>
#include <common/macro.h>
#include <ec/ps2.h>
#define PS2(NUM) { \
@ -12,14 +9,6 @@
.data = &PSDAT ## NUM, \
}
#define PS2_TIMEOUT 10000
#define PSSTS_TIMEOUT_ERR BIT(6)
#define PSSTS_FRAME_ERR BIT(5)
#define PSSTS_PARITY_ERR BIT(4)
#define PSSTS_ALL_ERR (PSSTS_TIMEOUT_ERR | PSSTS_FRAME_ERR | PSSTS_PARITY_ERR)
#define PSSTS_DONE BIT(3)
struct Ps2 __code PS2_1 = PS2(1);
struct Ps2 __code PS2_2 = PS2(2);
struct Ps2 __code PS2_3 = PS2(3);
@ -30,55 +19,3 @@ void ps2_reset(struct Ps2 * ps2) {
// Clear status
*(ps2->status) = *(ps2->status);
}
static int ps2_transaction(struct Ps2 * ps2, uint8_t * data, int length, bool read) {
int i;
for (i = 0; i < length; i++) {
if (read) {
// Begin read
*(ps2->control) = 0x07;
} else {
// Begin write
*(ps2->control) = 0x0D;
*(ps2->data) = data[i];
// Pull data line low
*(ps2->control) = 0x0C;
// Pull clock line high
*(ps2->control) = 0x0E;
}
uint32_t timeout;
for (timeout = PS2_TIMEOUT; timeout > 0; timeout--) {
uint8_t status = *(ps2->status);
// If an error happened, clear status and return the error
if (status & PSSTS_ALL_ERR) {
ps2_reset(ps2);
return -(int)status;
}
// If transaction is done, break
if (status & PSSTS_DONE) {
break;
}
}
// If a timeout happened, return the error
if (timeout == 0) {
ps2_reset(ps2);
return -0x1000;
}
if (read) {
data[i] = *(ps2->data);
}
// Set interface to defaults
ps2_reset(ps2);
}
return i;
}
int ps2_read(struct Ps2 * ps2, uint8_t * data, int length) {
return ps2_transaction(ps2, data, length, true);
}
int ps2_write(struct Ps2 * ps2, uint8_t * data, int length) {
return ps2_transaction(ps2, data, length, false);
}

View File

@ -5,6 +5,12 @@
#include <stdint.h>
#define PSSTS_TIMEOUT_ERR BIT(6)
#define PSSTS_FRAME_ERR BIT(5)
#define PSSTS_PARITY_ERR BIT(4)
#define PSSTS_ALL_ERR (PSSTS_TIMEOUT_ERR | PSSTS_FRAME_ERR | PSSTS_PARITY_ERR)
#define PSSTS_DONE BIT(3)
struct Ps2 {
volatile uint8_t * control;
volatile uint8_t * interrupt;
@ -17,8 +23,6 @@ extern struct Ps2 __code PS2_2;
extern struct Ps2 __code PS2_3;
void ps2_reset(struct Ps2 * ps2);
int ps2_read(struct Ps2 * ps2, uint8_t * data, int length);
int ps2_write(struct Ps2 * ps2, uint8_t * data, int length);
volatile uint8_t __xdata __at(0x1700) PSCTL1;
volatile uint8_t __xdata __at(0x1701) PSCTL2;

View File

@ -1,8 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-only
#include <stdbool.h>
#include <common/macro.h>
#include <ec/ps2.h>
#define PS2(NUM) { \
@ -12,14 +9,6 @@
.data = &PSDAT ## NUM, \
}
#define PS2_TIMEOUT 10000
#define PSSTS_TIMEOUT_ERR BIT(6)
#define PSSTS_FRAME_ERR BIT(5)
#define PSSTS_PARITY_ERR BIT(4)
#define PSSTS_ALL_ERR (PSSTS_TIMEOUT_ERR | PSSTS_FRAME_ERR | PSSTS_PARITY_ERR)
#define PSSTS_DONE BIT(3)
struct Ps2 __code PS2_1 = PS2(1);
struct Ps2 __code PS2_2 = PS2(2);
struct Ps2 __code PS2_3 = PS2(3);
@ -30,55 +19,3 @@ void ps2_reset(struct Ps2 * ps2) {
// Clear status
*(ps2->status) = *(ps2->status);
}
static int ps2_transaction(struct Ps2 * ps2, uint8_t * data, int length, bool read) {
int i;
for (i = 0; i < length; i++) {
if (read) {
// Begin read
*(ps2->control) = 0x07;
} else {
// Begin write
*(ps2->control) = 0x0D;
*(ps2->data) = data[i];
// Pull data line low
*(ps2->control) = 0x0C;
// Pull clock line high
*(ps2->control) = 0x0E;
}
uint32_t timeout;
for (timeout = PS2_TIMEOUT; timeout > 0; timeout--) {
uint8_t status = *(ps2->status);
// If an error happened, clear status and return the error
if (status & PSSTS_ALL_ERR) {
ps2_reset(ps2);
return -(int)status;
}
// If transaction is done, break
if (status & PSSTS_DONE) {
break;
}
}
// If a timeout happened, return the error
if (timeout == 0) {
ps2_reset(ps2);
return -0x1000;
}
if (read) {
data[i] = *(ps2->data);
}
// Set interface to defaults
ps2_reset(ps2);
}
return i;
}
int ps2_read(struct Ps2 * ps2, uint8_t * data, int length) {
return ps2_transaction(ps2, data, length, true);
}
int ps2_write(struct Ps2 * ps2, uint8_t * data, int length) {
return ps2_transaction(ps2, data, length, false);
}