Relocate PS2 code (#14895)
* Relocate ps2 protocol code * clang * Move makefile logic
This commit is contained in:
		
							parent
							
								
									5500c428dd
								
							
						
					
					
						commit
						d4be4b67a2
					
				
					 11 changed files with 38 additions and 32 deletions
				
			
		
							
								
								
									
										139
									
								
								drivers/ps2/ps2.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								drivers/ps2/ps2.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,139 @@ | |||
| /*
 | ||||
| Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com> | ||||
| 
 | ||||
| This software is licensed with a Modified BSD License. | ||||
| All of this is supposed to be Free Software, Open Source, DFSG-free, | ||||
| GPL-compatible, and OK to use in both free and proprietary applications. | ||||
| Additions and corrections to this file are welcome. | ||||
| 
 | ||||
| 
 | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
| 
 | ||||
| * Redistributions of source code must retain the above copyright | ||||
|   notice, this list of conditions and the following disclaimer. | ||||
| 
 | ||||
| * Redistributions in binary form must reproduce the above copyright | ||||
|   notice, this list of conditions and the following disclaimer in | ||||
|   the documentation and/or other materials provided with the | ||||
|   distribution. | ||||
| 
 | ||||
| * Neither the name of the copyright holders nor the names of | ||||
|   contributors may be used to endorse or promote products derived | ||||
|   from this software without specific prior written permission. | ||||
| 
 | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||||
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
| POSSIBILITY OF SUCH DAMAGE. | ||||
| */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include "wait.h" | ||||
| #include "ps2_io.h" | ||||
| #include "print.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * Primitive PS/2 Library for AVR | ||||
|  * | ||||
|  * PS/2 Resources | ||||
|  * -------------- | ||||
|  * [1] The PS/2 Mouse/Keyboard Protocol | ||||
|  * http://www.computer-engineering.org/ps2protocol/
 | ||||
|  * Concise and thorough primer of PS/2 protocol. | ||||
|  * | ||||
|  * [2] Keyboard and Auxiliary Device Controller | ||||
|  * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
 | ||||
|  * Signal Timing and Format | ||||
|  * | ||||
|  * [3] Keyboards(101- and 102-key) | ||||
|  * http://www.mcamafia.de/pdf/ibm_hitrc11.pdf
 | ||||
|  * Keyboard Layout, Scan Code Set, POR, and Commands. | ||||
|  * | ||||
|  * [4] PS/2 Reference Manuals | ||||
|  * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
 | ||||
|  * Collection of IBM Personal System/2 documents. | ||||
|  * | ||||
|  * [5] TrackPoint Engineering Specifications for version 3E | ||||
|  * https://web.archive.org/web/20100526161812/http://wwwcssrv.almaden.ibm.com/trackpoint/download.html
 | ||||
|  */ | ||||
| #define PS2_ACK 0xFA | ||||
| #define PS2_RESEND 0xFE | ||||
| #define PS2_SET_LED 0xED | ||||
| 
 | ||||
| // TODO: error numbers
 | ||||
| #define PS2_ERR_NONE 0 | ||||
| #define PS2_ERR_STARTBIT1 1 | ||||
| #define PS2_ERR_STARTBIT2 2 | ||||
| #define PS2_ERR_STARTBIT3 3 | ||||
| #define PS2_ERR_PARITY 0x10 | ||||
| #define PS2_ERR_NODATA 0x20 | ||||
| 
 | ||||
| #define PS2_LED_SCROLL_LOCK 0 | ||||
| #define PS2_LED_NUM_LOCK 1 | ||||
| #define PS2_LED_CAPS_LOCK 2 | ||||
| 
 | ||||
| extern uint8_t ps2_error; | ||||
| 
 | ||||
| void    ps2_host_init(void); | ||||
| uint8_t ps2_host_send(uint8_t data); | ||||
| uint8_t ps2_host_recv_response(void); | ||||
| uint8_t ps2_host_recv(void); | ||||
| void    ps2_host_set_led(uint8_t usb_led); | ||||
| 
 | ||||
| /*--------------------------------------------------------------------
 | ||||
|  * static functions | ||||
|  *------------------------------------------------------------------*/ | ||||
| static inline uint16_t wait_clock_lo(uint16_t us) { | ||||
|     while (clock_in() && us) { | ||||
|         asm(""); | ||||
|         wait_us(1); | ||||
|         us--; | ||||
|     } | ||||
|     return us; | ||||
| } | ||||
| static inline uint16_t wait_clock_hi(uint16_t us) { | ||||
|     while (!clock_in() && us) { | ||||
|         asm(""); | ||||
|         wait_us(1); | ||||
|         us--; | ||||
|     } | ||||
|     return us; | ||||
| } | ||||
| static inline uint16_t wait_data_lo(uint16_t us) { | ||||
|     while (data_in() && us) { | ||||
|         asm(""); | ||||
|         wait_us(1); | ||||
|         us--; | ||||
|     } | ||||
|     return us; | ||||
| } | ||||
| static inline uint16_t wait_data_hi(uint16_t us) { | ||||
|     while (!data_in() && us) { | ||||
|         asm(""); | ||||
|         wait_us(1); | ||||
|         us--; | ||||
|     } | ||||
|     return us; | ||||
| } | ||||
| 
 | ||||
| /* idle state that device can send */ | ||||
| static inline void idle(void) { | ||||
|     clock_hi(); | ||||
|     data_hi(); | ||||
| } | ||||
| 
 | ||||
| /* inhibit device to send */ | ||||
| static inline void inhibit(void) { | ||||
|     clock_lo(); | ||||
|     data_hi(); | ||||
| } | ||||
							
								
								
									
										187
									
								
								drivers/ps2/ps2_busywait.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								drivers/ps2/ps2_busywait.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,187 @@ | |||
| /*
 | ||||
| Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com> | ||||
| 
 | ||||
| This software is licensed with a Modified BSD License. | ||||
| All of this is supposed to be Free Software, Open Source, DFSG-free, | ||||
| GPL-compatible, and OK to use in both free and proprietary applications. | ||||
| Additions and corrections to this file are welcome. | ||||
| 
 | ||||
| 
 | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
| 
 | ||||
| * Redistributions of source code must retain the above copyright | ||||
|   notice, this list of conditions and the following disclaimer. | ||||
| 
 | ||||
| * Redistributions in binary form must reproduce the above copyright | ||||
|   notice, this list of conditions and the following disclaimer in | ||||
|   the documentation and/or other materials provided with the | ||||
|   distribution. | ||||
| 
 | ||||
| * Neither the name of the copyright holders nor the names of | ||||
|   contributors may be used to endorse or promote products derived | ||||
|   from this software without specific prior written permission. | ||||
| 
 | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||||
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
| POSSIBILITY OF SUCH DAMAGE. | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|  * PS/2 protocol busywait version | ||||
|  */ | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include "wait.h" | ||||
| #include "ps2.h" | ||||
| #include "ps2_io.h" | ||||
| #include "debug.h" | ||||
| 
 | ||||
| #define WAIT(stat, us, err)     \ | ||||
|     do {                        \ | ||||
|         if (!wait_##stat(us)) { \ | ||||
|             ps2_error = err;    \ | ||||
|             goto ERROR;         \ | ||||
|         }                       \ | ||||
|     } while (0) | ||||
| 
 | ||||
| uint8_t ps2_error = PS2_ERR_NONE; | ||||
| 
 | ||||
| void ps2_host_init(void) { | ||||
|     clock_init(); | ||||
|     data_init(); | ||||
| 
 | ||||
|     // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
 | ||||
|     wait_ms(2500); | ||||
| 
 | ||||
|     inhibit(); | ||||
| } | ||||
| 
 | ||||
| uint8_t ps2_host_send(uint8_t data) { | ||||
|     bool parity = true; | ||||
|     ps2_error   = PS2_ERR_NONE; | ||||
| 
 | ||||
|     /* terminate a transmission if we have */ | ||||
|     inhibit(); | ||||
|     wait_us(100);  // 100us [4]p.13, [5]p.50
 | ||||
| 
 | ||||
|     /* 'Request to Send' and Start bit */ | ||||
|     data_lo(); | ||||
|     clock_hi(); | ||||
|     WAIT(clock_lo, 10000, 10);  // 10ms [5]p.50
 | ||||
| 
 | ||||
|     /* Data bit */ | ||||
|     for (uint8_t i = 0; i < 8; i++) { | ||||
|         wait_us(15); | ||||
|         if (data & (1 << i)) { | ||||
|             parity = !parity; | ||||
|             data_hi(); | ||||
|         } else { | ||||
|             data_lo(); | ||||
|         } | ||||
|         WAIT(clock_hi, 50, 2); | ||||
|         WAIT(clock_lo, 50, 3); | ||||
|     } | ||||
| 
 | ||||
|     /* Parity bit */ | ||||
|     wait_us(15); | ||||
|     if (parity) { | ||||
|         data_hi(); | ||||
|     } else { | ||||
|         data_lo(); | ||||
|     } | ||||
|     WAIT(clock_hi, 50, 4); | ||||
|     WAIT(clock_lo, 50, 5); | ||||
| 
 | ||||
|     /* Stop bit */ | ||||
|     wait_us(15); | ||||
|     data_hi(); | ||||
| 
 | ||||
|     /* Ack */ | ||||
|     WAIT(data_lo, 50, 6); | ||||
|     WAIT(clock_lo, 50, 7); | ||||
| 
 | ||||
|     /* wait for idle state */ | ||||
|     WAIT(clock_hi, 50, 8); | ||||
|     WAIT(data_hi, 50, 9); | ||||
| 
 | ||||
|     inhibit(); | ||||
|     return ps2_host_recv_response(); | ||||
| ERROR: | ||||
|     inhibit(); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /* receive data when host want else inhibit communication */ | ||||
| uint8_t ps2_host_recv_response(void) { | ||||
|     // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
 | ||||
|     // 250 * 100us(wait for start bit in ps2_host_recv)
 | ||||
|     uint8_t data = 0; | ||||
|     uint8_t try | ||||
|         = 250; | ||||
|     do { | ||||
|         data = ps2_host_recv(); | ||||
|     } while (try --&&ps2_error); | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| /* called after start bit comes */ | ||||
| uint8_t ps2_host_recv(void) { | ||||
|     uint8_t data   = 0; | ||||
|     bool    parity = true; | ||||
|     ps2_error      = PS2_ERR_NONE; | ||||
| 
 | ||||
|     /* release lines(idle state) */ | ||||
|     idle(); | ||||
| 
 | ||||
|     /* start bit [1] */ | ||||
|     WAIT(clock_lo, 100, 1);  // TODO: this is enough?
 | ||||
|     WAIT(data_lo, 1, 2); | ||||
|     WAIT(clock_hi, 50, 3); | ||||
| 
 | ||||
|     /* data [2-9] */ | ||||
|     for (uint8_t i = 0; i < 8; i++) { | ||||
|         WAIT(clock_lo, 50, 4); | ||||
|         if (data_in()) { | ||||
|             parity = !parity; | ||||
|             data |= (1 << i); | ||||
|         } | ||||
|         WAIT(clock_hi, 50, 5); | ||||
|     } | ||||
| 
 | ||||
|     /* parity [10] */ | ||||
|     WAIT(clock_lo, 50, 6); | ||||
|     if (data_in() != parity) { | ||||
|         ps2_error = PS2_ERR_PARITY; | ||||
|         goto ERROR; | ||||
|     } | ||||
|     WAIT(clock_hi, 50, 7); | ||||
| 
 | ||||
|     /* stop bit [11] */ | ||||
|     WAIT(clock_lo, 50, 8); | ||||
|     WAIT(data_hi, 1, 9); | ||||
|     WAIT(clock_hi, 50, 10); | ||||
| 
 | ||||
|     inhibit(); | ||||
|     return data; | ||||
| ERROR: | ||||
|     if (ps2_error > PS2_ERR_STARTBIT3) { | ||||
|         xprintf("x%02X\n", ps2_error); | ||||
|     } | ||||
|     inhibit(); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /* send LED state to keyboard */ | ||||
| void ps2_host_set_led(uint8_t led) { | ||||
|     ps2_host_send(0xED); | ||||
|     ps2_host_send(led); | ||||
| } | ||||
							
								
								
									
										340
									
								
								drivers/ps2/ps2_interrupt.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										340
									
								
								drivers/ps2/ps2_interrupt.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,340 @@ | |||
| /*
 | ||||
| Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com> | ||||
| 
 | ||||
| This software is licensed with a Modified BSD License. | ||||
| All of this is supposed to be Free Software, Open Source, DFSG-free, | ||||
| GPL-compatible, and OK to use in both free and proprietary applications. | ||||
| Additions and corrections to this file are welcome. | ||||
| 
 | ||||
| 
 | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
| 
 | ||||
| * Redistributions of source code must retain the above copyright | ||||
|   notice, this list of conditions and the following disclaimer. | ||||
| 
 | ||||
| * Redistributions in binary form must reproduce the above copyright | ||||
|   notice, this list of conditions and the following disclaimer in | ||||
|   the documentation and/or other materials provided with the | ||||
|   distribution. | ||||
| 
 | ||||
| * Neither the name of the copyright holders nor the names of | ||||
|   contributors may be used to endorse or promote products derived | ||||
|   from this software without specific prior written permission. | ||||
| 
 | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||||
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
| POSSIBILITY OF SUCH DAMAGE. | ||||
| */ | ||||
| 
 | ||||
| /*
 | ||||
|  * PS/2 protocol Pin interrupt version | ||||
|  */ | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #if defined(__AVR__) | ||||
| #    include <avr/interrupt.h> | ||||
| #elif defined(PROTOCOL_CHIBIOS)  // TODO: or STM32 ?
 | ||||
| // chibiOS headers
 | ||||
| #    include "ch.h" | ||||
| #    include "hal.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "ps2.h" | ||||
| #include "ps2_io.h" | ||||
| #include "print.h" | ||||
| #include "wait.h" | ||||
| 
 | ||||
| #define WAIT(stat, us, err)     \ | ||||
|     do {                        \ | ||||
|         if (!wait_##stat(us)) { \ | ||||
|             ps2_error = err;    \ | ||||
|             goto ERROR;         \ | ||||
|         }                       \ | ||||
|     } while (0) | ||||
| 
 | ||||
| uint8_t ps2_error = PS2_ERR_NONE; | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| #if defined(PROTOCOL_CHIBIOS) | ||||
| void ps2_interrupt_service_routine(void); | ||||
| void palCallback(void *arg) { ps2_interrupt_service_routine(); } | ||||
| 
 | ||||
| #    define PS2_INT_INIT()                                 \ | ||||
|         { palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_INPUT); } \ | ||||
|         while (0) | ||||
| #    define PS2_INT_ON()                                                    \ | ||||
|         {                                                                   \ | ||||
|             palEnableLineEvent(PS2_CLOCK_PIN, PAL_EVENT_MODE_FALLING_EDGE); \ | ||||
|             palSetLineCallback(PS2_CLOCK_PIN, palCallback, NULL);           \ | ||||
|         }                                                                   \ | ||||
|         while (0) | ||||
| #    define PS2_INT_OFF()                       \ | ||||
|         { palDisableLineEvent(PS2_CLOCK_PIN); } \ | ||||
|         while (0) | ||||
| #endif  // PROTOCOL_CHIBIOS
 | ||||
| 
 | ||||
| void ps2_host_init(void) { | ||||
|     idle(); | ||||
|     PS2_INT_INIT(); | ||||
|     PS2_INT_ON(); | ||||
|     // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
 | ||||
|     // wait_ms(2500);
 | ||||
| } | ||||
| 
 | ||||
| uint8_t ps2_host_send(uint8_t data) { | ||||
|     bool parity = true; | ||||
|     ps2_error   = PS2_ERR_NONE; | ||||
| 
 | ||||
|     PS2_INT_OFF(); | ||||
| 
 | ||||
|     /* terminate a transmission if we have */ | ||||
|     inhibit(); | ||||
|     wait_us(100);  // 100us [4]p.13, [5]p.50
 | ||||
| 
 | ||||
|     /* 'Request to Send' and Start bit */ | ||||
|     data_lo(); | ||||
|     clock_hi(); | ||||
|     WAIT(clock_lo, 10000, 10);  // 10ms [5]p.50
 | ||||
| 
 | ||||
|     /* Data bit[2-9] */ | ||||
|     for (uint8_t i = 0; i < 8; i++) { | ||||
|         if (data & (1 << i)) { | ||||
|             parity = !parity; | ||||
|             data_hi(); | ||||
|         } else { | ||||
|             data_lo(); | ||||
|         } | ||||
|         WAIT(clock_hi, 50, 2); | ||||
|         WAIT(clock_lo, 50, 3); | ||||
|     } | ||||
| 
 | ||||
|     /* Parity bit */ | ||||
|     wait_us(15); | ||||
|     if (parity) { | ||||
|         data_hi(); | ||||
|     } else { | ||||
|         data_lo(); | ||||
|     } | ||||
|     WAIT(clock_hi, 50, 4); | ||||
|     WAIT(clock_lo, 50, 5); | ||||
| 
 | ||||
|     /* Stop bit */ | ||||
|     wait_us(15); | ||||
|     data_hi(); | ||||
| 
 | ||||
|     /* Ack */ | ||||
|     WAIT(data_lo, 50, 6); | ||||
|     WAIT(clock_lo, 50, 7); | ||||
| 
 | ||||
|     /* wait for idle state */ | ||||
|     WAIT(clock_hi, 50, 8); | ||||
|     WAIT(data_hi, 50, 9); | ||||
| 
 | ||||
|     idle(); | ||||
|     PS2_INT_ON(); | ||||
|     return ps2_host_recv_response(); | ||||
| ERROR: | ||||
|     idle(); | ||||
|     PS2_INT_ON(); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| uint8_t ps2_host_recv_response(void) { | ||||
|     // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
 | ||||
|     uint8_t retry = 25; | ||||
|     while (retry-- && !pbuf_has_data()) { | ||||
|         wait_ms(1); | ||||
|     } | ||||
|     return pbuf_dequeue(); | ||||
| } | ||||
| 
 | ||||
| /* get data received by interrupt */ | ||||
| uint8_t ps2_host_recv(void) { | ||||
|     if (pbuf_has_data()) { | ||||
|         ps2_error = PS2_ERR_NONE; | ||||
|         return pbuf_dequeue(); | ||||
|     } else { | ||||
|         ps2_error = PS2_ERR_NODATA; | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ps2_interrupt_service_routine(void) { | ||||
|     static enum { | ||||
|         INIT, | ||||
|         START, | ||||
|         BIT0, | ||||
|         BIT1, | ||||
|         BIT2, | ||||
|         BIT3, | ||||
|         BIT4, | ||||
|         BIT5, | ||||
|         BIT6, | ||||
|         BIT7, | ||||
|         PARITY, | ||||
|         STOP, | ||||
|     } state               = INIT; | ||||
|     static uint8_t data   = 0; | ||||
|     static uint8_t parity = 1; | ||||
| 
 | ||||
|     // TODO: abort if elapse 100us from previous interrupt
 | ||||
| 
 | ||||
|     // return unless falling edge
 | ||||
|     if (clock_in()) { | ||||
|         goto RETURN; | ||||
|     } | ||||
| 
 | ||||
|     state++; | ||||
|     switch (state) { | ||||
|         case START: | ||||
|             if (data_in()) goto ERROR; | ||||
|             break; | ||||
|         case BIT0: | ||||
|         case BIT1: | ||||
|         case BIT2: | ||||
|         case BIT3: | ||||
|         case BIT4: | ||||
|         case BIT5: | ||||
|         case BIT6: | ||||
|         case BIT7: | ||||
|             data >>= 1; | ||||
|             if (data_in()) { | ||||
|                 data |= 0x80; | ||||
|                 parity++; | ||||
|             } | ||||
|             break; | ||||
|         case PARITY: | ||||
|             if (data_in()) { | ||||
|                 if (!(parity & 0x01)) goto ERROR; | ||||
|             } else { | ||||
|                 if (parity & 0x01) goto ERROR; | ||||
|             } | ||||
|             break; | ||||
|         case STOP: | ||||
|             if (!data_in()) goto ERROR; | ||||
|             pbuf_enqueue(data); | ||||
|             goto DONE; | ||||
|             break; | ||||
|         default: | ||||
|             goto ERROR; | ||||
|     } | ||||
|     goto RETURN; | ||||
| ERROR: | ||||
|     ps2_error = state; | ||||
| DONE: | ||||
|     state  = INIT; | ||||
|     data   = 0; | ||||
|     parity = 1; | ||||
| RETURN: | ||||
|     return; | ||||
| } | ||||
| 
 | ||||
| #if defined(__AVR__) | ||||
| ISR(PS2_INT_VECT) { ps2_interrupt_service_routine(); } | ||||
| #endif | ||||
| 
 | ||||
| /* send LED state to keyboard */ | ||||
| void ps2_host_set_led(uint8_t led) { | ||||
|     ps2_host_send(0xED); | ||||
|     ps2_host_send(led); | ||||
| } | ||||
| 
 | ||||
| /*--------------------------------------------------------------------
 | ||||
|  * Ring buffer to store scan codes from keyboard | ||||
|  *------------------------------------------------------------------*/ | ||||
| #define PBUF_SIZE 32 | ||||
| static uint8_t     pbuf[PBUF_SIZE]; | ||||
| static uint8_t     pbuf_head = 0; | ||||
| static uint8_t     pbuf_tail = 0; | ||||
| static inline void pbuf_enqueue(uint8_t data) { | ||||
| #if defined(__AVR__) | ||||
|     uint8_t sreg = SREG; | ||||
|     cli(); | ||||
| #elif defined(PROTOCOL_CHIBIOS) | ||||
|     chSysLockFromISR(); | ||||
| #endif | ||||
| 
 | ||||
|     uint8_t next = (pbuf_head + 1) % PBUF_SIZE; | ||||
|     if (next != pbuf_tail) { | ||||
|         pbuf[pbuf_head] = data; | ||||
|         pbuf_head       = next; | ||||
|     } else { | ||||
|         print("pbuf: full\n"); | ||||
|     } | ||||
| 
 | ||||
| #if defined(__AVR__) | ||||
|     SREG = sreg; | ||||
| #elif defined(PROTOCOL_CHIBIOS) | ||||
|     chSysUnlockFromISR(); | ||||
| #endif | ||||
| } | ||||
| static inline uint8_t pbuf_dequeue(void) { | ||||
|     uint8_t val = 0; | ||||
| 
 | ||||
| #if defined(__AVR__) | ||||
|     uint8_t sreg = SREG; | ||||
|     cli(); | ||||
| #elif defined(PROTOCOL_CHIBIOS) | ||||
|     chSysLock(); | ||||
| #endif | ||||
| 
 | ||||
|     if (pbuf_head != pbuf_tail) { | ||||
|         val       = pbuf[pbuf_tail]; | ||||
|         pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE; | ||||
|     } | ||||
| 
 | ||||
| #if defined(__AVR__) | ||||
|     SREG = sreg; | ||||
| #elif defined(PROTOCOL_CHIBIOS) | ||||
|     chSysUnlock(); | ||||
| #endif | ||||
| 
 | ||||
|     return val; | ||||
| } | ||||
| static inline bool pbuf_has_data(void) { | ||||
| #if defined(__AVR__) | ||||
|     uint8_t sreg = SREG; | ||||
|     cli(); | ||||
| #elif defined(PROTOCOL_CHIBIOS) | ||||
|     chSysLock(); | ||||
| #endif | ||||
| 
 | ||||
|     bool has_data = (pbuf_head != pbuf_tail); | ||||
| 
 | ||||
| #if defined(__AVR__) | ||||
|     SREG = sreg; | ||||
| #elif defined(PROTOCOL_CHIBIOS) | ||||
|     chSysUnlock(); | ||||
| #endif | ||||
|     return has_data; | ||||
| } | ||||
| static inline void pbuf_clear(void) { | ||||
| #if defined(__AVR__) | ||||
|     uint8_t sreg = SREG; | ||||
|     cli(); | ||||
| #elif defined(PROTOCOL_CHIBIOS) | ||||
|     chSysLock(); | ||||
| #endif | ||||
| 
 | ||||
|     pbuf_head = pbuf_tail = 0; | ||||
| 
 | ||||
| #if defined(__AVR__) | ||||
|     SREG = sreg; | ||||
| #elif defined(PROTOCOL_CHIBIOS) | ||||
|     chSysUnlock(); | ||||
| #endif | ||||
| } | ||||
							
								
								
									
										11
									
								
								drivers/ps2/ps2_io.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								drivers/ps2/ps2_io.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| #pragma once | ||||
| 
 | ||||
| void clock_init(void); | ||||
| void clock_lo(void); | ||||
| void clock_hi(void); | ||||
| bool clock_in(void); | ||||
| 
 | ||||
| void data_init(void); | ||||
| void data_lo(void); | ||||
| void data_hi(void); | ||||
| bool data_in(void); | ||||
							
								
								
									
										270
									
								
								drivers/ps2/ps2_mouse.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								drivers/ps2/ps2_mouse.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,270 @@ | |||
| /*
 | ||||
| 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" | ||||
| #include "wait.h" | ||||
| #include "gpio.h" | ||||
| #include "host.h" | ||||
| #include "timer.h" | ||||
| #include "print.h" | ||||
| #include "report.h" | ||||
| #include "debug.h" | ||||
| #include "ps2.h" | ||||
| 
 | ||||
| /* ============================= MACROS ============================ */ | ||||
| 
 | ||||
| static report_mouse_t mouse_report = {}; | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| /* ============================= IMPLEMENTATION ============================ */ | ||||
| 
 | ||||
| /* supports only 3 button mouse at this time */ | ||||
| void ps2_mouse_init(void) { | ||||
|     ps2_host_init(); | ||||
| 
 | ||||
|     wait_ms(PS2_MOUSE_INIT_DELAY);  // wait for powering up
 | ||||
| 
 | ||||
|     PS2_MOUSE_SEND(PS2_MOUSE_RESET, "ps2_mouse_init: sending reset"); | ||||
| 
 | ||||
|     PS2_MOUSE_RECEIVE("ps2_mouse_init: read BAT"); | ||||
|     PS2_MOUSE_RECEIVE("ps2_mouse_init: read DevID"); | ||||
| 
 | ||||
| #ifdef PS2_MOUSE_USE_REMOTE_MODE | ||||
|     ps2_mouse_set_remote_mode(); | ||||
| #else | ||||
|     ps2_mouse_enable_data_reporting(); | ||||
| #endif | ||||
| 
 | ||||
| #ifdef PS2_MOUSE_ENABLE_SCROLLING | ||||
|     ps2_mouse_enable_scrolling(); | ||||
| #endif | ||||
| 
 | ||||
| #ifdef PS2_MOUSE_USE_2_1_SCALING | ||||
|     ps2_mouse_set_scaling_2_1(); | ||||
| #endif | ||||
| 
 | ||||
|     ps2_mouse_init_user(); | ||||
| } | ||||
| 
 | ||||
| __attribute__((weak)) void ps2_mouse_init_user(void) {} | ||||
| 
 | ||||
| __attribute__((weak)) void ps2_mouse_moved_user(report_mouse_t *mouse_report) {} | ||||
| 
 | ||||
| void ps2_mouse_task(void) { | ||||
|     static uint8_t buttons_prev = 0; | ||||
|     extern int     tp_buttons; | ||||
| 
 | ||||
|     /* 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() | tp_buttons; | ||||
|         mouse_report.x       = ps2_host_recv_response() * PS2_MOUSE_X_MULTIPLIER; | ||||
|         mouse_report.y       = ps2_host_recv_response() * PS2_MOUSE_Y_MULTIPLIER; | ||||
| #ifdef PS2_MOUSE_ENABLE_SCROLLING | ||||
|         mouse_report.v = -(ps2_host_recv_response() & PS2_MOUSE_SCROLL_MASK) * PS2_MOUSE_V_MULTIPLIER; | ||||
| #endif | ||||
|     } else { | ||||
|         if (debug_mouse) print("ps2_mouse: fail to get mouse packet\n"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     /* if mouse moves or buttons state changes */ | ||||
|     if (mouse_report.x || mouse_report.y || mouse_report.v || ((mouse_report.buttons ^ buttons_prev) & PS2_MOUSE_BTN_MASK)) { | ||||
| #ifdef PS2_MOUSE_DEBUG_RAW | ||||
|         // Used to debug raw ps2 bytes from mouse
 | ||||
|         ps2_mouse_print_report(&mouse_report); | ||||
| #endif | ||||
|         buttons_prev = mouse_report.buttons; | ||||
|         ps2_mouse_convert_report_to_hid(&mouse_report); | ||||
| #if PS2_MOUSE_SCROLL_BTN_MASK | ||||
|         ps2_mouse_scroll_button_task(&mouse_report); | ||||
| #endif | ||||
|         if (mouse_report.x || mouse_report.y || mouse_report.v) { | ||||
|             ps2_mouse_moved_user(&mouse_report); | ||||
|         } | ||||
| #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); | ||||
|     } | ||||
| 
 | ||||
|     ps2_mouse_clear_report(&mouse_report); | ||||
| } | ||||
| 
 | ||||
| void ps2_mouse_disable_data_reporting(void) { PS2_MOUSE_SEND(PS2_MOUSE_DISABLE_DATA_REPORTING, "ps2 mouse disable data reporting"); } | ||||
| 
 | ||||
| void ps2_mouse_enable_data_reporting(void) { PS2_MOUSE_SEND(PS2_MOUSE_ENABLE_DATA_REPORTING, "ps2 mouse enable data reporting"); } | ||||
| 
 | ||||
| void ps2_mouse_set_remote_mode(void) { | ||||
|     PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_REMOTE_MODE, "ps2 mouse set remote mode"); | ||||
|     ps2_mouse_mode = PS2_MOUSE_REMOTE_MODE; | ||||
| } | ||||
| 
 | ||||
| void ps2_mouse_set_stream_mode(void) { | ||||
|     PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_STREAM_MODE, "ps2 mouse set stream mode"); | ||||
|     ps2_mouse_mode = PS2_MOUSE_STREAM_MODE; | ||||
| } | ||||
| 
 | ||||
| void ps2_mouse_set_scaling_2_1(void) { PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_SCALING_2_1, "ps2 mouse set scaling 2:1"); } | ||||
| 
 | ||||
| void ps2_mouse_set_scaling_1_1(void) { PS2_MOUSE_SEND_SAFE(PS2_MOUSE_SET_SCALING_1_1, "ps2 mouse set scaling 1:1"); } | ||||
| 
 | ||||
| void ps2_mouse_set_resolution(ps2_mouse_resolution_t resolution) { PS2_MOUSE_SET_SAFE(PS2_MOUSE_SET_RESOLUTION, resolution, "ps2 mouse set resolution"); } | ||||
| 
 | ||||
| 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"); } | ||||
| 
 | ||||
| /* ============================= HELPERS ============================ */ | ||||
| 
 | ||||
| #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)) | ||||
| 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.
 | ||||
|     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); | ||||
| 
 | ||||
| #ifdef PS2_MOUSE_INVERT_BUTTONS | ||||
|     // swap left & right buttons
 | ||||
|     uint8_t needs_left    = mouse_report->buttons & PS2_MOUSE_BTN_RIGHT; | ||||
|     uint8_t needs_right   = mouse_report->buttons & PS2_MOUSE_BTN_LEFT; | ||||
|     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 | ||||
|     // remove sign and overflow flags
 | ||||
|     mouse_report->buttons &= PS2_MOUSE_BTN_MASK; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef PS2_MOUSE_INVERT_X | ||||
|     mouse_report->x = -mouse_report->x; | ||||
| #endif | ||||
| #ifndef PS2_MOUSE_INVERT_Y  // NOTE if not!
 | ||||
|     // invert coordinate of y to conform to USB HID mouse
 | ||||
|     mouse_report->y = -mouse_report->y; | ||||
| #endif | ||||
| 
 | ||||
| #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 | ||||
| } | ||||
| 
 | ||||
| static inline void ps2_mouse_clear_report(report_mouse_t *mouse_report) { | ||||
|     mouse_report->x       = 0; | ||||
|     mouse_report->y       = 0; | ||||
|     mouse_report->v       = 0; | ||||
|     mouse_report->h       = 0; | ||||
|     mouse_report->buttons = 0; | ||||
| } | ||||
| 
 | ||||
| static inline void ps2_mouse_print_report(report_mouse_t *mouse_report) { | ||||
|     if (!debug_mouse) return; | ||||
|     print("ps2_mouse: ["); | ||||
|     print_hex8(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"); | ||||
| } | ||||
| 
 | ||||
| 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"); | ||||
|     wait_ms(20); | ||||
| } | ||||
| 
 | ||||
| #define PRESS_SCROLL_BUTTONS mouse_report->buttons |= (PS2_MOUSE_SCROLL_BTN_MASK) | ||||
| #define RELEASE_SCROLL_BUTTONS mouse_report->buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK) | ||||
| static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report) { | ||||
|     static enum { | ||||
|         SCROLL_NONE, | ||||
|         SCROLL_BTN, | ||||
|         SCROLL_SENT, | ||||
|     } scroll_state                     = SCROLL_NONE; | ||||
|     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(); | ||||
|             scroll_state       = SCROLL_BTN; | ||||
|         } | ||||
| 
 | ||||
