luajitos

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

usb_uhci.c (18477B)


      1 /* USB UHCI Host Controller Driver with Mouse Support */
      2 #include <stdint.h>
      3 #include <stddef.h>
      4 #include "usb.h"
      5 #include "terminal.h"
      6 #include "lua.h"
      7 #include "lualib.h"
      8 #include "lauxlib.h"
      9 
     10 /* UHCI Register Offsets */
     11 #define UHCI_USBCMD     0x00  /* USB Command */
     12 #define UHCI_USBSTS     0x02  /* USB Status */
     13 #define UHCI_USBINTR    0x04  /* USB Interrupt Enable */
     14 #define UHCI_FRNUM      0x06  /* Frame Number */
     15 #define UHCI_FRBASEADD  0x08  /* Frame List Base Address */
     16 #define UHCI_SOFMOD     0x0C  /* Start of Frame Modify */
     17 #define UHCI_PORTSC1    0x10  /* Port 1 Status/Control */
     18 #define UHCI_PORTSC2    0x12  /* Port 2 Status/Control */
     19 
     20 /* UHCI Command Register Bits */
     21 #define UHCI_CMD_RS     0x0001  /* Run/Stop */
     22 #define UHCI_CMD_HCRESET 0x0002  /* Host Controller Reset */
     23 #define UHCI_CMD_GRESET 0x0004  /* Global Reset */
     24 #define UHCI_CMD_MAXP   0x0080  /* Max Packet (0=32, 1=64) */
     25 #define UHCI_CMD_CF     0x0040  /* Configure Flag */
     26 
     27 /* UHCI Status Register Bits */
     28 #define UHCI_STS_USBINT 0x0001  /* USB Interrupt */
     29 #define UHCI_STS_ERROR  0x0002  /* USB Error Interrupt */
     30 #define UHCI_STS_RD     0x0004  /* Resume Detect */
     31 #define UHCI_STS_HSE    0x0008  /* Host System Error */
     32 #define UHCI_STS_HCPE   0x0010  /* Host Controller Process Error */
     33 #define UHCI_STS_HCH    0x0020  /* HC Halted */
     34 
     35 /* UHCI Port Status/Control Bits */
     36 #define UHCI_PORT_CCS   0x0001  /* Current Connect Status */
     37 #define UHCI_PORT_CSC   0x0002  /* Connect Status Change */
     38 #define UHCI_PORT_PED   0x0004  /* Port Enable/Disable */
     39 #define UHCI_PORT_PEDC  0x0008  /* Port Enable/Disable Change */
     40 #define UHCI_PORT_LSDA  0x0100  /* Low Speed Device Attached */
     41 #define UHCI_PORT_PR    0x0200  /* Port Reset */
     42 #define UHCI_PORT_SUSP  0x1000  /* Suspend */
     43 
     44 /* Transfer Descriptor (TD) */
     45 typedef struct uhci_td {
     46     uint32_t link_ptr;       /* Link to next TD */
     47     uint32_t status;         /* Status and control */
     48     uint32_t token;          /* Packet header */
     49     uint32_t buffer;         /* Data buffer pointer */
     50     /* Software fields */
     51     uint32_t reserved[4];
     52 } __attribute__((aligned(16))) uhci_td_t;
     53 
     54 /* Queue Head (QH) */
     55 typedef struct uhci_qh {
     56     uint32_t head_link_ptr;  /* Queue head link pointer */
     57     uint32_t element_link_ptr; /* Queue element link pointer */
     58     /* Software fields */
     59     uint32_t reserved[2];
     60 } __attribute__((aligned(16))) uhci_qh_t;
     61 
     62 /* TD Status Bits */
     63 #define TD_STATUS_ACTLEN_MASK 0x7FF
     64 #define TD_STATUS_BITSTUFF    (1 << 17)
     65 #define TD_STATUS_CRCTO       (1 << 18)
     66 #define TD_STATUS_NAK         (1 << 19)
     67 #define TD_STATUS_BABBLE      (1 << 20)
     68 #define TD_STATUS_DBUFFER     (1 << 21)
     69 #define TD_STATUS_STALLED     (1 << 22)
     70 #define TD_STATUS_ACTIVE      (1 << 23)
     71 #define TD_STATUS_IOC         (1 << 24)  /* Interrupt on Complete */
     72 #define TD_STATUS_IOS         (1 << 25)  /* Isochronous Select */
     73 #define TD_STATUS_LS          (1 << 26)  /* Low Speed Device */
     74 #define TD_STATUS_SPD         (1 << 29)  /* Short Packet Detect */
     75 
     76 /* TD Token Bits */
     77 #define TD_TOKEN_PID_IN       0x69
     78 #define TD_TOKEN_PID_OUT      0xE1
     79 #define TD_TOKEN_PID_SETUP    0x2D
     80 
     81 /* UHCI Controller State */
     82 static uint16_t uhci_iobase = 0;
     83 static uint32_t* frame_list = NULL;
     84 static uhci_qh_t* control_qh = NULL;
     85 static uhci_qh_t* interrupt_qh = NULL;
     86 static uhci_td_t* mouse_td = NULL;
     87 static usb_mouse_report_t* mouse_report_buffer = NULL;
     88 static usb_mouse_state_t mouse_state = {512, 384, 0, 0};
     89 
     90 /* I/O port functions */
     91 static inline void outb(uint16_t port, uint8_t val) {
     92     __asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
     93 }
     94 
     95 static inline void outw(uint16_t port, uint16_t val) {
     96     __asm__ volatile ("outw %0, %1" : : "a"(val), "Nd"(port));
     97 }
     98 
     99 static inline void outl(uint16_t port, uint32_t val) {
    100     __asm__ volatile ("outl %0, %1" : : "a"(val), "Nd"(port));
    101 }
    102 
    103 static inline uint8_t inb(uint16_t port) {
    104     uint8_t ret;
    105     __asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
    106     return ret;
    107 }
    108 
    109 static inline uint16_t inw(uint16_t port) {
    110     uint16_t ret;
    111     __asm__ volatile ("inw %1, %0" : "=a"(ret) : "Nd"(port));
    112     return ret;
    113 }
    114 
    115 static inline uint32_t inl(uint16_t port) {
    116     uint32_t ret;
    117     __asm__ volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port));
    118     return ret;
    119 }
    120 
    121 /* PCI Configuration Space Access */
    122 #define PCI_CONFIG_ADDRESS 0xCF8
    123 #define PCI_CONFIG_DATA    0xCFC
    124 
    125 static uint32_t pci_read_config(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
    126     uint32_t address = (1 << 31) | ((uint32_t)bus << 16) | ((uint32_t)slot << 11) |
    127                        ((uint32_t)func << 8) | (offset & 0xFC);
    128     outl(PCI_CONFIG_ADDRESS, address);
    129     return inl(PCI_CONFIG_DATA);
    130 }
    131 
    132 static void pci_write_config(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t value) {
    133     uint32_t address = (1 << 31) | ((uint32_t)bus << 16) | ((uint32_t)slot << 11) |
    134                        ((uint32_t)func << 8) | (offset & 0xFC);
    135     outl(PCI_CONFIG_ADDRESS, address);
    136     outl(PCI_CONFIG_DATA, value);
    137 }
    138 
    139 /* Find UHCI controller on PCI bus */
    140 static int find_uhci_controller(void) {
    141     terminal_writestring("Scanning PCI bus for UHCI controller...\n");
    142 
    143     for (uint16_t bus = 0; bus < 256; bus++) {
    144         for (uint8_t slot = 0; slot < 32; slot++) {
    145             uint32_t vendor_device = pci_read_config(bus, slot, 0, 0);
    146             if (vendor_device == 0xFFFFFFFF) continue;
    147 
    148             uint32_t class_code = pci_read_config(bus, slot, 0, 0x08);
    149             uint8_t class = (class_code >> 24) & 0xFF;
    150             uint8_t subclass = (class_code >> 16) & 0xFF;
    151             uint8_t prog_if = (class_code >> 8) & 0xFF;
    152 
    153             /* USB Controller (Class 0x0C, Subclass 0x03, ProgIF 0x00 = UHCI) */
    154             if (class == 0x0C && subclass == 0x03 && prog_if == 0x00) {
    155                 terminal_writestring("Found UHCI controller at bus ");
    156                 terminal_putchar('0' + (bus / 100));
    157                 terminal_putchar('0' + ((bus / 10) % 10));
    158                 terminal_putchar('0' + (bus % 10));
    159                 terminal_writestring(" slot ");
    160                 terminal_putchar('0' + (slot / 10));
    161                 terminal_putchar('0' + (slot % 10));
    162                 terminal_writestring("\n");
    163 
    164                 /* Read BAR4 (I/O Base Address) */
    165                 uint32_t bar4 = pci_read_config(bus, slot, 0, 0x20);
    166                 uhci_iobase = bar4 & 0xFFE0;  /* Mask off lower bits */
    167 
    168                 terminal_writestring("UHCI I/O Base: 0x");
    169                 for (int i = 3; i >= 0; i--) {
    170                     uint8_t nibble = (uhci_iobase >> (i * 4)) & 0xF;
    171                     terminal_putchar(nibble < 10 ? '0' + nibble : 'A' + nibble - 10);
    172                 }
    173                 terminal_writestring("\n");
    174 
    175                 /* Enable bus mastering and I/O space */
    176                 uint32_t command = pci_read_config(bus, slot, 0, 0x04);
    177                 command |= 0x05;  /* Enable I/O Space and Bus Master */
    178                 pci_write_config(bus, slot, 0, 0x04, command);
    179 
    180                 return 0;
    181             }
    182         }
    183     }
    184 
    185     terminal_writestring("No UHCI controller found\n");
    186     return -1;
    187 }
    188 
    189 /* Simple memory allocator for USB structures (aligned) */
    190 static uint8_t usb_memory_pool[8192] __attribute__((aligned(4096)));
    191 static uint32_t usb_memory_offset = 0;
    192 
    193 static void* usb_malloc(uint32_t size, uint32_t alignment) {
    194     /* Align offset */
    195     uint32_t mask = alignment - 1;
    196     usb_memory_offset = (usb_memory_offset + mask) & ~mask;
    197 
    198     if (usb_memory_offset + size > sizeof(usb_memory_pool)) {
    199         return NULL;
    200     }
    201 
    202     void* ptr = &usb_memory_pool[usb_memory_offset];
    203     usb_memory_offset += size;
    204 
    205     /* Zero the memory */
    206     for (uint32_t i = 0; i < size; i++) {
    207         ((uint8_t*)ptr)[i] = 0;
    208     }
    209 
    210     return ptr;
    211 }
    212 
    213 /* Get physical address (identity mapped in our case) */
    214 static uint32_t virt_to_phys(void* ptr) {
    215     return (uint32_t)ptr;
    216 }
    217 
    218 /* Reset UHCI controller */
    219 static int uhci_reset(void) {
    220     terminal_writestring("Resetting UHCI controller...\n");
    221 
    222     /* Global reset */
    223     outw(uhci_iobase + UHCI_USBCMD, UHCI_CMD_GRESET);
    224 
    225     /* Wait 10ms (approximate) */
    226     for (volatile int i = 0; i < 1000000; i++);
    227 
    228     outw(uhci_iobase + UHCI_USBCMD, 0);
    229 
    230     /* Host controller reset */
    231     outw(uhci_iobase + UHCI_USBCMD, UHCI_CMD_HCRESET);
    232 
    233     /* Wait for reset to complete */
    234     int timeout = 10000;
    235     while ((inw(uhci_iobase + UHCI_USBCMD) & UHCI_CMD_HCRESET) && timeout--);
    236 
    237     if (timeout == 0) {
    238         terminal_writestring("UHCI reset timeout\n");
    239         return -1;
    240     }
    241 
    242     terminal_writestring("UHCI reset complete\n");
    243     return 0;
    244 }
    245 
    246 /* Initialize USB controller */
    247 int usb_init(void) {
    248     terminal_writestring("Initializing USB subsystem...\n");
    249 
    250     /* Find UHCI controller */
    251     if (find_uhci_controller() != 0) {
    252         return -1;
    253     }
    254 
    255     /* Reset controller */
    256     if (uhci_reset() != 0) {
    257         return -1;
    258     }
    259 
    260     /* Allocate frame list (1024 entries, 4KB aligned) */
    261     frame_list = (uint32_t*)usb_malloc(1024 * sizeof(uint32_t), 4096);
    262     if (!frame_list) {
    263         terminal_writestring("Failed to allocate frame list\n");
    264         return -1;
    265     }
    266 
    267     /* Initialize frame list to terminate */
    268     for (int i = 0; i < 1024; i++) {
    269         frame_list[i] = 1;  /* Terminate bit */
    270     }
    271 
    272     /* Allocate control queue head */
    273     control_qh = (uhci_qh_t*)usb_malloc(sizeof(uhci_qh_t), 16);
    274     if (!control_qh) {
    275         terminal_writestring("Failed to allocate control QH\n");
    276         return -1;
    277     }
    278     control_qh->head_link_ptr = 1;  /* Terminate */
    279     control_qh->element_link_ptr = 1;  /* Terminate */
    280 
    281     /* Allocate interrupt queue head */
    282     interrupt_qh = (uhci_qh_t*)usb_malloc(sizeof(uhci_qh_t), 16);
    283     if (!interrupt_qh) {
    284         terminal_writestring("Failed to allocate interrupt QH\n");
    285         return -1;
    286     }
    287     interrupt_qh->head_link_ptr = virt_to_phys(control_qh) | 0x02;  /* QH pointer */
    288     interrupt_qh->element_link_ptr = 1;  /* Terminate */
    289 
    290     /* Link frame list to interrupt queue */
    291     uint32_t int_qh_ptr = virt_to_phys(interrupt_qh) | 0x02;  /* QH pointer */
    292     for (int i = 0; i < 1024; i++) {
    293         frame_list[i] = int_qh_ptr;
    294     }
    295 
    296     /* Set frame list base address */
    297     outl(uhci_iobase + UHCI_FRBASEADD, virt_to_phys(frame_list));
    298 
    299     /* Set frame number to 0 */
    300     outw(uhci_iobase + UHCI_FRNUM, 0);
    301 
    302     /* Start controller */
    303     outw(uhci_iobase + UHCI_USBCMD, UHCI_CMD_RS | UHCI_CMD_CF | UHCI_CMD_MAXP);
    304 
    305     terminal_writestring("UHCI controller started\n");
    306 
    307     /* Wait for controller to start */
    308     for (volatile int i = 0; i < 100000; i++);
    309 
    310     /* Check status */
    311     uint16_t status = inw(uhci_iobase + UHCI_USBSTS);
    312     terminal_writestring("UHCI Status: 0x");
    313     for (int i = 3; i >= 0; i--) {
    314         uint8_t nibble = (status >> (i * 4)) & 0xF;
    315         terminal_putchar(nibble < 10 ? '0' + nibble : 'A' + nibble - 10);
    316     }
    317     terminal_writestring("\n");
    318 
    319     /* Check frame number is advancing */
    320     uint16_t frame1 = inw(uhci_iobase + UHCI_FRNUM);
    321     for (volatile int i = 0; i < 100000; i++);
    322     uint16_t frame2 = inw(uhci_iobase + UHCI_FRNUM);
    323     terminal_writestring("Frame#: ");
    324     for (int i = 3; i >= 0; i--) {
    325         uint8_t nibble = (frame1 >> (i * 4)) & 0xF;
    326         terminal_putchar(nibble < 10 ? '0' + nibble : 'A' + nibble - 10);
    327     }
    328     terminal_writestring(" -> ");
    329     for (int i = 3; i >= 0; i--) {
    330         uint8_t nibble = (frame2 >> (i * 4)) & 0xF;
    331         terminal_putchar(nibble < 10 ? '0' + nibble : 'A' + nibble - 10);
    332     }
    333     if (frame2 != frame1) {
    334         terminal_writestring(" (advancing OK)\n");
    335     } else {
    336         terminal_writestring(" (STUCK!)\n");
    337     }
    338 
    339     return 0;
    340 }
    341 
    342 /* Reset USB port */
    343 static int uhci_port_reset(int port) {
    344     uint16_t port_reg = UHCI_PORTSC1 + (port * 2);
    345 
    346     terminal_writestring("Resetting USB port ");
    347     terminal_putchar('0' + port);
    348     terminal_writestring("\n");
    349 
    350     /* Set port reset */
    351     uint16_t val = inw(uhci_iobase + port_reg);
    352     outw(uhci_iobase + port_reg, val | UHCI_PORT_PR);
    353 
    354     /* Wait 50ms (approximate) */
    355     for (volatile int i = 0; i < 5000000; i++);
    356 
    357     /* Clear port reset */
    358     val = inw(uhci_iobase + port_reg);
    359     outw(uhci_iobase + port_reg, val & ~UHCI_PORT_PR);
    360 
    361     /* Wait for reset to complete */
    362     for (volatile int i = 0; i < 1000000; i++);
    363 
    364     /* Enable port */
    365     val = inw(uhci_iobase + port_reg);
    366     outw(uhci_iobase + port_reg, val | UHCI_PORT_PED);
    367 
    368     return 0;
    369 }
    370 
    371 /* Enumerate USB devices */
    372 int usb_enumerate_devices(void) {
    373     terminal_writestring("Enumerating USB devices...\n");
    374 
    375     /* Check port 1 */
    376     uint16_t port1 = inw(uhci_iobase + UHCI_PORTSC1);
    377     terminal_writestring("Port 1 Status: 0x");
    378     for (int i = 3; i >= 0; i--) {
    379         uint8_t nibble = (port1 >> (i * 4)) & 0xF;
    380         terminal_putchar(nibble < 10 ? '0' + nibble : 'A' + nibble - 10);
    381     }
    382     terminal_writestring("\n");
    383 
    384     if (port1 & UHCI_PORT_CCS) {
    385         terminal_writestring("Device detected on port 1\n");
    386         if (port1 & UHCI_PORT_LSDA) {
    387             terminal_writestring("  Low speed device\n");
    388         }
    389         uhci_port_reset(0);
    390     }
    391 
    392     /* Check port 2 */
    393     uint16_t port2 = inw(uhci_iobase + UHCI_PORTSC2);
    394     terminal_writestring("Port 2 Status: 0x");
    395     for (int i = 3; i >= 0; i--) {
    396         uint8_t nibble = (port2 >> (i * 4)) & 0xF;
    397         terminal_putchar(nibble < 10 ? '0' + nibble : 'A' + nibble - 10);
    398     }
    399     terminal_writestring("\n");
    400 
    401     if (port2 & UHCI_PORT_CCS) {
    402         terminal_writestring("Device detected on port 2\n");
    403         if (port2 & UHCI_PORT_LSDA) {
    404             terminal_writestring("  Low speed device\n");
    405         }
    406         uhci_port_reset(1);
    407     }
    408 
    409     return 0;
    410 }
    411 
    412 /* Initialize USB mouse with proper enumeration */
    413 int usb_mouse_init(void) {
    414     terminal_writestring("Initializing USB mouse (boot protocol)...\n");
    415 
    416     /* TODO: Send SET_ADDRESS to device at address 0 to assign it address 1 */
    417     /* For now, we'll use address 0 and endpoint 1 for the interrupt endpoint */
    418     /* This is a simplified approach that may not work with all USB stacks */
    419 
    420     terminal_writestring("WARNING: Using simplified enumeration (address 0)\n");
    421     terminal_writestring("Mouse may not respond without proper SET_ADDRESS\n");
    422 
    423     /* Allocate mouse report buffer */
    424     mouse_report_buffer = (usb_mouse_report_t*)usb_malloc(sizeof(usb_mouse_report_t), 16);
    425     if (!mouse_report_buffer) {
    426         terminal_writestring("Failed to allocate mouse report buffer\n");
    427         return -1;
    428     }
    429 
    430     /* Allocate mouse TD */
    431     mouse_td = (uhci_td_t*)usb_malloc(sizeof(uhci_td_t), 16);
    432     if (!mouse_td) {
    433         terminal_writestring("Failed to allocate mouse TD\n");
    434         return -1;
    435     }
    436 
    437     /* Set up interrupt transfer for mouse */
    438     /* Token format: MaxLen(11) | 0 | DataToggle(1) | Endpoint(4) | DevAddr(7) | PID(8) */
    439     /* Using: Device 0, Endpoint 1, Data Toggle 0, MaxLen 2 (3 bytes - 1) */
    440     mouse_td->link_ptr = 1;  /* Terminate */
    441     mouse_td->status = TD_STATUS_ACTIVE | TD_STATUS_IOC | TD_STATUS_LS | (3 << 27);  /* 3 errors */
    442     mouse_td->token = (2 << 21) | (0 << 19) | (1 << 15) | (0 << 8) | TD_TOKEN_PID_IN;
    443     mouse_td->buffer = virt_to_phys(mouse_report_buffer);
    444 
    445     /* Link to interrupt queue */
    446     interrupt_qh->element_link_ptr = virt_to_phys(mouse_td);
    447 
    448     /* Debug: print TD configuration */
    449     terminal_writestring("TD Config:\n");
    450     terminal_writestring("  status=0x");
    451     for (int i = 7; i >= 0; i--) {
    452         uint8_t nibble = (mouse_td->status >> (i * 4)) & 0xF;
    453         terminal_putchar(nibble < 10 ? '0' + nibble : 'A' + nibble - 10);
    454     }
    455     terminal_writestring("\n  token=0x");
    456     for (int i = 7; i >= 0; i--) {
    457         uint8_t nibble = (mouse_td->token >> (i * 4)) & 0xF;
    458         terminal_putchar(nibble < 10 ? '0' + nibble : 'A' + nibble - 10);
    459     }
    460     terminal_writestring("\n  buffer=0x");
    461     for (int i = 7; i >= 0; i--) {
    462         uint8_t nibble = (mouse_td->buffer >> (i * 4)) & 0xF;
    463         terminal_putchar(nibble < 10 ? '0' + nibble : 'A' + nibble - 10);
    464     }
    465     terminal_writestring("\n  IntQH.elem=0x");
    466     for (int i = 7; i >= 0; i--) {
    467         uint8_t nibble = (interrupt_qh->element_link_ptr >> (i * 4)) & 0xF;
    468         terminal_putchar(nibble < 10 ? '0' + nibble : 'A' + nibble - 10);
    469     }
    470     terminal_writestring("\n");
    471 
    472     mouse_state.initialized = 1;
    473     terminal_writestring("USB mouse initialized\n");
    474 
    475     return 0;
    476 }
    477 
    478 /* Poll USB mouse for updates */
    479 void usb_mouse_poll(void) {
    480     static int poll_counter = 0;
    481     if (!mouse_state.initialized || !mouse_td) return;
    482 
    483     poll_counter++;
    484 
    485     /* Check if transfer completed */
    486     if (!(mouse_td->status & TD_STATUS_ACTIVE)) {
    487         /* Check for errors */
    488         if (mouse_td->status & (TD_STATUS_STALLED | TD_STATUS_BABBLE | TD_STATUS_CRCTO)) {
    489             /* Error - reactivate */
    490             mouse_td->status = TD_STATUS_ACTIVE | TD_STATUS_IOC | TD_STATUS_LS | (3 << 27);
    491             return;
    492         }
    493 
    494         /* Update mouse state */
    495         mouse_state.buttons = mouse_report_buffer->buttons;
    496         mouse_state.x += mouse_report_buffer->x;
    497         mouse_state.y -= mouse_report_buffer->y;  /* Invert Y */
    498 
    499         /* Clamp to screen bounds */
    500         if (mouse_state.x < 0) mouse_state.x = 0;
    501         if (mouse_state.x >= 1024) mouse_state.x = 1023;
    502         if (mouse_state.y < 0) mouse_state.y = 0;
    503         if (mouse_state.y >= 768) mouse_state.y = 767;
    504 
    505         /* Reactivate TD for next transfer */
    506         mouse_td->status = TD_STATUS_ACTIVE | TD_STATUS_IOC | TD_STATUS_LS | (3 << 27);
    507     }
    508 }
    509 
    510 /* Get current USB mouse state */
    511 void usb_mouse_get_state(usb_mouse_state_t* state) {
    512     if (state) {
    513         state->x = mouse_state.x;
    514         state->y = mouse_state.y;
    515         state->buttons = mouse_state.buttons;
    516         state->initialized = mouse_state.initialized;
    517     }
    518 }
    519 
    520 /* Lua binding for USB mouse polling */
    521 int lua_usb_mouse_poll(lua_State* L) {
    522     (void)L;  /* Unused parameter */
    523     usb_mouse_poll();
    524     return 0;
    525 }
    526 
    527 /* Lua binding for USB mouse state */
    528 int lua_usb_mouse_get_state(lua_State* L) {
    529     lua_newtable(L);
    530 
    531     lua_pushinteger(L, mouse_state.x);
    532     lua_setfield(L, -2, "x");
    533 
    534     lua_pushinteger(L, mouse_state.y);
    535     lua_setfield(L, -2, "y");
    536 
    537     lua_pushinteger(L, mouse_state.buttons);
    538     lua_setfield(L, -2, "buttons");
    539 
    540     lua_pushboolean(L, mouse_state.initialized);
    541     lua_setfield(L, -2, "initialized");
    542 
    543     return 1;
    544 }