ibmpc_usb: Add Mouse support

for Intellimouse, Explorer and Logitech PS/2++
This commit is contained in:
tmk 2021-06-21 13:45:07 +09:00
parent c3a0141878
commit 536d267465
3 changed files with 197 additions and 5 deletions

View file

@ -42,6 +42,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// G80-2551 terminal keyboard support // G80-2551 terminal keyboard support
#define G80_2551_SUPPORT #define G80_2551_SUPPORT
// PS/2 Mouse support
#define IBMPC_MOUSE_ENABLE
/* /*
* Pin and interrupt configuration * Pin and interrupt configuration

View file

@ -135,6 +135,15 @@ uint8_t matrix_scan(void)
} state = INIT; } state = INIT;
static uint16_t init_time; static uint16_t init_time;
#ifdef IBMPC_MOUSE_ENABLE
static enum {
MOUSE_DEFAULT = 0, // Default three-button
MOUSE_INTELLI = 3, // Intellimouse Explorer 3-button & wheel
MOUSE_EXPLORER = 4, // Intellimouse Explorer 5-button & wheel
MOUSE_LOGITECH = 9 // Logitech PS/2++
} mouse_id = MOUSE_DEFAULT;
static uint8_t mouse_btn = 0;
#endif
if (ibmpc_error) { if (ibmpc_error) {
xprintf("\n%u ERR:%02X ISR:%04X ", timer_read(), ibmpc_error, ibmpc_isr_debug); xprintf("\n%u ERR:%02X ISR:%04X ", timer_read(), ibmpc_error, ibmpc_isr_debug);
@ -288,8 +297,7 @@ uint8_t matrix_scan(void)
} else if (0xFFFD == keyboard_id) { // Zenith Z-150 AT } else if (0xFFFD == keyboard_id) { // Zenith Z-150 AT
keyboard_kind = PC_AT; keyboard_kind = PC_AT;
} else if (0x00FF == keyboard_id) { // Mouse is not supported } else if (0x00FF == keyboard_id) { // Mouse is not supported
xprintf("Mouse: not supported\n"); keyboard_kind = PC_MOUSE;
keyboard_kind = NONE;
} else if (0xAB85 == keyboard_id || // IBM 122-key Model M, NCD N-97 } else if (0xAB85 == keyboard_id || // IBM 122-key Model M, NCD N-97
0xAB86 == keyboard_id || // Cherry G80-2551, IBM 1397000 0xAB86 == keyboard_id || // Cherry G80-2551, IBM 1397000
0xAB92 == keyboard_id) { // IBM 5576-001 0xAB92 == keyboard_id) { // IBM 5576-001
@ -363,6 +371,83 @@ uint8_t matrix_scan(void)
// This should not be harmful // This should not be harmful
led_set(host_keyboard_leds()); led_set(host_keyboard_leds());
break; break;
#ifdef IBMPC_MOUSE_ENABLE
case PC_MOUSE: {
uint8_t s[3];
void read_status(void) {
ibmpc_host_send(0xE9);
s[0] = ibmpc_host_recv_response();
s[1] = ibmpc_host_recv_response();
s[2] = ibmpc_host_recv_response();
xprintf("S[%02X %02X %02X] ", s[0], s[1], s[2]);
}
ibmpc_host_send(0xF5); // Disable
ibmpc_host_send(0xEA); // Set Stream Mode
read_status();
// Logitech Magic Status
// https://github.com/torvalds/linux/blob/master/drivers/input/mouse/logips2pp.c#L352
xprintf("\nLMS: ");
ibmpc_host_send(0xE8); ibmpc_host_send(0x00);
ibmpc_host_send(0xE6); ibmpc_host_send(0xE6); ibmpc_host_send(0xE6);
read_status();
if (s[0] == 0 || s[1] == 0) {
// Not Logitech
goto MOUSE_INTELLI;
}
// Logitech Magic Knock
// https://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html
// https://web.archive.org/web/20030714000535/www.dqcs.com/logitech/ps2ppspec.htm
// https://github.com/torvalds/linux/blob/5bfc75d92efd494db37f5c4c173d3639d4772966/drivers/input/serio/libps2.c#L347
xprintf("\nLOG: ");
// sliced magic byte: 0x39
ibmpc_host_send(0xE6);
ibmpc_host_send(0xE8); ibmpc_host_send(0x00);
ibmpc_host_send(0xE8); ibmpc_host_send(0x03);
ibmpc_host_send(0xE8); ibmpc_host_send(0x02);
ibmpc_host_send(0xE8); ibmpc_host_send(0x01);
// sliced magic byte: 0xDB
ibmpc_host_send(0xE6);
ibmpc_host_send(0xE8); ibmpc_host_send(0x03);
ibmpc_host_send(0xE8); ibmpc_host_send(0x01);
ibmpc_host_send(0xE8); ibmpc_host_send(0x02);
ibmpc_host_send(0xE8); ibmpc_host_send(0x03);
mouse_id = MOUSE_LOGITECH; // 9
goto MOUSE_DONE;
MOUSE_INTELLI:
// Intellimouse protocol: 3
xprintf("\nINT: ");
ibmpc_host_send(0xF3); ibmpc_host_send(0xC8);
ibmpc_host_send(0xF3); ibmpc_host_send(0x64);
ibmpc_host_send(0xF3); ibmpc_host_send(0x50);
mouse_id = read_keyboard_id() >> 8;
// Intellimouse Explorer protocol: 4
xprintf("\nEXP: ");
ibmpc_host_send(0xF3); ibmpc_host_send(0xC8);
ibmpc_host_send(0xF3); ibmpc_host_send(0xC8);
ibmpc_host_send(0xF3); ibmpc_host_send(0x50);
mouse_id = read_keyboard_id() >> 8;
// Not Intellimouse
if (mouse_id == 0) {
xprintf("\nDEF: ");
ibmpc_host_send(0xF6); // Set Default
}
MOUSE_DONE:
//ibmpc_host_send(0xEA); // Set Stream Mode
ibmpc_host_send(0xF4); // Enable
read_status();
xprintf("\nMouse: %s\n", ((mouse_id == MOUSE_LOGITECH) ? "LOGITECH" :
((mouse_id == MOUSE_INTELLI) ? "INTELLI" :
((mouse_id == MOUSE_EXPLORER) ? "EXPLORER" :
((mouse_id == MOUSE_DEFAULT) ? "DEFAULT" : "???")))));
break; }
#endif
default: default:
break; break;
} }
@ -380,12 +465,12 @@ uint8_t matrix_scan(void)
// Scan Code Set 1: 0xFF // Scan Code Set 1: 0xFF
// Scan Code Set 2 and 3: 0x00 // Scan Code Set 2 and 3: 0x00
// Buffer full(IBMPC_ERR_FULL): 0xFF // Buffer full(IBMPC_ERR_FULL): 0xFF
if (code == 0x00 || code == 0xFF) { if (keyboard_kind != PC_MOUSE && (code == 0x00 || code == 0xFF)) {
// clear stuck keys // clear stuck keys
matrix_clear(); matrix_clear();
clear_keyboard(); clear_keyboard();
xprintf("\n[OVR] "); xprintf("\n[CLR] ");
break; break;
} }
@ -399,6 +484,108 @@ uint8_t matrix_scan(void)
case PC_TERMINAL: case PC_TERMINAL:
if (process_cs3(code) == -1) state = INIT; if (process_cs3(code) == -1) state = INIT;
break; break;
#ifdef IBMPC_MOUSE_ENABLE
case PC_MOUSE: {
// Logitec Mouse Data:
// https://github.com/torvalds/linux/blob/d2912cb15bdda8ba4a5dd73396ad62641af2f520/drivers/input/mouse/logips2pp.c#L41
// Intellimouse Data:
// https://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html
int16_t b0, b1, b2, b3;
int16_t x = 0, y = 0;
int8_t v = 0, h = 0;
b0 = code;
b1 = ibmpc_host_recv_response();
if (b1 == -1) break;
b2 = ibmpc_host_recv_response();
if (b2 == -1) break;
switch (mouse_id) {
case MOUSE_DEFAULT:
case MOUSE_INTELLI:
case MOUSE_EXPLORER:
mouse_btn = (mouse_btn & 0xF8) | (b0 & 0x07);
x = (b0 & 0x10) ? (b1 | 0xFF00) : b1;
y = (b0 & 0x20) ? (b2 | 0xFF00) : b2;
break;
case MOUSE_LOGITECH:
if ((b0 & 0x48) == 0x48 && (b1 & 0x02) == 0x02) {
switch (((b0 & 0x30) >> 2) | ((b1 & 0x30) >> 4)) {
case 1: // C8 Dx xx
// Ignored while Scroll-Up/Down is pressed
if (!(b2 & 0x40)) {
if (b2 & 0x80)
h = ((b2 & 0x08) ? 0xF0 : 0x00) | (b2 & 0x0F);
else
v = ((b2 & 0x08) ? 0xF0 : 0x00) | (b2 & 0x0F);
}
// Back
if (b2 & 0x10) mouse_btn |= (1 << 3); else mouse_btn &= ~(1 << 3);
// Forward
if (b2 & 0x20) mouse_btn |= (1 << 4); else mouse_btn &= ~(1 << 4);
break;
case 2: // C8 Ex xx
if (b2 & 0x01) mouse_btn |= (1 << 6); else mouse_btn &= ~(1 << 6);
if (b2 & 0x02) mouse_btn |= (1 << 7); else mouse_btn &= ~(1 << 7);
// Task
if (b2 & 0x04) mouse_btn |= (1 << 5); else mouse_btn &= ~(1 << 5);
// Scroll-Up
if (b2 & 0x08) mouse_btn |= (1 << 6); else mouse_btn &= ~(1 << 6);
// Scroll-Down
if (b2 & 0x10) mouse_btn |= (1 << 7); else mouse_btn &= ~(1 << 7);
break;
case 3: // TouchPad?
if (b2 & 0x80)
h = ((b2 & 0x80) ? 0xF0 : 0x00) | ((b2 >> 4) & 0x0F);
else
v = ((b2 & 0x80) ? 0xF0 : 0x00) | ((b2 >> 4) & 0x0F);
mouse_btn = (mouse_btn & 0xF8) | (b2 & 0x07);
break;
}
} else {
mouse_btn = (mouse_btn & 0xF8) | (b0 & 0x07);
x = (b0 & 0x10) ? (b1 | 0xFF00) : b1;
y = (b0 & 0x20) ? (b2 | 0xFF00) : b2;
}
break;
}
// Extra byte
switch (mouse_id) {
case MOUSE_INTELLI:
b3 = ibmpc_host_recv_response();
if (b3 == -1) break;
v = b3 & 0xFF;
break;
case MOUSE_EXPLORER:
b3 = ibmpc_host_recv_response();
if (b3 == -1) break;
// sign extension
v = ((b3 & 0x08) ? 0xF0 : 0x00) | (b3 & 0x0F);
// Back/Forward
if (b3 & 0x10) mouse_btn |= (1 << 3); else mouse_btn &= ~(1 << 3);
if (b3 & 0x20) mouse_btn |= (1 << 4); else mouse_btn &= ~(1 << 4);
break;
default:
break;
}
// chop to 8-bit
#define CHOP8(a) (((a) > 127) ? 127 : (((a) < -127) ? -127 : (a)))
report_mouse_t mouse_report = {};
mouse_report.buttons = mouse_btn;
mouse_report.x = CHOP8(x);
mouse_report.y = -(CHOP8(y));
mouse_report.v = -(CHOP8(v));
mouse_report.h = CHOP8(h);
host_mouse_send(&mouse_report);
xprintf("M[x:%d y:%d v:%d h:%d b:%02X]\n", mouse_report.x, mouse_report.y,
mouse_report.v, mouse_report.h, mouse_report.buttons);
break; }
#endif
default: default:
break; break;
} }
@ -461,6 +648,7 @@ void led_set(uint8_t usb_led)
// XT keyobard doesn't support any command and it is harmful perhaps // XT keyobard doesn't support any command and it is harmful perhaps
// https://github.com/tmk/tmk_keyboard/issues/635#issuecomment-626993437 // https://github.com/tmk/tmk_keyboard/issues/635#issuecomment-626993437
if (keyboard_kind == PC_XT) return; if (keyboard_kind == PC_XT) return;
if (keyboard_kind == PC_MOUSE) return;
// It should be safe to send the command to keyboards with AT protocol // It should be safe to send the command to keyboards with AT protocol
// - IBM Terminal doesn't support the command and response with 0xFE but it is not harmful. // - IBM Terminal doesn't support the command and response with 0xFE but it is not harmful.

View file

@ -1,11 +1,12 @@
#ifndef IBMPC_USB_H #ifndef IBMPC_USB_H
#define IBMPC_USB_H #define IBMPC_USB_H
typedef enum { NONE, PC_XT, PC_AT, PC_TERMINAL } keyboard_kind_t; typedef enum { NONE, PC_XT, PC_AT, PC_TERMINAL, PC_MOUSE } keyboard_kind_t;
#define KEYBOARD_KIND_STR(kind) \ #define KEYBOARD_KIND_STR(kind) \
(kind == PC_XT ? "XT" : \ (kind == PC_XT ? "XT" : \
kind == PC_AT ? "AT" : \ kind == PC_AT ? "AT" : \
kind == PC_TERMINAL ? "TERMINAL" : \ kind == PC_TERMINAL ? "TERMINAL" : \
kind == PC_MOUSE ? "MOUSE" : \
"NONE") "NONE")