|         // If the mouse has moved, update the report to scroll instead of move the mouse
 | ||||
|         if (mouse_report->x || mouse_report->y) { | ||||
|             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); | ||||
|             mouse_report->x = 0; | ||||
|             mouse_report->y = 0; | ||||
| #ifdef PS2_MOUSE_INVERT_H | ||||
|             mouse_report->h = -mouse_report->h; | ||||
| #endif | ||||
| #ifdef PS2_MOUSE_INVERT_V | ||||
|             mouse_report->v = -mouse_report->v; | ||||
| #endif | ||||
|         } | ||||
|     } else if (0 == (PS2_MOUSE_SCROLL_BTN_MASK & mouse_report->buttons)) { | ||||
|         // None of the scroll buttons are pressed
 | ||||
| 
 | ||||
| #if PS2_MOUSE_SCROLL_BTN_SEND | ||||
|         if (scroll_state == SCROLL_BTN && timer_elapsed(scroll_button_time) < PS2_MOUSE_SCROLL_BTN_SEND) { | ||||
|             PRESS_SCROLL_BUTTONS; | ||||
|             host_mouse_send(mouse_report); | ||||
|             wait_ms(100); | ||||
|             RELEASE_SCROLL_BUTTONS; | ||||
|         } | ||||
| #endif | ||||
|         scroll_state = SCROLL_NONE; | ||||
|     } | ||||
| 
 | ||||
|     RELEASE_SCROLL_BUTTONS; | ||||
| } | ||||
							
								
								
									
										177
									
								
								drivers/ps2/ps2_mouse.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								drivers/ps2/ps2_mouse.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,177 @@ | |||
| /*
 | ||||
| Copyright 2011 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/>.
 | ||||
| */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include "debug.h" | ||||
| #include "report.h" | ||||
| 
 | ||||
| #define PS2_MOUSE_SEND(command, message)                                                \ | ||||
|     do {                                                                                \ | ||||
|         __attribute__((unused)) uint8_t rcv = ps2_host_send(command);                   \ | ||||
|         if (debug_mouse) {                                                              \ | ||||
|             print((message));                                                           \ | ||||
|             xprintf(" command: %X, result: %X, error: %X \n", command, rcv, ps2_error); \ | ||||
|         }                                                                               \ | ||||
|     } while (0) | ||||
| 
 | ||||
| #define PS2_MOUSE_SEND_SAFE(command, message)          \ | ||||
|     do {                                               \ | ||||
|         if (PS2_MOUSE_STREAM_MODE == ps2_mouse_mode) { \ | ||||
|             ps2_mouse_disable_data_reporting();        \ | ||||
|         }                                              \ | ||||
|         PS2_MOUSE_SEND(command, message);              \ | ||||
|         if (PS2_MOUSE_STREAM_MODE == ps2_mouse_mode) { \ | ||||
|             ps2_mouse_enable_data_reporting();         \ | ||||
|         }                                              \ | ||||
|     } while (0) | ||||
| 
 | ||||
