luajitos

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

mouse.c (6812B)


      1 /* PS/2 Mouse Driver */
      2 #include <stdint.h>
      3 #include "mouse.h"
      4 #include "terminal.h"
      5 
      6 /* PS/2 Controller Ports */
      7 #define PS2_DATA_PORT    0x60
      8 #define PS2_STATUS_PORT  0x64
      9 #define PS2_COMMAND_PORT 0x64
     10 
     11 /* Mouse state */
     12 static mouse_state_t mouse_state = {
     13     .x = 512,  /* Center of 1024x768 */
     14     .y = 384,
     15     .buttons = 0,
     16     .initialized = 0
     17 };
     18 
     19 /* Mouse packet buffer */
     20 static uint8_t mouse_packet[3];
     21 static uint8_t mouse_packet_index = 0;
     22 
     23 /* I/O port functions */
     24 static inline void outb(uint16_t port, uint8_t val) {
     25     __asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
     26 }
     27 
     28 static inline uint8_t inb(uint16_t port) {
     29     uint8_t ret;
     30     __asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
     31     return ret;
     32 }
     33 
     34 /* Wait for PS/2 controller to be ready to read */
     35 static void mouse_wait_input(void) {
     36     uint32_t timeout = 100000;
     37     while (timeout--) {
     38         if ((inb(PS2_STATUS_PORT) & 0x01)) {
     39             return;
     40         }
     41     }
     42 }
     43 
     44 /* Wait for PS/2 controller to be ready to write */
     45 static void mouse_wait_output(void) {
     46     uint32_t timeout = 100000;
     47     while (timeout--) {
     48         if (!(inb(PS2_STATUS_PORT) & 0x02)) {
     49             return;
     50         }
     51     }
     52 }
     53 
     54 /* Write to mouse */
     55 static void mouse_write(uint8_t data) {
     56     mouse_wait_output();
     57     outb(PS2_COMMAND_PORT, 0xD4);  /* Tell controller we're sending to mouse */
     58     mouse_wait_output();
     59     outb(PS2_DATA_PORT, data);
     60 }
     61 
     62 /* Read from mouse */
     63 static uint8_t mouse_read(void) {
     64     mouse_wait_input();
     65     return inb(PS2_DATA_PORT);
     66 }
     67 
     68 /* Flush any pending data from the PS/2 controller */
     69 static void mouse_flush(void) {
     70     uint32_t timeout = 1000;
     71     while (timeout-- && (inb(PS2_STATUS_PORT) & 0x01)) {
     72         inb(PS2_DATA_PORT);  /* Read and discard */
     73     }
     74 }
     75 
     76 /* Initialize PS/2 mouse */
     77 int mouse_init(void) {
     78     terminal_writestring("Initializing PS/2 mouse...\n");
     79 
     80     /* Enable auxiliary device (mouse) */
     81     mouse_wait_output();
     82     outb(PS2_COMMAND_PORT, 0xA8);
     83     /* Command 0xA8 doesn't produce a response, no read needed */
     84 
     85     /* Enable interrupts for mouse (IRQ12) */
     86     mouse_wait_output();
     87     outb(PS2_COMMAND_PORT, 0x20);  /* Get controller config */
     88     mouse_wait_input();
     89     uint8_t status = inb(PS2_DATA_PORT) | 0x02;  /* Enable IRQ12 */
     90     mouse_wait_output();
     91     outb(PS2_COMMAND_PORT, 0x60);  /* Set controller config */
     92     mouse_wait_output();
     93     outb(PS2_DATA_PORT, status);
     94     /* Command 0x60 doesn't produce a response, no read needed */
     95 
     96     /* Flush any stale data from the buffer before sending mouse commands */
     97     mouse_flush();
     98     terminal_writestring("Mouse: Buffer flushed\n");
     99 
    100     /* Use default settings */
    101     mouse_write(0xF6);
    102     uint8_t ack = mouse_read();
    103     if (ack != 0xFA) {
    104         terminal_writestring("Mouse: Failed to set defaults (ACK=");
    105         terminal_putchar('0' + ((ack >> 4) & 0xF));
    106         terminal_putchar('0' + (ack & 0xF));
    107         terminal_writestring(")\n");
    108     }
    109 
    110     /* Set sample rate to 100 reports/sec for more responsive movement */
    111     mouse_write(0xF3);  /* Set sample rate command */
    112     ack = mouse_read();
    113     if (ack != 0xFA) {
    114         terminal_writestring("Mouse: Failed to set sample rate cmd (ACK!=0xFA)\n");
    115     }
    116     mouse_write(100);   /* 100 samples/sec */
    117     ack = mouse_read();
    118     if (ack != 0xFA) {
    119         terminal_writestring("Mouse: Failed to set sample rate value (ACK!=0xFA)\n");
    120     }
    121 
    122     /* Set resolution to 4 counts/mm */
    123     mouse_write(0xE8);  /* Set resolution command */
    124     ack = mouse_read();
    125     if (ack != 0xFA) {
    126         terminal_writestring("Mouse: Failed to set resolution cmd (ACK!=0xFA)\n");
    127     }
    128     mouse_write(0x03);  /* 8 counts/mm (highest sensitivity) */
    129     ack = mouse_read();
    130     if (ack != 0xFA) {
    131         terminal_writestring("Mouse: Failed to set resolution value (ACK!=0xFA)\n");
    132     }
    133 
    134     /* Enable data reporting */
    135     mouse_write(0xF4);
    136     ack = mouse_read();
    137     if (ack != 0xFA) {
    138         terminal_writestring("Mouse: Failed to enable data reporting (ACK!=0xFA)\n");
    139         return -1;
    140     }
    141     terminal_writestring("Mouse: Data reporting enabled (ACK=0xFA)\n");
    142 
    143     /* Unmask IRQ12 in PIC (slave PIC) */
    144     /* IRQ12 is bit 4 on the slave PIC (0xA1) */
    145     uint8_t slave_mask = inb(0xA1);
    146     slave_mask &= ~(1 << 4);  /* Clear bit 4 to unmask IRQ12 */
    147     outb(0xA1, slave_mask);
    148 
    149     /* Also unmask IRQ2 (cascade) on master PIC so slave interrupts work */
    150     uint8_t master_mask = inb(0x21);
    151     master_mask &= ~(1 << 2);  /* Clear bit 2 to unmask IRQ2 */
    152     outb(0x21, master_mask);
    153 
    154     mouse_state.initialized = 1;
    155     terminal_writestring("Mouse initialized!\n");
    156 
    157     return 0;
    158 }
    159 
    160 /* Packet counter for debugging */
    161 static uint32_t packet_count = 0;
    162 
    163 /* Handle mouse interrupt (called from IRQ12 handler) */
    164 void mouse_handler(void) {
    165     uint8_t data = inb(PS2_DATA_PORT);
    166 
    167     /* First byte must have bit 3 set for valid packet */
    168     if (mouse_packet_index == 0 && !(data & 0x08)) {
    169         /* Invalid first byte, ignore and resync */
    170         return;
    171     }
    172 
    173     /* Build mouse packet (3 bytes) */
    174     mouse_packet[mouse_packet_index] = data;
    175     mouse_packet_index++;
    176 
    177     if (mouse_packet_index == 3) {
    178         /* Full packet received */
    179         mouse_packet_index = 0;
    180         packet_count++;
    181 
    182         /* Parse packet */
    183         uint8_t flags = mouse_packet[0];
    184         int8_t dx = (int8_t)mouse_packet[1];
    185         int8_t dy = (int8_t)mouse_packet[2];
    186 
    187         /* Update button state */
    188         mouse_state.buttons = flags & 0x07;  /* Left, Right, Middle */
    189 
    190         /* Update position */
    191         mouse_state.x += dx;
    192         mouse_state.y -= dy;  /* Y is inverted */
    193 
    194         /* Clamp to screen bounds (1024x768) */
    195         if (mouse_state.x < 0) mouse_state.x = 0;
    196         if (mouse_state.x >= 1024) mouse_state.x = 1023;
    197         if (mouse_state.y < 0) mouse_state.y = 0;
    198         if (mouse_state.y >= 768) mouse_state.y = 767;
    199 
    200         /* Print every packet with delta for debugging */
    201         // Disabled to reduce boot noise
    202         // if (dx != 0 || dy != 0) {
    203         //     terminal_putchar('M');
    204         // }
    205     }
    206 }
    207 
    208 /* Get current mouse state */
    209 void mouse_get_state(mouse_state_t* state) {
    210     if (state) {
    211         state->x = mouse_state.x;
    212         state->y = mouse_state.y;
    213         state->buttons = mouse_state.buttons;
    214         state->initialized = mouse_state.initialized;
    215     }
    216 }
    217 
    218 /* Lua binding: Get mouse position and buttons */
    219 int lua_mouse_get_state(lua_State* L) {
    220     lua_newtable(L);
    221 
    222     lua_pushinteger(L, mouse_state.x);
    223     lua_setfield(L, -2, "x");
    224 
    225     lua_pushinteger(L, mouse_state.y);
    226     lua_setfield(L, -2, "y");
    227 
    228     lua_pushinteger(L, mouse_state.buttons);
    229     lua_setfield(L, -2, "buttons");
    230 
    231     lua_pushboolean(L, mouse_state.initialized);
    232     lua_setfield(L, -2, "initialized");
    233 
    234     return 1;
    235 }