keyboard stuff
1# PS/2 Mouse Support {#ps2-mouse-support}
2
3Its possible to hook up a PS/2 mouse (for example touchpads or trackpoints) to your keyboard as a composite device.
4
5To 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
7There 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
11To 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 |
19MODULE 5+ --------+--+--------- PWR CONTROLLER
20 |
21 4.7K
22 |
23 CLK ------+------------ PIN
24```
25
26## Driver Configuration {#driver-configuration}
27
28Driver 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
32Note: This is not recommended, you may encounter jerky movement or unsent inputs. Please use interrupt or USART version if possible.
33
34In rules.mk:
35
36```make
37PS2_MOUSE_ENABLE = yes
38PS2_ENABLE = yes
39PS2_DRIVER = busywait
40```
41
42In 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
53The 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
55In rules.mk:
56
57```make
58PS2_MOUSE_ENABLE = yes
59PS2_ENABLE = yes
60PS2_DRIVER = interrupt
61```
62
63In 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
86Pretty 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
88In rules.mk:
89
90```
91PS2_MOUSE_ENABLE = yes
92PS2_ENABLE = yes
93PS2_DRIVER = interrupt
94```
95
96In your keyboard `config.h`:
97
98```c
99#define PS2_CLOCK_PIN A8
100#define PS2_DATA_PIN A9
101```
102
103And 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
115To 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
117In rules.mk:
118
119```make
120PS2_MOUSE_ENABLE = yes
121PS2_ENABLE = yes
122PS2_DRIVER = usart
123```
124
125In 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
167The `PIO` subsystem is a Raspberry Pi RP2040 specific implementation, using the integrated PIO peripheral and is therefore only available on this MCU.
168
169There 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
171You 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
176Example 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
192These 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
211You can also call the following functions from ps2_mouse.h
212
213```c
214void ps2_mouse_disable_data_reporting(void);
215
216void ps2_mouse_enable_data_reporting(void);
217
218void ps2_mouse_set_remote_mode(void);
219
220void ps2_mouse_set_stream_mode(void);
221
222void ps2_mouse_set_scaling_2_1(void);
223
224void ps2_mouse_set_scaling_1_1(void);
225
226void ps2_mouse_set_resolution(ps2_mouse_resolution_t resolution);
227
228void ps2_mouse_set_sample_rate(ps2_mouse_sample_rate_t sample_rate);
229```
230
231### Fine Control {#fine-control}
232
233Use the following defines to change the sensitivity and speed of the mouse.
234Note: 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
244If you're using a trackpoint, you will likely want to be able to use it for scrolling.
245It's possible to enable a "scroll button/s" that when pressed will cause the mouse to scroll instead of moving.
246To 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
252To disable the scroll button feature:
253
254```c
255#define PS2_MOUSE_SCROLL_BTN_MASK 0
256```
257
258The 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
266You can also combine buttons in the mask by `|`ing them together.
267
268Once you've configured your scroll button mask, you must configure the scroll button send interval.
269This is the interval before which if the scroll buttons were released they would be sent to the host.
270After 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
276To disable sending the scroll buttons:
277
278```c
279#define PS2_MOUSE_SCROLL_BTN_SEND 0
280```
281
282Fine 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
291To invert the left & right buttons you can put:
292
293```c
294#define PS2_MOUSE_INVERT_BUTTONS
295```
296
297into config.h.
298
299### Invert Mouse and Scroll Axes {#invert-mouse-and-scroll-axes}
300
301To 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
308into config.h.
309
310To reverse the scroll axes you can put:
311
312```c
313#define PS2_MOUSE_INVERT_H
314#define PS2_MOUSE_INVERT_V
315```
316
317into config.h.
318
319### Rotate Mouse Axes {#rotate-mouse-axes}
320
321Transform the output of the device with a clockwise rotation of 90, 180, or 270
322degrees.
323
324When compensating for device orientation, rotate the output the same amount in
325the opposite direction. E.g. if the normal device orientation is considered to
326be 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
340To 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
350Process mouse movement in the keymap before it is sent to the host. Example
351uses include filtering noise, adding acceleration, and automatically activating
352a layer. To use, define the following function in your keymap:
353
354```c
355void ps2_mouse_moved_user(report_mouse_t *mouse_report);
356```