Revert "Rework disabling of ps2 port irqs."
[seabios.git] / src / mouse.c
1 // 16bit code to handle mouse events.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002  MandrakeSoft S.A.
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "biosvar.h" // GET_EBDA
9 #include "util.h" // debug_isr
10 #include "pic.h" // eoi_pic2
11 #include "bregs.h" // struct bregs
12 #include "ps2port.h" // aux_command
13
14 void
15 mouse_setup(void)
16 {
17     if (! CONFIG_MOUSE)
18         return;
19     dprintf(3, "init mouse\n");
20     // pointing device installed
21     SETBITS_BDA(equipment_list_flags, 0x04);
22 }
23
24 #define RET_SUCCESS      0x00
25 #define RET_EINVFUNCTION 0x01
26 #define RET_EINVINPUT    0x02
27 #define RET_EINTERFACE   0x03
28 #define RET_ENEEDRESEND  0x04
29 #define RET_ENOHANDLER   0x05
30
31 static int
32 disable_mouse(u16 ebda_seg)
33 {
34     u8 ps2ctr = GET_EBDA2(ebda_seg, ps2ctr);
35     ps2ctr |= I8042_CTR_AUXDIS;
36     ps2ctr &= ~I8042_CTR_AUXINT;
37     SET_EBDA2(ebda_seg, ps2ctr, ps2ctr);
38
39     return aux_command(PSMOUSE_CMD_DISABLE, NULL);
40 }
41
42 // Disable Mouse
43 static void
44 mouse_15c20000(struct bregs *regs)
45 {
46     u16 ebda_seg = get_ebda_seg();
47     int ret = disable_mouse(ebda_seg);
48     if (ret)
49         set_code_invalid(regs, RET_ENEEDRESEND);
50     else
51         set_code_success(regs);
52 }
53
54 // Enable Mouse
55 static void
56 mouse_15c20001(struct bregs *regs)
57 {
58     u16 ebda_seg = get_ebda_seg();
59     u8 mouse_flags_2 = GET_EBDA2(ebda_seg, mouse_flag2);
60     if ((mouse_flags_2 & 0x80) == 0) {
61         set_code_invalid(regs, RET_ENOHANDLER);
62         return;
63     }
64
65     u8 ps2ctr = GET_EBDA2(ebda_seg, ps2ctr);
66     ps2ctr &= ~I8042_CTR_AUXDIS;
67     ps2ctr |= I8042_CTR_AUXINT;
68     SET_EBDA2(ebda_seg, ps2ctr, ps2ctr);
69
70     int ret = aux_command(PSMOUSE_CMD_ENABLE, NULL);
71     if (ret)
72         set_code_invalid(regs, RET_ENEEDRESEND);
73     else
74         set_code_success(regs);
75 }
76
77 static void
78 mouse_15c200XX(struct bregs *regs)
79 {
80     set_code_unimplemented(regs, RET_EINVFUNCTION);
81 }
82
83 // Disable/Enable Mouse
84 static void
85 mouse_15c200(struct bregs *regs)
86 {
87     switch (regs->bh) {
88     case 0x00: mouse_15c20000(regs); break;
89     case 0x01: mouse_15c20001(regs); break;
90     default:   mouse_15c200XX(regs); break;
91     }
92 }
93
94 // Reset Mouse
95 static void
96 mouse_15c201(struct bregs *regs)
97 {
98     u8 param[2];
99     int ret = aux_command(PSMOUSE_CMD_RESET_BAT, param);
100     if (ret) {
101         set_code_invalid(regs, RET_ENEEDRESEND);
102         return;
103     }
104     regs->bl = param[0];
105     regs->bh = param[1];
106     set_code_success(regs);
107 }
108
109 // Set Sample Rate
110 static void
111 mouse_15c202(struct bregs *regs)
112 {
113     static u8 VAR16 sample_rates[7] = {10, 20, 40, 60, 80, 100, 200};
114     if (regs->bh >= ARRAY_SIZE(sample_rates)) {
115         set_code_invalid(regs, RET_EINVINPUT);
116         return;
117     }
118     u8 mouse_data1 = GET_GLOBAL(sample_rates[regs->bh]);
119     int ret = aux_command(PSMOUSE_CMD_SETRATE, &mouse_data1);
120     if (ret)
121         set_code_invalid(regs, RET_ENEEDRESEND);
122     else
123         set_code_success(regs);
124 }
125
126 // Set Resolution
127 static void
128 mouse_15c203(struct bregs *regs)
129 {
130     // BH:
131     //      0 =  25 dpi, 1 count  per millimeter
132     //      1 =  50 dpi, 2 counts per millimeter
133     //      2 = 100 dpi, 4 counts per millimeter
134     //      3 = 200 dpi, 8 counts per millimeter
135     if (regs->bh >= 4) {
136         set_code_invalid(regs, RET_EINVINPUT);
137         return;
138     }
139     u8 param = regs->bh;
140     int ret = aux_command(PSMOUSE_CMD_SETRES, &param);
141     if (ret)
142         set_code_invalid(regs, RET_ENEEDRESEND);
143     else
144         set_code_success(regs);
145 }
146
147 // Get Device ID
148 static void
149 mouse_15c204(struct bregs *regs)
150 {
151     u8 param[2];
152     int ret = aux_command(PSMOUSE_CMD_GETID, param);
153     if (ret) {
154         set_code_invalid(regs, RET_ENEEDRESEND);
155         return;
156     }
157     regs->bh = param[0];
158     set_code_success(regs);
159 }
160
161 // Initialize Mouse
162 static void
163 mouse_15c205(struct bregs *regs)
164 {
165     if (regs->bh != 3) {
166         set_code_invalid(regs, RET_EINTERFACE);
167         return;
168     }
169     u16 ebda_seg = get_ebda_seg();
170     SET_EBDA2(ebda_seg, mouse_flag1, 0x00);
171     SET_EBDA2(ebda_seg, mouse_flag2, regs->bh);
172
173     // Reset Mouse
174     mouse_15c201(regs);
175 }
176
177 // Return Status
178 static void
179 mouse_15c20600(struct bregs *regs)
180 {
181     u8 param[3];
182     int ret = aux_command(PSMOUSE_CMD_GETINFO, param);
183     if (ret) {
184         set_code_invalid(regs, RET_ENEEDRESEND);
185         return;
186     }
187     regs->bl = param[0];
188     regs->cl = param[1];
189     regs->dl = param[2];
190     set_code_success(regs);
191 }
192
193 // Set Scaling Factor to 1:1
194 static void
195 mouse_15c20601(struct bregs *regs)
196 {
197     int ret = aux_command(PSMOUSE_CMD_SETSCALE11, NULL);
198     if (ret)
199         set_code_invalid(regs, RET_ENEEDRESEND);
200     else
201         set_code_success(regs);
202 }
203
204 // Set Scaling Factor to 2:1
205 static void
206 mouse_15c20602(struct bregs *regs)
207 {
208     int ret = aux_command(PSMOUSE_CMD_SETSCALE21, NULL);
209     if (ret)
210         set_code_invalid(regs, RET_ENEEDRESEND);
211     else
212         set_code_success(regs);
213 }
214
215 static void
216 mouse_15c206XX(struct bregs *regs)
217 {
218     set_code_unimplemented(regs, RET_EINVFUNCTION);
219 }
220
221 // Return Status & Set Scaling Factor...
222 static void
223 mouse_15c206(struct bregs *regs)
224 {
225     switch (regs->bh) {
226     case 0x00: mouse_15c20600(regs); break;
227     case 0x01: mouse_15c20601(regs); break;
228     case 0x02: mouse_15c20602(regs); break;
229     default:   mouse_15c206XX(regs); break;
230     }
231 }
232
233 // Set Mouse Handler Address
234 static void
235 mouse_15c207(struct bregs *regs)
236 {
237     struct segoff_s farptr = SEGOFF(regs->es, regs->bx);
238     u16 ebda_seg = get_ebda_seg();
239     u8 mouse_flags_2 = GET_EBDA2(ebda_seg, mouse_flag2);
240     if (! farptr.segoff) {
241         /* remove handler */
242         if ((mouse_flags_2 & 0x80) != 0) {
243             mouse_flags_2 &= ~0x80;
244             disable_mouse(ebda_seg);
245         }
246     } else {
247         /* install handler */
248         mouse_flags_2 |= 0x80;
249     }
250     SET_EBDA2(ebda_seg, mouse_flag2, mouse_flags_2);
251     SET_EBDA2(ebda_seg, far_call_pointer, farptr);
252     set_code_success(regs);
253 }
254
255 static void
256 mouse_15c2XX(struct bregs *regs)
257 {
258     set_code_unimplemented(regs, RET_EINVFUNCTION);
259 }
260
261 void
262 handle_15c2(struct bregs *regs)
263 {
264     //debug_stub(regs);
265
266     if (! CONFIG_MOUSE) {
267         set_code_invalid(regs, RET_EUNSUPPORTED);
268         return;
269     }
270
271     switch (regs->al) {
272     case 0x00: mouse_15c200(regs); break;
273     case 0x01: mouse_15c201(regs); break;
274     case 0x02: mouse_15c202(regs); break;
275     case 0x03: mouse_15c203(regs); break;
276     case 0x04: mouse_15c204(regs); break;
277     case 0x05: mouse_15c205(regs); break;
278     case 0x06: mouse_15c206(regs); break;
279     case 0x07: mouse_15c207(regs); break;
280     default:   mouse_15c2XX(regs); break;
281     }
282 }
283
284 void noinline
285 process_mouse(u8 data)
286 {
287     if (!CONFIG_MOUSE)
288         return;
289
290     u16 ebda_seg = get_ebda_seg();
291     u8 mouse_flags_1 = GET_EBDA2(ebda_seg, mouse_flag1);
292     u8 mouse_flags_2 = GET_EBDA2(ebda_seg, mouse_flag2);
293
294     if (! (mouse_flags_2 & 0x80))
295         // far call handler not installed
296         return;
297
298     u8 package_count = mouse_flags_2 & 0x07;
299     u8 index = mouse_flags_1 & 0x07;
300     SET_EBDA2(ebda_seg, mouse_data[index], data);
301
302     if ((index+1) < package_count) {
303         mouse_flags_1++;
304         SET_EBDA2(ebda_seg, mouse_flag1, mouse_flags_1);
305         return;
306     }
307
308     //BX_DEBUG_INT74("int74_function: make_farcall=1\n");
309     u16 status = GET_EBDA2(ebda_seg, mouse_data[0]);
310     u16 X      = GET_EBDA2(ebda_seg, mouse_data[1]);
311     u16 Y      = GET_EBDA2(ebda_seg, mouse_data[2]);
312     SET_EBDA2(ebda_seg, mouse_flag1, 0);
313
314     struct segoff_s func = GET_EBDA2(ebda_seg, far_call_pointer);
315
316     asm volatile(
317         "sti\n"
318
319         "pushl %0\n"
320         "pushw %w1\n"  // status
321         "pushw %w2\n"  // X
322         "pushw %w3\n"  // Y
323         "pushw $0\n"   // Z
324         "lcallw *8(%%esp)\n"
325         "addl $12, %%esp\n"
326
327         "cli\n"
328         "cld\n"
329         :
330         : "r"(func.segoff), "r"(status), "r"(X), "r"(Y)
331         : "cc"
332         );
333 }