/* Initializes the controller and the keyboard part */ static status_t ps2_keyboard_init() { int nError = 0; g_nKbdLedStatus = 0; memset( &g_sKbdPort, 0, sizeof( g_sKbdPort ) ); /* Flush buffer */ ps2_flush(); /* Read control register */ uint8 nControl = 0; nError = ps2_read_command( PS2_CMD_RCTR, &nControl ); if( nError < 0 ) { printk( "PS2 I/O error\n" ); return( -EIO ); } /* TODO: Disable keyboard */ nControl |= PS2_CTR_KBDDIS; nControl &= ~PS2_CTR_KBDINT; /* Check if translated mode is enabled */ if( !( nControl & PS2_CTR_XLATE ) ) { printk( "Keyboard is in non-translated mode. This is not supported\n" ); return( -ENOENT ); } /* Write control register */ nError = ps2_write_command( PS2_CMD_WCTR, nControl ); if( nError < 0 ) { printk( "PS2 I/O error\n" ); return( -EIO ); } g_sKbdPort.bPresent = true; g_sKbdPort.hWait = create_semaphore( "ps2_wait", 0, 0 ); g_sKbdPort.nIrq = 1; g_sKbdPort.nDevHandle = register_device( "", "isa" ); claim_device( g_nDevNum, g_sKbdPort.nDevHandle, "PS/2 or AT keyboard", DEVICE_INPUT ); set_device_data( g_sKbdPort.nDevHandle, &g_sKbdPort ); nError = create_device_node( g_nDevNum, g_sKbdPort.nDevHandle, "keybd", &g_sOperations, &g_sKbdPort ); printk( "PS2 or AT Keyboard detected\n" ); return( 0 ); }
status_t ps2_open( void* pNode, uint32 nFlags, void **pCookie ) { uint8 nControl; uint32 nFlg; PS2_Port_s* psPort = (PS2_Port_s*)pNode; printk( "ps2_open()\n" ); if ( atomic_inc_and_read( &psPort->nOpenCount ) > 0 ) { atomic_dec( &psPort->nOpenCount ); return( -EBUSY ); } ps2_flush(); psPort->nIrqHandle = request_irq( psPort->nIrq, ps2_interrupt, NULL, 0, "ps2", psPort ); if ( psPort->nIrqHandle < 0 ) { printk( "PS2: Could not get irq %i\n", psPort->nIrq ); atomic_dec( &psPort->nOpenCount ); return( -EBUSY ); } /* Enable device */ if( psPort->bIsAux ) ps2_command( PS2_CMD_AUX_ENABLE ); nFlg = spinlock_disable( &g_sLock ); ps2_read_command( PS2_CMD_RCTR, &nControl ); if( psPort->bIsAux ) { nControl &= ~PS2_CTR_AUXDIS; nControl |= PS2_CTR_AUXINT; } else { nControl &= ~PS2_CTR_KBDDIS; nControl |= PS2_CTR_KBDINT; } ps2_write_command( PS2_CMD_WCTR, nControl ); spinunlock_enable( &g_sLock, nFlg ); atomic_set( &psPort->nBytesReceived, 0 ); atomic_set( &psPort->nInPos, 0 ); atomic_set( &psPort->nOutPos, 0 ); return( 0 ); }
void KBM::init() { // disable ports ctl_send(CMD_DISABLE_PORT1); ctl_send(CMD_DISABLE_PORT2); ps2_flush(); // configure controller ctl_send(0x20); uint8_t config = read_data(); bool second_port = config & (1 << 5); (void) second_port; config |= 0x1 | 0x2; // enable interrupts config &= ~(1 << 6); // write config ctl_send(0x60); send_data(config); ps2_flush(); // enable port1 ctl_send(CMD_ENABLE_PORT1); ps2_flush(); // self-test (port1) write_port1(0xFF); uint8_t selftest = read_data(); assert(selftest == 0xAA); write_port1(DEV_IDENTIFY); uint8_t id1 = read_data(); if (id1 == 0xAA || id1 == 0xAB) { // port1 is the keyboard debug("keyboard on port1\n"); keyboard_write = write_port1; mouse_write = write_port2; } else { // port2 is the keyboard debug("keyboard on port2\n"); mouse_write = write_port1; keyboard_write = write_port2; } // enable keyboard keyboard_write(0xF4); // get and set scancode keyboard_write(0xF0); send_data(0x01); keyboard_write(0xF0); send_data(0x00); uint8_t scanset = 0xFA; while (scanset == 0xFA) scanset = read_data(); // route and enable interrupt handlers const uint8_t KEYB_IRQ = (keyboard_write == write_port1) ? PORT1_IRQ : PORT2_IRQ; const uint8_t MOUS_IRQ = (KEYB_IRQ == PORT1_IRQ) ? PORT2_IRQ : PORT1_IRQ; assert(KEYB_IRQ != MOUS_IRQ); // need to route IRQs from IO APIC to BSP LAPIC IRQ_manager::get().enable_irq(KEYB_IRQ); IRQ_manager::get().enable_irq(MOUS_IRQ); IRQ_manager::get().subscribe(KEYB_IRQ, [KEYB_IRQ] { //IRQ_manager::eoi(KEYB_IRQ); uint8_t byte = read_fast(); // transform to virtual key int key = get().transform_vk(byte); // call handler get().on_virtualkey(key); }); IRQ_manager::get().subscribe(MOUS_IRQ, [MOUS_IRQ] { //IRQ_manager::eoi(MOUS_IRQ); get().handle_mouse(read_fast()); }); /* // reset and enable keyboard send_data(0xF6); // enable keyboard scancodes send_data(0xF4); // enable interrupts //ctl_send(0x60, ctl_read(0x20) | 0x1 | 0x2); */ }
static status_t ps2_aux_init() { int nError = 0; struct RMREGS rm; /* TODO: Do this without calling the bios */ memset( &rm, 0, sizeof( struct RMREGS ) ); realint( 0x11, &rm ); if( ( rm.EAX & 0x04 ) == 0 ) { printk( "No PS2 mouse present\n" ); return( -EIO ); } memset( &g_sAuxPort, 0, sizeof( g_sAuxPort ) ); g_sAuxPort.bIsAux = true; /* Flush buffer */ ps2_flush(); /* Test loop command */ uint8 nData = 0x5a; nError = ps2_write_read_command( PS2_CMD_AUX_LOOP, &nData ); if( nError < 0 || nData != 0x5a ) { /* According to linux driver the loop test fails on some chipsets */ printk( "PS2 Aux loop test failed (error = %i, data = %x)! Trying test command...\n", nError, (uint)nData ); if( ps2_read_command( PS2_CMD_AUX_TEST, &nData ) < 0 ) { printk( "Failed -> Aux port not present!\n" ); return( -ENOENT ); } printk( "Test command returned %x\n", (uint)nData ); if( nData && nData != 0xfa && nData != 0xff ) { printk( "Invalid return code!\n" ); return( -ENOENT ); } } /* Disable and then enable the auxport */ if( ps2_command( PS2_CMD_AUX_DISABLE ) < 0 ) return( -ENOENT ); if( ps2_command( PS2_CMD_AUX_ENABLE ) < 0 ) return( -ENOENT ); if( ps2_read_command( PS2_CMD_RCTR, &nData ) < 0 || ( nData & PS2_CTR_AUXDIS ) ) return( -EIO ); /* Disable aux port */ nData |= PS2_CTR_AUXDIS; nData &= ~PS2_CTR_AUXINT; /* Write control register */ nError = ps2_write_command( PS2_CMD_WCTR, nData ); if( nError < 0 ) { printk( "PS2 I/O error\n" ); return( -EIO ); } printk( "PS2 AUX port detected\n" ); /* Register device */ g_sAuxPort.bPresent = true; g_sAuxPort.hWait = create_semaphore( "ps2_wait", 0, 0 ); g_sAuxPort.nDevHandle = register_device( "", "isa" ); g_sAuxPort.nIrq = 12; claim_device( g_nDevNum, g_sAuxPort.nDevHandle, "PS/2 Aux port", DEVICE_PORT ); set_device_data( g_sAuxPort.nDevHandle, &g_sAuxPort ); nError = create_device_node( g_nDevNum, g_sAuxPort.nDevHandle, "misc/ps2aux", &g_sOperations, &g_sAuxPort ); if( nError < 0 ) return( -EIO ); return( 0 ); }