/trunk/kernel/genarch/include/kbd/ns16550.h |
---|
37,30 → 37,10 |
#ifndef KERN_NS16550_H_ |
#define KERN_NS16550_H_ |
#include <console/chardev.h> |
#include <ddi/irq.h> |
#include <ipc/irq.h> |
extern void ns16550_init(devno_t, uintptr_t, inr_t, cir_t, void *); |
extern void ns16550_poll(void); |
extern void ns16550_grab(void); |
extern void ns16550_release(void); |
extern char ns16550_key_read(chardev_t *); |
extern irq_ownership_t ns16550_claim(void *); |
extern void ns16550_irq_handler(irq_t *); |
#include <arch/types.h> |
#include <arch/drivers/kbd.h> |
/* NS16550 registers */ |
#define RBR_REG 0 /** Receiver Buffer Register. */ |
#define IER_REG 1 /** Interrupt Enable Register. */ |
#define IIR_REG 2 /** Interrupt Ident Register (read). */ |
#define FCR_REG 2 /** FIFO control register (write). */ |
#define LCR_REG 3 /** Line Control register. */ |
#define MCR_REG 4 /** Modem Control Register. */ |
#define LSR_REG 5 /** Line Status Register. */ |
#define IER_ERBFI 0x01 /** Enable Receive Buffer Full Interrupt. */ |
#define LCR_DLAB 0x80 /** Divisor Latch Access bit. */ |
67,67 → 47,33 |
#define MCR_OUT2 0x08 /** OUT2. */ |
/** NS16550 registers. */ |
struct ns16550 { |
ioport8_t rbr; /**< Receiver Buffer Register. */ |
ioport8_t ier; /**< Interrupt Enable Register. */ |
union { |
ioport8_t iir; /**< Interrupt Ident Register (read). */ |
ioport8_t fcr; /**< FIFO control register (write). */ |
} __attribute__ ((packed)); |
ioport8_t lcr; /**< Line Control register. */ |
ioport8_t mcr; /**< Modem Control Register. */ |
ioport8_t lsr; /**< Line Status Register. */ |
} __attribute__ ((packed)); |
typedef struct ns16550 ns16550_t; |
/** Structure representing the ns16550 device. */ |
typedef struct { |
typedef struct ns16550_instance { |
devno_t devno; |
/** Memory mapped registers of the ns16550. */ |
volatile ioport_t io_port; |
} ns16550_t; |
ns16550_t *ns16550; |
irq_t *irq; |
} ns16550_instance_t; |
static inline uint8_t ns16550_rbr_read(ns16550_t *dev) |
{ |
return pio_read_8(dev->io_port + RBR_REG); |
} |
static inline void ns16550_rbr_write(ns16550_t *dev, uint8_t v) |
{ |
pio_write_8(dev->io_port + RBR_REG, v); |
} |
extern bool ns16550_init(ns16550_t *, devno_t, inr_t, cir_t, void *); |
extern void ns16550_grab(void); |
extern void ns16550_release(void); |
extern irq_ownership_t ns16550_claim(void *); |
extern void ns16550_irq_handler(irq_t *); |
static inline uint8_t ns16550_ier_read(ns16550_t *dev) |
{ |
return pio_read_8(dev->io_port + IER_REG); |
} |
static inline void ns16550_ier_write(ns16550_t *dev, uint8_t v) |
{ |
pio_write_8(dev->io_port + IER_REG, v); |
} |
static inline uint8_t ns16550_iir_read(ns16550_t *dev) |
{ |
return pio_read_8(dev->io_port + IIR_REG); |
} |
static inline void ns16550_fcr_write(ns16550_t *dev, uint8_t v) |
{ |
pio_write_8(dev->io_port + FCR_REG, v); |
} |
static inline uint8_t ns16550_lcr_read(ns16550_t *dev) |
{ |
return pio_read_8(dev->io_port + LCR_REG); |
} |
static inline void ns16550_lcr_write(ns16550_t *dev, uint8_t v) |
{ |
pio_write_8(dev->io_port + LCR_REG, v); |
} |
static inline uint8_t ns16550_lsr_read(ns16550_t *dev) |
{ |
return pio_read_8(dev->io_port + LSR_REG); |
} |
static inline uint8_t ns16550_mcr_read(ns16550_t *dev) |
{ |
return pio_read_8(dev->io_port + MCR_REG); |
} |
static inline void ns16550_mcr_write(ns16550_t *dev, uint8_t v) |
{ |
pio_write_8(dev->io_port + MCR_REG, v); |
} |
#endif |
/** @} |
/trunk/kernel/genarch/include/kbd/i8042.h |
---|
36,7 → 36,7 |
#define KERN_I8042_H_ |
#include <arch/types.h> |
#include <console/chardev.h> |
#include <typedefs.h> |
struct i8042 { |
ioport8_t data; |
52,7 → 52,6 |
extern void i8042_init(devno_t kbd_devno, inr_t kbd_inr, devno_t mouse_devno, inr_t mouse_inr); |
extern void i8042_grab(void); |
extern void i8042_release(void); |
extern char i8042_key_read(chardev_t *d); |
#endif |
/trunk/kernel/genarch/include/drivers/legacy/ia32/io.h |
---|
39,11 → 39,13 |
#include <arch/types.h> |
#define i8042_BASE ((ioport8_t *)0x60) |
#define I8042_BASE ((ioport8_t *)0x60) |
#define EGA_VIDEORAM 0xb8000 |
#define EGA_BASE ((ioport8_t *)0x3d4) |
#define NS16550_BASE ((ioport8_t *)0x3f8) |
#endif |
/** @} |
/trunk/kernel/genarch/src/kbd/ns16550.c |
---|
50,15 → 50,12 |
#include <arch/interrupt.h> |
#include <sysinfo/sysinfo.h> |
#include <synch/spinlock.h> |
#include <mm/slab.h> |
#define LSR_DATA_READY 0x01 |
/** Structure representing the ns16550. */ |
static ns16550_t ns16550; |
static irq_t *ns16550_irq; |
/** Structure for ns16550's IRQ. */ |
static irq_t ns16550_irq; |
/* |
* These codes read from ns16550 data register are silently ignored. |
*/ |
70,24 → 67,15 |
static chardev_operations_t ops = { |
.suspend = ns16550_suspend, |
.resume = ns16550_resume, |
.read = ns16550_key_read |
}; |
void ns16550_interrupt(void); |
/** Initialize keyboard and service interrupts using kernel routine */ |
void ns16550_grab(void) |
{ |
ipl_t ipl = interrupts_disable(); |
ns16550_ier_write(&ns16550, IER_ERBFI); /* enable receiver interrupt */ |
while (ns16550_lsr_read(&ns16550) & LSR_DATA_READY) |
(void) ns16550_rbr_read(&ns16550); |
spinlock_lock(&ns16550_irq.lock); |
ns16550_irq.notif_cfg.notify = false; |
spinlock_unlock(&ns16550_irq.lock); |
spinlock_lock(&ns16550_irq->lock); |
ns16550_irq->notif_cfg.notify = false; |
spinlock_unlock(&ns16550_irq->lock); |
interrupts_restore(ipl); |
} |
95,68 → 83,75 |
void ns16550_release(void) |
{ |
ipl_t ipl = interrupts_disable(); |
spinlock_lock(&ns16550_irq.lock); |
if (ns16550_irq.notif_cfg.answerbox) |
ns16550_irq.notif_cfg.notify = true; |
spinlock_unlock(&ns16550_irq.lock); |
spinlock_lock(&ns16550_irq->lock); |
if (ns16550_irq->notif_cfg.answerbox) |
ns16550_irq->notif_cfg.notify = true; |
spinlock_unlock(&ns16550_irq->lock); |
interrupts_restore(ipl); |
} |
/** Initialize ns16550. |
* |
* @param dev Addrress of the beginning of the device in I/O space. |
* @param devno Device number. |
* @param port Virtual/IO address of device's registers. |
* @param inr Interrupt number. |
* @param cir Clear interrupt function. |
* @param cir_arg First argument to cir. |
* |
* @return True on success, false on failure. |
*/ |
void |
ns16550_init(devno_t devno, ioport_t port, inr_t inr, cir_t cir, void *cir_arg) |
bool |
ns16550_init(ns16550_t *dev, devno_t devno, inr_t inr, cir_t cir, void *cir_arg) |
{ |
ns16550_instance_t *instance; |
irq_t *irq; |
chardev_initialize("ns16550_kbd", &kbrd, &ops); |
stdin = &kbrd; |
ns16550.devno = devno; |
ns16550.io_port = port; |
instance = malloc(sizeof(ns16550_instance_t), FRAME_ATOMIC); |
if (!instance) |
return false; |
irq_initialize(&ns16550_irq); |
ns16550_irq.devno = devno; |
ns16550_irq.inr = inr; |
ns16550_irq.claim = ns16550_claim; |
ns16550_irq.handler = ns16550_irq_handler; |
ns16550_irq.cir = cir; |
ns16550_irq.cir_arg = cir_arg; |
irq_register(&ns16550_irq); |
irq = malloc(sizeof(irq_t), FRAME_ATOMIC); |
if (!irq) { |
free(instance); |
return false; |
} |
while ((ns16550_lsr_read(&ns16550) & LSR_DATA_READY)) |
ns16550_rbr_read(&ns16550); |
instance->devno = devno; |
instance->ns16550 = dev; |
instance->irq = irq; |
irq_initialize(irq); |
irq->devno = devno; |
irq->inr = inr; |
irq->claim = ns16550_claim; |
irq->handler = ns16550_irq_handler; |
irq->instance = instance; |
irq->cir = cir; |
irq->cir_arg = cir_arg; |
irq_register(irq); |
ns16550_irq = irq; /* TODO: remove me soon */ |
while ((pio_read_8(&dev->lsr) & LSR_DATA_READY)) |
(void) pio_read_8(&dev->rbr); |
sysinfo_set_item_val("kbd", NULL, true); |
sysinfo_set_item_val("kbd.type", NULL, KBD_NS16550); |
sysinfo_set_item_val("kbd.devno", NULL, devno); |
sysinfo_set_item_val("kbd.inr", NULL, inr); |
sysinfo_set_item_val("kbd.address.virtual", NULL, port); |
sysinfo_set_item_val("kbd.port", NULL, port); |
sysinfo_set_item_val("kbd.address.virtual", NULL, (uintptr_t) dev); |
sysinfo_set_item_val("kbd.port", NULL, (uintptr_t) dev); |
/* Enable interrupts */ |
ns16550_ier_write(&ns16550, IER_ERBFI); |
ns16550_mcr_write(&ns16550, MCR_OUT2); |
pio_write_8(&dev->ier, IER_ERBFI); |
pio_write_8(&dev->mcr, MCR_OUT2); |
uint8_t c; |
// This switches rbr & ier to mode when accept baudrate constant |
c = ns16550_lcr_read(&ns16550); |
ns16550_lcr_write(&ns16550, 0x80 | c); |
ns16550_rbr_write(&ns16550, 0x0c); |
ns16550_ier_write(&ns16550, 0x00); |
ns16550_lcr_write(&ns16550, c); |
ns16550_grab(); |
} |
/** Process ns16550 interrupt. */ |
void ns16550_interrupt(void) |
{ |
ns16550_poll(); |
return true; |
} |
/* Called from getc(). */ |
169,37 → 164,34 |
{ |
} |
char ns16550_key_read(chardev_t *d) |
irq_ownership_t ns16550_claim(void *instance) |
{ |
char ch; |
ns16550_instance_t *ns16550_instance = instance; |
ns16550_t *dev = ns16550_instance->ns16550; |
while(!(ch = active_read_buff_read())) { |
uint8_t x; |
while (!(ns16550_lsr_read(&ns16550) & LSR_DATA_READY)); |
x = ns16550_rbr_read(&ns16550); |
if (x != IGNORE_CODE) { |
if (x & KEY_RELEASE) |
key_released(x ^ KEY_RELEASE); |
if (pio_read_8(&dev->lsr) & LSR_DATA_READY) |
return IRQ_ACCEPT; |
else |
active_read_key_pressed(x); |
return IRQ_DECLINE; |
} |
void ns16550_irq_handler(irq_t *irq) |
{ |
if (irq->notif_cfg.notify && irq->notif_cfg.answerbox) { |
/* |
* This will hopefully go to the IRQ dispatch code soon. |
*/ |
ipc_irq_send_notif(irq); |
return; |
} |
return ch; |
} |
/** Poll for key press and release events. |
* |
* This function can be used to implement keyboard polling. |
*/ |
void ns16550_poll(void) |
{ |
while (ns16550_lsr_read(&ns16550) & LSR_DATA_READY) { |
ns16550_instance_t *ns16550_instance = irq->instance; |
ns16550_t *dev = ns16550_instance->ns16550; |
if (pio_read_8(&dev->lsr) & LSR_DATA_READY) { |
uint8_t x; |
x = ns16550_rbr_read(&ns16550); |
x = pio_read_8(&dev->rbr); |
if (x != IGNORE_CODE) { |
if (x & KEY_RELEASE) |
208,20 → 200,8 |
key_pressed(x); |
} |
} |
} |
irq_ownership_t ns16550_claim(void *instance) |
{ |
return (ns16550_lsr_read(&ns16550) & LSR_DATA_READY); |
} |
void ns16550_irq_handler(irq_t *irq) |
{ |
if (irq->notif_cfg.notify && irq->notif_cfg.answerbox) |
ipc_irq_send_notif(irq); |
else |
ns16550_interrupt(); |
} |
/** @} |
*/ |
/trunk/kernel/genarch/src/kbd/i8042.c |
---|
52,7 → 52,7 |
#include <ipc/irq.h> |
i8042_instance_t lgcy_i8042_instance = { |
.i8042 = (i8042_t *) i8042_BASE, |
.i8042 = (i8042_t *) I8042_BASE, |
}; |
/* Keyboard commands. */ |
88,7 → 88,6 |
static chardev_operations_t ops = { |
.suspend = i8042_suspend, |
.resume = i8042_resume, |
.read = i8042_key_read |
}; |
/** Structure for i8042's IRQ. */ |
228,25 → 227,5 |
{ |
} |
char i8042_key_read(chardev_t *d) |
{ |
i8042_t *dev = lgcy_i8042_instance.i8042; |
char ch; |
while (!(ch = active_read_buff_read())) { |
uint8_t x; |
while (!(pio_read_8(&dev->status) & i8042_BUFFER_FULL_MASK)) |
; |
x = pio_read_8(&dev->data); |
if (x & KEY_RELEASE) |
key_released(x ^ KEY_RELEASE); |
else |
active_read_key_pressed(x); |
} |
return ch; |
} |
/** @} |
*/ |
/trunk/kernel/arch/ia64/src/smp/smp.c |
---|
51,7 → 51,6 |
#include <syscall/syscall.h> |
#include <ddi/irq.h> |
#include <ddi/device.h> |
#include <arch/drivers/ega.h> |
#include <arch/bootinfo.h> |
#include <genarch/kbd/i8042.h> |
#include <genarch/kbd/ns16550.h> |
/trunk/kernel/arch/ia64/src/ia64.c |
---|
65,7 → 65,6 |
/* NS16550 as a COM 1 */ |
#define NS16550_IRQ (4 + LEGACY_INTERRUPT_BASE) |
#define NS16550_PORT 0x3f8 |
bootinfo_t *bootinfo; |
164,7 → 163,8 |
devno_t kbd = device_assign_devno(); |
#ifdef CONFIG_NS16550 |
ns16550_init(kbd, NS16550_PORT, NS16550_IRQ, NULL, NULL); |
(void) ns16550_init((ns16550_t *)NS16550_BASE, kbd, NS16550_IRQ, NULL, |
NULL); |
#else |
devno_t mouse = device_assign_devno(); |
i8042_init(kbd, IRQ_KBD, mouse, IRQ_MOUSE); |
249,7 → 249,7 |
void arch_reboot(void) |
{ |
pio_write_8(0x64, 0xfe); |
pio_write_8((ioport8_t *)0x64, 0xfe); |
while (1) |
; |
} |