/trunk/kernel/genarch/src/kbd/ns16550.c |
---|
90,6 → 90,11 |
sysinfo_set_item_val("kbd", NULL, true); |
sysinfo_set_item_val("kbd.irq", NULL, 0); |
sysinfo_set_item_val("kbd.address.virtual", NULL, (uintptr_t) kbd_virt_address); |
ns16550_ier_write(IER_ERBFI); /* enable receiver interrupt */ |
while (ns16550_lsr_read() & LSR_DATA_READY) |
(void) ns16550_rbr_read(); |
} |
/** Process ns16550 interrupt. |
144,7 → 149,7 |
{ |
uint8_t x; |
while (((x = ns16550_lsr_read() & LSR_DATA_READY))) { |
while (ns16550_lsr_read() & LSR_DATA_READY) { |
x = ns16550_rbr_read(); |
if (x != IGNORE_CODE) { |
if (x & KEY_RELEASE) |
/trunk/kernel/genarch/src/ofw/ebus.c |
---|
36,12 → 36,15 |
*/ |
#include <genarch/ofw/ofw_tree.h> |
#include <arch/drivers/pci.h> |
#include <arch/memstr.h> |
#include <arch/trap/interrupt.h> |
#include <func.h> |
#include <panic.h> |
#include <debug.h> |
#include <macros.h> |
/** Apply EBUS ranges to EBUS register. */ |
bool ofw_ebus_apply_ranges(ofw_tree_node_t *node, ofw_ebus_reg_t *reg, uintptr_t *pa) |
{ |
ofw_tree_property_t *prop; |
112,11 → 115,34 |
/* |
* We found the device that functions as an interrupt controller |
* for the interrupt. We also found mapping from interrupt to INR. |
* What needs to be done now is to verify that this indeed is a PCI |
* node. |
*/ |
controller = ofw_tree_find_node_by_handle(ofw_tree_lookup("/"), intr_map[i].controller_handle); |
if (!controller) |
return false; |
if (strcmp(ofw_tree_node_name(controller), "pci") != 0) { |
/* |
* This is not a PCI node. |
*/ |
return false; |
} |
pci_t *pci = controller->device; |
if (!pci) { |
pci = pci_init(controller); |
if (!pci) |
return false; |
controller->device = pci; |
} |
pci_enable_interrupt(pci, intr_map[i].controller_inr); |
*inr = intr_map[i].controller_inr; |
*inr |= 0x1f << IGN_SHIFT; /* 0x1f is hardwired IGN */ |
*inr = intr_map[i].controller_inr; |
return true; |
} |
/trunk/kernel/genarch/src/ofw/upa.c |
---|
45,7 → 45,7 |
bool ofw_upa_apply_ranges(ofw_tree_node_t *node, ofw_upa_reg_t *reg, uintptr_t *pa) |
{ |
*pa = reg->addr; |
return false; |
return true; |
} |
/** @} |
/trunk/kernel/arch/sparc64/include/asm.h |
---|
324,7 → 324,7 |
{ |
uint64_t v; |
__asm__ volatile ("ldxa [%1] %2, %0\n" : "=r" (v) : "r" (va), "i" (asi)); |
__asm__ volatile ("ldxa [%1] %2, %0\n" : "=r" (v) : "r" (va), "i" ((unsigned) asi)); |
return v; |
} |
337,7 → 337,7 |
*/ |
static inline void asi_u64_write(asi_t asi, uintptr_t va, uint64_t v) |
{ |
__asm__ volatile ("stxa %0, [%1] %2\n" : : "r" (v), "r" (va), "i" (asi) : "memory"); |
__asm__ volatile ("stxa %0, [%1] %2\n" : : "r" (v), "r" (va), "i" ((unsigned) asi) : "memory"); |
} |
/** Flush all valid register windows to memory. */ |
/trunk/kernel/arch/sparc64/include/trap/interrupt.h |
---|
40,6 → 40,14 |
#include <arch/trap/trap_table.h> |
#include <arch/stack.h> |
/* IMAP register bits */ |
#define IGN_MASK 0x7c0 |
#define INO_MASK 0x1f |
#define IMAP_V_MASK (1ULL<<31) |
#define IGN_SHIFT 6 |
/* Interrupt ASI registers. */ |
#define ASI_UDB_INTR_W 0x77 |
#define ASI_INTR_DISPATCH_STATUS 0x48 |
/trunk/kernel/arch/sparc64/include/drivers/pci.h |
---|
0,0 → 1,70 |
/* |
* Copyright (C) 2006 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_sparc64_PCI_H_ |
#define KERN_sparc64_PCI_H_ |
#include <arch/types.h> |
#include <genarch/ofw/ofw_tree.h> |
#include <arch/arch.h> |
#include <arch/asm.h> |
typedef enum pci_model pci_model_t; |
typedef struct pci pci_t; |
typedef struct pci_operations pci_operations_t; |
enum pci_model { |
PCI_UNKNOWN, |
PCI_SABRE |
}; |
struct pci_operations { |
void (* enable_interrupt)(pci_t *pci, int inr); |
void (* clear_interrupt)(pci_t *pci, int inr); |
}; |
struct pci { |
pci_model_t model; |
pci_operations_t *op; |
volatile uint64_t *reg; /**< Registers including interrupt registers. */ |
}; |
extern pci_t *pci_init(ofw_tree_node_t *node); |
extern void pci_enable_interrupt(pci_t *pci, int inr); |
extern void pci_clear_interrupt(pci_t *pci, int inr); |
#endif |
/** @} |
*/ |
/trunk/kernel/arch/sparc64/include/drivers/ns16550.h |
---|
38,10 → 38,18 |
#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 LSR_REG 5 /** Line Status Register. */ |
#define IER_ERBFI 0x01 /** Enable Receive Buffer Full Interrupt. */ |
#define LCR_DLAB 0x80 /** Divisor Latch Access bit. */ |
static inline uint8_t ns16550_rbr_read(void) |
{ |
return kbd_virt_address[RBR_REG]; |
57,6 → 65,26 |
kbd_virt_address[IER_REG] = v; |
} |
static inline uint8_t ns16550_iir_read(void) |
{ |
return kbd_virt_address[IIR_REG]; |
} |
static inline void ns16550_fcr_write(uint8_t v) |
{ |
kbd_virt_address[FCR_REG] = v; |
} |
static inline uint8_t ns16550_lcr_read(void) |
{ |
return kbd_virt_address[LCR_REG]; |
} |
static inline void ns16550_lcr_write(uint8_t v) |
{ |
kbd_virt_address[LCR_REG] = v; |
} |
static inline uint8_t ns16550_lsr_read(void) |
{ |
return kbd_virt_address[LSR_REG]; |
/trunk/kernel/arch/sparc64/Makefile.inc |
---|
100,7 → 100,8 |
arch/$(ARCH)/src/ddi/ddi.c \ |
arch/$(ARCH)/src/drivers/tick.c \ |
arch/$(ARCH)/src/drivers/kbd.c \ |
arch/$(ARCH)/src/drivers/scr.c |
arch/$(ARCH)/src/drivers/scr.c \ |
arch/$(ARCH)/src/drivers/pci.c |
ifeq ($(CONFIG_SMP),y) |
ARCH_SOURCES += \ |
/trunk/kernel/arch/sparc64/src/drivers/kbd.c |
---|
99,7 → 99,7 |
uintptr_t pa; |
size_t size; |
int ino; |
int inr; |
switch (kbd_type) { |
case KBD_Z8530: |
108,7 → 108,7 |
printf("Failed to determine keyboard address.\n"); |
return; |
} |
if (!ofw_fhc_map_interrupts(node->parent, ((ofw_fhc_reg_t *) prop->value), interrupts, &ino)) { |
if (!ofw_fhc_map_interrupts(node->parent, ((ofw_fhc_reg_t *) prop->value), interrupts, &inr)) { |
printf("Failed to determine keyboard interrupts.\n"); |
return; |
} |
119,7 → 119,7 |
printf("Failed to determine keyboard address.\n"); |
return; |
} |
if (!ofw_ebus_map_interrupts(node->parent, ((ofw_ebus_reg_t *) prop->value), interrupts, &ino)) { |
if (!ofw_ebus_map_interrupts(node->parent, ((ofw_ebus_reg_t *) prop->value), interrupts, &inr)) { |
printf("Failed to determine keyboard interrupts.\n"); |
return; |
} |
/trunk/kernel/arch/sparc64/src/drivers/pci.c |
---|
0,0 → 1,157 |
/* |
* Copyright (C) 2006 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup sparc64 |
* @{ |
*/ |
/** |
* @file |
* @brief PCI driver. |
*/ |
#include <arch/drivers/pci.h> |
#include <genarch/ofw/ofw_tree.h> |
#include <arch/trap/interrupt.h> |
#include <arch/mm/page.h> |
#include <mm/slab.h> |
#include <arch/types.h> |
#include <typedefs.h> |
#include <debug.h> |
#include <print.h> |
#include <func.h> |
#include <arch/asm.h> |
#define PCI_SABRE_REGS_REG 0 |
#define PCI_SABRE_IMAP_BASE 0x200 |
#define PCI_SABRE_ICLR_BASE 0x300 |
static pci_t *pci_sabre_init(ofw_tree_node_t *node); |
static void pci_sabre_enable_interrupt(pci_t *pci, int inr); |
static void pci_sabre_clear_interrupt(pci_t *pci, int inr); |
/** PCI operations for Sabre model. */ |
static pci_operations_t pci_sabre_ops = { |
.enable_interrupt = pci_sabre_enable_interrupt, |
.clear_interrupt = pci_sabre_clear_interrupt |
}; |
/** Initialize PCI controller (model Sabre). */ |
pci_t *pci_sabre_init(ofw_tree_node_t *node) |
{ |
pci_t *pci; |
ofw_tree_property_t *prop; |
/* |
* Get registers. |
*/ |
prop = ofw_tree_getprop(node, "reg"); |
if (!prop || !prop->value) |
return NULL; |
ofw_upa_reg_t *reg = prop->value; |
count_t regs = prop->size / sizeof(ofw_upa_reg_t); |
if (regs < PCI_SABRE_REGS_REG + 1) |
return NULL; |
uintptr_t paddr; |
if (!ofw_upa_apply_ranges(node->parent, ®[PCI_SABRE_REGS_REG], &paddr)) |
return NULL; |
pci = (pci_t *) malloc(sizeof(pci_t), FRAME_ATOMIC); |
if (!pci) |
return NULL; |
pci->model = PCI_SABRE; |
pci->op = &pci_sabre_ops; |
pci->reg = (uint64_t *) hw_map(paddr, reg[PCI_SABRE_REGS_REG].size); |
return pci; |
} |
void pci_sabre_enable_interrupt(pci_t *pci, int inr) |
{ |
pci->reg[PCI_SABRE_ICLR_BASE + (inr & INO_MASK)] = 0; |
pci->reg[PCI_SABRE_IMAP_BASE + (inr & INO_MASK)] |= IMAP_V_MASK; |
} |
void pci_sabre_clear_interrupt(pci_t *pci, int inr) |
{ |
pci->reg[PCI_SABRE_ICLR_BASE + (inr & INO_MASK)] = 0; |
} |
/** Initialize PCI controller. */ |
pci_t *pci_init(ofw_tree_node_t *node) |
{ |
ofw_tree_property_t *prop; |
/* |
* First, verify this is a PCI node. |
*/ |
ASSERT(strcmp(ofw_tree_node_name(node), "pci") == 0); |
/* |
* Determine PCI controller model. |
*/ |
prop = ofw_tree_getprop(node, "model"); |
if (!prop || !prop->value) |
return NULL; |
if (strcmp(prop->value, "SUNW,sabre") == 0) { |
/* |
* PCI controller Sabre. |
* This model is found on UltraSPARC IIi based machines. |
*/ |
return pci_sabre_init(node); |
} else { |
/* |
* Unsupported model. |
*/ |
printf("Unsupported PCI controller model (%s).\n", prop->value); |
} |
return NULL; |
} |
void pci_enable_interrupt(pci_t *pci, int inr) |
{ |
ASSERT(pci->model); |
ASSERT(pci->op && pci->op->enable_interrupt); |
pci->op->enable_interrupt(pci, inr); |
} |
void pci_clear_interrupt(pci_t *pci, int inr) |
{ |
ASSERT(pci->model); |
ASSERT(pci->op && pci->op->clear_interrupt); |
pci->op->clear_interrupt(pci, inr); |
} |
/** @} |
*/ |