aboutsummaryrefslogtreecommitdiff
path: root/tmk_core/protocol/ps2_mouse.c
diff options
context:
space:
mode:
Diffstat (limited to 'tmk_core/protocol/ps2_mouse.c')
-rw-r--r--tmk_core/protocol/ps2_mouse.c330
1 files changed, 178 insertions, 152 deletions
diff --git a/tmk_core/protocol/ps2_mouse.c b/tmk_core/protocol/ps2_mouse.c
index c3e8b3c1c..d9ccbecb4 100644
--- a/tmk_core/protocol/ps2_mouse.c
+++ b/tmk_core/protocol/ps2_mouse.c
@@ -18,60 +18,59 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
18#include <stdbool.h> 18#include <stdbool.h>
19#include<avr/io.h> 19#include<avr/io.h>
20#include<util/delay.h> 20#include<util/delay.h>
21#include "ps2.h"
22#include "ps2_mouse.h" 21#include "ps2_mouse.h"
23#include "report.h"
24#include "host.h" 22#include "host.h"
25#include "timer.h" 23#include "timer.h"
26#include "print.h" 24#include "print.h"
25#include "report.h"
27#include "debug.h" 26#include "debug.h"
27#include "ps2.h"
28 28
29/* ============================= MACROS ============================ */
29 30
30static report_mouse_t mouse_report = {}; 31static report_mouse_t mouse_report = {};
31 32
33static inline void ps2_mouse_print_report(report_mouse_t *mouse_report);
34static inline void ps2_mouse_convert_report_to_hid(report_mouse_t *mouse_report);
35static inline void ps2_mouse_clear_report(report_mouse_t *mouse_report);
36static inline void ps2_mouse_enable_scrolling(void);
37static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report);
32 38
33static void print_usb_data(void); 39/* ============================= IMPLEMENTATION ============================ */
34
35 40
36/* supports only 3 button mouse at this time */ 41/* supports only 3 button mouse at this time */
37uint8_t ps2_mouse_init(void) { 42void ps2_mouse_init(void) {
38 uint8_t rcv;
39
40 ps2_host_init(); 43 ps2_host_init();
41 44
42 _delay_ms(1000); // wait for powering up 45 _delay_ms(PS2_MOUSE_INIT_DELAY); // wait for powering up
43 46
44 // send Reset 47 PS2_MOUSE_SEND(PS2_MOUSE_RESET, "ps2_mouse_init: sending reset");
45 rcv = ps2_host_send(0xFF);
46 print("ps2_mouse_init: send Reset: ");
47 phex(rcv); phex(ps2_error); print("\n");
48 48
49 // read completion code of BAT 49 PS2_MOUSE_RECEIVE("ps2_mouse_init: read BAT");
50 rcv = ps2_host_recv_response(); 50 PS2_MOUSE_RECEIVE("ps2_mouse_init: read DevID");
51 print("ps2_mouse_init: read BAT: ");
52 phex(rcv); phex(ps2_error); print("\n");
53 51
54 // read Device ID 52#ifdef PS2_MOUSE_USE_REMOTE_MODE
55 rcv = ps2_host_recv_response(); 53 ps2_mouse_set_remote_mode();
56 print("ps2_mouse_init: read DevID: "); 54#else
57 phex(rcv); phex(ps2_error); print("\n"); 55 ps2_mouse_enable_data_reporting();
56#endif
57
58#ifdef PS2_MOUSE_ENABLE_SCROLLING
59 ps2_mouse_enable_scrolling();
60#endif
58 61
59 // send Set Remote mode 62#ifdef PS2_MOUSE_USE_2_1_SCALING
60 rcv = ps2_host_send(0xF0); 63 ps2_mouse_set_scaling_2_1();
61 print("ps2_mouse_init: send 0xF0: "); 64#endif
62 phex(rcv); phex(ps2_error); print("\n");
63 65
64 return 0; 66 ps2_mouse_init_user();
65} 67}
66 68
67#define X_IS_NEG (mouse_report.buttons & (1<<PS2_MOUSE_X_SIGN)) 69__attribute__((weak))
68#define Y_IS_NEG (mouse_report.buttons & (1<<PS2_MOUSE_Y_SIGN)) 70void ps2_mouse_init_user(void) {
69#define X_IS_OVF (mouse_report.buttons & (1<<PS2_MOUSE_X_OVFLW)) 71}
70#define Y_IS_OVF (mouse_report.buttons & (1<<PS2_MOUSE_Y_OVFLW)) 72
71void ps2_mouse_task(void) 73void ps2_mouse_task(void) {
72{
73 enum { SCROLL_NONE, SCROLL_BTN, SCROLL_SENT };
74 static uint8_t scroll_state = SCROLL_NONE;
75 static uint8_t buttons_prev = 0; 74 static uint8_t buttons_prev = 0;
76 75
77 /* receives packet from mouse */ 76 /* receives packet from mouse */
@@ -79,142 +78,169 @@ void ps2_mouse_task(void)
79 rcv = ps2_host_send(PS2_MOUSE_READ_DATA); 78 rcv = ps2_host_send(PS2_MOUSE_READ_DATA);
80 if (rcv == PS2_ACK) { 79 if (rcv == PS2_ACK) {
81 mouse_report.buttons = ps2_host_recv_response(); 80 mouse_report.buttons = ps2_host_recv_response();
82 mouse_report.x = ps2_host_recv_response(); 81 mouse_report.x = ps2_host_recv_response() * PS2_MOUSE_X_MULTIPLIER;
83 mouse_report.y = ps2_host_recv_response(); 82 mouse_report.y = ps2_host_recv_response() * PS2_MOUSE_Y_MULTIPLIER;
83#ifdef PS2_MOUSE_ENABLE_SCROLLING
84 mouse_report.v = -(ps2_host_recv_response() & PS2_MOUSE_SCROLL_MASK) * PS2_MOUSE_V_MULTIPLIER;
85#endif
84 } else { 86 } else {
85 if (debug_mouse) print("ps2_mouse: fail to get mouse packet\n"); 87 if (debug_mouse) print("ps2_mouse: fail to get mouse packet\n");
86 return; 88 return;
87 } 89 }
88 xprintf("%ud ", timer_read());
89 print("ps2_mouse raw: [");
90 phex(mouse_report.buttons); print("|");
91 print_hex8((uint8_t)mouse_report.x); print(" ");
92 print_hex8((uint8_t)mouse_report.y); print("]\n");
93 90
94 /* if mouse moves or buttons state changes */ 91 /* if mouse moves or buttons state changes */
95 if (mouse_report.x || mouse_report.y || 92 if (mouse_report.x || mouse_report.y || mouse_report.v ||
96 ((mouse_report.buttons ^ buttons_prev) & PS2_MOUSE_BTN_MASK)) { 93 ((mouse_report.buttons ^ buttons_prev) & PS2_MOUSE_BTN_MASK)) {
97 94#ifdef PS2_MOUSE_DEBUG_RAW
98#ifdef PS2_MOUSE_DEBUG 95 // Used to debug raw ps2 bytes from mouse
99 print("ps2_mouse raw: ["); 96 ps2_mouse_print_report(&mouse_report);
100 phex(mouse_report.buttons); print("|");
101 print_hex8((uint8_t)mouse_report.x); print(" ");
102 print_hex8((uint8_t)mouse_report.y); print("]\n");
103#endif 97#endif
104
105 buttons_prev = mouse_report.buttons; 98 buttons_prev = mouse_report.buttons;
99 ps2_mouse_convert_report_to_hid(&mouse_report);
100#if PS2_MOUSE_SCROLL_BTN_MASK
101 ps2_mouse_scroll_button_task(&mouse_report);
102#endif
103#ifdef PS2_MOUSE_DEBUG_HID
104 // Used to debug the bytes sent to the host
105 ps2_mouse_print_report(&mouse_report);
106#endif
107 host_mouse_send(&mouse_report);
108 }
109
110 ps2_mouse_clear_report(&mouse_report);
111}
106 112
107 // PS/2 mouse data is '9-bit integer'(-256 to 255) which is comprised of sign-bit and 8-bit value. 113void ps2_mouse_disable_data_reporting(void) {
108 // bit: 8 7 ... 0 114 PS2_MOUSE_SEND(PS2_MOUSE_DISABLE_DATA_REPORTING, "ps2 mouse disable data reporting");
109 // sign \8-bit/ 115}
110 //
111 // Meanwhile USB HID mouse indicates 8bit data(-127 to 127), note that -128 is not used.
112 //
113 // This converts PS/2 data into HID value. Use only -127-127 out of PS/2 9-bit.
114 mouse_report.x = X_IS_NEG ?
115 ((!X_IS_OVF && -127 <= mouse_report.x && mouse_report.x <= -1) ? mouse_report.x : -127) :
116 ((!X_IS_OVF && 0 <= mouse_report.x && mouse_report.x <= 127) ? mouse_report.x : 127);
117 mouse_report.y = Y_IS_NEG ?
118 ((!Y_IS_OVF && -127 <= mouse_report.y && mouse_report.y <= -1) ? mouse_report.y : -127) :
119 ((!Y_IS_OVF && 0 <= mouse_report.y && mouse_report.y <= 127) ? mouse_report.y : 127);
120 116
121 // remove sign and overflow flags 117void ps2_mouse_enable_data_reporting(void) {
122 mouse_report.buttons &= PS2_MOUSE_BTN_MASK; 118 PS2_MOUSE_SEND(PS2_MOUSE_ENABLE_DATA_REPORTING, "ps2 mouse enable data reporting");
119}
123 120
124 // invert coordinate of y to conform to USB HID mouse 121void ps2_mouse_set_remote_mode(void) {
125 mouse_report.y = -mouse_report.y; 122 PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_REMOTE_MODE, "ps2 mouse set remote mode");
123 ps2_mouse_mode = PS2_MOUSE_REMOTE_MODE;
124}
126 125
126void ps2_mouse_set_stream_mode(void) {
127 PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_STREAM_MODE, "ps2 mouse set stream mode");
128 ps2_mouse_mode = PS2_MOUSE_STREAM_MODE;
129}
127 130
128#if PS2_MOUSE_SCROLL_BTN_MASK 131void ps2_mouse_set_scaling_2_1(void) {
129 static uint16_t scroll_button_time = 0; 132 PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_SCALING_2_1, "ps2 mouse set scaling 2:1");
130 if ((mouse_report.buttons & (PS2_MOUSE_SCROLL_BTN_MASK)) == (PS2_MOUSE_SCROLL_BTN_MASK)) { 133}
131 if (scroll_state == SCROLL_NONE) { 134
132 scroll_button_time = timer_read(); 135void ps2_mouse_set_scaling_1_1(void) {
133 scroll_state = SCROLL_BTN; 136 PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_SCALING_1_1, "ps2 mouse set scaling 1:1");
134 } 137}
135 138
136 // doesn't send Scroll Button 139void ps2_mouse_set_resolution(ps2_mouse_resolution_t resolution) {
137 //mouse_report.buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK); 140 PS2_MOUSE_SET_SAFE(PS2_MOUSE_SET_RESOLUTION, resolution, "ps2 mouse set resolution");
138 141}
139 if (mouse_report.x || mouse_report.y) { 142
140 scroll_state = SCROLL_SENT; 143void ps2_mouse_set_sample_rate(ps2_mouse_sample_rate_t sample_rate) {
141 144 PS2_MOUSE_SET_SAFE(PS2_MOUSE_SET_SAMPLE_RATE, sample_rate, "ps2 mouse set sample rate");
142 mouse_report.v = -mouse_report.y/(PS2_MOUSE_SCROLL_DIVISOR_V); 145}
143 mouse_report.h = mouse_report.x/(PS2_MOUSE_SCROLL_DIVISOR_H); 146
144 mouse_report.x = 0; 147/* ============================= HELPERS ============================ */
145 mouse_report.y = 0; 148
146 //host_mouse_send(&mouse_report); 149#define X_IS_NEG (mouse_report->buttons & (1<<PS2_MOUSE_X_SIGN))
147 } 150#define Y_IS_NEG (mouse_report->buttons & (1<<PS2_MOUSE_Y_SIGN))
151#define X_IS_OVF (mouse_report->buttons & (1<<PS2_MOUSE_X_OVFLW))
152#define Y_IS_OVF (mouse_report->buttons & (1<<PS2_MOUSE_Y_OVFLW))
153static inline void ps2_mouse_convert_report_to_hid(report_mouse_t *mouse_report) {
154 // PS/2 mouse data is '9-bit integer'(-256 to 255) which is comprised of sign-bit and 8-bit value.
155 // bit: 8 7 ... 0
156 // sign \8-bit/
157 //
158 // Meanwhile USB HID mouse indicates 8bit data(-127 to 127), note that -128 is not used.
159 //
160 // This converts PS/2 data into HID value. Use only -127-127 out of PS/2 9-bit.
161 mouse_report->x = X_IS_NEG ?
162 ((!X_IS_OVF && -127 <= mouse_report->x && mouse_report->x <= -1) ? mouse_report->x : -127) :
163 ((!X_IS_OVF && 0 <= mouse_report->x && mouse_report->x <= 127) ? mouse_report->x : 127);
164 mouse_report->y = Y_IS_NEG ?
165 ((!Y_IS_OVF && -127 <= mouse_report->y && mouse_report->y <= -1) ? mouse_report->y : -127) :
166 ((!Y_IS_OVF && 0 <= mouse_report->y && mouse_report->y <= 127) ? mouse_report->y : 127);
167
168 // remove sign and overflow flags
169 mouse_report->buttons &= PS2_MOUSE_BTN_MASK;
170
171 // invert coordinate of y to conform to USB HID mouse
172 mouse_report->y = -mouse_report->y;
173}
174
175static inline void ps2_mouse_clear_report(report_mouse_t *mouse_report) {
176 mouse_report->x = 0;
177 mouse_report->y = 0;
178 mouse_report->v = 0;
179 mouse_report->h = 0;
180 mouse_report->buttons = 0;
181}
182
183static inline void ps2_mouse_print_report(report_mouse_t *mouse_report) {
184 if (!debug_mouse) return;
185 print("ps2_mouse: [");
186 phex(mouse_report->buttons); print("|");
187 print_hex8((uint8_t)mouse_report->x); print(" ");
188 print_hex8((uint8_t)mouse_report->y); print(" ");
189 print_hex8((uint8_t)mouse_report->v); print(" ");
190 print_hex8((uint8_t)mouse_report->h); print("]\n");
191}
192
193static inline void ps2_mouse_enable_scrolling(void) {
194 PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Initiaing scroll wheel enable: Set sample rate");
195 PS2_MOUSE_SEND(200, "200");
196 PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Set sample rate");
197 PS2_MOUSE_SEND(100, "100");
198 PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Set sample rate");
199 PS2_MOUSE_SEND(80, "80");
200 PS2_MOUSE_SEND(PS2_MOUSE_GET_DEVICE_ID, "Finished enabling scroll wheel");
201 _delay_ms(20);
202}
203
204#define PRESS_SCROLL_BUTTONS mouse_report->buttons |= (PS2_MOUSE_SCROLL_BTN_MASK)
205#define RELEASE_SCROLL_BUTTONS mouse_report->buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK)
206static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report) {
207 static enum {
208 SCROLL_NONE,
209 SCROLL_BTN,
210 SCROLL_SENT,
211 } scroll_state = SCROLL_NONE;
212 static uint16_t scroll_button_time = 0;
213
214 if (PS2_MOUSE_SCROLL_BTN_MASK == (mouse_report->buttons & (PS2_MOUSE_SCROLL_BTN_MASK))) {
215 // All scroll buttons are pressed
216
217 if (scroll_state == SCROLL_NONE) {
218 scroll_button_time = timer_read();
219 scroll_state = SCROLL_BTN;
148 } 220 }
149 else if ((mouse_report.buttons & (PS2_MOUSE_SCROLL_BTN_MASK)) == 0) { 221
222 // If the mouse has moved, update the report to scroll instead of move the mouse
223 if (mouse_report->x || mouse_report->y) {
224 scroll_state = SCROLL_SENT;
225 mouse_report->v = -mouse_report->y/(PS2_MOUSE_SCROLL_DIVISOR_V);
226 mouse_report->h = mouse_report->x/(PS2_MOUSE_SCROLL_DIVISOR_H);
227 mouse_report->x = 0;
228 mouse_report->y = 0;
229 }
230 } else if (0 == (PS2_MOUSE_SCROLL_BTN_MASK & mouse_report->buttons)) {
231 // None of the scroll buttons are pressed
232
150#if PS2_MOUSE_SCROLL_BTN_SEND 233#if PS2_MOUSE_SCROLL_BTN_SEND
151 if (scroll_state == SCROLL_BTN && 234 if (scroll_state == SCROLL_BTN
152 TIMER_DIFF_16(timer_read(), scroll_button_time) < PS2_MOUSE_SCROLL_BTN_SEND) { 235 && timer_elapsed(scroll_button_time) < PS2_MOUSE_SCROLL_BTN_SEND) {
153 // send Scroll Button(down and up at once) when not scrolled 236 PRESS_SCROLL_BUTTONS;
154 mouse_report.buttons |= (PS2_MOUSE_SCROLL_BTN_MASK); 237 host_mouse_send(mouse_report);
155 host_mouse_send(&mouse_report); 238 _delay_ms(100);
156 _delay_ms(100); 239 RELEASE_SCROLL_BUTTONS;
157 mouse_report.buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK);
158 }
159#endif
160 scroll_state = SCROLL_NONE;
161 } 240 }
162 // doesn't send Scroll Button
163 mouse_report.buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK);
164#endif 241#endif
165 242 scroll_state = SCROLL_NONE;
166
167 host_mouse_send(&mouse_report);
168 print_usb_data();
169 } 243 }
170 // clear report
171 mouse_report.x = 0;
172 mouse_report.y = 0;
173 mouse_report.v = 0;
174 mouse_report.h = 0;
175 mouse_report.buttons = 0;
176}
177 244
178static void print_usb_data(void) 245 RELEASE_SCROLL_BUTTONS;
179{ 246}
180 if (!debug_mouse) return;
181 print("ps2_mouse usb: [");
182 phex(mouse_report.buttons); print("|");
183 print_hex8((uint8_t)mouse_report.x); print(" ");
184 print_hex8((uint8_t)mouse_report.y); print(" ");
185 print_hex8((uint8_t)mouse_report.v); print(" ");
186 print_hex8((uint8_t)mouse_report.h); print("]\n");
187}
188
189
190/* PS/2 Mouse Synopsis
191 * http://www.computer-engineering.org/ps2mouse/
192 *
193 * Command:
194 * 0xFF: Reset
195 * 0xF6: Set Defaults Sampling; rate=100, resolution=4cnt/mm, scaling=1:1, reporting=disabled
196 * 0xF5: Disable Data Reporting
197 * 0xF4: Enable Data Reporting
198 * 0xF3: Set Sample Rate
199 * 0xF2: Get Device ID
200 * 0xF0: Set Remote Mode
201 * 0xEB: Read Data
202 * 0xEA: Set Stream Mode
203 * 0xE9: Status Request
204 * 0xE8: Set Resolution
205 * 0xE7: Set Scaling 2:1
206 * 0xE6: Set Scaling 1:1
207 *
208 * Mode:
209 * Stream Mode: devices sends the data when it changs its state
210 * Remote Mode: host polls the data periodically
211 *
212 * This code uses Remote Mode and polls the data with Read Data(0xEB).
213 *
214 * Data format:
215 * byte|7 6 5 4 3 2 1 0
216 * ----+--------------------------------------------------------------
217 * 0|Yovflw Xovflw Ysign Xsign 1 Middle Right Left
218 * 1| X movement
219 * 2| Y movement
220 */