VirtualBox

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

Last change on this file since 91881 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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

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