added PS/2 mouse code
[bootcensus] / src / psaux.c
1 /*
2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY, without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18 #include <stdio.h>
19 #include "psaux.h"
20 #include "intr.h"
21 #include "asmops.h"
22 #include "keyb.h"
23 #include "kbregs.h"
24
25 static void init_mouse();
26 static void psaux_intr();
27
28 static int mx, my;
29 static unsigned int bnstate;
30 static int present;
31 static int bounds[4];
32
33 void init_psaux(void)
34 {
35         interrupt(IRQ_TO_INTR(12), psaux_intr);
36
37         set_mouse_bounds(0, 0, 319, 199);
38
39         init_mouse();
40 }
41
42 static void init_mouse()
43 {
44         unsigned char val;
45
46         kb_send_cmd(KB_CMD_AUX_ENABLE);
47         if(kb_wait_read()) {
48                 val = kb_read_data();
49                 printf("aux enable: %02x\n", (unsigned int)val);
50         }
51
52         kb_send_cmd(KB_CMD_GET_CMDBYTE);
53         val = kb_read_data();
54         val &= ~KB_CCB_AUX_DISABLE;
55         val |= KB_CCB_AUX_INTREN;
56         kb_send_cmd(KB_CMD_SET_CMDBYTE);
57         kb_send_data(val);
58
59         if(kb_wait_read()) {
60                 val = kb_read_data();
61                 printf("set cmdbyte: %02x\n", (unsigned int)val);
62         }
63
64         kb_send_cmd(KB_CMD_PSAUX);
65         kb_send_data(AUX_CMD_DEFAULTS);
66         val = kb_read_data();
67
68         kb_send_cmd(KB_CMD_PSAUX);
69         kb_send_data(AUX_CMD_ENABLE);
70         val = kb_read_data();
71
72         present = (val == KB_ACK) ? 1 : 0;
73         printf("init_mouse: %spresent\n", present ? "" : "not ");
74 }
75
76 int have_mouse(void)
77 {
78         return present;
79 }
80
81 void set_mouse_bounds(int x0, int y0, int x1, int y1)
82 {
83         bounds[0] = x0;
84         bounds[1] = y0;
85         bounds[2] = x1;
86         bounds[3] = y1;
87 }
88
89 unsigned int mouse_state(int *xp, int *yp)
90 {
91         *xp = mx;
92         *yp = my;
93         return bnstate;
94 }
95
96 static void psaux_intr()
97 {
98         static unsigned char data[3];
99         static int idx;
100         int dx, dy;
101
102         if(!(inb(KB_STATUS_PORT) & KB_STAT_AUX)) {
103                 /* no mouse data pending, ignore interrupt */
104                 return;
105         }
106
107         data[idx] = kb_read_data();
108         if(++idx >= 3) {
109                 idx = 0;
110
111                 if(data[0] & AUX_PKT0_OVF_BITS) {
112                         /* consensus seems to be that if overflow bits are set, something is
113                          * fucked, and it's best to re-initialize the mouse
114                          */
115                         init_mouse();
116                 } else {
117                         /*
118                         printf("psaux data packet: %02x %02x %02x\n", (unsigned int)data[0],
119                                         (unsigned int)data[1], (unsigned int)data[2]);
120                         */
121
122                         bnstate = data[0] & AUX_PKT0_BUTTON_BITS;
123                         dx = data[1];
124                         dy = data[2];
125
126                         if(data[0] & AUX_PKT0_XSIGN) {
127                                 dx |= 0xffffff00;
128                         }
129                         if(data[0] & AUX_PKT0_YSIGN) {
130                                 dy |= 0xffffff00;
131                         }
132
133                         mx += dx;
134                         my -= dy;
135
136                         if(mx < bounds[0]) mx = bounds[0];
137                         if(mx > bounds[2]) mx = bounds[2];
138                         if(my < bounds[1]) my = bounds[1];
139                         if(my > bounds[3]) my = bounds[3];
140
141                         /*
142                         printf("mouse: %d,%d [%c%c%c]\n", mx, my, bnstate & AUX_PKT0_LEFTBN ? '1' : '0',
143                                         bnstate & AUX_PKT0_MIDDLEBN ? '1' : '0', bnstate & AUX_PKT0_RIGHTBN ? '1' : '0');
144                         */
145                 }
146         }
147 }