diff options
| author | tmk <nobody@nowhere> | 2013-11-21 13:01:47 +0900 |
|---|---|---|
| committer | tmk <nobody@nowhere> | 2013-11-21 13:01:47 +0900 |
| commit | 772ab7025ddf88126d9d6ddb654f62434985504b (patch) | |
| tree | f0b4558bba2621a824736ceea0b09b51fdd41613 /protocol | |
| parent | 821578293c79c5612f9b77e447295f2947fd6c3d (diff) | |
| parent | a9c3f4750b3d703b8bbbc90db2566afd2aab0ec9 (diff) | |
| download | qmk_firmware-772ab7025ddf88126d9d6ddb654f62434985504b.tar.gz qmk_firmware-772ab7025ddf88126d9d6ddb654f62434985504b.zip | |
Merge branch 'ps2_mouse_fix'
Diffstat (limited to 'protocol')
| -rw-r--r-- | protocol/lufa/lufa.c | 9 | ||||
| -rw-r--r-- | protocol/pjrc.mk | 6 | ||||
| -rw-r--r-- | protocol/ps2.c | 59 | ||||
| -rw-r--r-- | protocol/ps2_mouse.c | 303 | ||||
| -rw-r--r-- | protocol/ps2_mouse.h | 40 | ||||
| -rw-r--r-- | protocol/ps2_usart.c | 54 |
6 files changed, 257 insertions, 214 deletions
diff --git a/protocol/lufa/lufa.c b/protocol/lufa/lufa.c index a230d5ba2..04e8e78f3 100644 --- a/protocol/lufa/lufa.c +++ b/protocol/lufa/lufa.c | |||
| @@ -539,11 +539,18 @@ int main(void) | |||
| 539 | { | 539 | { |
| 540 | SetupHardware(); | 540 | SetupHardware(); |
| 541 | sei(); | 541 | sei(); |
| 542 | |||
| 543 | /* wait for USB startup & debug output */ | ||
| 544 | while (USB_DeviceState != DEVICE_STATE_Configured) { | ||
| 542 | #if defined(INTERRUPT_CONTROL_ENDPOINT) | 545 | #if defined(INTERRUPT_CONTROL_ENDPOINT) |
| 543 | while (USB_DeviceState != DEVICE_STATE_Configured) ; | 546 | ; |
| 547 | #else | ||
| 548 | USB_USBTask(); | ||
| 544 | #endif | 549 | #endif |
| 550 | } | ||
| 545 | print("USB configured.\n"); | 551 | print("USB configured.\n"); |
| 546 | 552 | ||
| 553 | /* init modules */ | ||
| 547 | keyboard_init(); | 554 | keyboard_init(); |
| 548 | host_set_driver(&lufa_driver); | 555 | host_set_driver(&lufa_driver); |
| 549 | #ifdef SLEEP_LED_ENABLE | 556 | #ifdef SLEEP_LED_ENABLE |
diff --git a/protocol/pjrc.mk b/protocol/pjrc.mk index 27f908b1c..5a4461382 100644 --- a/protocol/pjrc.mk +++ b/protocol/pjrc.mk | |||
| @@ -7,7 +7,11 @@ SRC += $(PJRC_DIR)/main.c \ | |||
| 7 | $(PJRC_DIR)/usb.c | 7 | $(PJRC_DIR)/usb.c |
| 8 | 8 | ||
| 9 | # Option modules | 9 | # Option modules |
| 10 | ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE) | 10 | ifdef MOUSEKEY_ENABLE |
| 11 | SRC += $(PJRC_DIR)/usb_mouse.c | ||
| 12 | endif | ||
| 13 | |||
| 14 | ifdef PS2_MOUSE_ENABLE | ||
| 11 | SRC += $(PJRC_DIR)/usb_mouse.c | 15 | SRC += $(PJRC_DIR)/usb_mouse.c |
| 12 | endif | 16 | endif |
| 13 | 17 | ||
diff --git a/protocol/ps2.c b/protocol/ps2.c index ed4560910..e5873a9bf 100644 --- a/protocol/ps2.c +++ b/protocol/ps2.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | Copyright 2010,2011 Jun WAKO <wakojun@gmail.com> | 2 | Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com> |
| 3 | 3 | ||
| 4 | This software is licensed with a Modified BSD License. | 4 | This software is licensed with a Modified BSD License. |
| 5 | All of this is supposed to be Free Software, Open Source, DFSG-free, | 5 | All of this is supposed to be Free Software, Open Source, DFSG-free, |
| @@ -43,7 +43,9 @@ POSSIBILITY OF SUCH DAMAGE. | |||
| 43 | #include "debug.h" | 43 | #include "debug.h" |
| 44 | 44 | ||
| 45 | 45 | ||
| 46 | #ifndef PS2_USE_INT | ||
| 46 | static uint8_t recv_data(void); | 47 | static uint8_t recv_data(void); |
| 48 | #endif | ||
| 47 | static inline void clock_lo(void); | 49 | static inline void clock_lo(void); |
| 48 | static inline void clock_hi(void); | 50 | static inline void clock_hi(void); |
| 49 | static inline bool clock_in(void); | 51 | static inline bool clock_in(void); |
| @@ -109,12 +111,12 @@ uint8_t ps2_host_send(uint8_t data) | |||
| 109 | #endif | 111 | #endif |
| 110 | /* terminate a transmission if we have */ | 112 | /* terminate a transmission if we have */ |
| 111 | inhibit(); | 113 | inhibit(); |
| 112 | _delay_us(100); | 114 | _delay_us(200); // at least 100us |
| 113 | 115 | ||
| 114 | /* start bit [1] */ | 116 | /* start bit [1] */ |
| 115 | data_lo(); | 117 | data_lo(); |
| 116 | clock_hi(); | 118 | clock_hi(); |
| 117 | WAIT(clock_lo, 15000, 1); | 119 | WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking |
| 118 | /* data [2-9] */ | 120 | /* data [2-9] */ |
| 119 | for (uint8_t i = 0; i < 8; i++) { | 121 | for (uint8_t i = 0; i < 8; i++) { |
| 120 | _delay_us(15); | 122 | _delay_us(15); |
| @@ -143,6 +145,9 @@ uint8_t ps2_host_send(uint8_t data) | |||
| 143 | WAIT(clock_hi, 50, 8); | 145 | WAIT(clock_hi, 50, 8); |
| 144 | WAIT(data_hi, 50, 9); | 146 | WAIT(data_hi, 50, 9); |
| 145 | 147 | ||
| 148 | #ifdef PS2_USE_INT | ||
| 149 | PS2_INT_ON(); | ||
| 150 | #endif | ||
| 146 | res = ps2_host_recv_response(); | 151 | res = ps2_host_recv_response(); |
| 147 | ERROR: | 152 | ERROR: |
| 148 | #ifdef PS2_USE_INT | 153 | #ifdef PS2_USE_INT |
| @@ -154,11 +159,15 @@ ERROR: | |||
| 154 | return res; | 159 | return res; |
| 155 | } | 160 | } |
| 156 | 161 | ||
| 162 | #ifndef PS2_USE_INT | ||
| 157 | /* receive data when host want else inhibit communication */ | 163 | /* receive data when host want else inhibit communication */ |
| 158 | uint8_t ps2_host_recv_response(void) | 164 | uint8_t ps2_host_recv_response(void) |
| 159 | { | 165 | { |
| 160 | uint8_t data = 0; | 166 | uint8_t data = 0; |
| 161 | 167 | ||
| 168 | #ifdef PS2_USE_INT | ||
| 169 | PS2_INT_OFF(); | ||
| 170 | #endif | ||
| 162 | /* terminate a transmission if we have */ | 171 | /* terminate a transmission if we have */ |
| 163 | inhibit(); | 172 | inhibit(); |
| 164 | _delay_us(100); | 173 | _delay_us(100); |
| @@ -167,12 +176,13 @@ uint8_t ps2_host_recv_response(void) | |||
| 167 | idle(); | 176 | idle(); |
| 168 | 177 | ||
| 169 | /* wait start bit */ | 178 | /* wait start bit */ |
| 170 | wait_clock_lo(2000); | 179 | wait_clock_lo(25000); // command response may take 20 ms at most |
| 171 | data = recv_data(); | 180 | data = recv_data(); |
| 172 | 181 | ||
| 173 | inhibit(); | 182 | inhibit(); |
| 174 | return data; | 183 | return data; |
| 175 | } | 184 | } |
| 185 | #endif | ||
| 176 | 186 | ||
| 177 | #ifndef PS2_USE_INT | 187 | #ifndef PS2_USE_INT |
| 178 | uint8_t ps2_host_recv(void) | 188 | uint8_t ps2_host_recv(void) |
| @@ -187,9 +197,6 @@ static uint8_t pbuf_head = 0; | |||
| 187 | static uint8_t pbuf_tail = 0; | 197 | static uint8_t pbuf_tail = 0; |
| 188 | static inline void pbuf_enqueue(uint8_t data) | 198 | static inline void pbuf_enqueue(uint8_t data) |
| 189 | { | 199 | { |
| 190 | if (!data) | ||
| 191 | return; | ||
| 192 | |||
| 193 | uint8_t sreg = SREG; | 200 | uint8_t sreg = SREG; |
| 194 | cli(); | 201 | cli(); |
| 195 | uint8_t next = (pbuf_head + 1) % PBUF_SIZE; | 202 | uint8_t next = (pbuf_head + 1) % PBUF_SIZE; |
| @@ -215,6 +222,21 @@ static inline uint8_t pbuf_dequeue(void) | |||
| 215 | 222 | ||
| 216 | return val; | 223 | return val; |
| 217 | } | 224 | } |
| 225 | static inline bool pbuf_has_data(void) | ||
| 226 | { | ||
| 227 | uint8_t sreg = SREG; | ||
| 228 | cli(); | ||
| 229 | bool has_data = (pbuf_head != pbuf_tail); | ||
| 230 | SREG = sreg; | ||
| 231 | return has_data; | ||
| 232 | } | ||
| 233 | static inline void pbuf_clear(void) | ||
| 234 | { | ||
| 235 | uint8_t sreg = SREG; | ||
| 236 | cli(); | ||
| 237 | pbuf_head = pbuf_tail = 0; | ||
| 238 | SREG = sreg; | ||
| 239 | } | ||
| 218 | 240 | ||
| 219 | /* get data received by interrupt */ | 241 | /* get data received by interrupt */ |
| 220 | uint8_t ps2_host_recv(void) | 242 | uint8_t ps2_host_recv(void) |
| @@ -229,13 +251,12 @@ uint8_t ps2_host_recv(void) | |||
| 229 | return pbuf_dequeue(); | 251 | return pbuf_dequeue(); |
| 230 | } | 252 | } |
| 231 | 253 | ||
| 232 | #if 0 | 254 | uint8_t ps2_host_recv_response(void) |
| 233 | #define DEBUGP_INIT() do { DDRC = 0xFF; } while (0) | 255 | { |
| 234 | #define DEBUGP(x) do { PORTC = x; } while (0) | 256 | while (!pbuf_has_data()) ; |
| 235 | #else | 257 | return pbuf_dequeue(); |
| 236 | #define DEBUGP_INIT() | 258 | } |
| 237 | #define DEBUGP(x) | 259 | |
| 238 | #endif | ||
| 239 | ISR(PS2_INT_VECT) | 260 | ISR(PS2_INT_VECT) |
| 240 | { | 261 | { |
| 241 | static enum { | 262 | static enum { |
| @@ -256,7 +277,6 @@ ISR(PS2_INT_VECT) | |||
| 256 | } | 277 | } |
| 257 | 278 | ||
| 258 | state++; | 279 | state++; |
| 259 | DEBUGP(state); | ||
| 260 | switch (state) { | 280 | switch (state) { |
| 261 | case START: | 281 | case START: |
| 262 | if (data_in()) | 282 | if (data_in()) |
| @@ -289,6 +309,7 @@ ISR(PS2_INT_VECT) | |||
| 289 | if (!data_in()) | 309 | if (!data_in()) |
| 290 | goto ERROR; | 310 | goto ERROR; |
| 291 | pbuf_enqueue(data); | 311 | pbuf_enqueue(data); |
| 312 | //phex(data); | ||
| 292 | goto DONE; | 313 | goto DONE; |
| 293 | break; | 314 | break; |
| 294 | default: | 315 | default: |
| @@ -296,7 +317,6 @@ ISR(PS2_INT_VECT) | |||
| 296 | } | 317 | } |
| 297 | goto RETURN; | 318 | goto RETURN; |
| 298 | ERROR: | 319 | ERROR: |
| 299 | DEBUGP(0x0F); | ||
| 300 | inhibit(); | 320 | inhibit(); |
| 301 | ps2_error = state; | 321 | ps2_error = state; |
| 302 | DONE: | 322 | DONE: |
| @@ -309,11 +329,6 @@ RETURN: | |||
| 309 | #endif | 329 | #endif |
| 310 | 330 | ||
| 311 | 331 | ||
| 312 | static void ps2_reset(void) | ||
| 313 | { | ||
| 314 | ps2_host_send(0xFF); | ||
| 315 | } | ||
| 316 | |||
| 317 | /* send LED state to keyboard */ | 332 | /* send LED state to keyboard */ |
| 318 | void ps2_host_set_led(uint8_t led) | 333 | void ps2_host_set_led(uint8_t led) |
| 319 | { | 334 | { |
| @@ -322,6 +337,7 @@ void ps2_host_set_led(uint8_t led) | |||
| 322 | } | 337 | } |
| 323 | 338 | ||
| 324 | 339 | ||
| 340 | #ifndef PS2_USE_INT | ||
| 325 | /* called after start bit comes */ | 341 | /* called after start bit comes */ |
| 326 | static uint8_t recv_data(void) | 342 | static uint8_t recv_data(void) |
| 327 | { | 343 | { |
| @@ -361,6 +377,7 @@ static uint8_t recv_data(void) | |||
| 361 | ERROR: | 377 | ERROR: |
| 362 | return 0; | 378 | return 0; |
| 363 | } | 379 | } |
| 380 | #endif | ||
| 364 | 381 | ||
| 365 | static inline void clock_lo() | 382 | static inline void clock_lo() |
| 366 | { | 383 | { |
diff --git a/protocol/ps2_mouse.c b/protocol/ps2_mouse.c index f796b2b4d..4702f12c4 100644 --- a/protocol/ps2_mouse.c +++ b/protocol/ps2_mouse.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | Copyright 2011 Jun Wako <wakojun@gmail.com> | 2 | Copyright 2011,2013 Jun Wako <wakojun@gmail.com> |
| 3 | 3 | ||
| 4 | This program is free software: you can redistribute it and/or modify | 4 | This program is free software: you can redistribute it and/or modify |
| 5 | it under the terms of the GNU General Public License as published by | 5 | 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/>. | |||
| 20 | #include<util/delay.h> | 20 | #include<util/delay.h> |
| 21 | #include "ps2.h" | 21 | #include "ps2.h" |
| 22 | #include "ps2_mouse.h" | 22 | #include "ps2_mouse.h" |
| 23 | #include "usb_mouse.h" | 23 | #include "report.h" |
| 24 | #include "host.h" | ||
| 25 | #include "timer.h" | ||
| 26 | #include "print.h" | ||
| 27 | #include "debug.h" | ||
| 24 | 28 | ||
| 25 | #define PS2_MOUSE_DEBUG | ||
| 26 | #ifdef PS2_MOUSE_DEBUG | ||
| 27 | # include "print.h" | ||
| 28 | # include "debug.h" | ||
| 29 | #else | ||
| 30 | # define print(s) | ||
| 31 | # define phex(h) | ||
| 32 | # define phex16(h) | ||
| 33 | #endif | ||
| 34 | 29 | ||
| 35 | // disable when errors occur 255 times. | 30 | static report_mouse_t mouse_report = {}; |
| 36 | #define ERROR_RETURN() do { \ | ||
| 37 | if (ps2_error) { \ | ||
| 38 | if (ps2_mouse_error_count < 255) { \ | ||
| 39 | ps2_mouse_error_count++; \ | ||
| 40 | } else { \ | ||
| 41 | ps2_mouse_error_count = 0; \ | ||
| 42 | ps2_mouse_enable = false; \ | ||
| 43 | } \ | ||
| 44 | return ps2_error; \ | ||
| 45 | } \ | ||
| 46 | } while (0) | ||
| 47 | 31 | ||
| 48 | 32 | ||
| 49 | /* | 33 | static void print_usb_data(void); |
| 50 | TODO | ||
| 51 | ---- | ||
| 52 | - Stream mode | ||
| 53 | - Tracpoint command support: needed | ||
| 54 | - Middle button + move = Wheel traslation | ||
| 55 | */ | ||
| 56 | bool ps2_mouse_enable = true; | ||
| 57 | uint8_t ps2_mouse_x = 0; | ||
| 58 | uint8_t ps2_mouse_y = 0; | ||
| 59 | uint8_t ps2_mouse_btn = 0; | ||
| 60 | uint8_t ps2_mouse_error_count = 0; | ||
| 61 | |||
| 62 | static uint8_t ps2_mouse_btn_prev = 0; | ||
| 63 | 34 | ||
| 64 | 35 | ||
| 36 | /* supports only 3 button mouse at this time */ | ||
| 65 | uint8_t ps2_mouse_init(void) { | 37 | uint8_t ps2_mouse_init(void) { |
| 66 | uint8_t rcv; | 38 | uint8_t rcv; |
| 67 | 39 | ||
| 68 | if (!ps2_mouse_enable) return 1; | ||
| 69 | |||
| 70 | ps2_host_init(); | 40 | ps2_host_init(); |
| 71 | 41 | ||
| 72 | // Reset | 42 | _delay_ms(1000); // wait for powering up |
| 73 | rcv = ps2_host_send(0xFF); | ||
| 74 | print("ps2_mouse_init: send 0xFF: "); | ||
| 75 | phex(ps2_error); print("\n"); | ||
| 76 | ERROR_RETURN(); | ||
| 77 | 43 | ||
| 78 | // ACK | 44 | // send Reset |
| 79 | rcv = ps2_host_recv(); | 45 | rcv = ps2_host_send(0xFF); |
| 80 | print("ps2_mouse_init: read ACK: "); | 46 | print("ps2_mouse_init: send Reset: "); |
| 81 | phex(rcv); phex(ps2_error); print("\n"); | 47 | phex(rcv); phex(ps2_error); print("\n"); |
| 82 | ERROR_RETURN(); | ||
| 83 | 48 | ||
| 84 | // BAT takes some time | 49 | // read completion code of BAT |
| 85 | _delay_ms(100); | 50 | rcv = ps2_host_recv_response(); |
| 86 | rcv = ps2_host_recv(); | ||
| 87 | print("ps2_mouse_init: read BAT: "); | 51 | print("ps2_mouse_init: read BAT: "); |
| 88 | phex(rcv); phex(ps2_error); print("\n"); | 52 | phex(rcv); phex(ps2_error); print("\n"); |
| 89 | ERROR_RETURN(); | ||
| 90 | 53 | ||
| 91 | // Device ID | 54 | // read Device ID |
| 92 | rcv = ps2_host_recv(); | 55 | rcv = ps2_host_recv_response(); |
| 93 | print("ps2_mouse_init: read DevID: "); | 56 | print("ps2_mouse_init: read DevID: "); |
| 94 | phex(rcv); phex(ps2_error); print("\n"); | 57 | phex(rcv); phex(ps2_error); print("\n"); |
| 95 | ERROR_RETURN(); | ||
| 96 | 58 | ||
| 97 | // Enable data reporting | 59 | // send Set Remote mode |
| 98 | ps2_host_send(0xF4); | 60 | rcv = ps2_host_send(0xF0); |
| 99 | print("ps2_mouse_init: send 0xF4: "); | ||
| 100 | phex(ps2_error); print("\n"); | ||
| 101 | ERROR_RETURN(); | ||
| 102 | |||
| 103 | // ACK | ||
| 104 | rcv = ps2_host_recv(); | ||
| 105 | print("ps2_mouse_init: read ACK: "); | ||
| 106 | phex(rcv); phex(ps2_error); print("\n"); | ||
| 107 | ERROR_RETURN(); | ||
| 108 | |||
| 109 | // Set Remote mode | ||
| 110 | ps2_host_send(0xF0); | ||
| 111 | print("ps2_mouse_init: send 0xF0: "); | 61 | print("ps2_mouse_init: send 0xF0: "); |
| 112 | phex(ps2_error); print("\n"); | ||
| 113 | ERROR_RETURN(); | ||
| 114 | |||
| 115 | // ACK | ||
| 116 | rcv = ps2_host_recv(); | ||
| 117 | print("ps2_mouse_init: read ACK: "); | ||
| 118 | phex(rcv); phex(ps2_error); print("\n"); | 62 | phex(rcv); phex(ps2_error); print("\n"); |
| 119 | ERROR_RETURN(); | ||
| 120 | 63 | ||
| 121 | return 0; | 64 | return 0; |
| 122 | } | 65 | } |
| 123 | 66 | ||
| 124 | /* | 67 | #define X_IS_NEG (mouse_report.buttons & (1<<PS2_MOUSE_X_SIGN)) |
| 125 | Data format: | 68 | #define Y_IS_NEG (mouse_report.buttons & (1<<PS2_MOUSE_Y_SIGN)) |
| 126 | bit: 7 6 5 4 3 2 1 0 | 69 | #define X_IS_OVF (mouse_report.buttons & (1<<PS2_MOUSE_X_OVFLW)) |
| 127 | ----------------------------------------------------------------------- | 70 | #define Y_IS_OVF (mouse_report.buttons & (1<<PS2_MOUSE_Y_OVFLW)) |
| 128 | 0 btn: Yovflw Xovflw Ysign Xsign 1 Middle Right Left | 71 | void ps2_mouse_task(void) |
| 129 | 1 x: X movement(0-255) | ||
| 130 | 2 y: Y movement(0-255) | ||
| 131 | */ | ||
| 132 | uint8_t ps2_mouse_read(void) | ||
| 133 | { | 72 | { |
| 73 | enum { SCROLL_NONE, SCROLL_BTN, SCROLL_SENT }; | ||
| 74 | static uint8_t scroll_state = SCROLL_NONE; | ||
| 75 | static uint8_t buttons_prev = 0; | ||
| 76 | |||
| 77 | /* receives packet from mouse */ | ||
| 134 | uint8_t rcv; | 78 | uint8_t rcv; |
| 79 | rcv = ps2_host_send(PS2_MOUSE_READ_DATA); | ||
| 80 | if (rcv == PS2_ACK) { | ||
| 81 | mouse_report.buttons = ps2_host_recv_response(); | ||
| 82 | mouse_report.x = ps2_host_recv_response(); | ||
| 83 | mouse_report.y = ps2_host_recv_response(); | ||
| 84 | } else { | ||
| 85 | if (!debug_mouse) print("ps2_mouse: fail to get mouse packet\n"); | ||
| 86 | return; | ||
| 87 | } | ||
| 135 | 88 | ||
| 136 | if (!ps2_mouse_enable) return 1; | 89 | /* if mouse moves or buttons state changes */ |
| 90 | if (mouse_report.x || mouse_report.y || | ||
| 91 | ((mouse_report.buttons ^ buttons_prev) & PS2_MOUSE_BTN_MASK)) { | ||
| 137 | 92 | ||
| 138 | ps2_host_send(0xEB); | 93 | #ifdef PS2_MOUSE_DEBUG |
| 139 | ERROR_RETURN(); | 94 | print("ps2_mouse raw: ["); |
| 95 | phex(mouse_report.buttons); print("|"); | ||
| 96 | print_hex8((uint8_t)mouse_report.x); print(" "); | ||
| 97 | print_hex8((uint8_t)mouse_report.y); print("]\n"); | ||
| 98 | #endif | ||
| 140 | 99 | ||
| 141 | rcv=ps2_host_recv(); | 100 | buttons_prev = mouse_report.buttons; |
| 142 | ERROR_RETURN(); | 101 | |
| 102 | // PS/2 mouse data is '9-bit integer'(-256 to 255) which is comprised of sign-bit and 8-bit value. | ||
| 103 | // bit: 8 7 ... 0 | ||
| 104 | // sign \8-bit/ | ||
| 105 | // | ||
| 106 | // Meanwhile USB HID mouse indicates 8bit data(-127 to 127), note that -128 is not used. | ||
| 107 | // | ||
| 108 | // This converts PS/2 data into HID value. Use only -127-127 out of PS/2 9-bit. | ||
| 109 | mouse_report.x = X_IS_NEG ? | ||
| 110 | ((!X_IS_OVF && -127 <= mouse_report.x && mouse_report.x <= -1) ? mouse_report.x : -127) : | ||
| 111 | ((!X_IS_OVF && 0 <= mouse_report.x && mouse_report.x <= 127) ? mouse_report.x : 127); | ||
| 112 | mouse_report.y = Y_IS_NEG ? | ||
| 113 | ((!Y_IS_OVF && -127 <= mouse_report.y && mouse_report.y <= -1) ? mouse_report.y : -127) : | ||
| 114 | ((!Y_IS_OVF && 0 <= mouse_report.y && mouse_report.y <= 127) ? mouse_report.y : 127); | ||
| 115 | |||
| 116 | // remove sign and overflow flags | ||
| 117 | mouse_report.buttons &= PS2_MOUSE_BTN_MASK; | ||
| 118 | |||
| 119 | // invert coordinate of y to conform to USB HID mouse | ||
| 120 | mouse_report.y = -mouse_report.y; | ||
| 121 | |||
| 122 | |||
| 123 | #if PS2_MOUSE_SCROLL_BTN_MASK | ||
| 124 | static uint16_t scroll_button_time = 0; | ||
| 125 | if ((mouse_report.buttons & (PS2_MOUSE_SCROLL_BTN_MASK)) == (PS2_MOUSE_SCROLL_BTN_MASK)) { | ||
| 126 | if (scroll_state == SCROLL_NONE) { | ||
| 127 | scroll_button_time = timer_read(); | ||
| 128 | scroll_state = SCROLL_BTN; | ||
| 129 | } | ||
| 143 | 130 | ||
| 144 | if(rcv==0xFA) { | 131 | // doesn't send Scroll Button |
| 145 | ps2_mouse_btn = ps2_host_recv(); | 132 | //mouse_report.buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK); |
| 146 | ERROR_RETURN(); | ||
| 147 | ps2_mouse_x = ps2_host_recv(); | ||
| 148 | ERROR_RETURN(); | ||
| 149 | ps2_mouse_y = ps2_host_recv(); | ||
| 150 | ERROR_RETURN(); | ||
| 151 | } | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | 133 | ||
| 155 | bool ps2_mouse_changed(void) | 134 | if (mouse_report.x || mouse_report.y) { |
| 156 | { | 135 | scroll_state = SCROLL_SENT; |
| 157 | return (ps2_mouse_x || ps2_mouse_y || (ps2_mouse_btn & PS2_MOUSE_BTN_MASK) != ps2_mouse_btn_prev); | ||
| 158 | } | ||
| 159 | 136 | ||
| 160 | #define PS2_MOUSE_SCROLL_BUTTON 0x04 | 137 | mouse_report.v = -mouse_report.y/(PS2_MOUSE_SCROLL_DIVISOR_V); |
| 161 | void ps2_mouse_usb_send(void) | 138 | mouse_report.h = mouse_report.x/(PS2_MOUSE_SCROLL_DIVISOR_H); |
| 162 | { | 139 | mouse_report.x = 0; |
| 163 | static bool scrolled = false; | 140 | mouse_report.y = 0; |
| 164 | 141 | //host_mouse_send(&mouse_report); | |
| 165 | if (!ps2_mouse_enable) return; | 142 | } |
| 166 | 143 | } | |
| 167 | if (ps2_mouse_changed()) { | 144 | else if ((mouse_report.buttons & (PS2_MOUSE_SCROLL_BTN_MASK)) == 0) { |
| 168 | int8_t x, y, v, h; | 145 | #if PS2_MOUSE_SCROLL_BTN_SEND |
| 169 | x = y = v = h = 0; | 146 | if (scroll_state == SCROLL_BTN && |
| 170 | 147 | TIMER_DIFF_16(timer_read(), scroll_button_time) < PS2_MOUSE_SCROLL_BTN_SEND) { | |
| 171 | // convert scale of X, Y: PS/2(-256/255) -> USB(-127/127) | 148 | // send Scroll Button(down and up at once) when not scrolled |
| 172 | if (ps2_mouse_btn & (1<<PS2_MOUSE_X_SIGN)) | 149 | mouse_report.buttons |= (PS2_MOUSE_SCROLL_BTN_MASK); |
| 173 | x = ps2_mouse_x > 128 ? (int8_t)ps2_mouse_x : -127; | 150 | host_mouse_send(&mouse_report); |
| 174 | else | ||
| 175 | x = ps2_mouse_x < 128 ? (int8_t)ps2_mouse_x : 127; | ||
| 176 | |||
| 177 | if (ps2_mouse_btn & (1<<PS2_MOUSE_Y_SIGN)) | ||
| 178 | y = ps2_mouse_y > 128 ? (int8_t)ps2_mouse_y : -127; | ||
| 179 | else | ||
| 180 | y = ps2_mouse_y < 128 ? (int8_t)ps2_mouse_y : 127; | ||
| 181 | |||
| 182 | // Y is needed to reverse | ||
| 183 | y = -y; | ||
| 184 | |||
| 185 | if (ps2_mouse_btn & PS2_MOUSE_SCROLL_BUTTON) { | ||
| 186 | // scroll | ||
| 187 | if (x > 0 || x < 0) h = (x > 64 ? 64 : (x < -64 ? -64 :x)); | ||
| 188 | if (y > 0 || y < 0) v = (y > 64 ? 64 : (y < -64 ? -64 :y)); | ||
| 189 | if (h || v) { | ||
| 190 | scrolled = true; | ||
| 191 | usb_mouse_send(0,0, -v/16, h/16, 0); | ||
| 192 | _delay_ms(100); | 151 | _delay_ms(100); |
| 152 | mouse_report.buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK); | ||
| 193 | } | 153 | } |
| 194 | } else if (!scrolled && (ps2_mouse_btn_prev & PS2_MOUSE_SCROLL_BUTTON)) { | 154 | #endif |
| 195 | usb_mouse_send(0,0,0,0, PS2_MOUSE_SCROLL_BUTTON); | 155 | scroll_state = SCROLL_NONE; |
| 196 | _delay_ms(100); | ||
| 197 | usb_mouse_send(0,0,0,0, 0); | ||
| 198 | } else { | ||
| 199 | scrolled = false; | ||
| 200 | usb_mouse_send(x, y, 0, 0, ps2_mouse_btn & PS2_MOUSE_BTN_MASK); | ||
| 201 | } | 156 | } |
| 157 | // doesn't send Scroll Button | ||
| 158 | mouse_report.buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK); | ||
| 159 | #endif | ||
| 160 | |||
| 202 | 161 | ||
| 203 | ps2_mouse_btn_prev = (ps2_mouse_btn & PS2_MOUSE_BTN_MASK); | 162 | host_mouse_send(&mouse_report); |
| 204 | ps2_mouse_print(); | 163 | print_usb_data(); |
| 205 | } | 164 | } |
| 206 | ps2_mouse_x = 0; | 165 | // clear report |
| 207 | ps2_mouse_y = 0; | 166 | mouse_report.x = 0; |
| 208 | ps2_mouse_btn = 0; | 167 | mouse_report.y = 0; |
| 168 | mouse_report.v = 0; | ||
| 169 | mouse_report.h = 0; | ||
| 170 | mouse_report.buttons = 0; | ||
| 209 | } | 171 | } |
| 210 | 172 | ||
| 211 | void ps2_mouse_print(void) | 173 | static void print_usb_data(void) |
| 212 | { | 174 | { |
| 213 | if (!debug_mouse) return; | 175 | if (!debug_mouse) return; |
| 214 | print("ps2_mouse[btn|x y]: "); | 176 | print("ps2_mouse usb: ["); |
| 215 | phex(ps2_mouse_btn); print("|"); | 177 | phex(mouse_report.buttons); print("|"); |
| 216 | phex(ps2_mouse_x); print(" "); | 178 | print_hex8((uint8_t)mouse_report.x); print(" "); |
| 217 | phex(ps2_mouse_y); print("\n"); | 179 | print_hex8((uint8_t)mouse_report.y); print(" "); |
| 180 | print_hex8((uint8_t)mouse_report.v); print(" "); | ||
| 181 | print_hex8((uint8_t)mouse_report.h); print("]\n"); | ||
| 218 | } | 182 | } |
| 183 | |||
| 184 | |||
| 185 | /* PS/2 Mouse Synopsis | ||
| 186 | * http://www.computer-engineering.org/ps2mouse/ | ||
| 187 | * | ||
| 188 | * Command: | ||
| 189 | * 0xFF: Reset | ||
| 190 | * 0xF6: Set Defaults Sampling; rate=100, resolution=4cnt/mm, scaling=1:1, reporting=disabled | ||
| 191 | * 0xF5: Disable Data Reporting | ||
| 192 | * 0xF4: Enable Data Reporting | ||
| 193 | * 0xF3: Set Sample Rate | ||
| 194 | * 0xF2: Get Device ID | ||
| 195 | * 0xF0: Set Remote Mode | ||
| 196 | * 0xEB: Read Data | ||
| 197 | * 0xEA: Set Stream Mode | ||
| 198 | * 0xE9: Status Request | ||
| 199 | * 0xE8: Set Resolution | ||
| 200 | * 0xE7: Set Scaling 2:1 | ||
| 201 | * 0xE6: Set Scaling 1:1 | ||
| 202 | * | ||
| 203 | * Mode: | ||
| 204 | * Stream Mode: devices sends the data when it changs its state | ||
| 205 | * Remote Mode: host polls the data periodically | ||
| 206 | * | ||
| 207 | * This code uses Remote Mode and polls the data with Read Data(0xEB). | ||
| 208 | * | ||
| 209 | * Data format: | ||
| 210 | * byte|7 6 5 4 3 2 1 0 | ||
| 211 | * ----+-------------------------------------------------------------- | ||
| 212 | * 0|Yovflw Xovflw Ysign Xsign 1 Middle Right Left | ||
| 213 | * 1| X movement | ||
| 214 | * 2| Y movement | ||
| 215 | */ | ||
diff --git a/protocol/ps2_mouse.h b/protocol/ps2_mouse.h index 4529ce113..27d9790d4 100644 --- a/protocol/ps2_mouse.h +++ b/protocol/ps2_mouse.h | |||
| @@ -20,6 +20,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 20 | 20 | ||
| 21 | #include <stdbool.h> | 21 | #include <stdbool.h> |
| 22 | 22 | ||
| 23 | #define PS2_MOUSE_READ_DATA 0xEB | ||
| 24 | |||
| 25 | /* | ||
| 26 | * Data format: | ||
| 27 | * byte|7 6 5 4 3 2 1 0 | ||
| 28 | * ----+-------------------------------------------------------------- | ||
| 29 | * 0|Yovflw Xovflw Ysign Xsign 1 Middle Right Left | ||
| 30 | * 1| X movement(0-255) | ||
| 31 | * 2| Y movement(0-255) | ||
| 32 | */ | ||
| 23 | #define PS2_MOUSE_BTN_MASK 0x07 | 33 | #define PS2_MOUSE_BTN_MASK 0x07 |
| 24 | #define PS2_MOUSE_BTN_LEFT 0 | 34 | #define PS2_MOUSE_BTN_LEFT 0 |
| 25 | #define PS2_MOUSE_BTN_RIGHT 1 | 35 | #define PS2_MOUSE_BTN_RIGHT 1 |
| @@ -29,16 +39,28 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 29 | #define PS2_MOUSE_X_OVFLW 6 | 39 | #define PS2_MOUSE_X_OVFLW 6 |
| 30 | #define PS2_MOUSE_Y_OVFLW 7 | 40 | #define PS2_MOUSE_Y_OVFLW 7 |
| 31 | 41 | ||
| 32 | bool ps2_mouse_enable; | 42 | |
| 33 | extern uint8_t ps2_mouse_x; | 43 | /* |
| 34 | extern uint8_t ps2_mouse_y; | 44 | * Scroll by mouse move with pressing button |
| 35 | extern uint8_t ps2_mouse_btn; | 45 | */ |
| 36 | extern uint8_t ps2_mouse_error_count; | 46 | /* mouse button to start scrolling; set 0 to disable scroll */ |
| 47 | #ifndef PS2_MOUSE_SCROLL_BTN_MASK | ||
| 48 | #define PS2_MOUSE_SCROLL_BTN_MASK (1<<PS2_MOUSE_BTN_MIDDLE) | ||
| 49 | #endif | ||
| 50 | /* send button event when button is released within this value(ms); set 0 to disable */ | ||
| 51 | #ifndef PS2_MOUSE_SCROLL_BTN_SEND | ||
| 52 | #define PS2_MOUSE_SCROLL_BTN_SEND 300 | ||
| 53 | #endif | ||
| 54 | /* divide virtical and horizontal mouse move by this to convert to scroll move */ | ||
| 55 | #ifndef PS2_MOUSE_SCROLL_DIVISOR_V | ||
| 56 | #define PS2_MOUSE_SCROLL_DIVISOR_V 2 | ||
| 57 | #endif | ||
| 58 | #ifndef PS2_MOUSE_SCROLL_DIVISOR_H | ||
| 59 | #define PS2_MOUSE_SCROLL_DIVISOR_H 2 | ||
| 60 | #endif | ||
| 61 | |||
| 37 | 62 | ||
| 38 | uint8_t ps2_mouse_init(void); | 63 | uint8_t ps2_mouse_init(void); |
| 39 | uint8_t ps2_mouse_read(void); | 64 | void ps2_mouse_task(void); |
| 40 | bool ps2_mouse_changed(void); | ||
| 41 | void ps2_mouse_usb_send(void); | ||
| 42 | void ps2_mouse_print(void); | ||
| 43 | 65 | ||
| 44 | #endif | 66 | #endif |
diff --git a/protocol/ps2_usart.c b/protocol/ps2_usart.c index 9ea6b7786..40c46c497 100644 --- a/protocol/ps2_usart.c +++ b/protocol/ps2_usart.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | Copyright 2010,2011 Jun WAKO <wakojun@gmail.com> | 2 | Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com> |
| 3 | 3 | ||
| 4 | This software is licensed with a Modified BSD License. | 4 | This software is licensed with a Modified BSD License. |
| 5 | All of this is supposed to be Free Software, Open Source, DFSG-free, | 5 | 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 | |||
| 64 | #include "debug.h" | 64 | #include "debug.h" |
| 65 | 65 | ||
| 66 | 66 | ||
| 67 | #if 0 | ||
| 68 | #define DEBUGP_INIT() do { DDRC = 0xFF; } while (0) | ||
| 69 | #define DEBUGP(x) do { PORTC = x; } while (0) | ||
| 70 | #else | ||
| 71 | #define DEBUGP_INIT() | ||
| 72 | #define DEBUGP(x) | ||
| 73 | #endif | ||
| 74 | |||
| 75 | #define WAIT(stat, us, err) do { \ | 67 | #define WAIT(stat, us, err) do { \ |
| 76 | if (!wait_##stat(us)) { \ | 68 | if (!wait_##stat(us)) { \ |
| 77 | ps2_error = err; \ | 69 | ps2_error = err; \ |
| @@ -97,12 +89,12 @@ static inline void idle(void); | |||
| 97 | static inline void inhibit(void); | 89 | static inline void inhibit(void); |
| 98 | static inline uint8_t pbuf_dequeue(void); | 90 | static inline uint8_t pbuf_dequeue(void); |
| 99 | static inline void pbuf_enqueue(uint8_t data); | 91 | static inline void pbuf_enqueue(uint8_t data); |
| 92 | static inline bool pbuf_has_data(void); | ||
| 93 | static inline void pbuf_clear(void); | ||
| 100 | 94 | ||
| 101 | 95 | ||
| 102 | void ps2_host_init(void) | 96 | void ps2_host_init(void) |
| 103 | { | 97 | { |
| 104 | DEBUGP_INIT(); | ||
| 105 | DEBUGP(0x1); | ||
| 106 | idle(); | 98 | idle(); |
| 107 | PS2_USART_INIT(); | 99 | PS2_USART_INIT(); |
| 108 | PS2_USART_RX_INT_ON(); | 100 | PS2_USART_RX_INT_ON(); |
| @@ -114,7 +106,6 @@ uint8_t ps2_host_send(uint8_t data) | |||
| 114 | bool parity = true; | 106 | bool parity = true; |
| 115 | ps2_error = PS2_ERR_NONE; | 107 | ps2_error = PS2_ERR_NONE; |
| 116 | 108 | ||
| 117 | DEBUGP(0x6); | ||
| 118 | PS2_USART_OFF(); | 109 | PS2_USART_OFF(); |
| 119 | 110 | ||
| 120 | /* terminate a transmission if we have */ | 111 | /* terminate a transmission if we have */ |
| @@ -153,6 +144,8 @@ uint8_t ps2_host_send(uint8_t data) | |||
| 153 | WAIT(clock_hi, 50, 8); | 144 | WAIT(clock_hi, 50, 8); |
| 154 | WAIT(data_hi, 50, 9); | 145 | WAIT(data_hi, 50, 9); |
| 155 | 146 | ||
| 147 | PS2_USART_INIT(); | ||
| 148 | PS2_USART_RX_INT_ON(); | ||
| 156 | res = ps2_host_recv_response(); | 149 | res = ps2_host_recv_response(); |
| 157 | ERROR: | 150 | ERROR: |
| 158 | idle(); | 151 | idle(); |
| @@ -164,15 +157,10 @@ ERROR: | |||
| 164 | // Do polling data from keyboard to get response to last command. | 157 | // Do polling data from keyboard to get response to last command. |
| 165 | uint8_t ps2_host_recv_response(void) | 158 | uint8_t ps2_host_recv_response(void) |
| 166 | { | 159 | { |
| 167 | uint8_t data = 0; | 160 | while (!pbuf_has_data()) { |
| 168 | PS2_USART_INIT(); | 161 | _delay_ms(1); // without this delay it seems to fall into deadlock |
| 169 | PS2_USART_RX_POLL_ON(); | 162 | } |
| 170 | while (!PS2_USART_RX_READY) | 163 | return pbuf_dequeue(); |
| 171 | ; | ||
| 172 | data = PS2_USART_RX_DATA; | ||
| 173 | PS2_USART_OFF(); | ||
| 174 | DEBUGP(0x9); | ||
| 175 | return data; | ||
| 176 | } | 164 | } |
| 177 | 165 | ||
| 178 | uint8_t ps2_host_recv(void) | 166 | uint8_t ps2_host_recv(void) |
| @@ -182,15 +170,11 @@ uint8_t ps2_host_recv(void) | |||
| 182 | 170 | ||
| 183 | ISR(PS2_USART_RX_VECT) | 171 | ISR(PS2_USART_RX_VECT) |
| 184 | { | 172 | { |
| 185 | DEBUGP(0x7); | ||
| 186 | uint8_t error = PS2_USART_ERROR; | 173 | uint8_t error = PS2_USART_ERROR; |
| 187 | uint8_t data = PS2_USART_RX_DATA; | 174 | uint8_t data = PS2_USART_RX_DATA; |
| 188 | if (error) { | 175 | if (!error) { |
| 189 | DEBUGP(error>>2); | ||
| 190 | } else { | ||
| 191 | pbuf_enqueue(data); | 176 | pbuf_enqueue(data); |
| 192 | } | 177 | } |
| 193 | DEBUGP(0x8); | ||
| 194 | } | 178 | } |
| 195 | 179 | ||
| 196 | /* send LED state to keyboard */ | 180 | /* send LED state to keyboard */ |
| @@ -293,9 +277,6 @@ static uint8_t pbuf_head = 0; | |||
| 293 | static uint8_t pbuf_tail = 0; | 277 | static uint8_t pbuf_tail = 0; |
| 294 | static inline void pbuf_enqueue(uint8_t data) | 278 | static inline void pbuf_enqueue(uint8_t data) |
| 295 | { | 279 | { |
| 296 | if (!data) | ||
| 297 | return; | ||
| 298 | |||
| 299 | uint8_t sreg = SREG; | 280 | uint8_t sreg = SREG; |
| 300 | cli(); | 281 | cli(); |
| 301 | uint8_t next = (pbuf_head + 1) % PBUF_SIZE; | 282 | uint8_t next = (pbuf_head + 1) % PBUF_SIZE; |
| @@ -322,3 +303,18 @@ static inline uint8_t pbuf_dequeue(void) | |||
| 322 | 303 | ||
| 323 | return val; | 304 | return val; |
| 324 | } | 305 | } |
| 306 | static inline bool pbuf_has_data(void) | ||
| 307 | { | ||
| 308 | uint8_t sreg = SREG; | ||
| 309 | cli(); | ||
| 310 | bool has_data = (pbuf_head != pbuf_tail); | ||
| 311 | SREG = sreg; | ||
| 312 | return has_data; | ||
| 313 | } | ||
| 314 | static inline void pbuf_clear(void) | ||
| 315 | { | ||
| 316 | uint8_t sreg = SREG; | ||
| 317 | cli(); | ||
| 318 | pbuf_head = pbuf_tail = 0; | ||
| 319 | SREG = sreg; | ||
| 320 | } | ||
