mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Update kernel/kb/ps2.{cpp,h} to current coding conventions.
This commit is contained in:
parent
6e6df64fa8
commit
bb3b6b0260
2 changed files with 247 additions and 229 deletions
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <sortix/keycodes.h>
|
#include <sortix/keycodes.h>
|
||||||
|
@ -36,198 +38,210 @@
|
||||||
|
|
||||||
#include "ps2.h"
|
#include "ps2.h"
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix {
|
||||||
|
|
||||||
|
const uint16_t DATA = 0x0;
|
||||||
|
const uint16_t COMMAND = 0x0;
|
||||||
|
const uint16_t STATUS = 0x4;
|
||||||
|
const uint8_t CMD_SETLED = 0xED;
|
||||||
|
const uint8_t LED_SCRLCK = 1 << 0;
|
||||||
|
const uint8_t LED_NUMLCK = 1 << 1;
|
||||||
|
const uint8_t LED_CAPSLCK = 1 << 2;
|
||||||
|
|
||||||
|
void PS2Keyboard__OnInterrupt(CPU::InterruptRegisters* regs, void* user)
|
||||||
{
|
{
|
||||||
const uint16_t DATA = 0x0;
|
((PS2Keyboard*) user)->OnInterrupt(regs);
|
||||||
const uint16_t COMMAND = 0x0;
|
|
||||||
const uint16_t STATUS = 0x4;
|
|
||||||
const uint8_t CMD_SETLED = 0xED;
|
|
||||||
const uint8_t LED_SCRLCK = (1<<0);
|
|
||||||
const uint8_t LED_NUMLCK = (1<<1);
|
|
||||||
const uint8_t LED_CAPSLCK = (1<<2);
|
|
||||||
|
|
||||||
void PS2Keyboard__OnInterrupt(CPU::InterruptRegisters* regs, void* user)
|
|
||||||
{
|
|
||||||
((PS2Keyboard*) user)->OnInterrupt(regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
PS2Keyboard::PS2Keyboard(uint16_t iobase, uint8_t interrupt)
|
|
||||||
{
|
|
||||||
this->queue = NULL;
|
|
||||||
this->queuelength = 0;
|
|
||||||
this->queueoffset = 0;
|
|
||||||
this->queueused = 0;
|
|
||||||
this->owner = NULL;
|
|
||||||
this->ownerptr = NULL;
|
|
||||||
this->iobase = iobase;
|
|
||||||
this->interrupt = interrupt;
|
|
||||||
this->leds = 0;
|
|
||||||
this->scancodeescaped = false;
|
|
||||||
this->kblock = KTHREAD_MUTEX_INITIALIZER;
|
|
||||||
Interrupt::RegisterHandler(interrupt, PS2Keyboard__OnInterrupt, this);
|
|
||||||
|
|
||||||
// If any scancodes were already pending, our interrupt handler will
|
|
||||||
// never be called. Let's just discard anything pending.
|
|
||||||
PopScancode();
|
|
||||||
}
|
|
||||||
|
|
||||||
PS2Keyboard::~PS2Keyboard()
|
|
||||||
{
|
|
||||||
Interrupt::RegisterHandler(interrupt, NULL, NULL);
|
|
||||||
delete[] queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct PS2KeyboardWork
|
|
||||||
{
|
|
||||||
PS2Keyboard* kb;
|
|
||||||
uint8_t scancode;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void PS2Keyboard__InterruptWork(void* payload, size_t size)
|
|
||||||
{
|
|
||||||
assert(size == sizeof(PS2KeyboardWork));
|
|
||||||
PS2KeyboardWork* work = (PS2KeyboardWork*) payload;
|
|
||||||
work->kb->InterruptWork(work->scancode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* regs)
|
|
||||||
{
|
|
||||||
uint8_t scancode = PopScancode();
|
|
||||||
if ( scancode == KBKEY_F10 )
|
|
||||||
{
|
|
||||||
CurrentThread()->SaveRegisters(regs);
|
|
||||||
Debugger::Run();
|
|
||||||
}
|
|
||||||
PS2KeyboardWork work;
|
|
||||||
work.kb = this;
|
|
||||||
work.scancode = scancode;
|
|
||||||
Interrupt::ScheduleWork(PS2Keyboard__InterruptWork, &work, sizeof(work));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PS2Keyboard::InterruptWork(uint8_t scancode)
|
|
||||||
{
|
|
||||||
kthread_mutex_lock(&kblock);
|
|
||||||
int kbkey = DecodeScancode(scancode);
|
|
||||||
if ( !kbkey ) { kthread_mutex_unlock(&kblock); return; }
|
|
||||||
|
|
||||||
if ( !PushKey(kbkey) )
|
|
||||||
{
|
|
||||||
Log::PrintF("Warning: dropping keystroke due to insufficient "
|
|
||||||
"storage space in PS2 keyboard driver.\n");
|
|
||||||
kthread_mutex_unlock(&kblock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t newleds = leds;
|
|
||||||
|
|
||||||
if ( kbkey == KBKEY_CAPSLOCK ) { newleds ^= LED_CAPSLCK; }
|
|
||||||
if ( kbkey == KBKEY_SCROLLLOCK ) { newleds ^= LED_SCRLCK; }
|
|
||||||
if ( kbkey == KBKEY_NUMLOCK ) { newleds ^= LED_NUMLCK; }
|
|
||||||
|
|
||||||
if ( newleds != leds ) { UpdateLEDs(leds = newleds); }
|
|
||||||
|
|
||||||
kthread_mutex_unlock(&kblock);
|
|
||||||
|
|
||||||
NotifyOwner();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PS2Keyboard::NotifyOwner()
|
|
||||||
{
|
|
||||||
if ( !owner) { return; }
|
|
||||||
owner->OnKeystroke(this, ownerptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int PS2Keyboard::DecodeScancode(uint8_t scancode)
|
|
||||||
{
|
|
||||||
const uint8_t SCANCODE_ESCAPE = 0xE0;
|
|
||||||
if ( scancode == SCANCODE_ESCAPE )
|
|
||||||
{
|
|
||||||
scancodeescaped = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int offset = (scancodeescaped) ? 0x80 : 0;
|
|
||||||
int kbkey = scancode & 0x7F;
|
|
||||||
if ( scancode & 0x80 ) { kbkey = -kbkey - offset; }
|
|
||||||
else { kbkey = kbkey + offset; }
|
|
||||||
|
|
||||||
scancodeescaped = false;
|
|
||||||
|
|
||||||
// kbkey is now in the format specified in <sortix/keycodes.h>.
|
|
||||||
|
|
||||||
return kbkey;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t PS2Keyboard::PopScancode()
|
|
||||||
{
|
|
||||||
return CPU::InPortB(iobase + DATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PS2Keyboard::UpdateLEDs(int ledval)
|
|
||||||
{
|
|
||||||
while ( (CPU::InPortB(iobase + STATUS) & (1<<1)) != 0 ) { }
|
|
||||||
CPU::OutPortB(iobase + COMMAND, CMD_SETLED);
|
|
||||||
while ( (CPU::InPortB(iobase + STATUS) & (1<<1)) != 0 ) { }
|
|
||||||
CPU::OutPortB(iobase + COMMAND, ledval);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PS2Keyboard::SetOwner(KeyboardOwner* owner, void* user)
|
|
||||||
{
|
|
||||||
kthread_mutex_lock(&kblock);
|
|
||||||
this->owner = owner;
|
|
||||||
this->ownerptr = user;
|
|
||||||
kthread_mutex_unlock(&kblock);
|
|
||||||
if ( queueused ) { NotifyOwner(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PS2Keyboard::PushKey(int key)
|
|
||||||
{
|
|
||||||
// Check if we need to allocate or resize the circular queue.
|
|
||||||
if ( queueused == queuelength )
|
|
||||||
{
|
|
||||||
size_t newqueuelength = (queuelength) ? queuelength * 2 : 32UL;
|
|
||||||
int* newqueue = new int[newqueuelength];
|
|
||||||
if ( !newqueue ) { return false; }
|
|
||||||
size_t elemsize = sizeof(*queue);
|
|
||||||
size_t leadingavai = queuelength-queueoffset;
|
|
||||||
size_t leading = (leadingavai < queueused) ? leadingavai : queueused;
|
|
||||||
size_t trailing = queueused - leading;
|
|
||||||
memcpy(newqueue, queue + queueoffset, leading * elemsize);
|
|
||||||
memcpy(newqueue + leading, queue, trailing * elemsize);
|
|
||||||
delete[] queue;
|
|
||||||
queue = newqueue;
|
|
||||||
queuelength = newqueuelength;
|
|
||||||
queueoffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
queue[(queueoffset + queueused++) % queuelength] = key;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PS2Keyboard::PopKey()
|
|
||||||
{
|
|
||||||
if ( !queueused ) { return 0; }
|
|
||||||
int kbkey = queue[queueoffset];
|
|
||||||
queueoffset = (queueoffset + 1) % queuelength;
|
|
||||||
queueused--;
|
|
||||||
return kbkey;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PS2Keyboard::Read()
|
|
||||||
{
|
|
||||||
ScopedLock lock(&kblock);
|
|
||||||
return PopKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t PS2Keyboard::GetPending() const
|
|
||||||
{
|
|
||||||
ScopedLock lock(&kblock);
|
|
||||||
return queueused;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PS2Keyboard::HasPending() const
|
|
||||||
{
|
|
||||||
ScopedLock lock(&kblock);
|
|
||||||
return queueused;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PS2Keyboard::PS2Keyboard(uint16_t iobase, uint8_t interrupt)
|
||||||
|
{
|
||||||
|
this->queue = NULL;
|
||||||
|
this->queuelength = 0;
|
||||||
|
this->queueoffset = 0;
|
||||||
|
this->queueused = 0;
|
||||||
|
this->owner = NULL;
|
||||||
|
this->ownerptr = NULL;
|
||||||
|
this->iobase = iobase;
|
||||||
|
this->interrupt = interrupt;
|
||||||
|
this->leds = 0;
|
||||||
|
this->scancodeescaped = false;
|
||||||
|
this->kblock = KTHREAD_MUTEX_INITIALIZER;
|
||||||
|
Interrupt::RegisterHandler(interrupt, PS2Keyboard__OnInterrupt, this);
|
||||||
|
|
||||||
|
// If any scancodes were already pending, our interrupt handler will
|
||||||
|
// never be called. Let's just discard anything pending.
|
||||||
|
PopScancode();
|
||||||
|
}
|
||||||
|
|
||||||
|
PS2Keyboard::~PS2Keyboard()
|
||||||
|
{
|
||||||
|
Interrupt::RegisterHandler(interrupt, NULL, NULL);
|
||||||
|
delete[] queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PS2KeyboardWork
|
||||||
|
{
|
||||||
|
PS2Keyboard* kb;
|
||||||
|
uint8_t scancode;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void PS2Keyboard__InterruptWork(void* payload, size_t size)
|
||||||
|
{
|
||||||
|
assert(size == sizeof(PS2KeyboardWork));
|
||||||
|
PS2KeyboardWork* work = (PS2KeyboardWork*) payload;
|
||||||
|
work->kb->InterruptWork(work->scancode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* regs)
|
||||||
|
{
|
||||||
|
uint8_t scancode = PopScancode();
|
||||||
|
if ( scancode == KBKEY_F10 )
|
||||||
|
{
|
||||||
|
CurrentThread()->SaveRegisters(regs);
|
||||||
|
Debugger::Run();
|
||||||
|
}
|
||||||
|
PS2KeyboardWork work;
|
||||||
|
work.kb = this;
|
||||||
|
work.scancode = scancode;
|
||||||
|
Interrupt::ScheduleWork(PS2Keyboard__InterruptWork, &work, sizeof(work));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Keyboard::InterruptWork(uint8_t scancode)
|
||||||
|
{
|
||||||
|
kthread_mutex_lock(&kblock);
|
||||||
|
int kbkey = DecodeScancode(scancode);
|
||||||
|
if ( !kbkey )
|
||||||
|
{
|
||||||
|
kthread_mutex_unlock(&kblock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !PushKey(kbkey) )
|
||||||
|
{
|
||||||
|
Log::PrintF("Warning: dropping keystroke due to insufficient "
|
||||||
|
"storage space in PS2 keyboard driver.\n");
|
||||||
|
kthread_mutex_unlock(&kblock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t newleds = leds;
|
||||||
|
|
||||||
|
if ( kbkey == KBKEY_CAPSLOCK )
|
||||||
|
newleds ^= LED_CAPSLCK;
|
||||||
|
if ( kbkey == KBKEY_SCROLLLOCK )
|
||||||
|
newleds ^= LED_SCRLCK;
|
||||||
|
if ( kbkey == KBKEY_NUMLOCK )
|
||||||
|
newleds ^= LED_NUMLCK;
|
||||||
|
|
||||||
|
if ( newleds != leds )
|
||||||
|
UpdateLEDs(leds = newleds);
|
||||||
|
|
||||||
|
kthread_mutex_unlock(&kblock);
|
||||||
|
|
||||||
|
NotifyOwner();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Keyboard::NotifyOwner()
|
||||||
|
{
|
||||||
|
if ( !owner)
|
||||||
|
return;
|
||||||
|
owner->OnKeystroke(this, ownerptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS2Keyboard::DecodeScancode(uint8_t scancode)
|
||||||
|
{
|
||||||
|
const uint8_t SCANCODE_ESCAPE = 0xE0;
|
||||||
|
if ( scancode == SCANCODE_ESCAPE )
|
||||||
|
{
|
||||||
|
scancodeescaped = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = scancodeescaped ? 0x80 : 0;
|
||||||
|
int kbkey = scancode & 0x7F;
|
||||||
|
kbkey = scancode & 0x80 ? -kbkey - offset : kbkey + offset;
|
||||||
|
|
||||||
|
scancodeescaped = false;
|
||||||
|
|
||||||
|
// kbkey is now in the format specified in <sortix/keycodes.h>.
|
||||||
|
|
||||||
|
return kbkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t PS2Keyboard::PopScancode()
|
||||||
|
{
|
||||||
|
return CPU::InPortB(iobase + DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Keyboard::UpdateLEDs(int ledval)
|
||||||
|
{
|
||||||
|
while ( (CPU::InPortB(iobase + STATUS) & (1<<1)) );
|
||||||
|
CPU::OutPortB(iobase + COMMAND, CMD_SETLED);
|
||||||
|
while ( (CPU::InPortB(iobase + STATUS) & (1<<1)) );
|
||||||
|
CPU::OutPortB(iobase + COMMAND, ledval);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS2Keyboard::SetOwner(KeyboardOwner* owner, void* user)
|
||||||
|
{
|
||||||
|
kthread_mutex_lock(&kblock);
|
||||||
|
this->owner = owner;
|
||||||
|
this->ownerptr = user;
|
||||||
|
kthread_mutex_unlock(&kblock);
|
||||||
|
if ( queueused )
|
||||||
|
NotifyOwner();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PS2Keyboard::PushKey(int key)
|
||||||
|
{
|
||||||
|
// Check if we need to allocate or resize the circular queue.
|
||||||
|
if ( queueused == queuelength )
|
||||||
|
{
|
||||||
|
size_t newqueuelength = (queuelength) ? queuelength * 2 : 32UL;
|
||||||
|
int* newqueue = new int[newqueuelength];
|
||||||
|
if ( !newqueue )
|
||||||
|
return false;
|
||||||
|
size_t elemsize = sizeof(*queue);
|
||||||
|
size_t leadingavai = queuelength-queueoffset;
|
||||||
|
size_t leading = (leadingavai < queueused) ? leadingavai : queueused;
|
||||||
|
size_t trailing = queueused - leading;
|
||||||
|
memcpy(newqueue, queue + queueoffset, leading * elemsize);
|
||||||
|
memcpy(newqueue + leading, queue, trailing * elemsize);
|
||||||
|
delete[] queue;
|
||||||
|
queue = newqueue;
|
||||||
|
queuelength = newqueuelength;
|
||||||
|
queueoffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
queue[(queueoffset + queueused++) % queuelength] = key;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS2Keyboard::PopKey()
|
||||||
|
{
|
||||||
|
if ( !queueused )
|
||||||
|
return 0;
|
||||||
|
int kbkey = queue[queueoffset];
|
||||||
|
queueoffset = (queueoffset + 1) % queuelength;
|
||||||
|
queueused--;
|
||||||
|
return kbkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PS2Keyboard::Read()
|
||||||
|
{
|
||||||
|
ScopedLock lock(&kblock);
|
||||||
|
return PopKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t PS2Keyboard::GetPending() const
|
||||||
|
{
|
||||||
|
ScopedLock lock(&kblock);
|
||||||
|
return queueused;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PS2Keyboard::HasPending() const
|
||||||
|
{
|
||||||
|
ScopedLock lock(&kblock);
|
||||||
|
return queueused;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Sortix
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
|
||||||
|
|
||||||
This file is part of Sortix.
|
This file is part of Sortix.
|
||||||
|
|
||||||
|
@ -25,47 +25,51 @@
|
||||||
#ifndef SORTIX_KB_PS2_H
|
#ifndef SORTIX_KB_PS2_H
|
||||||
#define SORTIX_KB_PS2_H
|
#define SORTIX_KB_PS2_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
#include <sortix/kernel/keyboard.h>
|
#include <sortix/kernel/keyboard.h>
|
||||||
|
|
||||||
namespace Sortix
|
namespace Sortix {
|
||||||
|
|
||||||
|
class PS2Keyboard : public Keyboard
|
||||||
{
|
{
|
||||||
class PS2Keyboard : public Keyboard
|
public:
|
||||||
{
|
PS2Keyboard(uint16_t iobase, uint8_t interrupt);
|
||||||
public:
|
virtual ~PS2Keyboard();
|
||||||
PS2Keyboard(uint16_t iobase, uint8_t interrupt);
|
virtual int Read();
|
||||||
virtual ~PS2Keyboard();
|
virtual size_t GetPending() const;
|
||||||
virtual int Read();
|
virtual bool HasPending() const;
|
||||||
virtual size_t GetPending() const;
|
virtual void SetOwner(KeyboardOwner* owner, void* user);
|
||||||
virtual bool HasPending() const;
|
|
||||||
virtual void SetOwner(KeyboardOwner* owner, void* user);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void OnInterrupt(CPU::InterruptRegisters* regs);
|
void OnInterrupt(CPU::InterruptRegisters* regs);
|
||||||
void InterruptWork(uint8_t scancode);
|
void InterruptWork(uint8_t scancode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t PopScancode();
|
uint8_t PopScancode();
|
||||||
int DecodeScancode(uint8_t scancode);
|
int DecodeScancode(uint8_t scancode);
|
||||||
void UpdateLEDs(int ledval);
|
void UpdateLEDs(int ledval);
|
||||||
bool PushKey(int key);
|
bool PushKey(int key);
|
||||||
int PopKey();
|
int PopKey();
|
||||||
void NotifyOwner();
|
void NotifyOwner();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int* queue;
|
int* queue;
|
||||||
size_t queuelength;
|
size_t queuelength;
|
||||||
size_t queueoffset;
|
size_t queueoffset;
|
||||||
size_t queueused;
|
size_t queueused;
|
||||||
KeyboardOwner* owner;
|
KeyboardOwner* owner;
|
||||||
void* ownerptr;
|
void* ownerptr;
|
||||||
uint16_t iobase;
|
uint16_t iobase;
|
||||||
uint8_t interrupt;
|
uint8_t interrupt;
|
||||||
bool scancodeescaped;
|
bool scancodeescaped;
|
||||||
uint8_t leds;
|
uint8_t leds;
|
||||||
mutable kthread_mutex_t kblock;
|
mutable kthread_mutex_t kblock;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
} // namespace Sortix
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue