2015-04-09 18:32:04 +02:00
/*
Copyright 2011 , 2013 Jun Wako < wakojun @ gmail . com >
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
the Free Software Foundation , either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <stdbool.h>
# include "ps2_mouse.h"
2021-08-05 23:51:24 +02:00
# include "wait.h"
2021-10-20 22:18:49 +02:00
# include "gpio.h"
2015-04-09 18:32:04 +02:00
# include "host.h"
# include "timer.h"
# include "print.h"
2016-12-03 12:05:02 +01:00
# include "report.h"
2015-04-09 18:32:04 +02:00
# include "debug.h"
2016-12-03 12:05:02 +01:00
# include "ps2.h"
2015-04-09 18:32:04 +02:00
2016-12-03 12:05:02 +01:00
/* ============================= MACROS ============================ */
2016-12-04 19:22:40 +01:00
static report_mouse_t mouse_report = { } ;
2015-04-09 18:32:04 +02:00
2016-12-03 12:05:02 +01:00
static inline void ps2_mouse_print_report ( report_mouse_t * mouse_report ) ;
static inline void ps2_mouse_convert_report_to_hid ( report_mouse_t * mouse_report ) ;
static inline void ps2_mouse_clear_report ( report_mouse_t * mouse_report ) ;
static inline void ps2_mouse_enable_scrolling ( void ) ;
static inline void ps2_mouse_scroll_button_task ( report_mouse_t * mouse_report ) ;
2015-04-09 18:32:04 +02:00
2016-12-03 12:05:02 +01:00
/* ============================= IMPLEMENTATION ============================ */
2015-04-09 18:32:04 +02:00
/* supports only 3 button mouse at this time */
2016-12-03 12:05:02 +01:00
void ps2_mouse_init ( void ) {
2015-04-09 18:32:04 +02:00
ps2_host_init ( ) ;
2021-08-05 23:51:24 +02:00
wait_ms ( PS2_MOUSE_INIT_DELAY ) ; // wait for powering up
2015-04-09 18:32:04 +02:00
2016-12-03 12:05:02 +01:00
PS2_MOUSE_SEND ( PS2_MOUSE_RESET , " ps2_mouse_init: sending reset " ) ;
2015-04-09 18:32:04 +02:00
2016-12-03 12:05:02 +01:00
PS2_MOUSE_RECEIVE ( " ps2_mouse_init: read BAT " ) ;
PS2_MOUSE_RECEIVE ( " ps2_mouse_init: read DevID " ) ;
2015-04-09 18:32:04 +02:00
2016-12-03 12:05:02 +01:00
# ifdef PS2_MOUSE_USE_REMOTE_MODE
ps2_mouse_set_remote_mode ( ) ;
# else
ps2_mouse_enable_data_reporting ( ) ;
# endif
2015-04-09 18:32:04 +02:00
2016-12-03 12:05:02 +01:00
# ifdef PS2_MOUSE_ENABLE_SCROLLING
ps2_mouse_enable_scrolling ( ) ;
# endif
2015-04-09 18:32:04 +02:00
2016-12-03 12:05:02 +01:00
# ifdef PS2_MOUSE_USE_2_1_SCALING
ps2_mouse_set_scaling_2_1 ( ) ;
# endif
2016-12-04 19:07:12 +01:00
ps2_mouse_init_user ( ) ;
}
2019-08-30 20:19:03 +02:00
__attribute__ ( ( weak ) ) void ps2_mouse_init_user ( void ) { }
2015-04-09 18:32:04 +02:00
2020-07-02 22:54:15 +02:00
__attribute__ ( ( weak ) ) void ps2_mouse_moved_user ( report_mouse_t * mouse_report ) { }
2016-12-03 12:05:02 +01:00
void ps2_mouse_task ( void ) {
2015-04-09 18:32:04 +02:00
static uint8_t buttons_prev = 0 ;
2019-08-30 20:19:03 +02:00
extern int tp_buttons ;
2015-04-09 18:32:04 +02:00
/* receives packet from mouse */
uint8_t rcv ;
rcv = ps2_host_send ( PS2_MOUSE_READ_DATA ) ;
if ( rcv = = PS2_ACK ) {
2017-05-26 20:35:31 +02:00
mouse_report . buttons = ps2_host_recv_response ( ) | tp_buttons ;
2019-08-30 20:19:03 +02:00
mouse_report . x = ps2_host_recv_response ( ) * PS2_MOUSE_X_MULTIPLIER ;
mouse_report . y = ps2_host_recv_response ( ) * PS2_MOUSE_Y_MULTIPLIER ;
2016-12-03 12:05:02 +01:00
# ifdef PS2_MOUSE_ENABLE_SCROLLING
mouse_report . v = - ( ps2_host_recv_response ( ) & PS2_MOUSE_SCROLL_MASK ) * PS2_MOUSE_V_MULTIPLIER ;
# endif
2015-04-09 18:32:04 +02:00
} else {
if ( debug_mouse ) print ( " ps2_mouse: fail to get mouse packet \n " ) ;
return ;
}
/* if mouse moves or buttons state changes */
2019-08-30 20:19:03 +02:00
if ( mouse_report . x | | mouse_report . y | | mouse_report . v | | ( ( mouse_report . buttons ^ buttons_prev ) & PS2_MOUSE_BTN_MASK ) ) {
2016-12-03 12:05:02 +01:00
# ifdef PS2_MOUSE_DEBUG_RAW
// Used to debug raw ps2 bytes from mouse
ps2_mouse_print_report ( & mouse_report ) ;
2015-04-09 18:32:04 +02:00
# endif
buttons_prev = mouse_report . buttons ;
2016-12-03 12:05:02 +01:00
ps2_mouse_convert_report_to_hid ( & mouse_report ) ;
# if PS2_MOUSE_SCROLL_BTN_MASK
ps2_mouse_scroll_button_task ( & mouse_report ) ;
# endif
2020-07-02 22:54:15 +02:00
if ( mouse_report . x | | mouse_report . y | | mouse_report . v ) {
ps2_mouse_moved_user ( & mouse_report ) ;
}
2016-12-03 12:05:02 +01:00
# ifdef PS2_MOUSE_DEBUG_HID
// Used to debug the bytes sent to the host
ps2_mouse_print_report ( & mouse_report ) ;
# endif
host_mouse_send ( & mouse_report ) ;
}
2017-05-26 20:35:31 +02:00
2016-12-03 12:05:02 +01:00
ps2_mouse_clear_report ( & mouse_report ) ;
}
2015-04-09 18:32:04 +02:00
2019-08-30 20:19:03 +02:00
void ps2_mouse_disable_data_reporting ( void ) { PS2_MOUSE_SEND ( PS2_MOUSE_DISABLE_DATA_REPORTING , " ps2 mouse disable data reporting " ) ; }
2015-04-09 18:32:04 +02:00
2019-08-30 20:19:03 +02:00
void ps2_mouse_enable_data_reporting ( void ) { PS2_MOUSE_SEND ( PS2_MOUSE_ENABLE_DATA_REPORTING , " ps2 mouse enable data reporting " ) ; }
2015-04-09 18:32:04 +02:00
2017-05-26 20:35:31 +02:00
void ps2_mouse_set_remote_mode ( void ) {
PS2_MOUSE_SEND_SAFE ( PS2_MOUSE_SET_REMOTE_MODE , " ps2 mouse set remote mode " ) ;
2016-12-03 12:05:02 +01:00
ps2_mouse_mode = PS2_MOUSE_REMOTE_MODE ;
}
2015-04-09 18:32:04 +02:00
2017-05-26 20:35:31 +02:00
void ps2_mouse_set_stream_mode ( void ) {
PS2_MOUSE_SEND_SAFE ( PS2_MOUSE_SET_STREAM_MODE , " ps2 mouse set stream mode " ) ;
2016-12-03 12:05:02 +01:00
ps2_mouse_mode = PS2_MOUSE_STREAM_MODE ;
}
2015-04-09 18:32:04 +02:00
2019-08-30 20:19:03 +02:00
void ps2_mouse_set_scaling_2_1 ( void ) { PS2_MOUSE_SEND_SAFE ( PS2_MOUSE_SET_SCALING_2_1 , " ps2 mouse set scaling 2:1 " ) ; }
2015-04-09 18:32:04 +02:00
2019-08-30 20:19:03 +02:00
void ps2_mouse_set_scaling_1_1 ( void ) { PS2_MOUSE_SEND_SAFE ( PS2_MOUSE_SET_SCALING_1_1 , " ps2 mouse set scaling 1:1 " ) ; }
2015-04-09 18:32:04 +02:00
2019-08-30 20:19:03 +02:00
void ps2_mouse_set_resolution ( ps2_mouse_resolution_t resolution ) { PS2_MOUSE_SET_SAFE ( PS2_MOUSE_SET_RESOLUTION , resolution , " ps2 mouse set resolution " ) ; }
2016-12-03 12:05:02 +01:00
2019-08-30 20:19:03 +02:00
void ps2_mouse_set_sample_rate ( ps2_mouse_sample_rate_t sample_rate ) { PS2_MOUSE_SET_SAFE ( PS2_MOUSE_SET_SAMPLE_RATE , sample_rate , " ps2 mouse set sample rate " ) ; }
2016-12-03 12:05:02 +01:00
/* ============================= HELPERS ============================ */
2019-08-30 20:19:03 +02:00
# 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))
2016-12-03 12:05:02 +01:00
static inline void ps2_mouse_convert_report_to_hid ( report_mouse_t * mouse_report ) {
// 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.
2019-08-30 20:19:03 +02:00
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 ) ;
2016-12-03 12:05:02 +01:00
2021-08-06 01:09:58 +02:00
# ifdef PS2_MOUSE_INVERT_BUTTONS
// swap left & right buttons
2021-10-20 22:18:49 +02:00
uint8_t needs_left = mouse_report - > buttons & PS2_MOUSE_BTN_RIGHT ;
uint8_t needs_right = mouse_report - > buttons & PS2_MOUSE_BTN_LEFT ;
2021-08-06 01:09:58 +02:00
mouse_report - > buttons = ( mouse_report - > buttons & ~ ( PS2_MOUSE_BTN_MASK ) ) | ( needs_left ? PS2_MOUSE_BTN_LEFT : 0 ) | ( needs_right ? PS2_MOUSE_BTN_RIGHT : 0 ) ;
# else
2016-12-03 12:05:02 +01:00
// remove sign and overflow flags
mouse_report - > buttons & = PS2_MOUSE_BTN_MASK ;
2021-08-06 01:09:58 +02:00
# endif
2016-12-03 12:05:02 +01:00
2017-09-22 13:58:49 +02:00
# ifdef PS2_MOUSE_INVERT_X
mouse_report - > x = - mouse_report - > x ;
# endif
2019-08-30 20:19:03 +02:00
# ifndef PS2_MOUSE_INVERT_Y // NOTE if not!
2016-12-03 12:05:02 +01:00
// invert coordinate of y to conform to USB HID mouse
mouse_report - > y = - mouse_report - > y ;
2017-09-22 13:58:49 +02:00
# endif
2020-04-09 10:29:27 +02:00
# ifdef PS2_MOUSE_ROTATE
int8_t x = mouse_report - > x ;
int8_t y = mouse_report - > y ;
# if PS2_MOUSE_ROTATE == 90
mouse_report - > x = y ;
mouse_report - > y = - x ;
# elif PS2_MOUSE_ROTATE == 180
mouse_report - > x = - x ;
mouse_report - > y = - y ;
# elif PS2_MOUSE_ROTATE == 270
mouse_report - > x = - y ;
mouse_report - > y = x ;
# endif
# endif
2015-04-09 18:32:04 +02:00
}
2016-12-03 12:05:02 +01:00
static inline void ps2_mouse_clear_report ( report_mouse_t * mouse_report ) {
2019-08-30 20:19:03 +02:00
mouse_report - > x = 0 ;
mouse_report - > y = 0 ;
mouse_report - > v = 0 ;
mouse_report - > h = 0 ;
2016-12-03 12:05:02 +01:00
mouse_report - > buttons = 0 ;
}
static inline void ps2_mouse_print_report ( report_mouse_t * mouse_report ) {
2015-04-09 18:32:04 +02:00
if ( ! debug_mouse ) return ;
2016-12-03 12:05:02 +01:00
print ( " ps2_mouse: [ " ) ;
2021-02-06 17:56:13 +01:00
print_hex8 ( mouse_report - > buttons ) ;
2019-08-30 20:19:03 +02:00
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 " ) ;
2016-12-03 12:05:02 +01:00
}
static inline void ps2_mouse_enable_scrolling ( void ) {
PS2_MOUSE_SEND ( PS2_MOUSE_SET_SAMPLE_RATE , " Initiaing scroll wheel enable: Set sample rate " ) ;
PS2_MOUSE_SEND ( 200 , " 200 " ) ;
PS2_MOUSE_SEND ( PS2_MOUSE_SET_SAMPLE_RATE , " Set sample rate " ) ;
PS2_MOUSE_SEND ( 100 , " 100 " ) ;
PS2_MOUSE_SEND ( PS2_MOUSE_SET_SAMPLE_RATE , " Set sample rate " ) ;
PS2_MOUSE_SEND ( 80 , " 80 " ) ;
PS2_MOUSE_SEND ( PS2_MOUSE_GET_DEVICE_ID , " Finished enabling scroll wheel " ) ;
2021-08-05 23:51:24 +02:00
wait_ms ( 20 ) ;
2015-04-09 18:32:04 +02:00
}
2019-08-30 20:19:03 +02:00
# define PRESS_SCROLL_BUTTONS mouse_report->buttons |= (PS2_MOUSE_SCROLL_BTN_MASK)
# define RELEASE_SCROLL_BUTTONS mouse_report->buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK)
2016-12-03 12:05:02 +01:00
static inline void ps2_mouse_scroll_button_task ( report_mouse_t * mouse_report ) {
2017-05-26 20:35:31 +02:00
static enum {
SCROLL_NONE ,
SCROLL_BTN ,
2016-12-03 12:05:02 +01:00
SCROLL_SENT ,
2019-08-30 20:19:03 +02:00
} scroll_state = SCROLL_NONE ;
2016-12-03 12:05:02 +01:00
static uint16_t scroll_button_time = 0 ;
if ( PS2_MOUSE_SCROLL_BTN_MASK = = ( mouse_report - > buttons & ( PS2_MOUSE_SCROLL_BTN_MASK ) ) ) {
// All scroll buttons are pressed
if ( scroll_state = = SCROLL_NONE ) {
scroll_button_time = timer_read ( ) ;
2019-08-30 20:19:03 +02:00
scroll_state = SCROLL_BTN ;
2016-12-03 12:05:02 +01:00
}
// If the mouse has moved, update the report to scroll instead of move the mouse
if ( mouse_report - > x | | mouse_report - > y ) {
2019-08-30 20:19:03 +02:00
scroll_state = SCROLL_SENT ;
mouse_report - > v = - mouse_report - > y / ( PS2_MOUSE_SCROLL_DIVISOR_V ) ;
mouse_report - > h = mouse_report - > x / ( PS2_MOUSE_SCROLL_DIVISOR_H ) ;
2016-12-03 12:05:02 +01:00
mouse_report - > x = 0 ;
mouse_report - > y = 0 ;
2017-09-22 13:58:49 +02:00
# ifdef PS2_MOUSE_INVERT_H
mouse_report - > h = - mouse_report - > h ;
# endif
# ifdef PS2_MOUSE_INVERT_V
mouse_report - > v = - mouse_report - > v ;
# endif
2016-12-03 12:05:02 +01:00
}
} else if ( 0 = = ( PS2_MOUSE_SCROLL_BTN_MASK & mouse_report - > buttons ) ) {
2017-05-26 20:35:31 +02:00
// None of the scroll buttons are pressed
2016-12-03 12:05:02 +01:00
# if PS2_MOUSE_SCROLL_BTN_SEND
2019-08-30 20:19:03 +02:00
if ( scroll_state = = SCROLL_BTN & & timer_elapsed ( scroll_button_time ) < PS2_MOUSE_SCROLL_BTN_SEND ) {
2016-12-03 12:05:02 +01:00
PRESS_SCROLL_BUTTONS ;
host_mouse_send ( mouse_report ) ;
2021-08-05 23:51:24 +02:00
wait_ms ( 100 ) ;
2016-12-03 12:05:02 +01:00
RELEASE_SCROLL_BUTTONS ;
}
# endif
scroll_state = SCROLL_NONE ;
}
2015-04-09 18:32:04 +02:00
2016-12-03 12:05:02 +01:00
RELEASE_SCROLL_BUTTONS ;
2016-12-03 12:09:42 +01:00
}