qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

ps2_mouse.md (9752B)


      1 # PS/2 Mouse Support {#ps2-mouse-support}
      2 
      3 Its possible to hook up a PS/2 mouse (for example touchpads or trackpoints) to your keyboard as a composite device.
      4 
      5 To hook up a Trackpoint, you need to obtain a Trackpoint module (i.e. harvest from a Thinkpad keyboard), identify the function of each pin of the module, and make the necessary circuitry between controller and Trackpoint module. For more information, please refer to [Trackpoint Hardware](https://deskthority.net/wiki/TrackPoint_Hardware) page on Deskthority Wiki.
      6 
      7 There are three available modes for hooking up PS/2 devices: USART (best), interrupts (better) or busywait (not recommended).
      8 
      9 ## The Circuitry between Trackpoint and Controller {#the-circuitry-between-trackpoint-and-controller}
     10 
     11 To get the things working, a 4.7K drag is needed between the two lines DATA and CLK and the line 5+. 
     12 
     13 ```
     14 
     15           DATA ----------+--------- PIN
     16                          |
     17                         4.7K
     18                          |
     19 MODULE    5+  --------+--+--------- PWR   CONTROLLER
     20                       |
     21                      4.7K
     22                       |    
     23           CLK   ------+------------ PIN
     24 ```
     25 
     26 ## Driver Configuration {#driver-configuration}
     27 
     28 Driver selection can be configured in `rules.mk` as `PS2_DRIVER`, or in `info.json` as `ps2.driver`. Valid values are `busywait` (default), `interrupt`, `usart`, or `vendor`. See below for information on individual drivers.
     29 
     30 ### Busywait Driver {#busywait-driver}
     31 
     32 Note: This is not recommended, you may encounter jerky movement or unsent inputs. Please use interrupt or USART version if possible.
     33 
     34 In rules.mk:
     35 
     36 ```make
     37 PS2_MOUSE_ENABLE = yes
     38 PS2_ENABLE = yes
     39 PS2_DRIVER = busywait
     40 ```
     41 
     42 In your keyboard config.h:
     43 
     44 ```c
     45 #ifdef PS2_DRIVER_BUSYWAIT
     46 # define PS2_CLOCK_PIN   D1
     47 # define PS2_DATA_PIN    D2
     48 #endif
     49 ```
     50 
     51 ### Interrupt Driver (AVR/ATMega32u4) {#interrupt-driver-avr}
     52 
     53 The following example uses D2 for clock and D5 for data. You can use any INT or PCINT pin for clock, and any pin for data.
     54 
     55 In rules.mk:
     56 
     57 ```make
     58 PS2_MOUSE_ENABLE = yes
     59 PS2_ENABLE = yes
     60 PS2_DRIVER = interrupt
     61 ```
     62 
     63 In your keyboard config.h:
     64 
     65 ```c
     66 #ifdef PS2_DRIVER_INTERRUPT
     67 #define PS2_CLOCK_PIN   D2
     68 #define PS2_DATA_PIN    D5
     69 
     70 #define PS2_INT_INIT()  do {    \
     71     EICRA |= ((1<<ISC21) |      \
     72               (0<<ISC20));      \
     73 } while (0)
     74 #define PS2_INT_ON()  do {      \
     75     EIMSK |= (1<<INT2);         \
     76 } while (0)
     77 #define PS2_INT_OFF() do {      \
     78     EIMSK &= ~(1<<INT2);        \
     79 } while (0)
     80 #define PS2_INT_VECT   INT2_vect
     81 #endif
     82 ```
     83 
     84 ### Interrupt Driver (ARM chibios) {#interrupt-driver-chibios}
     85 
     86 Pretty much any two pins can be used for the (software) interrupt variant on ARM cores. The example below uses A8 for clock, and A9 for data.
     87 
     88 In rules.mk:
     89 
     90 ```
     91 PS2_MOUSE_ENABLE = yes
     92 PS2_ENABLE = yes
     93 PS2_DRIVER = interrupt
     94 ```
     95 
     96 In your keyboard `config.h`:
     97 
     98 ```c
     99 #define PS2_CLOCK_PIN A8
    100 #define PS2_DATA_PIN  A9
    101 ```
    102 
    103 And in the ChibiOS specific `halconf.h`:
    104 
    105 ```c
    106 #pragma once
    107 
    108 #define PAL_USE_CALLBACKS TRUE // [!code focus]
    109 
    110 #include_next <halconf.h>
    111 ```
    112 
    113 ### USART Driver {#usart-driver}
    114 
    115 To use USART on the ATMega32u4, you have to use PD5 for clock and PD2 for data. If one of those are unavailable, you need to use interrupt version.
    116 
    117 In rules.mk:
    118 
    119 ```make
    120 PS2_MOUSE_ENABLE = yes
    121 PS2_ENABLE = yes
    122 PS2_DRIVER = usart
    123 ```
    124 
    125 In your keyboard config.h:
    126 
    127 ```c
    128 #ifdef PS2_DRIVER_USART
    129 #define PS2_CLOCK_PIN   D5
    130 #define PS2_DATA_PIN    D2
    131 
    132 /* synchronous, odd parity, 1-bit stop, 8-bit data, sample at falling edge */
    133 /* set DDR of CLOCK as input to be slave */
    134 #define PS2_USART_INIT() do {   \
    135     PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);   \
    136     PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);     \
    137     UCSR1C = ((1 << UMSEL10) |  \
    138               (3 << UPM10)   |  \
    139               (0 << USBS1)   |  \
    140               (3 << UCSZ10)  |  \
    141               (0 << UCPOL1));   \
    142     UCSR1A = 0;                 \
    143     UBRR1H = 0;                 \
    144     UBRR1L = 0;                 \
    145 } while (0)
    146 #define PS2_USART_RX_INT_ON() do {  \
    147     UCSR1B = ((1 << RXCIE1) |       \
    148               (1 << RXEN1));        \
    149 } while (0)
    150 #define PS2_USART_RX_POLL_ON() do { \
    151     UCSR1B = (1 << RXEN1);          \
    152 } while (0)
    153 #define PS2_USART_OFF() do {    \
    154     UCSR1C = 0;                 \
    155     UCSR1B &= ~((1 << RXEN1) |  \
    156                 (1 << TXEN1));  \
    157 } while (0)
    158 #define PS2_USART_RX_READY      (UCSR1A & (1<<RXC1))
    159 #define PS2_USART_RX_DATA       UDR1
    160 #define PS2_USART_ERROR         (UCSR1A & ((1<<FE1) | (1<<DOR1) | (1<<UPE1)))
    161 #define PS2_USART_RX_VECT       USART1_RX_vect
    162 #endif
    163 ```
    164 
    165 ### RP2040 PIO Driver {#rp2040-pio-driver}
    166 
    167 The `PIO` subsystem is a Raspberry Pi RP2040 specific implementation, using the integrated PIO peripheral and is therefore only available on this MCU.
    168 
    169 There are strict requirements for pin ordering but any pair of GPIO pins can be used. The GPIO used for clock must be directly after data, see the included info.json snippet for an example of correct order.
    170 
    171 You may optionally switch the PIO peripheral used with the following define in config.h:
    172 ```c
    173 #define PS2_PIO_USE_PIO1 // Force the usage of PIO1 peripheral, by default the PS2 implementation uses the PIO0 peripheral
    174 ```
    175 
    176 Example info.json content:
    177 
    178 ```json
    179     "ps2": {
    180         "clock_pin": "GP1",
    181         "data_pin": "GP0",
    182         "driver": "vendor",
    183         "enabled": true,
    184         "mouse_enabled": true
    185     }
    186 ```
    187 
    188 ## Additional Settings {#additional-settings}
    189 
    190 ### PS/2 Mouse Features {#ps2-mouse-features}
    191 
    192 These enable settings supported by the PS/2 mouse protocol.
    193 
    194 ```c
    195 /* Use remote mode instead of the default stream mode (see link) */
    196 #define PS2_MOUSE_USE_REMOTE_MODE
    197 
    198 /* Enable the scrollwheel or scroll gesture on your mouse or touchpad */
    199 #define PS2_MOUSE_ENABLE_SCROLLING
    200 
    201 /* Some mice will need a scroll mask to be configured. The default is 0xFF. */
    202 #define PS2_MOUSE_SCROLL_MASK 0x0F
    203 
    204 /* Applies a transformation to the movement before sending to the host (see link) */
    205 #define PS2_MOUSE_USE_2_1_SCALING
    206 
    207 /* The time to wait after initializing the ps2 host */
    208 #define PS2_MOUSE_INIT_DELAY 1000 /* Default */
    209 ```
    210 
    211 You can also call the following functions from ps2_mouse.h
    212 
    213 ```c
    214 void ps2_mouse_disable_data_reporting(void);
    215 
    216 void ps2_mouse_enable_data_reporting(void);
    217 
    218 void ps2_mouse_set_remote_mode(void);
    219 
    220 void ps2_mouse_set_stream_mode(void);
    221 
    222 void ps2_mouse_set_scaling_2_1(void);
    223 
    224 void ps2_mouse_set_scaling_1_1(void);
    225 
    226 void ps2_mouse_set_resolution(ps2_mouse_resolution_t resolution);
    227 
    228 void ps2_mouse_set_sample_rate(ps2_mouse_sample_rate_t sample_rate);
    229 ```
    230 
    231 ### Fine Control {#fine-control}
    232 
    233 Use the following defines to change the sensitivity and speed of the mouse.
    234 Note: you can also use `ps2_mouse_set_resolution` for the same effect (not supported on most touchpads).
    235 
    236 ```c
    237 #define PS2_MOUSE_X_MULTIPLIER 3
    238 #define PS2_MOUSE_Y_MULTIPLIER 3
    239 #define PS2_MOUSE_V_MULTIPLIER 1
    240 ```
    241 
    242 ### Scroll Button {#scroll-button}
    243 
    244 If you're using a trackpoint, you will likely want to be able to use it for scrolling.
    245 It's possible to enable a "scroll button/s" that when pressed will cause the mouse to scroll instead of moving.
    246 To enable the feature, you must set a scroll button mask as follows:
    247 
    248 ```c
    249 #define PS2_MOUSE_SCROLL_BTN_MASK (1<<PS2_MOUSE_BTN_MIDDLE) /* Default */
    250 ```
    251 
    252 To disable the scroll button feature:
    253 
    254 ```c
    255 #define PS2_MOUSE_SCROLL_BTN_MASK 0
    256 ```
    257 
    258 The available buttons are:
    259 
    260 ```c
    261 #define PS2_MOUSE_BTN_LEFT      0
    262 #define PS2_MOUSE_BTN_RIGHT     1
    263 #define PS2_MOUSE_BTN_MIDDLE    2
    264 ```
    265 
    266 You can also combine buttons in the mask by `|`ing them together.
    267 
    268 Once you've configured your scroll button mask, you must configure the scroll button send interval.
    269 This is the interval before which if the scroll buttons were released they would be sent to the host.
    270 After this interval, they will cause the mouse to scroll and will not be sent.
    271 
    272 ```c
    273 #define PS2_MOUSE_SCROLL_BTN_SEND 300 /* Default */
    274 ```
    275 
    276 To disable sending the scroll buttons:
    277 
    278 ```c
    279 #define PS2_MOUSE_SCROLL_BTN_SEND 0
    280 ```
    281 
    282 Fine control over the scrolling is supported with the following defines:
    283 
    284 ```c
    285 #define PS2_MOUSE_SCROLL_DIVISOR_H 2
    286 #define PS2_MOUSE_SCROLL_DIVISOR_V 2
    287 ```
    288 
    289 ### Invert Mouse buttons {#invert-buttons}
    290 
    291 To invert the left & right buttons you can put:
    292 
    293 ```c
    294 #define PS2_MOUSE_INVERT_BUTTONS
    295 ```
    296 
    297 into config.h.
    298 
    299 ### Invert Mouse and Scroll Axes {#invert-mouse-and-scroll-axes}
    300 
    301 To invert the X and Y axes you can put:
    302 
    303 ```c
    304 #define PS2_MOUSE_INVERT_X
    305 #define PS2_MOUSE_INVERT_Y
    306 ```
    307 
    308 into config.h.
    309 
    310 To reverse the scroll axes you can put:
    311 
    312 ```c
    313 #define PS2_MOUSE_INVERT_H
    314 #define PS2_MOUSE_INVERT_V
    315 ```
    316 
    317 into config.h.
    318 
    319 ### Rotate Mouse Axes {#rotate-mouse-axes}
    320 
    321 Transform the output of the device with a clockwise rotation of 90, 180, or 270
    322 degrees.
    323 
    324 When compensating for device orientation, rotate the output the same amount in
    325 the opposite direction.  E.g. if the normal device orientation is considered to
    326 be North-facing, compensate as follows:
    327 
    328 ```c
    329 #define PS2_MOUSE_ROTATE 270 /* Compensate for East-facing device orientation. */
    330 ```
    331 ```c
    332 #define PS2_MOUSE_ROTATE 180 /* Compensate for South-facing device orientation. */
    333 ```
    334 ```c
    335 #define PS2_MOUSE_ROTATE 90 /* Compensate for West-facing device orientation. */
    336 ```
    337 
    338 ### Debug Settings {#debug-settings}
    339 
    340 To debug the mouse, add `debug_mouse = true` or enable via bootmagic.
    341 
    342 ```c
    343 /* To debug the mouse reports */
    344 #define PS2_MOUSE_DEBUG_HID
    345 #define PS2_MOUSE_DEBUG_RAW
    346 ```
    347 
    348 ### Movement Hook {#movement-hook}
    349 
    350 Process mouse movement in the keymap before it is sent to the host.  Example
    351 uses include filtering noise, adding acceleration, and automatically activating
    352 a layer.  To use, define the following function in your keymap:
    353 
    354 ```c
    355 void ps2_mouse_moved_user(report_mouse_t *mouse_report);
    356 ```