mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 01:00:29 +08:00
pico hid: ps/2 mouse support (#148)
This commit is contained in:
parent
19c1c7b933
commit
a03c3c2367
@ -213,10 +213,10 @@ void ph_ps2_kbd_receive(u8 byte, u8 prev_byte) {
|
||||
|
||||
void ph_ps2_kbd_task(void) {
|
||||
ph_ps2_phy_task(&ph_ps2_kbd);
|
||||
ph_g_ps2_kbd_online = ph_ps2_kbd_scanning && ph_ps2_kbd.idle;
|
||||
ph_g_ps2_kbd_online = ph_ps2_kbd_scanning && !ph_ps2_kbd.busy;
|
||||
}
|
||||
|
||||
void ph_ps2_kbd_init(u8 gpio) {
|
||||
ph_ps2_phy_init(&ph_ps2_kbd, pio0, gpio, &ph_ps2_kbd_receive);
|
||||
ph_ps2_kbd_reset();
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,179 +4,134 @@
|
||||
extern bool ph_g_ps2_mouse_online;
|
||||
|
||||
ph_ps2_phy ph_ps2_mouse;
|
||||
u8 ms_type = 0;
|
||||
u8 ms_mode = 0;
|
||||
u8 ms_input_mode = 0;
|
||||
u8 ms_rate = 100;
|
||||
u32 ms_magic_seq = 0x00;
|
||||
|
||||
u8 buttons = 0;
|
||||
|
||||
#define MS_TYPE_STANDARD 0x00
|
||||
#define MS_TYPE_WHEEL_3 0x03
|
||||
#define MS_TYPE_WHEEL_5 0x04
|
||||
|
||||
#define MS_MODE_IDLE 0
|
||||
#define MS_MODE_STREAMING 1
|
||||
|
||||
#define MS_INPUT_CMD 0
|
||||
#define MS_INPUT_SET_RATE 1
|
||||
bool ph_ps2_mouse_streaming = false;
|
||||
u32 ph_ps2_mouse_magic_seq = 0;
|
||||
u8 ph_ps2_mouse_type = 0;
|
||||
u8 ph_ps2_mouse_buttons = 0;
|
||||
|
||||
void ph_ps2_mouse_send(u8 byte) {
|
||||
queue_try_add(&ph_ps2_mouse.qbytes, &byte);
|
||||
}
|
||||
|
||||
void ph_ps2_mouse_packet(u8 button, u8 x1, u8 y1) {
|
||||
if(ms_mode == MS_MODE_STREAMING) {
|
||||
u8 s = (button & 7) + 8;
|
||||
u8 x = x1 & 0x7f;
|
||||
u8 y = y1 & 0x7f;
|
||||
u8 z = 0;
|
||||
void ph_ps2_mouse_pack(s8 x, s8 y, s8 h, s8 v) {
|
||||
if (ph_ps2_mouse_streaming) {
|
||||
u8 byte1 = 0x8 | (ph_ps2_mouse_buttons & 0x7);
|
||||
s8 byte2 = x;
|
||||
s8 byte3 = 0x100 - y;
|
||||
s8 byte4 = 0; // = 0x100 - z;
|
||||
|
||||
if(x1 >> 7) {
|
||||
s += 0x10;
|
||||
x += 0x80;
|
||||
}
|
||||
if (byte2 < 0) byte1 |= 0x10;
|
||||
if (byte3 < 0) byte1 |= 0x20;
|
||||
|
||||
if(y1 >> 7) {
|
||||
y = 0x80 - y;
|
||||
} else if(y) {
|
||||
s += 0x20;
|
||||
y = 0x100 - y;
|
||||
}
|
||||
ph_ps2_mouse_send(byte1);
|
||||
ph_ps2_mouse_send(byte2);
|
||||
ph_ps2_mouse_send(byte3);
|
||||
|
||||
ph_ps2_mouse_send(s);
|
||||
ph_ps2_mouse_send(x);
|
||||
ph_ps2_mouse_send(y);
|
||||
|
||||
if (ms_type == MS_TYPE_WHEEL_3 || ms_type == MS_TYPE_WHEEL_5) {
|
||||
/*if(report[3] >> 7) {
|
||||
z = 0x8 - z;
|
||||
} else if(z) {
|
||||
z = 0x10 - z;
|
||||
if (ph_ps2_mouse_type == 3 || ph_ps2_mouse_type == 4) {
|
||||
//if (byte4 < -8) byte4 = -8;
|
||||
//if (byte4 > 7) byte4 = 7;
|
||||
//if (byte4 < 0) byte4 |= 0xf8;
|
||||
|
||||
if (v < 0) byte4 = 0x01;
|
||||
if (v > 0) byte4 = 0xff;
|
||||
if (h < 0) byte4 = 0x02;
|
||||
if (h > 0) byte4 = 0xfe;
|
||||
|
||||
if (ph_ps2_mouse_type == 4) {
|
||||
byte4 &= 0xf;
|
||||
byte4 |= (ph_ps2_mouse_buttons << 1) & 0x30;
|
||||
}
|
||||
|
||||
if (ms_type == MS_TYPE_WHEEL_5) {
|
||||
if (report[0] & 0x8) {
|
||||
z += 0x10;
|
||||
}
|
||||
|
||||
if (report[0] & 0x10) {
|
||||
z += 0x20;
|
||||
}
|
||||
}*/
|
||||
|
||||
ph_ps2_mouse_send(z);
|
||||
|
||||
ph_ps2_mouse_send(byte4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ph_ps2_mouse_send_button(u8 button, bool state) {
|
||||
// TODO: PS2: Send mouse button
|
||||
// @button - USB button code
|
||||
// @state - true if pressed, false if released
|
||||
// The function should take care not to send duplicate events (if needed for PS/2)
|
||||
// If the PS2 keyboard is not used (PH_O_IS_MOUSE_PS2 is false), the function should do nothing.
|
||||
(void)button; // Remove this
|
||||
(void)state; // Remove this
|
||||
|
||||
u8 bitval = 1;
|
||||
|
||||
button--;
|
||||
|
||||
if(state) {
|
||||
buttons = buttons | (bitval << button);
|
||||
} else {
|
||||
buttons = buttons & ~(bitval << button);
|
||||
if (PH_O_IS_MOUSE_PS2) {
|
||||
button--;
|
||||
|
||||
if (state) {
|
||||
ph_ps2_mouse_buttons = ph_ps2_mouse_buttons | (1 << button);
|
||||
} else {
|
||||
ph_ps2_mouse_buttons = ph_ps2_mouse_buttons & ~(1 << button);
|
||||
}
|
||||
|
||||
ph_ps2_mouse_pack(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
ph_ps2_mouse_packet(buttons, 0, 0);
|
||||
}
|
||||
|
||||
void ph_ps2_mouse_send_rel(s8 x1, s8 y1) {
|
||||
// TODO: PS2: Send relative move event
|
||||
// If the PS2 keyboard is not used (PH_O_IS_MOUSE_PS2 is false), the function should do nothing.
|
||||
ph_ps2_mouse_packet(buttons, x1, y1);
|
||||
void ph_ps2_mouse_send_rel(s8 x, s8 y) {
|
||||
if (PH_O_IS_MOUSE_PS2) {
|
||||
ph_ps2_mouse_pack(x, y, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ph_ps2_mouse_send_wheel(s8 h, s8 v) {
|
||||
(void)h;
|
||||
// TODO: PS2: Send wheel. As I understand, PS/2 has no horizontal scrolling, so @h just can be ignored.
|
||||
// @v - vertical scrolling like on USB
|
||||
// If the PS2 keyboard is not used (PH_O_IS_MOUSE_PS2 is false), the function should do nothing.
|
||||
(void)v; // Remove this
|
||||
if (PH_O_IS_MOUSE_PS2) {
|
||||
ph_ps2_mouse_pack(0, 0, h, v);
|
||||
}
|
||||
}
|
||||
|
||||
void ph_ps2_mouse_receive(u8 byte, u8 prev_byte) {
|
||||
|
||||
if(ms_input_mode == MS_INPUT_SET_RATE) {
|
||||
ms_rate = byte;
|
||||
ms_input_mode = MS_INPUT_CMD;
|
||||
ph_ps2_mouse_send(0xfa);
|
||||
|
||||
ms_magic_seq = (ms_magic_seq << 8) | byte;
|
||||
if(ms_type == MS_TYPE_STANDARD && ms_magic_seq == 0xc86450) {
|
||||
ms_type = MS_TYPE_WHEEL_3;
|
||||
} else if (ms_type == MS_TYPE_WHEEL_3 && ms_magic_seq == 0xc8c850) {
|
||||
ms_type = MS_TYPE_WHEEL_5;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(byte != 0xf3) {
|
||||
ms_magic_seq = 0x00;
|
||||
}
|
||||
|
||||
switch(byte) {
|
||||
case 0xff: // Reset
|
||||
ms_type = MS_TYPE_STANDARD;
|
||||
ms_mode = MS_MODE_IDLE;
|
||||
ms_rate = 100;
|
||||
|
||||
ph_ps2_mouse_send(0xfa);
|
||||
ph_ps2_mouse_send(0xaa);
|
||||
ph_ps2_mouse_send(ms_type);
|
||||
return;
|
||||
|
||||
case 0xf6: // Set Defaults
|
||||
ms_type = MS_TYPE_STANDARD;
|
||||
ms_rate = 100;
|
||||
case 0xf5: // Disable Data Reporting
|
||||
case 0xea: // Set Stream Mode
|
||||
ms_mode = MS_MODE_IDLE;
|
||||
ph_ps2_mouse_send(0xfa);
|
||||
return;
|
||||
|
||||
case 0xf4: // Enable Data Reporting
|
||||
ms_mode = MS_MODE_STREAMING;
|
||||
ph_ps2_mouse_send(0xfa);
|
||||
return;
|
||||
|
||||
switch (prev_byte) {
|
||||
case 0xf3: // Set Sample Rate
|
||||
ms_input_mode = MS_INPUT_SET_RATE;
|
||||
ph_ps2_mouse_send(0xfa);
|
||||
return;
|
||||
|
||||
case 0xf2: // Get Device ID
|
||||
ph_ps2_mouse_send(0xfa);
|
||||
ph_ps2_mouse_send(ms_type);
|
||||
return;
|
||||
|
||||
case 0xe9: // Status Request
|
||||
ph_ps2_mouse_send(0xfa);
|
||||
ph_ps2_mouse_send(0x00); // Bit6: Mode, Bit 5: Enable, Bit 4: Scaling, Bits[2,1,0] = Buttons[L,M,R]
|
||||
ph_ps2_mouse_send(0x02); // Resolution
|
||||
ph_ps2_mouse_send(ms_rate); // Sample Rate
|
||||
return;
|
||||
|
||||
// TODO: Implement (more of) these?
|
||||
// case 0xf0: // Set Remote Mode
|
||||
// case 0xee: // Set Wrap Mode
|
||||
// case 0xec: // Reset Wrap Mode
|
||||
// case 0xeb: // Read Data
|
||||
// case 0xe8: // Set Resolution
|
||||
// case 0xe7: // Set Scaling 2:1
|
||||
// case 0xe6: // Set Scaling 1:1
|
||||
ph_ps2_mouse_magic_seq = ((ph_ps2_mouse_magic_seq << 8) | byte) & 0xffffff;
|
||||
|
||||
if (ph_ps2_mouse_type == 0 && ph_ps2_mouse_magic_seq == 0xc86450) {
|
||||
ph_ps2_mouse_type = 3;
|
||||
} else if (ph_ps2_mouse_type == 3 && ph_ps2_mouse_magic_seq == 0xc8c850) {
|
||||
ph_ps2_mouse_type = 4;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (byte) {
|
||||
case 0xff: // Reset
|
||||
ph_ps2_mouse_streaming = false;
|
||||
ph_ps2_mouse_type = 0;
|
||||
|
||||
ph_ps2_mouse_send(0xfa);
|
||||
ph_ps2_mouse_send(0xaa);
|
||||
ph_ps2_mouse_send(ph_ps2_mouse_type);
|
||||
return;
|
||||
|
||||
case 0xf6: // Set Defaults
|
||||
ph_ps2_mouse_streaming = false;
|
||||
ph_ps2_mouse_type = 0;
|
||||
break;
|
||||
|
||||
case 0xf5: // Disable Data Reporting
|
||||
case 0xea: // Set Stream Mode
|
||||
ph_ps2_mouse_streaming = false;
|
||||
break;
|
||||
|
||||
case 0xf4: // Enable Data Reporting
|
||||
ph_ps2_mouse_streaming = true;
|
||||
break;
|
||||
|
||||
case 0xf2: // Get Device ID
|
||||
ph_ps2_mouse_send(0xfa);
|
||||
ph_ps2_mouse_send(ph_ps2_mouse_type);
|
||||
return;
|
||||
|
||||
case 0xe9: // Status Request
|
||||
ph_ps2_mouse_send(0xfa);
|
||||
ph_ps2_mouse_send(0x00); // Bit6: Mode, Bit 5: Enable, Bit 4: Scaling, Bits[2,1,0] = Buttons[L,M,R]
|
||||
ph_ps2_mouse_send(0x02); // Resolution
|
||||
ph_ps2_mouse_send(100); // Sample Rate
|
||||
return;
|
||||
|
||||
// TODO: Implement (more of) these?
|
||||
// case 0xf0: // Set Remote Mode
|
||||
// case 0xee: // Set Wrap Mode
|
||||
// case 0xec: // Reset Wrap Mode
|
||||
// case 0xeb: // Read Data
|
||||
// case 0xe8: // Set Resolution
|
||||
// case 0xe7: // Set Scaling 2:1
|
||||
// case 0xe6: // Set Scaling 1:1
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ph_ps2_mouse_send(0xfa);
|
||||
@ -184,6 +139,7 @@ void ph_ps2_mouse_receive(u8 byte, u8 prev_byte) {
|
||||
|
||||
void ph_ps2_mouse_task(void) {
|
||||
ph_ps2_phy_task(&ph_ps2_mouse);
|
||||
ph_g_ps2_mouse_online = ph_ps2_mouse_streaming && !ph_ps2_mouse.busy;
|
||||
}
|
||||
|
||||
void ph_ps2_mouse_init(u8 gpio) {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
#include "ph_ps2_phy.h"
|
||||
#include "ph_ps2_phy.pio.h"
|
||||
|
||||
uint prog = 0;
|
||||
s8 prog = -1;
|
||||
|
||||
u32 ph_ps2_phy_frame(u8 byte) {
|
||||
bool parity = 1;
|
||||
@ -15,7 +15,7 @@ u32 ph_ps2_phy_frame(u8 byte) {
|
||||
}
|
||||
|
||||
void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx) {
|
||||
if(!prog) {
|
||||
if (prog == -1) {
|
||||
prog = pio_add_program(pio, &ph_ps2_phy_program);
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx) {
|
||||
this->rx = rx;
|
||||
this->last_rx = 0;
|
||||
this->last_tx = 0;
|
||||
this->idle = true;
|
||||
this->busy = 0;
|
||||
}
|
||||
|
||||
void ph_ps2_phy_task(ph_ps2_phy* this) {
|
||||
@ -48,9 +48,18 @@ void ph_ps2_phy_task(ph_ps2_phy* this) {
|
||||
queue_try_add(&this->qpacks, &pack);
|
||||
}
|
||||
|
||||
this->idle = !pio_interrupt_get(this->pio, this->sm);
|
||||
if (pio_interrupt_get(this->pio, this->sm)) {
|
||||
this->busy = 1;
|
||||
} else {
|
||||
this->busy &= 2;
|
||||
}
|
||||
|
||||
if (!queue_is_empty(&this->qpacks) && pio_sm_is_tx_fifo_empty(this->pio, this->sm) && this->idle) {
|
||||
if (pio_interrupt_get(this->pio, this->sm + 4)) {
|
||||
this->sent--;
|
||||
pio_interrupt_clear(this->pio, this->sm + 4);
|
||||
}
|
||||
|
||||
if (!queue_is_empty(&this->qpacks) && pio_sm_is_tx_fifo_empty(this->pio, this->sm) && !this->busy) {
|
||||
if (queue_try_peek(&this->qpacks, &pack)) {
|
||||
if (this->sent == pack[0]) {
|
||||
this->sent = 0;
|
||||
@ -58,17 +67,12 @@ void ph_ps2_phy_task(ph_ps2_phy* this) {
|
||||
} else {
|
||||
this->sent++;
|
||||
this->last_tx = pack[this->sent];
|
||||
this->busy |= 2;
|
||||
pio_sm_put(this->pio, this->sm, ph_ps2_phy_frame(this->last_tx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pio_interrupt_get(this->pio, this->sm + 4)) {
|
||||
this->sent = 0;
|
||||
pio_sm_drain_tx_fifo(this->pio, this->sm);
|
||||
pio_interrupt_clear(this->pio, this->sm + 4);
|
||||
}
|
||||
|
||||
if (!pio_sm_is_rx_fifo_empty(this->pio, this->sm)) {
|
||||
u32 fifo = pio_sm_get(this->pio, this->sm) >> 23;
|
||||
|
||||
@ -87,8 +91,8 @@ void ph_ps2_phy_task(ph_ps2_phy* this) {
|
||||
return;
|
||||
}
|
||||
|
||||
while(queue_try_remove(&this->qbytes, &byte));
|
||||
while(queue_try_remove(&this->qpacks, &pack));
|
||||
while (queue_try_remove(&this->qbytes, &byte));
|
||||
while (queue_try_remove(&this->qpacks, &pack));
|
||||
|
||||
(*this->rx)(fifo, this->last_rx);
|
||||
this->last_rx = fifo;
|
||||
|
||||
@ -11,11 +11,11 @@ typedef struct {
|
||||
uint sm;
|
||||
queue_t qbytes;
|
||||
queue_t qpacks;
|
||||
u8 sent;
|
||||
rx_callback rx;
|
||||
u8 last_rx;
|
||||
u8 last_tx;
|
||||
bool idle;
|
||||
u8 sent;
|
||||
u8 busy;
|
||||
} ph_ps2_phy;
|
||||
|
||||
void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx);
|
||||
|
||||
@ -10,52 +10,54 @@
|
||||
.side_set 1 opt pindirs
|
||||
|
||||
restart:
|
||||
set pindirs 0 [4] // set clock to input mode
|
||||
irq clear 0 rel side 0 // clear busy flag, set data to input mode
|
||||
set pindirs, 0 // set clock to input mode
|
||||
irq clear 0 rel side 0 // clear busy flag, set data to input mode
|
||||
|
||||
receivecheck:
|
||||
jmp pin sendcheck // if clock is high, see if we have data to send
|
||||
irq set 0 rel // clock is being pulled low, set busy flag
|
||||
wait 1 pin 1 // wait for clock to be pulled high
|
||||
jmp pin, sendcheck // if clock is high, see if we have data to send
|
||||
irq nowait 0 rel // clock is being pulled low, set busy flag
|
||||
wait 1 pin, 1 // wait for clock to be pulled high
|
||||
|
||||
// we are not sending, look for a start bit (clock high, data low)
|
||||
in pins 1 // read in from data
|
||||
mov x isr // move what we read to x
|
||||
mov isr null // clear ISR
|
||||
jmp !x receive // if x is low, start the receive process
|
||||
jmp restart // not receiving
|
||||
in pins, 1 // read in from data
|
||||
mov x, isr // move what we read to x
|
||||
mov isr, null // clear ISR
|
||||
jmp !x, receive // if x is low, start the receive process
|
||||
jmp restart // not receiving
|
||||
|
||||
receive:
|
||||
set pindirs, 1 [6] // clock low
|
||||
set x, 8 // set loop counter
|
||||
set pindirs, 1 [6] // clock low
|
||||
set x, 8 // set loop counter
|
||||
|
||||
receiveloop:
|
||||
set pindirs, 0 [6] // clock high
|
||||
in pins, 1 [4] // read a bit into ISR
|
||||
set pindirs, 1 [6] // clock low
|
||||
jmp x-- receiveloop [4] // iterate
|
||||
set pindirs, 0 [6] // clock high
|
||||
nop side 1 [6] // data low
|
||||
set pindirs, 1 [7] // clock low
|
||||
jmp restart
|
||||
set pindirs, 0 [6] // clock high
|
||||
in pins, 1 [4] // read a bit into ISR
|
||||
set pindirs, 1 [6] // clock low
|
||||
jmp x--, receiveloop [4] // iterate
|
||||
set pindirs, 0 [6] // clock high
|
||||
nop side 1 [6] // data low
|
||||
set pindirs, 1 [7] // clock low
|
||||
jmp restart [7]
|
||||
|
||||
sendcheck:
|
||||
jmp !osre wait_to_write // see if we have data to send
|
||||
jmp receivecheck // no data to send, restart
|
||||
jmp !osre, send // see if we have data to send
|
||||
jmp receivecheck // no data to send, restart
|
||||
|
||||
wait_to_write:
|
||||
irq set 0 rel // set busy flag
|
||||
set x 10 // number of bits to write out
|
||||
send:
|
||||
irq nowait 0 rel // set busy flag
|
||||
set x, 10 // number of bits to write out
|
||||
|
||||
sendloop:
|
||||
set pindirs, 0 [6] // clock set to input (high)
|
||||
jmp pin sendcontinue // if clock is high, host is still receiving data
|
||||
irq wait 4 rel // clock was low, host wants to send data, notify of failure to send data
|
||||
jmp restart // and wait for restart
|
||||
set pindirs, 0 [6] // clock set to input (high)
|
||||
jmp pin, sendcontinue // if clock is high, host is still receiving data
|
||||
out null, 32 // clear OSR
|
||||
irq wait 4 rel // clock was low, host wants to send data, notify of failure to send data
|
||||
jmp restart // and wait for restart
|
||||
|
||||
sendcontinue:
|
||||
out pindirs, 1 [6] // write out data
|
||||
set pindirs, 1 [6] // set clock low
|
||||
jmp x-- sendloop [6]
|
||||
out pindirs, 1 [6] // write out data
|
||||
set pindirs, 1 [6] // set clock low
|
||||
jmp x--, sendloop [6]
|
||||
|
||||
% c-sdk {
|
||||
void ph_ps2_phy_program_init(PIO pio, uint sm, uint offset, uint dat) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user