2015-04-10 01:32:04 +09: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>
2019-08-30 11:19:03 -07:00
#include <avr/io.h>
#include <util/delay.h>
2015-04-10 01:32:04 +09:00
#include "ps2_mouse.h"
#include "host.h"
#include "timer.h"
#include "print.h"
2016-12-03 13:05:02 +02:00
#include "report.h"
2015-04-10 01:32:04 +09:00
#include "debug.h"
2016-12-03 13:05:02 +02:00
#include "ps2.h"
2015-04-10 01:32:04 +09:00
2016-12-03 13:05:02 +02:00
/* ============================= MACROS ============================ */
2016-12-05 01:22:40 +07:00
static report_mouse_t mouse_report = {};
2015-04-10 01:32:04 +09:00
2016-12-03 13:05:02 +02: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-10 01:32:04 +09:00
2016-12-03 13:05:02 +02:00
/* ============================= IMPLEMENTATION ============================ */
2015-04-10 01:32:04 +09:00
/* supports only 3 button mouse at this time */
2016-12-03 13:05:02 +02:00
void ps2_mouse_init ( void ) {
2015-04-10 01:32:04 +09:00
ps2_host_init ();
2019-08-30 11:19:03 -07:00
_delay_ms ( PS2_MOUSE_INIT_DELAY ); // wait for powering up
2015-04-10 01:32:04 +09:00
2016-12-03 13:05:02 +02:00
PS2_MOUSE_SEND ( PS2_MOUSE_RESET , "ps2_mouse_init: sending reset" );
2015-04-10 01:32:04 +09:00
2016-12-03 13:05:02 +02:00
PS2_MOUSE_RECEIVE ( "ps2_mouse_init: read BAT" );
PS2_MOUSE_RECEIVE ( "ps2_mouse_init: read DevID" );
2015-04-10 01:32:04 +09:00
2016-12-03 13:05:02 +02:00
#ifdef PS2_MOUSE_USE_REMOTE_MODE
ps2_mouse_set_remote_mode ();
#else
ps2_mouse_enable_data_reporting ();
#endif
2015-04-10 01:32:04 +09:00
2016-12-03 13:05:02 +02:00
#ifdef PS2_MOUSE_ENABLE_SCROLLING
ps2_mouse_enable_scrolling ();
#endif
2015-04-10 01:32:04 +09:00
2016-12-03 13:05:02 +02:00
#ifdef PS2_MOUSE_USE_2_1_SCALING
ps2_mouse_set_scaling_2_1 ();
#endif
2016-12-05 01:07:12 +07:00
ps2_mouse_init_user ();
}
2019-08-30 11:19:03 -07:00
__attribute__ (( weak )) void ps2_mouse_init_user ( void ) {}
2015-04-10 01:32:04 +09:00
2016-12-03 13:05:02 +02:00
void ps2_mouse_task ( void ) {
2015-04-10 01:32:04 +09:00
static uint8_t buttons_prev = 0 ;
2019-08-30 11:19:03 -07:00
extern int tp_buttons ;
2015-04-10 01:32:04 +09: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 11:19:03 -07: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 13:05:02 +02:00
#ifdef PS2_MOUSE_ENABLE_SCROLLING
mouse_report . v = - ( ps2_host_recv_response () & PS2_MOUSE_SCROLL_MASK ) * PS2_MOUSE_V_MULTIPLIER ;
#endif
2015-04-10 01:32:04 +09: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 11:19:03 -07:00
if ( mouse_report . x || mouse_report . y || mouse_report . v || (( mouse_report . buttons ^ buttons_prev ) & PS2_MOUSE_BTN_MASK )) {
2016-12-03 13:05:02 +02:00
#ifdef PS2_MOUSE_DEBUG_RAW
// Used to debug raw ps2 bytes from mouse
ps2_mouse_print_report ( & mouse_report );
2015-04-10 01:32:04 +09:00
#endif
buttons_prev = mouse_report . buttons ;
2016-12-03 13:05:02 +02:00
ps2_mouse_convert_report_to_hid ( & mouse_report );
2015-04-10 01:32:04 +09:00
#if PS2_MOUSE_SCROLL_BTN_MASK
2016-12-03 13:05:02 +02:00
ps2_mouse_scroll_button_task ( & mouse_report );
2015-04-10 01:32:04 +09:00
#endif
2016-12-03 13:05:02 +02:00
#ifdef PS2_MOUSE_DEBUG_HID
// Used to debug the bytes sent to the host
ps2_mouse_print_report ( & mouse_report );
2015-04-10 01:32:04 +09:00
#endif
host_mouse_send ( & mouse_report );
}
2017-05-26 20:35:31 +02:00
2016-12-03 13:05:02 +02:00
ps2_mouse_clear_report ( & mouse_report );
2015-04-10 01:32:04 +09:00
}
2019-08-30 11:19:03 -07:00
void ps2_mouse_disable_data_reporting ( void ) { PS2_MOUSE_SEND ( PS2_MOUSE_DISABLE_DATA_REPORTING , "ps2 mouse disable data reporting" ); }
2016-12-03 13:05:02 +02:00
2019-08-30 11:19:03 -07:00
void ps2_mouse_enable_data_reporting ( void ) { PS2_MOUSE_SEND ( PS2_MOUSE_ENABLE_DATA_REPORTING , "ps2 mouse enable data reporting" ); }
2016-12-03 13:05:02 +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 13:05:02 +02:00
ps2_mouse_mode = PS2_MOUSE_REMOTE_MODE ;
}
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 13:05:02 +02:00
ps2_mouse_mode = PS2_MOUSE_STREAM_MODE ;
}
2019-08-30 11:19:03 -07: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" ); }
2016-12-03 13:05:02 +02:00
2019-08-30 11:19:03 -07: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" ); }
2016-12-03 13:05:02 +02:00
2019-08-30 11:19:03 -07: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 13:05:02 +02:00
2019-08-30 11:19:03 -07: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 13:05:02 +02:00
/* ============================= HELPERS ============================ */
2019-08-30 11:19:03 -07: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 13:05:02 +02: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 11:19:03 -07: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 13:05:02 +02:00
// remove sign and overflow flags
mouse_report -> buttons &= PS2_MOUSE_BTN_MASK ;
2017-09-22 13:58:49 +02:00
#ifdef PS2_MOUSE_INVERT_X
mouse_report -> x = - mouse_report -> x ;
#endif
2019-08-30 11:19:03 -07:00
#ifndef PS2_MOUSE_INVERT_Y // NOTE if not!
2016-12-03 13:05:02 +02: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
2016-12-03 13:05:02 +02:00
}
static inline void ps2_mouse_clear_report ( report_mouse_t * mouse_report ) {
2019-08-30 11:19:03 -07:00
mouse_report -> x = 0 ;
mouse_report -> y = 0 ;
mouse_report -> v = 0 ;
mouse_report -> h = 0 ;
2016-12-03 13:05:02 +02:00
mouse_report -> buttons = 0 ;
}
static inline void ps2_mouse_print_report ( report_mouse_t * mouse_report ) {
2015-04-10 01:32:04 +09:00
if ( ! debug_mouse ) return ;
2016-12-03 13:05:02 +02:00
print ( "ps2_mouse: [" );
2019-08-30 11:19:03 -07:00
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 " );
2015-04-10 01:32:04 +09:00
}
2016-12-03 13:05:02 +02: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" );
_delay_ms ( 20 );
}
2015-04-10 01:32:04 +09:00
2019-08-30 11:19:03 -07: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 13:05:02 +02: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 13:05:02 +02:00
SCROLL_SENT ,
2019-08-30 11:19:03 -07:00
} scroll_state = SCROLL_NONE ;
2016-12-03 13:05:02 +02: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 11:19:03 -07:00
scroll_state = SCROLL_BTN ;
2016-12-03 13:05:02 +02: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 11:19:03 -07: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 13:05:02 +02: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 13:05:02 +02: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 13:05:02 +02:00
#if PS2_MOUSE_SCROLL_BTN_SEND
2019-08-30 11:19:03 -07:00
if ( scroll_state == SCROLL_BTN && timer_elapsed ( scroll_button_time ) < PS2_MOUSE_SCROLL_BTN_SEND ) {
2016-12-03 13:05:02 +02:00
PRESS_SCROLL_BUTTONS ;
host_mouse_send ( mouse_report );
_delay_ms ( 100 );
RELEASE_SCROLL_BUTTONS ;
}
#endif
scroll_state = SCROLL_NONE ;
}
RELEASE_SCROLL_BUTTONS ;
2016-12-03 13:09:42 +02:00
}