// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2002 MandrakeSoft S.A.
//
-// This file may be distributed under the terms of the GNU GPLv3 license.
+// This file may be distributed under the terms of the GNU LGPLv3 license.
-#include "biosvar.h" // struct bregs
-#include "util.h" // debug_enter
+#include "biosvar.h" // GET_EBDA
+#include "util.h" // debug_isr
+#include "pic.h" // eoi_pic2
+#include "bregs.h" // struct bregs
+#include "ps2port.h" // ps2_mouse_command
+#include "usb-hid.h" // usb_mouse_command
-static char panic_msg_keyb_buffer_full[] = "%s: keyboard input buffer full\n";
-
-static void
-set_kbd_command_byte(u8 command_byte)
-{
- if (inb(PORT_PS2_STATUS) & 0x02)
- BX_PANIC(panic_msg_keyb_buffer_full, "setkbdcomm");
- outb(0xD4, PORT_PS2_STATUS);
-
- outb(0x60, PORT_PS2_STATUS); // write command byte
- outb(command_byte, PORT_PS2_DATA);
-}
-
-static u8
-inhibit_mouse_int_and_events()
-{
- // Turn off IRQ generation and aux data line
- if (inb(PORT_PS2_STATUS) & 0x02)
- BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
- outb(0x20, PORT_PS2_STATUS); // get command byte
- while ((inb(PORT_PS2_STATUS) & 0x01) != 0x01)
- ;
- u8 prev_command_byte = inb(PORT_PS2_DATA);
- u8 command_byte = prev_command_byte;
- //while ( (inb(PORT_PS2_STATUS) & 0x02) );
- if ( inb(PORT_PS2_STATUS) & 0x02 )
- BX_PANIC(panic_msg_keyb_buffer_full,"inhibmouse");
- command_byte &= 0xfd; // turn off IRQ 12 generation
- command_byte |= 0x20; // disable mouse serial clock line
- outb(0x60, PORT_PS2_STATUS); // write command byte
- outb(command_byte, PORT_PS2_DATA);
- return prev_command_byte;
-}
-
-static void
-enable_mouse_int_and_events()
-{
- // Turn on IRQ generation and aux data line
- if ( inb(PORT_PS2_STATUS) & 0x02 )
- BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
- outb(0x20, PORT_PS2_STATUS); // get command byte
- while ((inb(PORT_PS2_STATUS) & 0x01) != 0x01)
- ;
- u8 command_byte = inb(PORT_PS2_DATA);
- //while ( (inb(PORT_PS2_STATUS) & 0x02) );
- if (inb(PORT_PS2_STATUS) & 0x02)
- BX_PANIC(panic_msg_keyb_buffer_full,"enabmouse");
- command_byte |= 0x02; // turn on IRQ 12 generation
- command_byte &= 0xdf; // enable mouse serial clock line
- outb(0x60, PORT_PS2_STATUS); // write command byte
- outb(command_byte, PORT_PS2_DATA);
-}
-
-static void
-send_to_mouse_ctrl(u8 sendbyte)
+void
+mouse_setup(void)
{
- // wait for chance to write to ctrl
- if (inb(PORT_PS2_STATUS) & 0x02)
- BX_PANIC(panic_msg_keyb_buffer_full,"sendmouse");
- outb(0xD4, PORT_PS2_STATUS);
- outb(sendbyte, PORT_PS2_DATA);
+ if (! CONFIG_MOUSE)
+ return;
+ dprintf(3, "init mouse\n");
+ // pointing device installed
+ SETBITS_BDA(equipment_list_flags, 0x04);
}
-static void
-get_mouse_data(u8 *data)
+static inline int
+mouse_command(int command, u8 *param)
{
- while ((inb(PORT_PS2_STATUS) & 0x21) != 0x21)
- ;
- *data = inb(PORT_PS2_DATA);
+ if (usb_mouse_active())
+ return usb_mouse_command(command, param);
+ return ps2_mouse_command(command, param);
}
#define RET_SUCCESS 0x00
static void
mouse_15c20000(struct bregs *regs)
{
- inhibit_mouse_int_and_events(); // disable IRQ12 and packets
- send_to_mouse_ctrl(0xF5); // disable mouse command
- u8 mouse_data1;
- get_mouse_data(&mouse_data1);
- handle_ret(regs, RET_SUCCESS);
+ int ret = mouse_command(PSMOUSE_CMD_DISABLE, NULL);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
}
-#define BX_DEBUG_INT15(args...)
-
// Enable Mouse
static void
mouse_15c20001(struct bregs *regs)
{
u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
if ((mouse_flags_2 & 0x80) == 0) {
- BX_DEBUG_INT15("INT 15h C2 Enable Mouse, no far call handler\n");
- handle_ret(regs, RET_ENOHANDLER);
+ set_code_invalid(regs, RET_ENOHANDLER);
return;
}
- inhibit_mouse_int_and_events(); // disable IRQ12 and packets
- send_to_mouse_ctrl(0xF4); // enable mouse command
- u8 mouse_data1;
- get_mouse_data(&mouse_data1);
- if (mouse_data1 == 0xFA) {
- enable_mouse_int_and_events(); // turn IRQ12 and packet generation on
- handle_ret(regs, RET_SUCCESS);
- return;
- }
- handle_ret(regs, RET_ENEEDRESEND);
+
+ int ret = mouse_command(PSMOUSE_CMD_ENABLE, NULL);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
}
static void
mouse_15c200XX(struct bregs *regs)
{
- handle_ret(regs, RET_EINVFUNCTION);
+ set_code_unimplemented(regs, RET_EINVFUNCTION);
}
// Disable/Enable Mouse
static void
mouse_15c201(struct bregs *regs)
{
- inhibit_mouse_int_and_events(); // disable IRQ12 and packets
- send_to_mouse_ctrl(0xFF); // reset mouse command
- u8 mouse_data1, mouse_data2, mouse_data3;
- get_mouse_data(&mouse_data3);
- // if no mouse attached, it will return RESEND
- if (mouse_data3 == 0xfe) {
- handle_ret(regs, RET_ENEEDRESEND);
+ u8 param[2];
+ int ret = mouse_command(PSMOUSE_CMD_RESET_BAT, param);
+ if (ret) {
+ set_code_invalid(regs, RET_ENEEDRESEND);
return;
}
- if (mouse_data3 != 0xfa)
- BX_PANIC("Mouse reset returned %02x (should be ack)\n"
- , (unsigned)mouse_data3);
- get_mouse_data(&mouse_data1);
- get_mouse_data(&mouse_data2);
- // turn IRQ12 and packet generation on
- enable_mouse_int_and_events();
- regs->bl = mouse_data1;
- regs->bh = mouse_data2;
- handle_ret(regs, RET_SUCCESS);
+ regs->bl = param[0];
+ regs->bh = param[1];
+ set_code_success(regs);
}
// Set Sample Rate
static void
mouse_15c202(struct bregs *regs)
{
- if (regs->bh >= 7) {
- handle_ret(regs, RET_EUNSUPPORTED);
+ static u8 VAR16 sample_rates[7] = {10, 20, 40, 60, 80, 100, 200};
+ if (regs->bh >= ARRAY_SIZE(sample_rates)) {
+ set_code_invalid(regs, RET_EINVINPUT);
return;
}
- u8 mouse_data1 = regs->bh * 20;
- if (!mouse_data1)
- mouse_data1 = 10;
- send_to_mouse_ctrl(0xF3); // set sample rate command
- u8 mouse_data2;
- get_mouse_data(&mouse_data2);
- send_to_mouse_ctrl(mouse_data1);
- get_mouse_data(&mouse_data2);
- handle_ret(regs, RET_SUCCESS);
+ u8 mouse_data1 = GET_GLOBAL(sample_rates[regs->bh]);
+ int ret = mouse_command(PSMOUSE_CMD_SETRATE, &mouse_data1);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
}
// Set Resolution
// 1 = 50 dpi, 2 counts per millimeter
// 2 = 100 dpi, 4 counts per millimeter
// 3 = 200 dpi, 8 counts per millimeter
- u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
if (regs->bh >= 4) {
- handle_ret(regs, RET_EUNSUPPORTED);
- goto done;
+ set_code_invalid(regs, RET_EINVINPUT);
+ return;
}
- send_to_mouse_ctrl(0xE8); // set resolution command
- u8 mouse_data1;
- get_mouse_data(&mouse_data1);
- if (mouse_data1 != 0xfa)
- BX_PANIC("Mouse status returned %02x (should be ack)\n"
- , (unsigned)mouse_data1);
- send_to_mouse_ctrl(regs->bh);
- get_mouse_data(&mouse_data1);
- if (mouse_data1 != 0xfa)
- BX_PANIC("Mouse status returned %02x (should be ack)\n"
- , (unsigned)mouse_data1);
- handle_ret(regs, RET_SUCCESS);
-
-done:
- set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
+ u8 param = regs->bh;
+ int ret = mouse_command(PSMOUSE_CMD_SETRES, ¶m);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
}
// Get Device ID
static void
mouse_15c204(struct bregs *regs)
{
- inhibit_mouse_int_and_events(); // disable IRQ12 and packets
- send_to_mouse_ctrl(0xF2); // get mouse ID command
- u8 mouse_data1, mouse_data2;
- get_mouse_data(&mouse_data1);
- get_mouse_data(&mouse_data2);
- regs->bh = mouse_data2;
- handle_ret(regs, RET_SUCCESS);
+ u8 param[2];
+ int ret = mouse_command(PSMOUSE_CMD_GETID, param);
+ if (ret) {
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ return;
+ }
+ regs->bh = param[0];
+ set_code_success(regs);
}
// Initialize Mouse
mouse_15c205(struct bregs *regs)
{
if (regs->bh != 3) {
- handle_ret(regs, RET_EINTERFACE);
+ set_code_invalid(regs, RET_EINTERFACE);
return;
}
- SET_EBDA(mouse_flag1, 0x00);
- SET_EBDA(mouse_flag2, regs->bh);
+ u16 ebda_seg = get_ebda_seg();
+ SET_EBDA2(ebda_seg, mouse_flag1, 0x00);
+ SET_EBDA2(ebda_seg, mouse_flag2, regs->bh);
// Reset Mouse
mouse_15c201(regs);
static void
mouse_15c20600(struct bregs *regs)
{
- u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
- send_to_mouse_ctrl(0xE9); // get mouse info command
- u8 mouse_data1, mouse_data2, mouse_data3;
- get_mouse_data(&mouse_data1);
- if (mouse_data1 != 0xfa)
- BX_PANIC("Mouse status returned %02x (should be ack)\n"
- , (unsigned)mouse_data1);
- get_mouse_data(&mouse_data1);
- get_mouse_data(&mouse_data2);
- get_mouse_data(&mouse_data3);
- regs->bl = mouse_data1;
- regs->cl = mouse_data2;
- regs->dl = mouse_data3;
- handle_ret(regs, RET_SUCCESS);
- set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
-}
-
-static void
-set_scaling(struct bregs *regs, u8 cmd)
-{
- u8 comm_byte = inhibit_mouse_int_and_events(); // disable IRQ12 and packets
- send_to_mouse_ctrl(0xE6);
- u8 mouse_data1;
- get_mouse_data(&mouse_data1);
- if (mouse_data1 != 0xFA)
- handle_ret(regs, RET_EUNSUPPORTED);
- else
- handle_ret(regs, RET_SUCCESS);
- set_kbd_command_byte(comm_byte); // restore IRQ12 and serial enable
+ u8 param[3];
+ int ret = mouse_command(PSMOUSE_CMD_GETINFO, param);
+ if (ret) {
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ return;
+ }
+ regs->bl = param[0];
+ regs->cl = param[1];
+ regs->dl = param[2];
+ set_code_success(regs);
}
// Set Scaling Factor to 1:1
static void
mouse_15c20601(struct bregs *regs)
{
- set_scaling(regs, 0xE6);
+ int ret = mouse_command(PSMOUSE_CMD_SETSCALE11, NULL);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
}
// Set Scaling Factor to 2:1
static void
mouse_15c20602(struct bregs *regs)
{
- set_scaling(regs, 0xE7);
+ int ret = mouse_command(PSMOUSE_CMD_SETSCALE21, NULL);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
}
static void
mouse_15c206XX(struct bregs *regs)
{
- BX_PANIC("INT 15h C2 AL=6, BH=%02x\n", regs->bh);
+ set_code_unimplemented(regs, RET_EINVFUNCTION);
}
// Return Status & Set Scaling Factor...
static void
mouse_15c207(struct bregs *regs)
{
- u32 farptr = (regs->es << 16) | regs->bx;
- SET_EBDA(far_call_pointer, farptr);
- u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
- if (! farptr) {
+ struct segoff_s farptr = SEGOFF(regs->es, regs->bx);
+ u16 ebda_seg = get_ebda_seg();
+ u8 mouse_flags_2 = GET_EBDA2(ebda_seg, mouse_flag2);
+ if (! farptr.segoff) {
/* remove handler */
if ((mouse_flags_2 & 0x80) != 0) {
mouse_flags_2 &= ~0x80;
- inhibit_mouse_int_and_events(); // disable IRQ12 and packets
+ mouse_command(PSMOUSE_CMD_DISABLE, NULL);
}
} else {
/* install handler */
mouse_flags_2 |= 0x80;
}
- SET_EBDA(mouse_flag2, mouse_flags_2);
- handle_ret(regs, RET_SUCCESS);
+ SET_EBDA2(ebda_seg, mouse_flag2, mouse_flags_2);
+ SET_EBDA2(ebda_seg, far_call_pointer, farptr);
+ set_code_success(regs);
}
static void
mouse_15c2XX(struct bregs *regs)
{
- handle_ret(regs, RET_EINVFUNCTION);
+ set_code_unimplemented(regs, RET_EINVFUNCTION);
}
void
{
//debug_stub(regs);
- if (! CONFIG_PS2_MOUSE) {
- handle_ret(regs, RET_EUNSUPPORTED);
+ if (! CONFIG_MOUSE) {
+ set_code_invalid(regs, RET_EUNSUPPORTED);
return;
}
}
}
-static void
-int74_function()
+void noinline
+process_mouse(u8 data)
{
- u8 v = inb(PORT_PS2_STATUS);
- if ((v & 0x21) != 0x21)
+ if (!CONFIG_MOUSE)
return;
- v = inb(PORT_PS2_DATA);
+ u16 ebda_seg = get_ebda_seg();
+ u8 mouse_flags_1 = GET_EBDA2(ebda_seg, mouse_flag1);
+ u8 mouse_flags_2 = GET_EBDA2(ebda_seg, mouse_flag2);
- u8 mouse_flags_1 = GET_EBDA(mouse_flag1);
- u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
-
- if ((mouse_flags_2 & 0x80) != 0x80)
+ if (! (mouse_flags_2 & 0x80))
+ // far call handler not installed
return;
u8 package_count = mouse_flags_2 & 0x07;
u8 index = mouse_flags_1 & 0x07;
- SET_EBDA(mouse_data[index], v);
+ SET_EBDA2(ebda_seg, mouse_data[index], data);
if ((index+1) < package_count) {
mouse_flags_1++;
- SET_EBDA(mouse_flag1, mouse_flags_1);
+ SET_EBDA2(ebda_seg, mouse_flag1, mouse_flags_1);
return;
}
- //BX_DEBUG_INT74("int74_function: make_farcall=1\n");
- u16 status = GET_EBDA(mouse_data[0]);
- u16 X = GET_EBDA(mouse_data[1]);
- u16 Y = GET_EBDA(mouse_data[2]);
- SET_EBDA(mouse_flag1, 0);
- // check if far call handler installed
- if (! (mouse_flags_2 & 0x80))
- return;
+ u16 status = GET_EBDA2(ebda_seg, mouse_data[0]);
+ u16 X = GET_EBDA2(ebda_seg, mouse_data[1]);
+ u16 Y = GET_EBDA2(ebda_seg, mouse_data[2]);
+ SET_EBDA2(ebda_seg, mouse_flag1, 0);
+
+ struct segoff_s func = GET_EBDA2(ebda_seg, far_call_pointer);
+ dprintf(16, "mouse farcall s=%04x x=%04x y=%04x func=%04x:%04x\n"
+ , status, X, Y, func.seg, func.offset);
- u32 func = GET_EBDA(far_call_pointer);
asm volatile(
"pushl %%ebp\n"
- "pushfl\n"
+ "sti\n"
+
"pushl %0\n"
"pushw %w1\n" // status
"pushw %w2\n" // X
"pushw $0\n" // Z
"lcallw *8(%%esp)\n"
"addl $12, %%esp\n"
- "popfl\n"
- "popl %%ebp\n"
- : "+a" (func), "+b" (status), "+c" (X), "+d" (Y)
- :
- : "esi", "edi"
- );
-}
-
-// INT74h : PS/2 mouse hardware interrupt
-void VISIBLE
-handle_74(struct bregs *regs)
-{
- //debug_isr(regs);
-
- irq_enable();
- int74_function();
- irq_disable();
- eoi_both_pics();
+ "cli\n"
+ "cld\n"
+ "popl %%ebp"
+ : "+a"(func.segoff), "+c"(status), "+d"(X), "+b"(Y)
+ :
+ : "edi", "esi", "cc", "memory");
}