VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/ps2mouse.c@ 69496

最後變更 在這個檔案從69496是 69496,由 vboxsync 提交於 7 年 前

*: scm --update-copyright-year

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette