#include #include #include #include #include #include #include #include #include u8 mouse_cycle = 0; u8 mouse_u8[3]; int mouse_x = 0; int mouse_y = 0; u8 mouse_left_button = 0; u8 mouse_middle_button = 0; u8 mouse_right_button = 0; vfs_inode_t *mouse_inode = NULL; struct mouse_event { u8 buttons; int x; int y; }; struct mouse_event previous_event = { .buttons = 0, .x = 0, .y = 0, }; int fs_mouse_has_data(vfs_inode_t *inode) { if (mouse_x != previous_event.x || mouse_y != previous_event.y) { return 1; } const struct ringbuffer *rb = inode->internal_object; return !ringbuffer_isempty(rb); } int fs_mouse_read(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) { mouse_middle_button = mouse_u8[0] & (1 << 2); mouse_right_button = mouse_u8[0] & (1 << 1); mouse_left_button = mouse_u8[0] & (1 << 0); struct ringbuffer *rb = fd->inode->internal_object; u32 rc = ringbuffer_read(rb, buffer, len); if (0 == rc && len > 0) { if (mouse_x != previous_event.x || mouse_y != previous_event.y) { int read_len = min(len, sizeof(struct mouse_event)); struct mouse_event e; e.x = mouse_x; e.y = mouse_y; e.buttons = 0; if (mouse_middle_button) { e.buttons |= (1 << 2); } if (mouse_right_button) { e.buttons |= (1 << 1); } if (mouse_left_button) { e.buttons |= (1 << 0); } memcpy(buffer, &e, read_len); previous_event = e; return read_len; } return -EAGAIN; } return rc; } void add_mouse(void) { mouse_inode = devfs_add_file("/mouse", fs_mouse_read, NULL, NULL, fs_mouse_has_data, always_can_write, FS_TYPE_CHAR_DEVICE); mouse_inode->internal_object = kmalloc(sizeof(struct ringbuffer)); ringbuffer_init(mouse_inode->internal_object, 4096); } void int_mouse(reg_t *r) { (void)r; switch (mouse_cycle) { case 0: mouse_u8[0] = inb(0x60); if (!(mouse_u8[0] & (1 << 3))) { mouse_cycle = 0; break; } mouse_cycle++; break; case 1: mouse_u8[1] = inb(0x60); mouse_cycle++; break; case 2: { mouse_u8[2] = inb(0x60); int16_t x = mouse_u8[1]; int16_t y = mouse_u8[2]; uint8_t xs = mouse_u8[0] & (1 << 4); uint8_t ys = mouse_u8[0] & (1 << 5); if (xs) { x |= 0xFF00; } if (ys) { y |= 0xFF00; } mouse_x += x; mouse_y -= y; if (mouse_x < 0) { mouse_x = 0; } if (mouse_y < 0) { mouse_y = 0; } mouse_middle_button = mouse_u8[0] & (1 << 2); mouse_right_button = mouse_u8[0] & (1 << 1); mouse_left_button = mouse_u8[0] & (1 << 0); mouse_cycle = 0; // If there is a change in the mouse buttons that event should be written. // The mouse movements will be generated upon request. This avoids // filling the ringbuffer with a ton of small mouse movements. int button_change = 0; if (mouse_middle_button != (previous_event.buttons & (1 << 2))) { button_change = 1; } else if (mouse_right_button != (previous_event.buttons & (1 << 1))) { button_change = 1; } else if (mouse_left_button != (previous_event.buttons & (1 << 0))) { button_change = 1; } if (!button_change) { break; } struct mouse_event e; e.buttons = mouse_u8[0]; e.x = mouse_x; e.y = mouse_y; previous_event = e; if (mouse_inode) { struct ringbuffer *rb = mouse_inode->internal_object; ringbuffer_write(rb, (u8 *)&e, sizeof(e)); } break; } } EOI(0xC); } void mouse_wait(u8 a_type) { u32 _time_out = 100000; if (a_type == 0) { while (_time_out--) { if ((inb(0x64) & 1) == 1) { return; } } return; } else { while (_time_out--) { if ((inb(0x64) & 2) == 0) { return; } } return; } } void mouse_write(u8 a_write) { // Wait to be able to send a command mouse_wait(1); // Tell the mouse we are sending a command outb(0x64, 0xD4); // Wait for the final part mouse_wait(1); // Finally write outb(0x60, a_write); } u8 mouse_read() { mouse_wait(0); return inb(0x60); } void install_mouse(void) { u8 _status; disable_interrupts(); // Enable the auxiliary mouse device mouse_wait(1); outb(0x64, 0xA8); // Enable the interrupts mouse_wait(1); outb(0x64, 0x20); mouse_wait(0); _status = (inb(0x60) | 2); mouse_wait(1); outb(0x64, 0x60); mouse_wait(1); outb(0x60, _status); // Tell the mouse to use default settings mouse_write(0xF6); mouse_read(); // Acknowledge // Enable the mouse mouse_write(0xF4); mouse_read(); // Acknowledge install_handler((interrupt_handler)int_mouse, INT_32_INTERRUPT_GATE(0x3), 0x2C); irq_clear_mask(0x2); }