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_isr
10 #include "pic.h" // unmask_pic2
12 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
17 if (! CONFIG_PS2_MOUSE)
19 dprintf(3, "init mouse\n");
20 // pointing device installed
21 SETBITS_BDA(equipment_list_flags, 0x04);
22 // Enable IRQ12 (handle_74)
23 unmask_pic2(PIC2_IRQ12);
27 set_kbd_command_byte(u8 command_byte)
29 if (inb(PORT_PS2_STATUS) & 0x02)
30 BX_PANIC(panic_msg_keyb_buffer_full, "setkbdcomm");
31 outb(0xD4, PORT_PS2_STATUS);
33 outb(0x60, PORT_PS2_STATUS); // write command byte
34 outb(command_byte, PORT_PS2_DATA);
38 inhibit_mouse_int_and_events()
40 // Turn off IRQ generation and aux data line
41 if (inb(PORT_PS2_STATUS) & 0x02)
42 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
43 outb(0x20, PORT_PS2_STATUS); // get command byte
44 while ((inb(PORT_PS2_STATUS) & 0x01) != 0x01)
46 u8 prev_command_byte = inb(PORT_PS2_DATA);
47 u8 command_byte = prev_command_byte;
48 //while ( (inb(PORT_PS2_STATUS) & 0x02) );
49 if ( inb(PORT_PS2_STATUS) & 0x02 )
50 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
51 command_byte &= 0xfd; // turn off IRQ 12 generation
52 command_byte |= 0x20; // disable mouse serial clock line
53 outb(0x60, PORT_PS2_STATUS); // write command byte
54 outb(command_byte, PORT_PS2_DATA);
55 return prev_command_byte;
59 enable_mouse_int_and_events()
61 // Turn on IRQ generation and aux data line
62 if ( inb(PORT_PS2_STATUS) & 0x02 )
63 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
64 outb(0x20, PORT_PS2_STATUS); // get command byte
65 while ((inb(PORT_PS2_STATUS) & 0x01) != 0x01)
67 u8 command_byte = inb(PORT_PS2_DATA);
68 //while ( (inb(PORT_PS2_STATUS) & 0x02) );
69 if (inb(PORT_PS2_STATUS) & 0x02)
70 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
71 command_byte |= 0x02; // turn on IRQ 12 generation
72 command_byte &= 0xdf; // enable mouse serial clock line
73 outb(0x60, PORT_PS2_STATUS); // write command byte
74 outb(command_byte, PORT_PS2_DATA);
78 send_to_mouse_ctrl(u8 sendbyte)
80 // wait for chance to write to ctrl
81 if (inb(PORT_PS2_STATUS) & 0x02)
82 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
83 outb(0xD4, PORT_PS2_STATUS);
84 outb(sendbyte, PORT_PS2_DATA);
88 get_mouse_data(u8 *data)
90 while ((inb(PORT_PS2_STATUS) & 0x21) != 0x21)
92 *data = inb(PORT_PS2_DATA);
95 #define RET_SUCCESS 0x00
96 #define RET_EINVFUNCTION 0x01
97 #define RET_EINVINPUT 0x02
98 #define RET_EINTERFACE 0x03
99 #define RET_ENEEDRESEND 0x04
100 #define RET_ENOHANDLER 0x05
104 mouse_15c20000(struct bregs *regs)
106 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
107 send_to_mouse_ctrl(0xF5); // disable mouse command
109 get_mouse_data(&mouse_data1);
110 set_code_success(regs);
113 #define BX_DEBUG_INT15(args...)
117 mouse_15c20001(struct bregs *regs)
119 u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
120 if ((mouse_flags_2 & 0x80) == 0) {
121 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
122 set_code_fail(regs, RET_ENOHANDLER);
125 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
126 send_to_mouse_ctrl(0xF4); // enable mouse command
128 get_mouse_data(&mouse_data1);
129 if (mouse_data1 == 0xFA) {
130 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
131 set_code_success(regs);
134 set_code_fail(regs, RET_ENEEDRESEND);
138 mouse_15c200XX(struct bregs *regs)
140 set_code_fail(regs, RET_EINVFUNCTION);
143 // Disable/Enable Mouse
145 mouse_15c200(struct bregs *regs)
148 case 0x00: mouse_15c20000(regs); break;
149 case 0x01: mouse_15c20001(regs); break;
150 default: mouse_15c200XX(regs); break;
156 mouse_15c201(struct bregs *regs)
158 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
159 send_to_mouse_ctrl(0xFF); // reset mouse command
160 u8 mouse_data1, mouse_data2, mouse_data3;
161 get_mouse_data(&mouse_data3);
162 // if no mouse attached, it will return RESEND
163 if (mouse_data3 == 0xfe) {
164 set_code_fail(regs, RET_ENEEDRESEND);
167 if (mouse_data3 != 0xfa)
168 BX_PANIC("Mouse reset returned %02x (should be ack)\n"
169 , (unsigned)mouse_data3);
170 get_mouse_data(&mouse_data1);
171 get_mouse_data(&mouse_data2);
172 // turn IRQ12 and packet generation on
173 enable_mouse_int_and_events();
174 regs->bl = mouse_data1;
175 regs->bh = mouse_data2;
176 set_code_success(regs);
181 mouse_15c202(struct bregs *regs)
184 set_code_fail(regs, RET_EUNSUPPORTED);
187 u8 mouse_data1 = regs->bh * 20;
190 send_to_mouse_ctrl(0xF3); // set sample rate command
192 get_mouse_data(&mouse_data2);
193 send_to_mouse_ctrl(mouse_data1);
194 get_mouse_data(&mouse_data2);
195 set_code_success(regs);
200 mouse_15c203(struct bregs *regs)
203 // 0 = 25 dpi, 1 count per millimeter
204 // 1 = 50 dpi, 2 counts per millimeter
205 // 2 = 100 dpi, 4 counts per millimeter
206 // 3 = 200 dpi, 8 counts per millimeter
207 u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
209 set_code_fail(regs, RET_EUNSUPPORTED);
212 send_to_mouse_ctrl(0xE8); // set resolution command
214 get_mouse_data(&mouse_data1);
215 if (mouse_data1 != 0xfa)
216 BX_PANIC("Mouse status returned %02x (should be ack)\n"
217 , (unsigned)mouse_data1);
218 send_to_mouse_ctrl(regs->bh);
219 get_mouse_data(&mouse_data1);
220 if (mouse_data1 != 0xfa)
221 BX_PANIC("Mouse status returned %02x (should be ack)\n"
222 , (unsigned)mouse_data1);
223 set_code_success(regs);
226 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
231 mouse_15c204(struct bregs *regs)
233 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
234 send_to_mouse_ctrl(0xF2); // get mouse ID command
235 u8 mouse_data1, mouse_data2;
236 get_mouse_data(&mouse_data1);
237 get_mouse_data(&mouse_data2);
238 regs->bh = mouse_data2;
239 set_code_success(regs);
244 mouse_15c205(struct bregs *regs)
247 set_code_fail(regs, RET_EINTERFACE);
250 SET_EBDA(mouse_flag1, 0x00);
251 SET_EBDA(mouse_flag2, regs->bh);
259 mouse_15c20600(struct bregs *regs)
261 u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
262 send_to_mouse_ctrl(0xE9); // get mouse info command
263 u8 mouse_data1, mouse_data2, mouse_data3;
264 get_mouse_data(&mouse_data1);
265 if (mouse_data1 != 0xfa)
266 BX_PANIC("Mouse status returned %02x (should be ack)\n"
267 , (unsigned)mouse_data1);
268 get_mouse_data(&mouse_data1);
269 get_mouse_data(&mouse_data2);
270 get_mouse_data(&mouse_data3);
271 regs->bl = mouse_data1;
272 regs->cl = mouse_data2;
273 regs->dl = mouse_data3;
274 set_code_success(regs);
275 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
279 set_scaling(struct bregs *regs, u8 cmd)
281 u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
282 send_to_mouse_ctrl(0xE6);
284 get_mouse_data(&mouse_data1);
285 if (mouse_data1 != 0xFA)
286 set_code_fail(regs, RET_EUNSUPPORTED);
288 set_code_success(regs);
289 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
292 // Set Scaling Factor to 1:1
294 mouse_15c20601(struct bregs *regs)
296 set_scaling(regs, 0xE6);
299 // Set Scaling Factor to 2:1
301 mouse_15c20602(struct bregs *regs)
303 set_scaling(regs, 0xE7);
307 mouse_15c206XX(struct bregs *regs)
309 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", regs->bh);
312 // Return Status & Set Scaling Factor...
314 mouse_15c206(struct bregs *regs)
317 case 0x00: mouse_15c20600(regs); break;
318 case 0x01: mouse_15c20601(regs); break;
319 case 0x02: mouse_15c20602(regs); break;
320 default: mouse_15c206XX(regs); break;
324 // Set Mouse Handler Address
326 mouse_15c207(struct bregs *regs)
328 u32 farptr = (regs->es << 16) | regs->bx;
329 SET_EBDA(far_call_pointer, farptr);
330 u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
333 if ((mouse_flags_2 & 0x80) != 0) {
334 mouse_flags_2 &= ~0x80;
335 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
338 /* install handler */
339 mouse_flags_2 |= 0x80;
341 SET_EBDA(mouse_flag2, mouse_flags_2);
342 set_code_success(regs);
346 mouse_15c2XX(struct bregs *regs)
348 set_code_fail(regs, RET_EINVFUNCTION);
352 handle_15c2(struct bregs *regs)
356 if (! CONFIG_PS2_MOUSE) {
357 set_code_fail(regs, RET_EUNSUPPORTED);
362 case 0x00: mouse_15c200(regs); break;
363 case 0x01: mouse_15c201(regs); break;
364 case 0x02: mouse_15c202(regs); break;
365 case 0x03: mouse_15c203(regs); break;
366 case 0x04: mouse_15c204(regs); break;
367 case 0x05: mouse_15c205(regs); break;
368 case 0x06: mouse_15c206(regs); break;
369 case 0x07: mouse_15c207(regs); break;
370 default: mouse_15c2XX(regs); break;
377 u8 v = inb(PORT_PS2_STATUS);
378 if ((v & 0x21) != 0x21)
381 v = inb(PORT_PS2_DATA);
383 u8 mouse_flags_1 = GET_EBDA(mouse_flag1);
384 u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
386 if ((mouse_flags_2 & 0x80) != 0x80)
389 u8 package_count = mouse_flags_2 & 0x07;
390 u8 index = mouse_flags_1 & 0x07;
391 SET_EBDA(mouse_data[index], v);
393 if ((index+1) < package_count) {
395 SET_EBDA(mouse_flag1, mouse_flags_1);
399 //BX_DEBUG_INT74("int74_function: make_farcall=1\n");
400 u16 status = GET_EBDA(mouse_data[0]);
401 u16 X = GET_EBDA(mouse_data[1]);
402 u16 Y = GET_EBDA(mouse_data[2]);
403 SET_EBDA(mouse_flag1, 0);
404 // check if far call handler installed
405 if (! (mouse_flags_2 & 0x80))
408 u32 func = GET_EBDA(far_call_pointer);
411 "pushw %w1\n" // status
418 : "+a" (func), "+b" (status), "+c" (X), "+d" (Y)
420 : "esi", "edi", "ebp", "cc"
424 // INT74h : PS/2 mouse hardware interrupt
428 debug_isr(DEBUG_ISR_74);