1 // 16bit code to handle mouse events.
3 // Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002 MandrakeSoft S.A.
6 // This file may be distributed under the terms of the GNU GPLv3 license.
8 #include "biosvar.h" // struct bregs
9 #include "util.h" // debug_enter
11 #define DEBUGF1(fmt, args...) bprintf(0, fmt , ##args)
12 #define DEBUGF(fmt, args...)
14 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
17 set_kbd_command_byte(u8 command_byte)
19 if (inb(PORT_PS2_STATUS) & 0x02)
20 BX_PANIC(panic_msg_keyb_buffer_full, "setkbdcomm");
21 outb(0xD4, PORT_PS2_STATUS);
23 outb(0x60, PORT_PS2_STATUS); // write command byte
24 outb(command_byte, PORT_PS2_DATA);
28 inhibit_mouse_int_and_events()
30 // Turn off IRQ generation and aux data line
31 if (inb(PORT_PS2_STATUS) & 0x02)
32 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
33 outb(0x20, PORT_PS2_STATUS); // get command byte
34 while ((inb(PORT_PS2_STATUS) & 0x01) != 0x01)
36 u8 prev_command_byte = inb(PORT_PS2_DATA);
37 u8 command_byte = prev_command_byte;
38 //while ( (inb(PORT_PS2_STATUS) & 0x02) );
39 if ( inb(PORT_PS2_STATUS) & 0x02 )
40 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
41 command_byte &= 0xfd; // turn off IRQ 12 generation
42 command_byte |= 0x20; // disable mouse serial clock line
43 outb(0x60, PORT_PS2_STATUS); // write command byte
44 outb(command_byte, PORT_PS2_DATA);
45 return prev_command_byte;
49 enable_mouse_int_and_events()
51 // Turn on IRQ generation and aux data line
52 if ( inb(PORT_PS2_STATUS) & 0x02 )
53 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
54 outb(0x20, PORT_PS2_STATUS); // get command byte
55 while ((inb(PORT_PS2_STATUS) & 0x01) != 0x01)
57 u8 command_byte = inb(PORT_PS2_DATA);
58 //while ( (inb(PORT_PS2_STATUS) & 0x02) );
59 if (inb(PORT_PS2_STATUS) & 0x02)
60 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
61 command_byte |= 0x02; // turn on IRQ 12 generation
62 command_byte &= 0xdf; // enable mouse serial clock line
63 outb(0x60, PORT_PS2_STATUS); // write command byte
64 outb(command_byte, PORT_PS2_DATA);
68 send_to_mouse_ctrl(u8 sendbyte)
70 // wait for chance to write to ctrl
71 if (inb(PORT_PS2_STATUS) & 0x02)
72 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
73 outb(0xD4, PORT_PS2_STATUS);
74 outb(sendbyte, PORT_PS2_DATA);
78 get_mouse_data(u8 *data)
80 while ((inb(PORT_PS2_STATUS) & 0x21) != 0x21)
82 *data = inb(PORT_PS2_DATA);
85 #define RET_SUCCESS 0x00
86 #define RET_EINVFUNCTION 0x01
87 #define RET_EINVINPUT 0x02
88 #define RET_EINTERFACE 0x03
89 #define RET_ENEEDRESEND 0x04
90 #define RET_ENOHANDLER 0x05
94 mouse_15c20000(struct bregs *regs)
96 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
97 send_to_mouse_ctrl(0xF5); // disable mouse command
99 get_mouse_data(&mouse_data1);
100 set_code_success(regs);
103 #define BX_DEBUG_INT15(args...)
107 mouse_15c20001(struct bregs *regs)
109 u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
110 if ((mouse_flags_2 & 0x80) == 0) {
111 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
112 set_code_fail(regs, RET_ENOHANDLER);
115 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
116 send_to_mouse_ctrl(0xF4); // enable mouse command
118 get_mouse_data(&mouse_data1);
119 if (mouse_data1 == 0xFA) {
120 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
121 set_code_success(regs);
124 set_code_fail(regs, RET_ENEEDRESEND);
128 mouse_15c200XX(struct bregs *regs)
130 set_code_fail(regs, RET_EINVFUNCTION);
133 // Disable/Enable Mouse
135 mouse_15c200(struct bregs *regs)
138 case 0x00: mouse_15c20000(regs); break;
139 case 0x01: mouse_15c20001(regs); break;
140 default: mouse_15c200XX(regs); break;
146 mouse_15c201(struct bregs *regs)
148 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
149 send_to_mouse_ctrl(0xFF); // reset mouse command
150 u8 mouse_data1, mouse_data2, mouse_data3;
151 get_mouse_data(&mouse_data3);
152 // if no mouse attached, it will return RESEND
153 if (mouse_data3 == 0xfe) {
154 set_code_fail(regs, RET_ENEEDRESEND);
157 if (mouse_data3 != 0xfa)
158 BX_PANIC("Mouse reset returned %02x (should be ack)\n"
159 , (unsigned)mouse_data3);
160 get_mouse_data(&mouse_data1);
161 get_mouse_data(&mouse_data2);
162 // turn IRQ12 and packet generation on
163 enable_mouse_int_and_events();
164 regs->bl = mouse_data1;
165 regs->bh = mouse_data2;
166 set_code_success(regs);
171 mouse_15c202(struct bregs *regs)
174 set_code_fail(regs, RET_EUNSUPPORTED);
177 u8 mouse_data1 = regs->bh * 20;
180 send_to_mouse_ctrl(0xF3); // set sample rate command
182 get_mouse_data(&mouse_data2);
183 send_to_mouse_ctrl(mouse_data1);
184 get_mouse_data(&mouse_data2);
185 set_code_success(regs);
190 mouse_15c203(struct bregs *regs)
193 // 0 = 25 dpi, 1 count per millimeter
194 // 1 = 50 dpi, 2 counts per millimeter
195 // 2 = 100 dpi, 4 counts per millimeter
196 // 3 = 200 dpi, 8 counts per millimeter
197 u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
199 set_code_fail(regs, RET_EUNSUPPORTED);
202 send_to_mouse_ctrl(0xE8); // set resolution command
204 get_mouse_data(&mouse_data1);
205 if (mouse_data1 != 0xfa)
206 BX_PANIC("Mouse status returned %02x (should be ack)\n"
207 , (unsigned)mouse_data1);
208 send_to_mouse_ctrl(regs->bh);
209 get_mouse_data(&mouse_data1);
210 if (mouse_data1 != 0xfa)
211 BX_PANIC("Mouse status returned %02x (should be ack)\n"
212 , (unsigned)mouse_data1);
213 set_code_success(regs);
216 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
221 mouse_15c204(struct bregs *regs)
223 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
224 send_to_mouse_ctrl(0xF2); // get mouse ID command
225 u8 mouse_data1, mouse_data2;
226 get_mouse_data(&mouse_data1);
227 get_mouse_data(&mouse_data2);
228 regs->bh = mouse_data2;
229 set_code_success(regs);
234 mouse_15c205(struct bregs *regs)
237 set_code_fail(regs, RET_EINTERFACE);
240 SET_EBDA(mouse_flag1, 0x00);
241 SET_EBDA(mouse_flag2, regs->bh);
249 mouse_15c20600(struct bregs *regs)
251 u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
252 send_to_mouse_ctrl(0xE9); // get mouse info command
253 u8 mouse_data1, mouse_data2, mouse_data3;
254 get_mouse_data(&mouse_data1);
255 if (mouse_data1 != 0xfa)
256 BX_PANIC("Mouse status returned %02x (should be ack)\n"
257 , (unsigned)mouse_data1);
258 get_mouse_data(&mouse_data1);
259 get_mouse_data(&mouse_data2);
260 get_mouse_data(&mouse_data3);
261 regs->bl = mouse_data1;
262 regs->cl = mouse_data2;
263 regs->dl = mouse_data3;
264 set_code_success(regs);
265 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
269 set_scaling(struct bregs *regs, u8 cmd)
271 u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
272 send_to_mouse_ctrl(0xE6);
274 get_mouse_data(&mouse_data1);
275 if (mouse_data1 != 0xFA)
276 set_code_fail(regs, RET_EUNSUPPORTED);
278 set_code_success(regs);
279 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
282 // Set Scaling Factor to 1:1
284 mouse_15c20601(struct bregs *regs)
286 set_scaling(regs, 0xE6);
289 // Set Scaling Factor to 2:1
291 mouse_15c20602(struct bregs *regs)
293 set_scaling(regs, 0xE7);
297 mouse_15c206XX(struct bregs *regs)
299 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", regs->bh);
302 // Return Status & Set Scaling Factor...
304 mouse_15c206(struct bregs *regs)
307 case 0x00: mouse_15c20600(regs); break;
308 case 0x01: mouse_15c20601(regs); break;
309 case 0x02: mouse_15c20602(regs); break;
310 default: mouse_15c206XX(regs); break;
314 // Set Mouse Handler Address
316 mouse_15c207(struct bregs *regs)
318 u32 farptr = (regs->es << 16) | regs->bx;
319 SET_EBDA(far_call_pointer, farptr);
320 u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
323 if ((mouse_flags_2 & 0x80) != 0) {
324 mouse_flags_2 &= ~0x80;
325 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
328 /* install handler */
329 mouse_flags_2 |= 0x80;
331 SET_EBDA(mouse_flag2, mouse_flags_2);
332 set_code_success(regs);
336 mouse_15c2XX(struct bregs *regs)
338 set_code_fail(regs, RET_EINVFUNCTION);
342 handle_15c2(struct bregs *regs)
346 if (! CONFIG_PS2_MOUSE) {
347 set_code_fail(regs, RET_EUNSUPPORTED);
352 case 0x00: mouse_15c200(regs); break;
353 case 0x01: mouse_15c201(regs); break;
354 case 0x02: mouse_15c202(regs); break;
355 case 0x03: mouse_15c203(regs); break;
356 case 0x04: mouse_15c204(regs); break;
357 case 0x05: mouse_15c205(regs); break;
358 case 0x06: mouse_15c206(regs); break;
359 case 0x07: mouse_15c207(regs); break;
360 default: mouse_15c2XX(regs); break;
367 u8 v = inb(PORT_PS2_STATUS);
368 if ((v & 0x21) != 0x21)
371 v = inb(PORT_PS2_DATA);
373 u8 mouse_flags_1 = GET_EBDA(mouse_flag1);
374 u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
376 if ((mouse_flags_2 & 0x80) != 0x80)
379 u8 package_count = mouse_flags_2 & 0x07;
380 u8 index = mouse_flags_1 & 0x07;
381 SET_EBDA(mouse_data[index], v);
383 if ((index+1) < package_count) {
385 SET_EBDA(mouse_flag1, mouse_flags_1);
389 //BX_DEBUG_INT74("int74_function: make_farcall=1\n");
390 u16 status = GET_EBDA(mouse_data[0]);
391 u16 X = GET_EBDA(mouse_data[1]);
392 u16 Y = GET_EBDA(mouse_data[2]);
393 SET_EBDA(mouse_flag1, 0);
394 // check if far call handler installed
395 if (! (mouse_flags_2 & 0x80))
398 u32 func = GET_EBDA(far_call_pointer);
401 "pushw %w1\n" // status
408 : "+a" (func), "+b" (status), "+c" (X), "+d" (Y)
410 : "esi", "edi", "ebp", "cc"
414 // INT74h : PS/2 mouse hardware interrupt