| #define PS2_MOUSE_SET_SAFE(command, value, message)    \ | ||||
|     do {                                               \ | ||||
|         if (PS2_MOUSE_STREAM_MODE == ps2_mouse_mode) { \ | ||||
|             ps2_mouse_disable_data_reporting();        \ | ||||
|         }                                              \ | ||||
|         PS2_MOUSE_SEND(command, message);              \ | ||||
|         PS2_MOUSE_SEND(value, "Sending value");        \ | ||||
|         if (PS2_MOUSE_STREAM_MODE == ps2_mouse_mode) { \ | ||||
|             ps2_mouse_enable_data_reporting();         \ | ||||
|         }                                              \ | ||||
|     } while (0) | ||||
| 
 | ||||
| #define PS2_MOUSE_RECEIVE(message)                                      \ | ||||
|     do {                                                                \ | ||||
|         __attribute__((unused)) uint8_t rcv = ps2_host_recv_response(); \ | ||||
|         if (debug_mouse) {                                              \ | ||||
|             print((message));                                           \ | ||||
|             xprintf(" result: %X, error: %X \n", rcv, ps2_error);       \ | ||||
|         }                                                               \ | ||||
|     } while (0) | ||||
| 
 | ||||
| __attribute__((unused)) static enum ps2_mouse_mode_e { | ||||
|     PS2_MOUSE_STREAM_MODE, | ||||
|     PS2_MOUSE_REMOTE_MODE, | ||||
| } ps2_mouse_mode = PS2_MOUSE_STREAM_MODE; | ||||
| 
 | ||||
