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" // GET_EBDA
9 #include "util.h" // debug_isr
10 #include "pic.h" // unmask_pic2
11 #include "bregs.h" // struct bregs
13 static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
18 if (! CONFIG_PS2_MOUSE)
20 dprintf(3, "init mouse\n");
21 // pointing device installed
22 SETBITS_BDA(equipment_list_flags, 0x04);
23 // Enable IRQ12 (handle_74)
24 unmask_pic2(PIC2_IRQ12);
28 set_kbd_command_byte(u8 command_byte)
30 if (inb(PORT_PS2_STATUS) & 0x02)
31 BX_PANIC(panic_msg_keyb_buffer_full, "setkbdcomm");
32 outb(0xD4, PORT_PS2_STATUS);
34 outb(0x60, PORT_PS2_STATUS); // write command byte
35 outb(command_byte, PORT_PS2_DATA);
39 inhibit_mouse_int_and_events()
41 // Turn off IRQ generation and aux data line
42 if (inb(PORT_PS2_STATUS) & 0x02)
43 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
44 outb(0x20, PORT_PS2_STATUS); // get command byte
45 while ((inb(PORT_PS2_STATUS) & 0x01) != 0x01)
47 u8 prev_command_byte = inb(PORT_PS2_DATA);
48 u8 command_byte = prev_command_byte;
49 //while ( (inb(PORT_PS2_STATUS) & 0x02) );
50 if ( inb(PORT_PS2_STATUS) & 0x02 )
51 BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
52 command_byte &= 0xfd; // turn off IRQ 12 generation
53 command_byte |= 0x20; // disable mouse serial clock line
54 outb(0x60, PORT_PS2_STATUS); // write command byte
55 outb(command_byte, PORT_PS2_DATA);
56 return prev_command_byte;
60 enable_mouse_int_and_events()
62 // Turn on IRQ generation and aux data line
63 if ( inb(PORT_PS2_STATUS) & 0x02 )
64 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
65 outb(0x20, PORT_PS2_STATUS); // get command byte
66 while ((inb(PORT_PS2_STATUS) & 0x01) != 0x01)
68 u8 command_byte = inb(PORT_PS2_DATA);
69 //while ( (inb(PORT_PS2_STATUS) & 0x02) );
70 if (inb(PORT_PS2_STATUS) & 0x02)
71 BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
72 command_byte |= 0x02; // turn on IRQ 12 generation
73 command_byte &= 0xdf; // enable mouse serial clock line
74 outb(0x60, PORT_PS2_STATUS); // write command byte
75 outb(command_byte, PORT_PS2_DATA);
79 send_to_mouse_ctrl(u8 sendbyte)
81 // wait for chance to write to ctrl
82 if (inb(PORT_PS2_STATUS) & 0x02)
83 BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
84 outb(0xD4, PORT_PS2_STATUS);
85 outb(sendbyte, PORT_PS2_DATA);
89 get_mouse_data(u8 *data)
91 while ((inb(PORT_PS2_STATUS) & 0x21) != 0x21)
93 *data = inb(PORT_PS2_DATA);
96 #define RET_SUCCESS 0x00
97 #define RET_EINVFUNCTION 0x01
98 #define RET_EINVINPUT 0x02
99 #define RET_EINTERFACE 0x03
100 #define RET_ENEEDRESEND 0x04
101 #define RET_ENOHANDLER 0x05
105 mouse_15c20000(struct bregs *regs)
107 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
108 send_to_mouse_ctrl(0xF5); // disable mouse command
110 get_mouse_data(&mouse_data1);
111 set_code_success(regs);
114 #define BX_DEBUG_INT15(args...)
118 mouse_15c20001(struct bregs *regs)
120 u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
121 if ((mouse_flags_2 & 0x80) == 0) {
122 BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
123 set_code_fail(regs, RET_ENOHANDLER);
126 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
127 send_to_mouse_ctrl(0xF4); // enable mouse command
129 get_mouse_data(&mouse_data1);
130 if (mouse_data1 == 0xFA) {
131 enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
132 set_code_success(regs);
135 set_code_fail(regs, RET_ENEEDRESEND);
139 mouse_15c200XX(struct bregs *regs)
141 set_code_fail(regs, RET_EINVFUNCTION);
144 // Disable/Enable Mouse
146 mouse_15c200(struct bregs *regs)
149 case 0x00: mouse_15c20000(regs); break;
150 case 0x01: mouse_15c20001(regs); break;
151 default: mouse_15c200XX(regs); break;
157 mouse_15c201(struct bregs *regs)
159 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
160 send_to_mouse_ctrl(0xFF); // reset mouse command
161 u8 mouse_data1, mouse_data2, mouse_data3;
162 get_mouse_data(&mouse_data3);
163 // if no mouse attached, it will return RESEND
164 if (mouse_data3 == 0xfe) {
165 set_code_fail(regs, RET_ENEEDRESEND);
168 if (mouse_data3 != 0xfa)
169 BX_PANIC("Mouse reset returned %02x (should be ack)\n"
170 , (unsigned)mouse_data3);
171 get_mouse_data(&mouse_data1);
172 get_mouse_data(&mouse_data2);
173 // turn IRQ12 and packet generation on
174 enable_mouse_int_and_events();
175 regs->bl = mouse_data1;
176 regs->bh = mouse_data2;
177 set_code_success(regs);
182 mouse_15c202(struct bregs *regs)
185 set_code_fail(regs, RET_EUNSUPPORTED);
188 u8 mouse_data1 = regs->bh * 20;
191 send_to_mouse_ctrl(0xF3); // set sample rate command
193 get_mouse_data(&mouse_data2);
194 send_to_mouse_ctrl(mouse_data1);
195 get_mouse_data(&mouse_data2);
196 set_code_success(regs);
201 mouse_15c203(struct bregs *regs)
204 // 0 = 25 dpi, 1 count per millimeter
205 // 1 = 50 dpi, 2 counts per millimeter
206 // 2 = 100 dpi, 4 counts per millimeter
207 // 3 = 200 dpi, 8 counts per millimeter
208 u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
210 set_code_fail(regs, RET_EUNSUPPORTED);
213 send_to_mouse_ctrl(0xE8); // set resolution command
215 get_mouse_data(&mouse_data1);
216 if (mouse_data1 != 0xfa)
217 BX_PANIC("Mouse status returned %02x (should be ack)\n"
218 , (unsigned)mouse_data1);
219 send_to_mouse_ctrl(regs->bh);
220 get_mouse_data(&mouse_data1);
221 if (mouse_data1 != 0xfa)
222 BX_PANIC("Mouse status returned %02x (should be ack)\n"
223 , (unsigned)mouse_data1);
224 set_code_success(regs);
227 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
232 mouse_15c204(struct bregs *regs)
234 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
235 send_to_mouse_ctrl(0xF2); // get mouse ID command
236 u8 mouse_data1, mouse_data2;
237 get_mouse_data(&mouse_data1);
238 get_mouse_data(&mouse_data2);
239 regs->bh = mouse_data2;
240 set_code_success(regs);
245 mouse_15c205(struct bregs *regs)
248 set_code_fail(regs, RET_EINTERFACE);
251 SET_EBDA(mouse_flag1, 0x00);
252 SET_EBDA(mouse_flag2, regs->bh);
260 mouse_15c20600(struct bregs *regs)
262 u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
263 send_to_mouse_ctrl(0xE9); // get mouse info command
264 u8 mouse_data1, mouse_data2, mouse_data3;
265 get_mouse_data(&mouse_data1);
266 if (mouse_data1 != 0xfa)
267 BX_PANIC("Mouse status returned %02x (should be ack)\n"
268 , (unsigned)mouse_data1);
269 get_mouse_data(&mouse_data1);
270 get_mouse_data(&mouse_data2);
271 get_mouse_data(&mouse_data3);
272 regs->bl = mouse_data1;
273 regs->cl = mouse_data2;
274 regs->dl = mouse_data3;
275 set_code_success(regs);
276 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
280 set_scaling(struct bregs *regs, u8 cmd)
282 u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
283 send_to_mouse_ctrl(0xE6);
285 get_mouse_data(&mouse_data1);
286 if (mouse_data1 != 0xFA)
287 set_code_fail(regs, RET_EUNSUPPORTED);
289 set_code_success(regs);
290 set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
293 // Set Scaling Factor to 1:1
295 mouse_15c20601(struct bregs *regs)
297 set_scaling(regs, 0xE6);
300 // Set Scaling Factor to 2:1
302 mouse_15c20602(struct bregs *regs)
304 set_scaling(regs, 0xE7);
308 mouse_15c206XX(struct bregs *regs)
310 BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", regs->bh);
313 // Return Status & Set Scaling Factor...
315 mouse_15c206(struct bregs *regs)
318 case 0x00: mouse_15c20600(regs); break;
319 case 0x01: mouse_15c20601(regs); break;
320 case 0x02: mouse_15c20602(regs); break;
321 default: mouse_15c206XX(regs); break;
325 // Set Mouse Handler Address
327 mouse_15c207(struct bregs *regs)
329 u32 farptr = (regs->es << 16) | regs->bx;
330 SET_EBDA(far_call_pointer, farptr);
331 u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
334 if ((mouse_flags_2 & 0x80) != 0) {
335 mouse_flags_2 &= ~0x80;
336 inhibit_mouse_int_and_events(); // disable IRQ12 and packets
339 /* install handler */
340 mouse_flags_2 |= 0x80;
342 SET_EBDA(mouse_flag2, mouse_flags_2);
343 set_code_success(regs);
347 mouse_15c2XX(struct bregs *regs)
349 set_code_fail(regs, RET_EINVFUNCTION);
353 handle_15c2(struct bregs *regs)
357 if (! CONFIG_PS2_MOUSE) {
358 set_code_fail(regs, RET_EUNSUPPORTED);
363 case 0x00: mouse_15c200(regs); break;
364 case 0x01: mouse_15c201(regs); break;
365 case 0x02: mouse_15c202(regs); break;
366 case 0x03: mouse_15c203(regs); break;
367 case 0x04: mouse_15c204(regs); break;
368 case 0x05: mouse_15c205(regs); break;
369 case 0x06: mouse_15c206(regs); break;
370 case 0x07: mouse_15c207(regs); break;
371 default: mouse_15c2XX(regs); break;
378 u8 v = inb(PORT_PS2_STATUS);
379 if ((v & 0x21) != 0x21)
382 v = inb(PORT_PS2_DATA);
384 u8 mouse_flags_1 = GET_EBDA(mouse_flag1);
385 u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
387 if (! (mouse_flags_2 & 0x80))
388 // far call handler not installed
391 u8 package_count = mouse_flags_2 & 0x07;
392 u8 index = mouse_flags_1 & 0x07;
393 SET_EBDA(mouse_data[index], v);
395 if ((index+1) < package_count) {
397 SET_EBDA(mouse_flag1, mouse_flags_1);
401 //BX_DEBUG_INT74("int74_function: make_farcall=1\n");
402 u16 status = GET_EBDA(mouse_data[0]);
403 u16 X = GET_EBDA(mouse_data[1]);
404 u16 Y = GET_EBDA(mouse_data[2]);
405 SET_EBDA(mouse_flag1, 0);
407 u32 func = GET_EBDA(far_call_pointer);
410 "pushw %w1\n" // status
417 : "+a" (func), "+b" (status), "+c" (X), "+d" (Y)
419 : "esi", "edi", "ebp", "cc"
423 // INT74h : PS/2 mouse hardware interrupt
427 debug_isr(DEBUG_ISR_74);