reorganize source
[com32] / src / kern / 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(void);
26 static void proc_mouse_data(unsigned char *data);
27 static void psaux_intr();
28
29 static int mx, my;
30 static unsigned int bnstate;
31 static int present;
32 static int bounds[4];
33 static int intr_mode;
34
35 void init_psaux(void)
36 {
37         interrupt(IRQ_TO_INTR(12), psaux_intr);
38         unmask_irq(12);
39
40         init_mouse();
41         set_mouse_bounds(0, 0, 319, 199);
42 }
43
44 static void init_mouse(void)
45 {
46         unsigned char val;
47
48         kb_send_cmd(KB_CMD_AUX_ENABLE);
49         if(kb_wait_read()) {
50                 val = kb_read_data();
51                 printf("aux enable: %02x\n", (unsigned int)val);
52         }
53
54         /*
55         kb_send_cmd(KB_CMD_PSAUX);
56         kb_send_data(AUX_CMD_REMOTE_MODE);
57         val = kb_read_data();
58         */
59
60         kb_send_cmd(KB_CMD_GET_CMDBYTE);
61         val = kb_read_data();
62         val &= ~KB_CCB_AUX_DISABLE;
63         val |= KB_CCB_AUX_INTREN;
64         kb_send_cmd(KB_CMD_SET_CMDBYTE);
65         kb_send_data(val);
66
67         if(kb_wait_read()) {
68                 val = kb_read_data();
69                 printf("set cmdbyte: %02x\n", (unsigned int)val);
70         }
71         intr_mode = 1;
72
73         kb_send_cmd(KB_CMD_PSAUX);
74         kb_send_data(AUX_CMD_DEFAULTS);
75         val = kb_read_data();
76
77         kb_send_cmd(KB_CMD_PSAUX);
78         kb_send_data(AUX_CMD_ENABLE);
79         val = kb_read_data();
80
81         present = (val == KB_ACK) ? 1 : 0;
82         printf("init_mouse: %spresent\n", present ? "" : "not ");
83 }
84
85 int have_mouse(void)
86 {
87         return present;
88 }
89
90 void set_mouse_bounds(int x0, int y0, int x1, int y1)
91 {
92         bounds[0] = x0;
93         bounds[1] = y0;
94         bounds[2] = x1;
95         bounds[3] = y1;
96 }
97
98 unsigned int mouse_state(int *xp, int *yp)
99 {
100         if(!intr_mode) {
101                 poll_mouse();
102         }
103
104         *xp = mx;
105         *yp = my;
106         return bnstate;
107 }
108
109 /* TODO: poll_mouse doesn't work (enable remote mode and disable interrupt on init to test) */
110 #define STAT_AUX_PENDING                (KB_STAT_OUTBUF_FULL | KB_STAT_AUX)
111 static inline int aux_pending(void)
112 {
113         return (inp(KB_STATUS_PORT) & STAT_AUX_PENDING) == STAT_AUX_PENDING ? 1 : 0;
114 }
115
116 void poll_mouse(void)
117 {
118         static int poll_state;
119         static unsigned char pkt[3];
120         unsigned char rd;
121
122         ser_printf("poll_mouse(%d)\n", poll_state);
123
124         switch(poll_state) {
125         case 0: /* send read mouse command */
126                 kb_send_cmd(KB_CMD_PSAUX);
127                 kb_send_data(AUX_CMD_READ_MOUSE);
128                 ++poll_state;
129                 break;
130
131         case 1: /* wait for ACK */
132                 if(kb_wait_read()) {// && aux_pending()) {
133                         if((rd = kb_read_data()) == KB_ACK) {
134                                 ++poll_state;
135                         } else {
136                                 ser_printf("poll_mouse state 1: expected ack: %02x\n", (unsigned int)rd);
137                         }
138                 }
139                 break;
140
141         case 2: /* read packet data */
142         case 3:
143         case 4:
144                 if(kb_wait_read() && aux_pending()) {
145                         int i = poll_state++ - 2;
146                         pkt[i] = kb_read_data();
147                 }
148                 if(poll_state == 5) {
149                         ser_printf("proc_mouse_data(%02x %02x %02x)\n", (unsigned int)pkt[0],
150                                         (unsigned int)pkt[1], (unsigned int)pkt[2]);
151                         proc_mouse_data(pkt);
152                         poll_state = 0;
153                 }
154                 break;
155
156         default:
157                 ser_printf("poll_mouse reached state: %d\n", poll_state);
158         }
159 }
160
161 static void proc_mouse_data(unsigned char *data)
162 {
163         int dx, dy;
164
165         if(data[0] & AUX_PKT0_OVF_BITS) {
166                 /* consensus seems to be that if overflow bits are set, something is
167                  * fucked, and it's best to re-initialize the mouse
168                  */
169                 /*init_mouse();*/
170         } else {
171                 bnstate = data[0] & AUX_PKT0_BUTTON_BITS;
172                 dx = data[1];
173                 dy = data[2];
174
175                 if(data[0] & AUX_PKT0_XSIGN) {
176                         dx |= 0xffffff00;
177                 }
178                 if(data[0] & AUX_PKT0_YSIGN) {
179                         dy |= 0xffffff00;
180                 }
181
182                 mx += dx;
183                 my -= dy;
184
185                 if(mx < bounds[0]) mx = bounds[0];
186                 if(mx > bounds[2]) mx = bounds[2];
187                 if(my < bounds[1]) my = bounds[1];
188                 if(my > bounds[3]) my = bounds[3];
189         }
190 }
191
192 static void psaux_intr()
193 {
194         static unsigned char data[3];
195         static int idx;
196
197         if(!(inp(KB_STATUS_PORT) & KB_STAT_AUX)) {
198                 /* no mouse data pending, ignore interrupt */
199                 return;
200         }
201
202         data[idx] = kb_read_data();
203         if(++idx >= 3) {
204                 idx = 0;
205
206                 proc_mouse_data(data);
207         }
208 }