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