| /*
 | ||||
|  * 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 | ||||
| #define PS2_MOUSE_BTN_MIDDLE 2 | ||||
| #define PS2_MOUSE_X_SIGN 4 | ||||
| #define PS2_MOUSE_Y_SIGN 5 | ||||
| #define PS2_MOUSE_X_OVFLW 6 | ||||
| #define PS2_MOUSE_Y_OVFLW 7 | ||||
| 
 | ||||
| /* 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 | ||||
| /* multiply reported mouse values by these */ | ||||
| #ifndef PS2_MOUSE_X_MULTIPLIER | ||||
| #    define PS2_MOUSE_X_MULTIPLIER 1 | ||||
| #endif | ||||
| #ifndef PS2_MOUSE_Y_MULTIPLIER | ||||
| #    define PS2_MOUSE_Y_MULTIPLIER 1 | ||||
| #endif | ||||
| #ifndef PS2_MOUSE_V_MULTIPLIER | ||||
| #    define PS2_MOUSE_V_MULTIPLIER 1 | ||||
| #endif | ||||
| /* For some mice this will need to be 0x0F */ | ||||
| #ifndef PS2_MOUSE_SCROLL_MASK | ||||
| #    define PS2_MOUSE_SCROLL_MASK 0xFF | ||||
| #endif | ||||
| #ifndef PS2_MOUSE_INIT_DELAY | ||||
| #    define PS2_MOUSE_INIT_DELAY 1000 | ||||
| #endif | ||||
| 
 | ||||
| enum ps2_mouse_command_e { | ||||
|     PS2_MOUSE_RESET                  = 0xFF, | ||||
|     PS2_MOUSE_RESEND                 = 0xFE, | ||||
|     PS2_MOSUE_SET_DEFAULTS           = 0xF6, | ||||
|     PS2_MOUSE_DISABLE_DATA_REPORTING = 0xF5, | ||||
|     PS2_MOUSE_ENABLE_DATA_REPORTING  = 0xF4, | ||||
|     PS2_MOUSE_SET_SAMPLE_RATE        = 0xF3, | ||||
|     PS2_MOUSE_GET_DEVICE_ID          = 0xF2, | ||||
|     PS2_MOUSE_SET_REMOTE_MODE        = 0xF0, | ||||
|     PS2_MOUSE_SET_WRAP_MODE          = 0xEC, | ||||
|     PS2_MOUSE_READ_DATA              = 0xEB, | ||||
|     PS2_MOUSE_SET_STREAM_MODE        = 0xEA, | ||||
|     PS2_MOUSE_STATUS_REQUEST         = 0xE9, | ||||
|     PS2_MOUSE_SET_RESOLUTION         = 0xE8, | ||||
|     PS2_MOUSE_SET_SCALING_2_1        = 0xE7, | ||||
|     PS2_MOUSE_SET_SCALING_1_1        = 0xE6, | ||||
| }; | ||||
| 
 | ||||
