Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3932 → Rev 3934

/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,70 → 83,77
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 = malloc(sizeof(irq_t), FRAME_ATOMIC);
if (!irq) {
free(instance);
return false;
}
 
instance->devno = devno;
instance->ns16550 = dev;
instance->irq = irq;
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_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 ((ns16550_lsr_read(&ns16550) & LSR_DATA_READY))
ns16550_rbr_read(&ns16550);
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();
ns16550_grab();
return true;
}
 
/** Process ns16550 interrupt. */
void ns16550_interrupt(void)
{
ns16550_poll();
}
 
/* Called from getc(). */
void ns16550_resume(chardev_t *d)
{
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);
else
active_read_key_pressed(x);
}
}
return ch;
if (pio_read_8(&dev->lsr) & LSR_DATA_READY)
return IRQ_ACCEPT;
else
return IRQ_DECLINE;
}
 
/** Poll for key press and release events.
*
* This function can be used to implement keyboard polling.
*/
void ns16550_poll(void)
void ns16550_irq_handler(irq_t *irq)
{
while (ns16550_lsr_read(&ns16550) & LSR_DATA_READY) {
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;
}
 
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)
;
}