@@ -25,6 +25,7 @@ endif | |||
ifdef MOUSEKEY_ENABLE | |||
SRC += $(COMMON_DIR)/mousekey.c | |||
OPT_DEFS += -DMOUSEKEY_ENABLE | |||
OPT_DEFS += -DMOUSE_ENABLE | |||
endif | |||
ifdef EXTRAKEY_ENABLE | |||
@@ -47,16 +48,6 @@ ifdef NKRO_ENABLE | |||
OPT_DEFS += -DNKRO_ENABLE | |||
endif | |||
ifdef PS2_MOUSE_ENABLE | |||
SRC += $(COMMON_DIR)/ps2.c \ | |||
$(COMMON_DIR)/ps2_mouse.c | |||
OPT_DEFS += -DPS2_MOUSE_ENABLE | |||
endif | |||
ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE) | |||
OPT_DEFS += -DMOUSE_ENABLE | |||
endif | |||
ifdef SLEEP_LED_ENABLE | |||
SRC += $(COMMON_DIR)/sleep_led.c | |||
OPT_DEFS += -DSLEEP_LED_ENABLE |
@@ -485,12 +485,6 @@ void clear_keyboard_but_mods(void) | |||
#endif | |||
} | |||
bool sending_anykey(void) | |||
{ | |||
return (has_anykey() || host_mouse_in_use() || | |||
host_last_sysytem_report() || host_last_consumer_report()); | |||
} | |||
bool is_tap_key(key_t key) | |||
{ | |||
action_t action = layer_switch_get_action(key); |
@@ -64,7 +64,6 @@ void unregister_mods(uint8_t mods); | |||
//void set_mods(uint8_t mods); | |||
void clear_keyboard(void); | |||
void clear_keyboard_but_mods(void); | |||
bool sending_anykey(void); | |||
void layer_switch(uint8_t new_layer); | |||
bool is_tap_key(key_t key); | |||
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#define ACTION_UTIL_H | |||
#include <stdint.h> | |||
#include "report.h" | |||
extern report_keyboard_t *keyboard_report; | |||
@@ -27,9 +27,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
bool keyboard_nkro = false; | |||
#endif | |||
report_mouse_t mouse_report = {}; | |||
static host_driver_t *driver; | |||
static uint16_t last_system_report = 0; | |||
static uint16_t last_consumer_report = 0; | |||
@@ -89,11 +86,6 @@ void host_consumer_send(uint16_t report) | |||
(*driver->send_consumer)(report); | |||
} | |||
uint8_t host_mouse_in_use(void) | |||
{ | |||
return (mouse_report.buttons | mouse_report.x | mouse_report.y | mouse_report.v | mouse_report.h); | |||
} | |||
uint16_t host_last_sysytem_report(void) | |||
{ | |||
return last_system_report; |
@@ -32,9 +32,6 @@ extern "C" { | |||
extern bool keyboard_nkro; | |||
#endif | |||
/* report */ | |||
extern report_mouse_t mouse_report; | |||
/* host driver */ | |||
void host_set_driver(host_driver_t *driver); | |||
@@ -47,9 +44,6 @@ void host_mouse_send(report_mouse_t *report); | |||
void host_system_send(uint16_t data); | |||
void host_consumer_send(uint16_t data); | |||
/* mouse report utils */ | |||
uint8_t host_mouse_in_use(void); | |||
uint16_t host_last_sysytem_report(void); | |||
uint16_t host_last_consumer_report(void); | |||
@@ -30,8 +30,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#include "sendchar.h" | |||
#include "bootmagic.h" | |||
#include "eeconfig.h" | |||
#include "mousekey.h" | |||
#include "backlight.h" | |||
#ifdef MOUSEKEY_ENABLE | |||
# include "mousekey.h" | |||
#endif | |||
#ifdef PS2_MOUSE_ENABLE | |||
# include "ps2_mouse.h" | |||
#endif | |||
#ifdef MATRIX_HAS_GHOST | |||
@@ -111,10 +116,16 @@ void keyboard_task(void) | |||
action_exec(TICK); | |||
MATRIX_LOOP_END: | |||
#ifdef MOUSEKEY_ENABLE | |||
// mousekey repeat & acceleration | |||
mousekey_task(); | |||
#endif | |||
#ifdef PS2_MOUSE_ENABLE | |||
ps2_mouse_task(); | |||
#endif | |||
// update LED | |||
if (led_status != host_keyboard_leds()) { | |||
led_status = host_keyboard_leds(); |
@@ -26,6 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
static report_mouse_t mouse_report = {}; | |||
static uint8_t mousekey_repeat = 0; | |||
static uint8_t mousekey_accel = 0; | |||
@@ -1,2 +1,27 @@ | |||
PROTOCOL_DIR = protocol | |||
ifdef PS2_MOUSE_ENABLE | |||
SRC += $(PROTOCOL_DIR)/ps2_mouse.c | |||
OPT_DEFS += -DPS2_MOUSE_ENABLE | |||
OPT_DEFS += -DMOUSE_ENABLE | |||
endif | |||
ifdef PS2_USE_BUSYWAIT | |||
SRC += protocol/ps2.c | |||
OPT_DEFS += -DPS2_USE_BUSYWAIT | |||
endif | |||
ifdef PS2_USE_INT | |||
SRC += protocol/ps2.c | |||
OPT_DEFS += -DPS2_USE_INT | |||
endif | |||
ifdef PS2_USE_USART | |||
SRC += protocol/ps2_usart.c | |||
OPT_DEFS += -DPS2_USE_USART | |||
endif | |||
# Search Path | |||
VPATH += $(TOP_DIR)/protocol |
@@ -539,11 +539,18 @@ int main(void) | |||
{ | |||
SetupHardware(); | |||
sei(); | |||
/* wait for USB startup & debug output */ | |||
while (USB_DeviceState != DEVICE_STATE_Configured) { | |||
#if defined(INTERRUPT_CONTROL_ENDPOINT) | |||
while (USB_DeviceState != DEVICE_STATE_Configured) ; | |||
; | |||
#else | |||
USB_USBTask(); | |||
#endif | |||
} | |||
print("USB configured.\n"); | |||
/* init modules */ | |||
keyboard_init(); | |||
host_set_driver(&lufa_driver); | |||
#ifdef SLEEP_LED_ENABLE |
@@ -7,7 +7,11 @@ SRC += $(PJRC_DIR)/main.c \ | |||
$(PJRC_DIR)/usb.c | |||
# Option modules | |||
ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE) | |||
ifdef MOUSEKEY_ENABLE | |||
SRC += $(PJRC_DIR)/usb_mouse.c | |||
endif | |||
ifdef PS2_MOUSE_ENABLE | |||
SRC += $(PJRC_DIR)/usb_mouse.c | |||
endif | |||
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2010,2011 Jun WAKO <[email protected]> | |||
Copyright 2010,2011,2012,2013 Jun WAKO <[email protected]> | |||
This software is licensed with a Modified BSD License. | |||
All of this is supposed to be Free Software, Open Source, DFSG-free, | |||
@@ -43,7 +43,9 @@ POSSIBILITY OF SUCH DAMAGE. | |||
#include "debug.h" | |||
#ifndef PS2_USE_INT | |||
static uint8_t recv_data(void); | |||
#endif | |||
static inline void clock_lo(void); | |||
static inline void clock_hi(void); | |||
static inline bool clock_in(void); | |||
@@ -109,12 +111,12 @@ uint8_t ps2_host_send(uint8_t data) | |||
#endif | |||
/* terminate a transmission if we have */ | |||
inhibit(); | |||
_delay_us(100); | |||
_delay_us(200); // at least 100us | |||
/* start bit [1] */ | |||
data_lo(); | |||
clock_hi(); | |||
WAIT(clock_lo, 15000, 1); | |||
WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking | |||
/* data [2-9] */ | |||
for (uint8_t i = 0; i < 8; i++) { | |||
_delay_us(15); | |||
@@ -143,6 +145,9 @@ uint8_t ps2_host_send(uint8_t data) | |||
WAIT(clock_hi, 50, 8); | |||
WAIT(data_hi, 50, 9); | |||
#ifdef PS2_USE_INT | |||
PS2_INT_ON(); | |||
#endif | |||
res = ps2_host_recv_response(); | |||
ERROR: | |||
#ifdef PS2_USE_INT | |||
@@ -154,11 +159,15 @@ ERROR: | |||
return res; | |||
} | |||
#ifndef PS2_USE_INT | |||
/* receive data when host want else inhibit communication */ | |||
uint8_t ps2_host_recv_response(void) | |||
{ | |||
uint8_t data = 0; | |||
#ifdef PS2_USE_INT | |||
PS2_INT_OFF(); | |||
#endif | |||
/* terminate a transmission if we have */ | |||
inhibit(); | |||
_delay_us(100); | |||
@@ -167,12 +176,13 @@ uint8_t ps2_host_recv_response(void) | |||
idle(); | |||
/* wait start bit */ | |||
wait_clock_lo(2000); | |||
wait_clock_lo(25000); // command response may take 20 ms at most | |||
data = recv_data(); | |||
inhibit(); | |||
return data; | |||
} | |||
#endif | |||
#ifndef PS2_USE_INT | |||
uint8_t ps2_host_recv(void) | |||
@@ -187,9 +197,6 @@ static uint8_t pbuf_head = 0; | |||
static uint8_t pbuf_tail = 0; | |||
static inline void pbuf_enqueue(uint8_t data) | |||
{ | |||
if (!data) | |||
return; | |||
uint8_t sreg = SREG; | |||
cli(); | |||
uint8_t next = (pbuf_head + 1) % PBUF_SIZE; | |||
@@ -215,6 +222,21 @@ static inline uint8_t pbuf_dequeue(void) | |||
return val; | |||
} | |||
static inline bool pbuf_has_data(void) | |||
{ | |||
uint8_t sreg = SREG; | |||
cli(); | |||
bool has_data = (pbuf_head != pbuf_tail); | |||
SREG = sreg; | |||
return has_data; | |||
} | |||
static inline void pbuf_clear(void) | |||
{ | |||
uint8_t sreg = SREG; | |||
cli(); | |||
pbuf_head = pbuf_tail = 0; | |||
SREG = sreg; | |||
} | |||
/* get data received by interrupt */ | |||
uint8_t ps2_host_recv(void) | |||
@@ -229,13 +251,12 @@ uint8_t ps2_host_recv(void) | |||
return pbuf_dequeue(); | |||
} | |||
#if 0 | |||
#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0) | |||
#define DEBUGP(x) do { PORTC = x; } while (0) | |||
#else | |||
#define DEBUGP_INIT() | |||
#define DEBUGP(x) | |||
#endif | |||
uint8_t ps2_host_recv_response(void) | |||
{ | |||
while (!pbuf_has_data()) ; | |||
return pbuf_dequeue(); | |||
} | |||
ISR(PS2_INT_VECT) | |||
{ | |||
static enum { | |||
@@ -256,7 +277,6 @@ ISR(PS2_INT_VECT) | |||
} | |||
state++; | |||
DEBUGP(state); | |||
switch (state) { | |||
case START: | |||
if (data_in()) | |||
@@ -289,6 +309,7 @@ ISR(PS2_INT_VECT) | |||
if (!data_in()) | |||
goto ERROR; | |||
pbuf_enqueue(data); | |||
//phex(data); | |||
goto DONE; | |||
break; | |||
default: | |||
@@ -296,7 +317,6 @@ ISR(PS2_INT_VECT) | |||
} | |||
goto RETURN; | |||
ERROR: | |||
DEBUGP(0x0F); | |||
inhibit(); | |||
ps2_error = state; | |||
DONE: | |||
@@ -309,11 +329,6 @@ RETURN: | |||
#endif | |||
static void ps2_reset(void) | |||
{ | |||
ps2_host_send(0xFF); | |||
} | |||
/* send LED state to keyboard */ | |||
void ps2_host_set_led(uint8_t led) | |||
{ | |||
@@ -322,6 +337,7 @@ void ps2_host_set_led(uint8_t led) | |||
} | |||
#ifndef PS2_USE_INT | |||
/* called after start bit comes */ | |||
static uint8_t recv_data(void) | |||
{ | |||
@@ -361,6 +377,7 @@ static uint8_t recv_data(void) | |||
ERROR: | |||
return 0; | |||
} | |||
#endif | |||
static inline void clock_lo() | |||
{ |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2011 Jun Wako <[email protected]> | |||
Copyright 2011,2013 Jun Wako <[email protected]> | |||
This program is free software: you can redistribute it and/or modify | |||
it under the terms of the GNU General Public License as published by | |||
@@ -20,199 +20,196 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#include<util/delay.h> | |||
#include "ps2.h" | |||
#include "ps2_mouse.h" | |||
#include "usb_mouse.h" | |||
#include "report.h" | |||
#include "host.h" | |||
#include "timer.h" | |||
#include "print.h" | |||
#include "debug.h" | |||
#define PS2_MOUSE_DEBUG | |||
#ifdef PS2_MOUSE_DEBUG | |||
# include "print.h" | |||
# include "debug.h" | |||
#else | |||
# define print(s) | |||
# define phex(h) | |||
# define phex16(h) | |||
#endif | |||
// disable when errors occur 255 times. | |||
#define ERROR_RETURN() do { \ | |||
if (ps2_error) { \ | |||
if (ps2_mouse_error_count < 255) { \ | |||
ps2_mouse_error_count++; \ | |||
} else { \ | |||
ps2_mouse_error_count = 0; \ | |||
ps2_mouse_enable = false; \ | |||
} \ | |||
return ps2_error; \ | |||
} \ | |||
} while (0) | |||
static report_mouse_t mouse_report = {}; | |||
/* | |||
TODO | |||
---- | |||
- Stream mode | |||
- Tracpoint command support: needed | |||
- Middle button + move = Wheel traslation | |||
*/ | |||
bool ps2_mouse_enable = true; | |||
uint8_t ps2_mouse_x = 0; | |||
uint8_t ps2_mouse_y = 0; | |||
uint8_t ps2_mouse_btn = 0; | |||
uint8_t ps2_mouse_error_count = 0; | |||
static uint8_t ps2_mouse_btn_prev = 0; | |||
static void print_usb_data(void); | |||
/* supports only 3 button mouse at this time */ | |||
uint8_t ps2_mouse_init(void) { | |||
uint8_t rcv; | |||
if (!ps2_mouse_enable) return 1; | |||
ps2_host_init(); | |||
// Reset | |||
rcv = ps2_host_send(0xFF); | |||
print("ps2_mouse_init: send 0xFF: "); | |||
phex(ps2_error); print("\n"); | |||
ERROR_RETURN(); | |||
_delay_ms(1000); // wait for powering up | |||
// ACK | |||
rcv = ps2_host_recv(); | |||
print("ps2_mouse_init: read ACK: "); | |||
// send Reset | |||
rcv = ps2_host_send(0xFF); | |||
print("ps2_mouse_init: send Reset: "); | |||
phex(rcv); phex(ps2_error); print("\n"); | |||
ERROR_RETURN(); | |||
// BAT takes some time | |||
_delay_ms(100); | |||
rcv = ps2_host_recv(); | |||
// read completion code of BAT | |||
rcv = ps2_host_recv_response(); | |||
print("ps2_mouse_init: read BAT: "); | |||
phex(rcv); phex(ps2_error); print("\n"); | |||
ERROR_RETURN(); | |||
// Device ID | |||
rcv = ps2_host_recv(); | |||
// read Device ID | |||
rcv = ps2_host_recv_response(); | |||
print("ps2_mouse_init: read DevID: "); | |||
phex(rcv); phex(ps2_error); print("\n"); | |||
ERROR_RETURN(); | |||
// Enable data reporting | |||
ps2_host_send(0xF4); | |||
print("ps2_mouse_init: send 0xF4: "); | |||
phex(ps2_error); print("\n"); | |||
ERROR_RETURN(); | |||
// ACK | |||
rcv = ps2_host_recv(); | |||
print("ps2_mouse_init: read ACK: "); | |||
phex(rcv); phex(ps2_error); print("\n"); | |||
ERROR_RETURN(); | |||
// Set Remote mode | |||
ps2_host_send(0xF0); | |||
// send Set Remote mode | |||
rcv = ps2_host_send(0xF0); | |||
print("ps2_mouse_init: send 0xF0: "); | |||
phex(ps2_error); print("\n"); | |||
ERROR_RETURN(); | |||
// ACK | |||
rcv = ps2_host_recv(); | |||
print("ps2_mouse_init: read ACK: "); | |||
phex(rcv); phex(ps2_error); print("\n"); | |||
ERROR_RETURN(); | |||
return 0; | |||
} | |||
/* | |||
Data format: | |||
bit: 7 6 5 4 3 2 1 0 | |||
----------------------------------------------------------------------- | |||
0 btn: Yovflw Xovflw Ysign Xsign 1 Middle Right Left | |||
1 x: X movement(0-255) | |||
2 y: Y movement(0-255) | |||
*/ | |||
uint8_t ps2_mouse_read(void) | |||
#define X_IS_NEG (mouse_report.buttons & (1<<PS2_MOUSE_X_SIGN)) | |||
#define Y_IS_NEG (mouse_report.buttons & (1<<PS2_MOUSE_Y_SIGN)) | |||
#define X_IS_OVF (mouse_report.buttons & (1<<PS2_MOUSE_X_OVFLW)) | |||
#define Y_IS_OVF (mouse_report.buttons & (1<<PS2_MOUSE_Y_OVFLW)) | |||
void ps2_mouse_task(void) | |||
{ | |||
enum { SCROLL_NONE, SCROLL_BTN, SCROLL_SENT }; | |||
static uint8_t scroll_state = SCROLL_NONE; | |||
static uint8_t buttons_prev = 0; | |||
/* receives packet from mouse */ | |||
uint8_t rcv; | |||
rcv = ps2_host_send(PS2_MOUSE_READ_DATA); | |||
if (rcv == PS2_ACK) { | |||
mouse_report.buttons = ps2_host_recv_response(); | |||
mouse_report.x = ps2_host_recv_response(); | |||
mouse_report.y = ps2_host_recv_response(); | |||
} else { | |||
if (!debug_mouse) print("ps2_mouse: fail to get mouse packet\n"); | |||
return; | |||
} | |||
if (!ps2_mouse_enable) return 1; | |||
/* if mouse moves or buttons state changes */ | |||
if (mouse_report.x || mouse_report.y || | |||
((mouse_report.buttons ^ buttons_prev) & PS2_MOUSE_BTN_MASK)) { | |||
ps2_host_send(0xEB); | |||
ERROR_RETURN(); | |||
#ifdef PS2_MOUSE_DEBUG | |||
print("ps2_mouse raw: ["); | |||
phex(mouse_report.buttons); print("|"); | |||
print_hex8((uint8_t)mouse_report.x); print(" "); | |||
print_hex8((uint8_t)mouse_report.y); print("]\n"); | |||
#endif | |||
rcv=ps2_host_recv(); | |||
ERROR_RETURN(); | |||
buttons_prev = mouse_report.buttons; | |||
// PS/2 mouse data is '9-bit integer'(-256 to 255) which is comprised of sign-bit and 8-bit value. | |||
// bit: 8 7 ... 0 | |||
// sign \8-bit/ | |||
// | |||
// Meanwhile USB HID mouse indicates 8bit data(-127 to 127), note that -128 is not used. | |||
// | |||
// This converts PS/2 data into HID value. Use only -127-127 out of PS/2 9-bit. | |||
mouse_report.x = X_IS_NEG ? | |||
((!X_IS_OVF && -127 <= mouse_report.x && mouse_report.x <= -1) ? mouse_report.x : -127) : | |||
((!X_IS_OVF && 0 <= mouse_report.x && mouse_report.x <= 127) ? mouse_report.x : 127); | |||
mouse_report.y = Y_IS_NEG ? | |||
((!Y_IS_OVF && -127 <= mouse_report.y && mouse_report.y <= -1) ? mouse_report.y : -127) : | |||
((!Y_IS_OVF && 0 <= mouse_report.y && mouse_report.y <= 127) ? mouse_report.y : 127); | |||
// remove sign and overflow flags | |||
mouse_report.buttons &= PS2_MOUSE_BTN_MASK; | |||
// invert coordinate of y to conform to USB HID mouse | |||
mouse_report.y = -mouse_report.y; | |||
#if PS2_MOUSE_SCROLL_BTN_MASK | |||
static uint16_t scroll_button_time = 0; | |||
if ((mouse_report.buttons & (PS2_MOUSE_SCROLL_BTN_MASK)) == (PS2_MOUSE_SCROLL_BTN_MASK)) { | |||
if (scroll_state == SCROLL_NONE) { | |||
scroll_button_time = timer_read(); | |||
scroll_state = SCROLL_BTN; | |||
} | |||
if(rcv==0xFA) { | |||
ps2_mouse_btn = ps2_host_recv(); | |||
ERROR_RETURN(); | |||
ps2_mouse_x = ps2_host_recv(); | |||
ERROR_RETURN(); | |||
ps2_mouse_y = ps2_host_recv(); | |||
ERROR_RETURN(); | |||
} | |||
return 0; | |||
} | |||
// doesn't send Scroll Button | |||
//mouse_report.buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK); | |||
bool ps2_mouse_changed(void) | |||
{ | |||
return (ps2_mouse_x || ps2_mouse_y || (ps2_mouse_btn & PS2_MOUSE_BTN_MASK) != ps2_mouse_btn_prev); | |||
} | |||
if (mouse_report.x || mouse_report.y) { | |||
scroll_state = SCROLL_SENT; | |||
#define PS2_MOUSE_SCROLL_BUTTON 0x04 | |||
void ps2_mouse_usb_send(void) | |||
{ | |||
static bool scrolled = false; | |||
if (!ps2_mouse_enable) return; | |||
if (ps2_mouse_changed()) { | |||
int8_t x, y, v, h; | |||
x = y = v = h = 0; | |||
// convert scale of X, Y: PS/2(-256/255) -> USB(-127/127) | |||
if (ps2_mouse_btn & (1<<PS2_MOUSE_X_SIGN)) | |||
x = ps2_mouse_x > 128 ? (int8_t)ps2_mouse_x : -127; | |||
else | |||
x = ps2_mouse_x < 128 ? (int8_t)ps2_mouse_x : 127; | |||
if (ps2_mouse_btn & (1<<PS2_MOUSE_Y_SIGN)) | |||
y = ps2_mouse_y > 128 ? (int8_t)ps2_mouse_y : -127; | |||
else | |||
y = ps2_mouse_y < 128 ? (int8_t)ps2_mouse_y : 127; | |||
// Y is needed to reverse | |||
y = -y; | |||
if (ps2_mouse_btn & PS2_MOUSE_SCROLL_BUTTON) { | |||
// scroll | |||
if (x > 0 || x < 0) h = (x > 64 ? 64 : (x < -64 ? -64 :x)); | |||
if (y > 0 || y < 0) v = (y > 64 ? 64 : (y < -64 ? -64 :y)); | |||
if (h || v) { | |||
scrolled = true; | |||
usb_mouse_send(0,0, -v/16, h/16, 0); | |||
mouse_report.v = -mouse_report.y/(PS2_MOUSE_SCROLL_DIVISOR_V); | |||
mouse_report.h = mouse_report.x/(PS2_MOUSE_SCROLL_DIVISOR_H); | |||
mouse_report.x = 0; | |||
mouse_report.y = 0; | |||
//host_mouse_send(&mouse_report); | |||
} | |||
} | |||
else if ((mouse_report.buttons & (PS2_MOUSE_SCROLL_BTN_MASK)) == 0) { | |||
#if PS2_MOUSE_SCROLL_BTN_SEND | |||
if (scroll_state == SCROLL_BTN && | |||
TIMER_DIFF_16(timer_read(), scroll_button_time) < PS2_MOUSE_SCROLL_BTN_SEND) { | |||
// send Scroll Button(down and up at once) when not scrolled | |||
mouse_report.buttons |= (PS2_MOUSE_SCROLL_BTN_MASK); | |||
host_mouse_send(&mouse_report); | |||
_delay_ms(100); | |||
mouse_report.buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK); | |||
} | |||
} else if (!scrolled && (ps2_mouse_btn_prev & PS2_MOUSE_SCROLL_BUTTON)) { | |||
usb_mouse_send(0,0,0,0, PS2_MOUSE_SCROLL_BUTTON); | |||
_delay_ms(100); | |||
usb_mouse_send(0,0,0,0, 0); | |||
} else { | |||
scrolled = false; | |||
usb_mouse_send(x, y, 0, 0, ps2_mouse_btn & PS2_MOUSE_BTN_MASK); | |||
#endif | |||
scroll_state = SCROLL_NONE; | |||
} | |||
// doesn't send Scroll Button | |||
mouse_report.buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK); | |||
#endif | |||
ps2_mouse_btn_prev = (ps2_mouse_btn & PS2_MOUSE_BTN_MASK); | |||
ps2_mouse_print(); | |||
host_mouse_send(&mouse_report); | |||
print_usb_data(); | |||
} | |||
ps2_mouse_x = 0; | |||
ps2_mouse_y = 0; | |||
ps2_mouse_btn = 0; | |||
// clear report | |||
mouse_report.x = 0; | |||
mouse_report.y = 0; | |||
mouse_report.v = 0; | |||
mouse_report.h = 0; | |||
mouse_report.buttons = 0; | |||
} | |||
void ps2_mouse_print(void) | |||
static void print_usb_data(void) | |||
{ | |||
if (!debug_mouse) return; | |||
print("ps2_mouse[btn|x y]: "); | |||
phex(ps2_mouse_btn); print("|"); | |||
phex(ps2_mouse_x); print(" "); | |||
phex(ps2_mouse_y); print("\n"); | |||
print("ps2_mouse usb: ["); | |||
phex(mouse_report.buttons); print("|"); | |||
print_hex8((uint8_t)mouse_report.x); print(" "); | |||
print_hex8((uint8_t)mouse_report.y); print(" "); | |||
print_hex8((uint8_t)mouse_report.v); print(" "); | |||
print_hex8((uint8_t)mouse_report.h); print("]\n"); | |||
} | |||
/* PS/2 Mouse Synopsis | |||
* http://www.computer-engineering.org/ps2mouse/ | |||
* | |||
* Command: | |||
* 0xFF: Reset | |||
* 0xF6: Set Defaults Sampling; rate=100, resolution=4cnt/mm, scaling=1:1, reporting=disabled | |||
* 0xF5: Disable Data Reporting | |||
* 0xF4: Enable Data Reporting | |||
* 0xF3: Set Sample Rate | |||
* 0xF2: Get Device ID | |||
* 0xF0: Set Remote Mode | |||
* 0xEB: Read Data | |||
* 0xEA: Set Stream Mode | |||
* 0xE9: Status Request | |||
* 0xE8: Set Resolution | |||
* 0xE7: Set Scaling 2:1 | |||
* 0xE6: Set Scaling 1:1 | |||
* | |||
* Mode: | |||
* Stream Mode: devices sends the data when it changs its state | |||
* Remote Mode: host polls the data periodically | |||
* | |||
* This code uses Remote Mode and polls the data with Read Data(0xEB). | |||
* | |||
* Data format: | |||
* byte|7 6 5 4 3 2 1 0 | |||
* ----+-------------------------------------------------------------- | |||
* 0|Yovflw Xovflw Ysign Xsign 1 Middle Right Left | |||
* 1| X movement | |||
* 2| Y movement | |||
*/ |
@@ -20,6 +20,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#include <stdbool.h> | |||
#define PS2_MOUSE_READ_DATA 0xEB | |||
/* | |||
* Data format: | |||
* byte|7 6 5 4 3 2 1 0 | |||
* ----+-------------------------------------------------------------- | |||
* 0|Yovflw Xovflw Ysign Xsign 1 Middle Right Left | |||
* 1| X movement(0-255) | |||
* 2| Y movement(0-255) | |||
*/ | |||
#define PS2_MOUSE_BTN_MASK 0x07 | |||
#define PS2_MOUSE_BTN_LEFT 0 | |||
#define PS2_MOUSE_BTN_RIGHT 1 | |||
@@ -29,16 +39,28 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#define PS2_MOUSE_X_OVFLW 6 | |||
#define PS2_MOUSE_Y_OVFLW 7 | |||
bool ps2_mouse_enable; | |||
extern uint8_t ps2_mouse_x; | |||
extern uint8_t ps2_mouse_y; | |||
extern uint8_t ps2_mouse_btn; | |||
extern uint8_t ps2_mouse_error_count; | |||
/* | |||
* Scroll by mouse move with pressing button | |||
*/ | |||
/* mouse button to start scrolling; set 0 to disable scroll */ | |||
#ifndef PS2_MOUSE_SCROLL_BTN_MASK | |||
#define PS2_MOUSE_SCROLL_BTN_MASK (1<<PS2_MOUSE_BTN_MIDDLE) | |||
#endif | |||
/* send button event when button is released within this value(ms); set 0 to disable */ | |||
#ifndef PS2_MOUSE_SCROLL_BTN_SEND | |||
#define PS2_MOUSE_SCROLL_BTN_SEND 300 | |||
#endif | |||
/* divide virtical and horizontal mouse move by this to convert to scroll move */ | |||
#ifndef PS2_MOUSE_SCROLL_DIVISOR_V | |||
#define PS2_MOUSE_SCROLL_DIVISOR_V 2 | |||
#endif | |||
#ifndef PS2_MOUSE_SCROLL_DIVISOR_H | |||
#define PS2_MOUSE_SCROLL_DIVISOR_H 2 | |||
#endif | |||
uint8_t ps2_mouse_init(void); | |||
uint8_t ps2_mouse_read(void); | |||
bool ps2_mouse_changed(void); | |||
void ps2_mouse_usb_send(void); | |||
void ps2_mouse_print(void); | |||
void ps2_mouse_task(void); | |||
#endif |
@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2010,2011 Jun WAKO <[email protected]> | |||
Copyright 2010,2011,2012,2013 Jun WAKO <[email protected]> | |||
This software is licensed with a Modified BSD License. | |||
All of this is supposed to be Free Software, Open Source, DFSG-free, | |||
@@ -64,14 +64,6 @@ http://www.mcamafia.de/pdf/ibm_hitrc07.pdf | |||
#include "debug.h" | |||
#if 0 | |||
#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0) | |||
#define DEBUGP(x) do { PORTC = x; } while (0) | |||
#else | |||
#define DEBUGP_INIT() | |||
#define DEBUGP(x) | |||
#endif | |||
#define WAIT(stat, us, err) do { \ | |||
if (!wait_##stat(us)) { \ | |||
ps2_error = err; \ | |||
@@ -97,12 +89,12 @@ static inline void idle(void); | |||
static inline void inhibit(void); | |||
static inline uint8_t pbuf_dequeue(void); | |||
static inline void pbuf_enqueue(uint8_t data); | |||
static inline bool pbuf_has_data(void); | |||
static inline void pbuf_clear(void); | |||
void ps2_host_init(void) | |||
{ | |||
DEBUGP_INIT(); | |||
DEBUGP(0x1); | |||
idle(); | |||
PS2_USART_INIT(); | |||
PS2_USART_RX_INT_ON(); | |||
@@ -114,7 +106,6 @@ uint8_t ps2_host_send(uint8_t data) | |||
bool parity = true; | |||
ps2_error = PS2_ERR_NONE; | |||
DEBUGP(0x6); | |||
PS2_USART_OFF(); | |||
/* terminate a transmission if we have */ | |||
@@ -153,6 +144,8 @@ uint8_t ps2_host_send(uint8_t data) | |||
WAIT(clock_hi, 50, 8); | |||
WAIT(data_hi, 50, 9); | |||
PS2_USART_INIT(); | |||
PS2_USART_RX_INT_ON(); | |||
res = ps2_host_recv_response(); | |||
ERROR: | |||
idle(); | |||
@@ -164,15 +157,10 @@ ERROR: | |||
// Do polling data from keyboard to get response to last command. | |||
uint8_t ps2_host_recv_response(void) | |||
{ | |||
uint8_t data = 0; | |||
PS2_USART_INIT(); | |||
PS2_USART_RX_POLL_ON(); | |||
while (!PS2_USART_RX_READY) | |||
; | |||
data = PS2_USART_RX_DATA; | |||
PS2_USART_OFF(); | |||
DEBUGP(0x9); | |||
return data; | |||
while (!pbuf_has_data()) { | |||
_delay_ms(1); // without this delay it seems to fall into deadlock | |||
} | |||
return pbuf_dequeue(); | |||
} | |||
uint8_t ps2_host_recv(void) | |||
@@ -182,15 +170,11 @@ uint8_t ps2_host_recv(void) | |||
ISR(PS2_USART_RX_VECT) | |||
{ | |||
DEBUGP(0x7); | |||
uint8_t error = PS2_USART_ERROR; | |||
uint8_t data = PS2_USART_RX_DATA; | |||
if (error) { | |||
DEBUGP(error>>2); | |||
} else { | |||
if (!error) { | |||
pbuf_enqueue(data); | |||
} | |||
DEBUGP(0x8); | |||
} | |||
/* send LED state to keyboard */ | |||
@@ -293,9 +277,6 @@ static uint8_t pbuf_head = 0; | |||
static uint8_t pbuf_tail = 0; | |||
static inline void pbuf_enqueue(uint8_t data) | |||
{ | |||
if (!data) | |||
return; | |||
uint8_t sreg = SREG; | |||
cli(); | |||
uint8_t next = (pbuf_head + 1) % PBUF_SIZE; | |||
@@ -322,3 +303,18 @@ static inline uint8_t pbuf_dequeue(void) | |||
return val; | |||
} | |||
static inline bool pbuf_has_data(void) | |||
{ | |||
uint8_t sreg = SREG; | |||
cli(); | |||
bool has_data = (pbuf_head != pbuf_tail); | |||
SREG = sreg; | |||
return has_data; | |||
} | |||
static inline void pbuf_clear(void) | |||
{ | |||
uint8_t sreg = SREG; | |||
cli(); | |||
pbuf_head = pbuf_tail = 0; | |||
SREG = sreg; | |||
} |