| typedef enum ps2_mouse_resolution_e { | ||||
|     PS2_MOUSE_1_COUNT_MM, | ||||
|     PS2_MOUSE_2_COUNT_MM, | ||||
|     PS2_MOUSE_4_COUNT_MM, | ||||
|     PS2_MOUSE_8_COUNT_MM, | ||||
| } ps2_mouse_resolution_t; | ||||
| 
 | ||||
| typedef enum ps2_mouse_sample_rate_e { | ||||
|     PS2_MOUSE_10_SAMPLES_SEC  = 10, | ||||
|     PS2_MOUSE_20_SAMPLES_SEC  = 20, | ||||
|     PS2_MOUSE_40_SAMPLES_SEC  = 40, | ||||
|     PS2_MOUSE_60_SAMPLES_SEC  = 60, | ||||
|     PS2_MOUSE_80_SAMPLES_SEC  = 80, | ||||
|     PS2_MOUSE_100_SAMPLES_SEC = 100, | ||||
|     PS2_MOUSE_200_SAMPLES_SEC = 200, | ||||
| } ps2_mouse_sample_rate_t; | ||||
| 
 | ||||
| void ps2_mouse_init(void); | ||||
| 
 | ||||
| void ps2_mouse_init_user(void); | ||||
| 
 | ||||
| void ps2_mouse_task(void); | ||||
| 
 | ||||
| void ps2_mouse_disable_data_reporting(void); | ||||
| 
 | ||||
| void ps2_mouse_enable_data_reporting(void); | ||||
| 
 | ||||
| void ps2_mouse_set_remote_mode(void); | ||||
| 
 | ||||
| void ps2_mouse_set_stream_mode(void); | ||||
| 
 | ||||
| void ps2_mouse_set_scaling_2_1(void); | ||||
| 
 | ||||
| void ps2_mouse_set_scaling_1_1(void); | ||||
| 
 | ||||
| void ps2_mouse_set_resolution(ps2_mouse_resolution_t resolution); | ||||
| 
 | ||||
| void ps2_mouse_set_sample_rate(ps2_mouse_sample_rate_t sample_rate); | ||||
| 
 | ||||
| void ps2_mouse_moved_user(report_mouse_t *mouse_report); | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Joel Challis
						Joel Challis