VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS-new/ps2mouse.c@ 40754

Last change on this file since 40754 was 38832, checked in by vboxsync, 13 years ago

Do not just loop forever.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.0 KB
Line 
1/*
2 * Copyright (C) 2006-2011 Oracle Corporation
3 *
4 * This file is part of VirtualBox Open Source Edition (OSE), as
5 * available from http://www.virtualbox.org. This file is free software;
6 * you can redistribute it and/or modify it under the terms of the GNU
7 * General Public License (GPL) as published by the Free Software
8 * Foundation, in version 2 as it comes in the "COPYING" file of the
9 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11 * --------------------------------------------------------------------
12 *
13 * This code is based on:
14 *
15 * ROM BIOS for use with Bochs/Plex86/QEMU emulation environment
16 *
17 * Copyright (C) 2002 MandrakeSoft S.A.
18 *
19 * MandrakeSoft S.A.
20 * 43, rue d'Aboukir
21 * 75002 Paris - France
22 * http://www.linux-mandrake.com/
23 * http://www.mandrakesoft.com/
24 *
25 * This library is free software; you can redistribute it and/or
26 * modify it under the terms of the GNU Lesser General Public
27 * License as published by the Free Software Foundation; either
28 * version 2 of the License, or (at your option) any later version.
29 *
30 * This library is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33 * Lesser General Public License for more details.
34 *
35 * You should have received a copy of the GNU Lesser General Public
36 * License along with this library; if not, write to the Free Software
37 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
38 *
39 */
40
41
42#include <stdint.h>
43#include "biosint.h"
44#include "inlines.h"
45
46
47#if DEBUG_INT15_MS
48# define BX_DEBUG_INT15_MS(...) BX_DEBUG(__VA_ARGS__)
49#else
50# define BX_DEBUG_INT15_MS(...)
51#endif
52
53#if DEBUG_INT74
54# define BX_DEBUG_INT74(...) BX_DEBUG(__VA_ARGS__)
55#else
56# define BX_DEBUG_INT74(...)
57#endif
58
59#if BX_USE_PS2_MOUSE
60
61static const char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
62
63uint8_t send_to_mouse_ctrl(uint8_t sendbyte)
64{
65 BX_DEBUG_INT15_MS("send %02x to mouse:\n", sendbyte);
66 // wait for chance to write to ctrl
67 if (inb(0x64) & 0x02)
68 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
69 outb(0x64, 0xD4);
70 outb(0x60, sendbyte);
71 return(0);
72}
73
74
75uint8_t get_mouse_data(uint8_t __far *data)
76{
77 int retries = 10000;
78 uint8_t response;
79
80 while ((inb(0x64) & 0x21) != 0x21 && retries)
81 --retries;
82
83 if (!retries)
84 return(1);
85
86 response = inb(0x60);
87 *data = response;
88 return(0);
89}
90
91void set_kbd_command_byte(uint8_t command_byte)
92{
93 if (inb(0x64) & 0x02)
94 BX_PANIC(panic_msg_keyb_buffer_full,"setkbdcomm");
95
96 outb(0x64, 0x60); // write command byte
97 outb(0x60, command_byte);
98}
99
100
101void BIOSCALL int74_function(volatile uint16_t make_farcall, volatile uint16_t Z,
102 volatile uint16_t Y, volatile uint16_t X, volatile uint16_t status)
103{
104 uint16_t ebda_seg=read_word(0x0040,0x000E);
105 uint8_t in_byte, index, package_count;
106 uint8_t mouse_flags_1, mouse_flags_2;
107
108 BX_DEBUG_INT74("entering int74_function\n");
109 make_farcall = 0;
110
111 in_byte = inb(0x64);
112 if ( (in_byte & 0x21) != 0x21 ) {
113 return;
114 }
115 in_byte = inb(0x60);
116 BX_DEBUG_INT74("int74: read byte %02x\n", in_byte);
117
118 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
119 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
120
121 if ( (mouse_flags_2 & 0x80) != 0x80 ) {
122 return;
123 }
124
125 package_count = mouse_flags_2 & 0x07;
126 index = mouse_flags_1 & 0x07;
127 write_byte(ebda_seg, 0x28 + index, in_byte);
128
129 if ( index >= package_count ) {
130 BX_DEBUG_INT74("int74_function: make_farcall=1\n");
131 status = read_byte(ebda_seg, 0x0028 + 0);
132 X = read_byte(ebda_seg, 0x0028 + 1);
133 Y = read_byte(ebda_seg, 0x0028 + 2);
134 Z = 0;
135 mouse_flags_1 = 0;
136 // check if far call handler installed
137 if (mouse_flags_2 & 0x80)
138 make_farcall = 1;
139 }
140 else {
141 mouse_flags_1++;
142 }
143 write_byte(ebda_seg, 0x0026, mouse_flags_1);
144}
145
146void BIOSCALL int15_function_mouse(pusha_regs_t regs, uint16_t ES, uint16_t DS, volatile uint16_t FLAGS)
147{
148 uint16_t ebda_seg=read_word(0x0040,0x000E);
149 uint8_t mouse_flags_1, mouse_flags_2;
150 uint16_t mouse_driver_seg;
151 uint16_t mouse_driver_offset;
152 uint8_t mouse_cmd;
153 uint8_t ret, mouse_data1, mouse_data2, mouse_data3;
154
155 BX_DEBUG_INT15_MS("int15 AX=%04x\n",regs.u.r16.ax);
156
157 // Return Codes status in AH
158 // =========================
159 // 00: success
160 // 01: invalid subfunction (AL > 7)
161 // 02: invalid input value (out of allowable range)
162 // 03: interface error
163 // 04: resend command received from mouse controller,
164 // device driver should attempt command again
165 // 05: cannot enable mouse, since no far call has been installed
166 // 80/86: mouse service not implemented
167
168 if (regs.u.r8.al > 7) {
169 BX_DEBUG_INT15_MS("unsupported subfn\n");
170 // invalid function
171 SET_CF();
172 regs.u.r8.ah = 1;
173 return;
174 }
175
176 // Valid subfn; disable AUX input and IRQ12, assume no error
177 set_kbd_command_byte(0x65);
178 CLEAR_CF();
179 regs.u.r8.ah = 0;
180
181 switch (regs.u.r8.al) {
182 case 0: // Disable/Enable Mouse
183 BX_DEBUG_INT15_MS("case 0: ");
184 if (regs.u.r8.bh > 1) {
185 BX_DEBUG_INT15_MS("INT 15h C2 AL=0, BH=%02x\n", (unsigned) regs.u.r8.bh);
186 // invalid subfunction
187 SET_CF();
188 regs.u.r8.ah = 1;
189 break;
190 }
191 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
192 if ( (mouse_flags_2 & 0x80) == 0 ) {
193 BX_DEBUG_INT15_MS("INT 15h C2 Enable/Disable Mouse, no far call handler\n");
194 SET_CF();
195 regs.u.r8.ah = 5; // no far call installed
196 break;
197 }
198 if (regs.u.r8.bh == 0) {
199 BX_DEBUG_INT15_MS("Disable Mouse\n");
200 mouse_cmd = 0xF5; // disable mouse command
201 } else {
202 BX_DEBUG_INT15_MS("Enable Mouse\n");
203 mouse_cmd = 0xF4; // enable mouse command
204 }
205
206 ret = send_to_mouse_ctrl(mouse_cmd); // disable mouse command
207 if (ret == 0) {
208 ret = get_mouse_data(&mouse_data1);
209 if ( (ret == 0) || (mouse_data1 == 0xFA) ) {
210 // success
211 break;
212 }
213 }
214
215 // interface error
216 SET_CF();
217 regs.u.r8.ah = 3;
218 break;
219
220 case 5: // Initialize Mouse
221 // Valid package sizes are 1 to 8
222 if ( (regs.u.r8.bh < 1) || (regs.u.r8.bh > 8) ) {
223 SET_CF();
224 regs.u.r8.ah = 2; // invalid input
225 break;
226 }
227 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
228 mouse_flags_2 = (mouse_flags_2 & 0xf8) | (regs.u.r8.bh - 1);
229 write_byte(ebda_seg, 0x0027, mouse_flags_2);
230 // fall through!
231
232 case 1: // Reset Mouse
233 BX_DEBUG_INT15_MS("case 1 or 5:\n");
234 // clear current package byte index
235 mouse_flags_1 = read_byte(ebda_seg, 0x0026);
236 mouse_flags_1 = mouse_flags_1 & 0xf8;
237 write_byte(ebda_seg, 0x0026, mouse_flags_1);
238 ret = send_to_mouse_ctrl(0xFF); // reset mouse command
239 if (ret == 0) {
240 ret = get_mouse_data(&mouse_data3);
241 // if no mouse attached, it will return RESEND
242 if (mouse_data3 == 0xfe) {
243 SET_CF();
244 regs.u.r8.ah = 4; // resend
245 break;
246 }
247 if (mouse_data3 != 0xfa)
248 BX_PANIC("Mouse reset returned %02x (should be ack)\n", (unsigned)mouse_data3);
249 if ( ret == 0 ) {
250 ret = get_mouse_data(&mouse_data1);
251 if ( ret == 0 ) {
252 ret = get_mouse_data(&mouse_data2);
253 if ( ret == 0 ) {
254 // success
255 regs.u.r8.bl = mouse_data1;
256 regs.u.r8.bh = mouse_data2;
257 break;
258 }
259 }
260 }
261 }
262
263 // interface error
264 SET_CF();
265 regs.u.r8.ah = 3;
266 break;
267
268 case 2: // Set Sample Rate
269 BX_DEBUG_INT15_MS("case 2:\n");
270 switch (regs.u.r8.bh) {
271 case 0: mouse_data1 = 10; break; // 10 reports/sec
272 case 1: mouse_data1 = 20; break; // 20 reports/sec
273 case 2: mouse_data1 = 40; break; // 40 reports/sec
274 case 3: mouse_data1 = 60; break; // 60 reports/sec
275 case 4: mouse_data1 = 80; break; // 80 reports/sec
276 case 5: mouse_data1 = 100; break; // 100 reports/sec (default)
277 case 6: mouse_data1 = 200; break; // 200 reports/sec
278 default: mouse_data1 = 0;
279 }
280 if (mouse_data1 > 0) {
281 ret = send_to_mouse_ctrl(0xF3); // set sample rate command
282 if (ret == 0) {
283 ret = get_mouse_data(&mouse_data2);
284 ret = send_to_mouse_ctrl(mouse_data1);
285 ret = get_mouse_data(&mouse_data2);
286 // success
287 } else {
288 // interface error
289 SET_CF();
290 regs.u.r8.ah = 3;
291 }
292 } else {
293 // invalid input
294 SET_CF();
295 regs.u.r8.ah = 2;
296 }
297 break;
298
299 case 3: // Set Resolution
300 BX_DEBUG_INT15_MS("case 3:\n");
301 // BX:
302 // 0 = 25 dpi, 1 count per millimeter
303 // 1 = 50 dpi, 2 counts per millimeter
304 // 2 = 100 dpi, 4 counts per millimeter
305 // 3 = 200 dpi, 8 counts per millimeter
306 if (regs.u.r8.bh < 4) {
307 ret = send_to_mouse_ctrl(0xE8); // set resolution command
308 if (ret == 0) {
309 ret = get_mouse_data(&mouse_data1);
310 if (mouse_data1 != 0xfa)
311 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
312 ret = send_to_mouse_ctrl(regs.u.r8.bh);
313 ret = get_mouse_data(&mouse_data1);
314 if (mouse_data1 != 0xfa)
315 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
316 // success
317 } else {
318 // interface error
319 SET_CF();
320 regs.u.r8.ah = 3;
321 }
322 } else {
323 // invalid input
324 SET_CF();
325 regs.u.r8.ah = 2;
326 }
327 break;
328
329 case 4: // Get Device ID
330 BX_DEBUG_INT15_MS("case 4:\n");
331 ret = send_to_mouse_ctrl(0xF2); // get mouse ID command
332 if (ret == 0) {
333 ret = get_mouse_data(&mouse_data1);
334 ret = get_mouse_data(&mouse_data2);
335 regs.u.r8.bh = mouse_data2;
336 // success
337 } else {
338 // interface error
339 SET_CF();
340 regs.u.r8.ah = 3;
341 }
342 break;
343
344 case 6: // Return Status & Set Scaling Factor...
345 BX_DEBUG_INT15_MS("case 6:\n");
346 switch (regs.u.r8.bh) {
347 case 0: // Return Status
348 ret = send_to_mouse_ctrl(0xE9); // get mouse info command
349 if (ret == 0) {
350 ret = get_mouse_data(&mouse_data1);
351 if (mouse_data1 != 0xfa)
352 BX_PANIC("Mouse status returned %02x (should be ack)\n", (unsigned)mouse_data1);
353 if (ret == 0) {
354 ret = get_mouse_data(&mouse_data1);
355 if ( ret == 0 ) {
356 ret = get_mouse_data(&mouse_data2);
357 if ( ret == 0 ) {
358 ret = get_mouse_data(&mouse_data3);
359 if ( ret == 0 ) {
360 regs.u.r8.bl = mouse_data1;
361 regs.u.r8.cl = mouse_data2;
362 regs.u.r8.dl = mouse_data3;
363 // success
364 break;
365 }
366 }
367 }
368 }
369 }
370
371 // interface error
372 SET_CF();
373 regs.u.r8.ah = 3;
374 break;
375
376 case 1: // Set Scaling Factor to 1:1
377 case 2: // Set Scaling Factor to 2:1
378 if (regs.u.r8.bh == 1) {
379 ret = send_to_mouse_ctrl(0xE6);
380 } else {
381 ret = send_to_mouse_ctrl(0xE7);
382 }
383 if (ret == 0) {
384 get_mouse_data(&mouse_data1);
385 ret = (mouse_data1 != 0xFA);
386 }
387 if (ret != 0) {
388 // interface error
389 SET_CF();
390 regs.u.r8.ah = 3;
391 }
392 break;
393
394 default:
395 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", (unsigned) regs.u.r8.bh);
396 // invalid subfunction
397 SET_CF();
398 regs.u.r8.ah = 1;
399 }
400 break;
401
402 case 7: // Set Mouse Handler Address
403 BX_DEBUG_INT15_MS("case 7:\n");
404 mouse_driver_seg = ES;
405 mouse_driver_offset = regs.u.r16.bx;
406 write_word(ebda_seg, 0x0022, mouse_driver_offset);
407 write_word(ebda_seg, 0x0024, mouse_driver_seg);
408 mouse_flags_2 = read_byte(ebda_seg, 0x0027);
409 if (mouse_driver_offset == 0 && mouse_driver_seg == 0) {
410 /* remove handler */
411 if ( (mouse_flags_2 & 0x80) != 0 ) {
412 mouse_flags_2 &= ~0x80;
413 }
414 }
415 else {
416 /* install handler */
417 mouse_flags_2 |= 0x80;
418 }
419 write_byte(ebda_seg, 0x0027, mouse_flags_2);
420 break;
421
422 default:
423 BX_PANIC("INT 15h C2 default case entered\n");
424 // invalid subfunction
425 SET_CF();
426 regs.u.r8.ah = 1;
427 }
428 BX_DEBUG_INT15_MS("returning cf = %u, ah = %02x\n", (unsigned)GET_CF(), (unsigned)regs.u.r8.ah);
429 // Re-enable AUX input and IRQ12
430 set_kbd_command_byte(0x47);
431}
432#endif // BX_USE_PS2_MOUSE
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use