Reorganized defines in the header.
Deallocate resources correcly in error case. Support for level and edge interrupts. Removed volatile keyword where it's not needed. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42882 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
bcf13367d4
commit
276a254c1c
@ -14,6 +14,7 @@
|
|||||||
#include <ACPI.h>
|
#include <ACPI.h>
|
||||||
#include <PCI.h>
|
#include <PCI.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ struct hpet_timer_cookie {
|
|||||||
int number;
|
int number;
|
||||||
int32 irq;
|
int32 irq;
|
||||||
sem_id sem;
|
sem_id sem;
|
||||||
|
hpet_timer* timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -92,7 +94,7 @@ hpet_convert_timeout(const bigtime_t &relativeTimeout)
|
|||||||
#define MIN_TIMEOUT 1
|
#define MIN_TIMEOUT 1
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
hpet_set_hardware_timer(bigtime_t relativeTimeout, volatile hpet_timer *timer)
|
hpet_set_hardware_timer(bigtime_t relativeTimeout, hpet_timer *timer)
|
||||||
{
|
{
|
||||||
// TODO:
|
// TODO:
|
||||||
if (relativeTimeout < MIN_TIMEOUT)
|
if (relativeTimeout < MIN_TIMEOUT)
|
||||||
@ -116,7 +118,7 @@ hpet_set_hardware_timer(bigtime_t relativeTimeout, volatile hpet_timer *timer)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
hpet_clear_hardware_timer(volatile hpet_timer *timer)
|
hpet_clear_hardware_timer(hpet_timer *timer)
|
||||||
{
|
{
|
||||||
// Disable timer interrupt
|
// Disable timer interrupt
|
||||||
timer->config &= ~HPET_CONF_TIMER_INT_ENABLE;
|
timer->config &= ~HPET_CONF_TIMER_INT_ENABLE;
|
||||||
@ -129,12 +131,14 @@ hpet_timer_interrupt(void *arg)
|
|||||||
{
|
{
|
||||||
//dprintf("HPET timer_interrupt!!!!\n");
|
//dprintf("HPET timer_interrupt!!!!\n");
|
||||||
hpet_timer_cookie* hpetCookie = (hpet_timer_cookie*)arg;
|
hpet_timer_cookie* hpetCookie = (hpet_timer_cookie*)arg;
|
||||||
|
hpet_timer* timer = &sHPETRegs->timer[hpetCookie->number];
|
||||||
|
|
||||||
// clear interrupt status
|
|
||||||
int32 intStatus = 1 << hpetCookie->number;
|
int32 intStatus = 1 << hpetCookie->number;
|
||||||
if (sHPETRegs->interrupt_status & intStatus) {
|
if (!HPET_GET_CONF_TIMER_INT_IS_LEVEL(timer)
|
||||||
|
|| (sHPETRegs->interrupt_status & intStatus)) {
|
||||||
|
// clear interrupt status
|
||||||
sHPETRegs->interrupt_status |= intStatus;
|
sHPETRegs->interrupt_status |= intStatus;
|
||||||
hpet_clear_hardware_timer(&sHPETRegs->timer[hpetCookie->number]);
|
hpet_clear_hardware_timer(timer);
|
||||||
|
|
||||||
release_sem_etc(hpetCookie->sem, 1, B_DO_NOT_RESCHEDULE);
|
release_sem_etc(hpetCookie->sem, 1, B_DO_NOT_RESCHEDULE);
|
||||||
return B_HANDLED_INTERRUPT;
|
return B_HANDLED_INTERRUPT;
|
||||||
@ -159,7 +163,7 @@ static status_t
|
|||||||
hpet_set_legacy(bool enabled)
|
hpet_set_legacy(bool enabled)
|
||||||
{
|
{
|
||||||
if (!HPET_IS_LEGACY_CAPABLE(sHPETRegs)) {
|
if (!HPET_IS_LEGACY_CAPABLE(sHPETRegs)) {
|
||||||
dprintf("hpet_init: HPET doesn't support legacy mode. Skipping.\n");
|
dprintf("hpet_init: HPET doesn't support legacy mode.\n");
|
||||||
return B_NOT_SUPPORTED;
|
return B_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,7 +201,7 @@ hpet_dump_timer(volatile struct hpet_timer *timer)
|
|||||||
dprintf("\tTimer type: %s\n",
|
dprintf("\tTimer type: %s\n",
|
||||||
timer->config & HPET_CONF_TIMER_TYPE ? "Periodic" : "OneShot");
|
timer->config & HPET_CONF_TIMER_TYPE ? "Periodic" : "OneShot");
|
||||||
dprintf("\tInterrupt Type: %s\n",
|
dprintf("\tInterrupt Type: %s\n",
|
||||||
timer->config & HPET_CONF_TIMER_INT_TYPE ? "Level" : "Edge");
|
HPET_GET_CONF_TIMER_INT_IS_LEVEL(timer) ? "Level" : "Edge");
|
||||||
|
|
||||||
dprintf("\tconfigured IRQ: %lld\n",
|
dprintf("\tconfigured IRQ: %lld\n",
|
||||||
HPET_GET_CONF_TIMER_INT_ROUTE(timer));
|
HPET_GET_CONF_TIMER_INT_ROUTE(timer));
|
||||||
@ -213,7 +217,7 @@ hpet_dump_timer(volatile struct hpet_timer *timer)
|
|||||||
static status_t
|
static status_t
|
||||||
hpet_init_timer(hpet_timer_cookie* cookie)
|
hpet_init_timer(hpet_timer_cookie* cookie)
|
||||||
{
|
{
|
||||||
volatile struct hpet_timer *timer = &sHPETRegs->timer[cookie->number];
|
struct hpet_timer *timer = cookie->timer;
|
||||||
|
|
||||||
uint32 interrupts = (uint32)HPET_GET_CAP_TIMER_ROUTE(timer);
|
uint32 interrupts = (uint32)HPET_GET_CAP_TIMER_ROUTE(timer);
|
||||||
|
|
||||||
@ -226,9 +230,10 @@ hpet_init_timer(hpet_timer_cookie* cookie)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interrupt == -1)
|
if (interrupt == -1) {
|
||||||
|
dprintf("hpet_init_timer(): timer can't be routed to any interrupt!")
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
}
|
||||||
// Non-periodic mode
|
// Non-periodic mode
|
||||||
timer->config &= ~HPET_CONF_TIMER_TYPE;
|
timer->config &= ~HPET_CONF_TIMER_TYPE;
|
||||||
|
|
||||||
@ -287,10 +292,9 @@ hpet_init()
|
|||||||
sHPETPeriod = HPET_GET_PERIOD(sHPETRegs);
|
sHPETPeriod = HPET_GET_PERIOD(sHPETRegs);
|
||||||
|
|
||||||
TRACE(("hpet_init: HPET is at %p.\n"
|
TRACE(("hpet_init: HPET is at %p.\n"
|
||||||
"\tVendor ID: %llx, rev: %llx, period: %lld\n"
|
"\tVendor ID: %llx, rev: %llx, period: %lld\n",
|
||||||
"\tin legacy mode: %s\n",
|
|
||||||
sHPETRegs, HPET_GET_VENDOR_ID(sHPETRegs), HPET_GET_REVID(sHPETRegs),
|
sHPETRegs, HPET_GET_VENDOR_ID(sHPETRegs), HPET_GET_REVID(sHPETRegs),
|
||||||
sHPETPeriod, sHPETRegs->config & HPET_CONF_MASK_LEGACY ? "yes" : "no"));
|
sHPETPeriod));
|
||||||
|
|
||||||
status_t status = hpet_set_enabled(false);
|
status_t status = hpet_set_enabled(false);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
@ -302,8 +306,10 @@ hpet_init()
|
|||||||
|
|
||||||
uint32 numTimers = HPET_GET_NUM_TIMERS(sHPETRegs) + 1;
|
uint32 numTimers = HPET_GET_NUM_TIMERS(sHPETRegs) + 1;
|
||||||
|
|
||||||
TRACE(("hpet_init: HPET supports %lu timers, and is %s bits wide.\n",
|
TRACE(("hpet_init: HPET supports %lu timers, is %s bits wide, "
|
||||||
numTimers, HPET_IS_64BIT(sHPETRegs) ? "64" : "32"));
|
"and is %sin legacy mode.\n",
|
||||||
|
numTimers, HPET_IS_64BIT(sHPETRegs) ? "64" : "32",
|
||||||
|
sHPETRegs->config & HPET_CONF_MASK_LEGACY ? "" : "not "));
|
||||||
|
|
||||||
TRACE(("hpet_init: configuration: 0x%llx, timer_interrupts: 0x%llx\n",
|
TRACE(("hpet_init: configuration: 0x%llx, timer_interrupts: 0x%llx\n",
|
||||||
sHPETRegs->config, sHPETRegs->interrupt_status));
|
sHPETRegs->config, sHPETRegs->interrupt_status));
|
||||||
@ -428,27 +434,44 @@ hpet_open(const char* name, uint32 flags, void** cookie)
|
|||||||
return B_BUSY;
|
return B_BUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
hpet_timer_cookie* hpetCookie = (hpet_timer_cookie*)malloc(sizeof(hpet_timer_cookie));
|
|
||||||
int timerNumber = 2;
|
int timerNumber = 2;
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
char semName[B_OS_NAME_LENGTH];
|
||||||
|
snprintf(semName, B_OS_NAME_LENGTH, "hpet_timer %d sem", timerNumber);
|
||||||
|
sem_id sem = create_sem(0, semName);
|
||||||
|
if (sem < 0) {
|
||||||
|
atomic_add(&sOpenCount, -1);
|
||||||
|
return sem;
|
||||||
|
}
|
||||||
|
|
||||||
|
hpet_timer_cookie* hpetCookie = (hpet_timer_cookie*)malloc(sizeof(hpet_timer_cookie));
|
||||||
|
if (hpetCookie == NULL) {
|
||||||
|
delete_sem(sem);
|
||||||
|
atomic_add(&sOpenCount, -1);
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
hpetCookie->number = timerNumber;
|
hpetCookie->number = timerNumber;
|
||||||
hpetCookie->sem = create_sem(0, "hpet_timer 2 sem");
|
hpetCookie->timer = &sHPETRegs->timer[timerNumber];
|
||||||
|
hpetCookie->sem = sem;
|
||||||
set_sem_owner(hpetCookie->sem, B_SYSTEM_TEAM);
|
set_sem_owner(hpetCookie->sem, B_SYSTEM_TEAM);
|
||||||
|
|
||||||
hpet_set_enabled(false);
|
hpet_set_enabled(false);
|
||||||
|
|
||||||
status_t status = hpet_init_timer(hpetCookie);
|
status_t status = hpet_init_timer(hpetCookie);
|
||||||
if (status != B_OK) {
|
if (status != B_OK)
|
||||||
dprintf("hpet_open: initializing timer failed: %s\n", strerror(status));
|
dprintf("hpet_open: initializing timer failed: %s\n", strerror(status));
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
hpet_set_enabled(true);
|
hpet_set_enabled(true);
|
||||||
|
|
||||||
*cookie = hpetCookie;
|
*cookie = hpetCookie;
|
||||||
|
|
||||||
if (status != B_OK)
|
if (status != B_OK) {
|
||||||
|
delete_sem(sem);
|
||||||
|
free(hpetCookie);
|
||||||
atomic_add(&sOpenCount, -1);
|
atomic_add(&sOpenCount, -1);
|
||||||
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,20 +12,20 @@
|
|||||||
/* Doing it this way is Required since the HPET only supports 32/64-bit aligned reads. */
|
/* Doing it this way is Required since the HPET only supports 32/64-bit aligned reads. */
|
||||||
|
|
||||||
/* Global Capability Register Masks */
|
/* Global Capability Register Masks */
|
||||||
#define HPET_CAP_MASK_REVID 0x00000000000000FFULL
|
#define HPET_CAP_MASK_REVID 0x00000000000000FFULL
|
||||||
#define HPET_CAP_MASK_NUMTIMERS 0x0000000000001F00ULL
|
#define HPET_CAP_MASK_NUMTIMERS 0x0000000000001F00ULL
|
||||||
#define HPET_CAP_MASK_WIDTH 0x0000000000002000ULL
|
#define HPET_CAP_MASK_WIDTH 0x0000000000002000ULL
|
||||||
#define HPET_CAP_MASK_LEGACY 0x0000000000008000ULL
|
#define HPET_CAP_MASK_LEGACY 0x0000000000008000ULL
|
||||||
#define HPET_CAP_MASK_VENDOR_ID 0x00000000FFFF0000ULL
|
#define HPET_CAP_MASK_VENDOR_ID 0x00000000FFFF0000ULL
|
||||||
#define HPET_CAP_MASK_PERIOD 0xFFFFFFFF00000000ULL
|
#define HPET_CAP_MASK_PERIOD 0xFFFFFFFF00000000ULL
|
||||||
|
|
||||||
/* Retrieve Global Capabilities */
|
/* Retrieve Global Capabilities */
|
||||||
#define HPET_GET_REVID(regs) ((regs)->capabilities & HPET_CAP_MASK_REVID)
|
#define HPET_GET_REVID(regs) ((regs)->capabilities & HPET_CAP_MASK_REVID)
|
||||||
#define HPET_GET_NUM_TIMERS(regs) (((regs)->capabilities & HPET_CAP_MASK_NUMTIMERS) >> 8)
|
#define HPET_GET_NUM_TIMERS(regs) (((regs)->capabilities & HPET_CAP_MASK_NUMTIMERS) >> 8)
|
||||||
#define HPET_IS_64BIT(regs) (((regs)->capabilities & HPET_CAP_MASK_WIDTH) >> 13)
|
#define HPET_IS_64BIT(regs) (((regs)->capabilities & HPET_CAP_MASK_WIDTH) >> 13)
|
||||||
#define HPET_IS_LEGACY_CAPABLE(regs) (((regs)->capabilities & HPET_CAP_MASK_LEGACY) >> 15)
|
#define HPET_IS_LEGACY_CAPABLE(regs) (((regs)->capabilities & HPET_CAP_MASK_LEGACY) >> 15)
|
||||||
#define HPET_GET_VENDOR_ID(regs) (((regs)->capabilities & HPET_CAP_MASK_VENDOR_ID) >> 16)
|
#define HPET_GET_VENDOR_ID(regs) (((regs)->capabilities & HPET_CAP_MASK_VENDOR_ID) >> 16)
|
||||||
#define HPET_GET_PERIOD(regs) (((regs)->capabilities & HPET_CAP_MASK_PERIOD) >> 32)
|
#define HPET_GET_PERIOD(regs) (((regs)->capabilities & HPET_CAP_MASK_PERIOD) >> 32)
|
||||||
|
|
||||||
/* Global Config Register Masks */
|
/* Global Config Register Masks */
|
||||||
#define HPET_CONF_MASK_ENABLED 0x00000001
|
#define HPET_CONF_MASK_ENABLED 0x00000001
|
||||||
@ -37,20 +37,21 @@
|
|||||||
|
|
||||||
/* Timer Configuration and Capabilities*/
|
/* Timer Configuration and Capabilities*/
|
||||||
#define HPET_CAP_TIMER_MASK 0xFFFFFFFF00000000ULL
|
#define HPET_CAP_TIMER_MASK 0xFFFFFFFF00000000ULL
|
||||||
|
#define HPET_CAP_TIMER_PER_INT 0x00000010UL
|
||||||
|
#define HPET_CAP_TIMER_SIZE 0x00000020UL
|
||||||
|
#define HPET_CAP_TIMER_FSB_INT_DEL 0x00008000UL
|
||||||
|
#define HPET_GET_CAP_TIMER_ROUTE(timer) (((timer)->config & HPET_CAP_TIMER_MASK) >> 32)
|
||||||
|
|
||||||
#define HPET_CONF_TIMER_INT_ROUTE_MASK 0x3e00UL
|
#define HPET_CONF_TIMER_INT_ROUTE_MASK 0x3e00UL
|
||||||
#define HPET_CONF_TIMER_INT_ROUTE_SHIFT 9
|
#define HPET_CONF_TIMER_INT_ROUTE_SHIFT 9
|
||||||
#define HPET_CONF_TIMER_INT_TYPE 0x00000002UL
|
#define HPET_CONF_TIMER_INT_TYPE 0x00000002UL
|
||||||
#define HPET_CONF_TIMER_INT_ENABLE 0x00000004UL
|
#define HPET_CONF_TIMER_INT_ENABLE 0x00000004UL
|
||||||
#define HPET_CONF_TIMER_TYPE 0x00000008UL
|
#define HPET_CONF_TIMER_TYPE 0x00000008UL
|
||||||
#define HPET_CONF_TIMER_VAL_SET 0x00000040UL
|
#define HPET_CONF_TIMER_VAL_SET 0x00000040UL
|
||||||
#define HPET_CONF_TIMER_32MODE 0x00000100UL
|
#define HPET_CONF_TIMER_32MODE 0x00000100UL
|
||||||
#define HPET_CONF_TIMER_FSB_ENABLE 0x00004000UL
|
#define HPET_CONF_TIMER_FSB_ENABLE 0x00004000UL
|
||||||
#define HPET_CAP_TIMER_PER_INT 0x00000010UL
|
|
||||||
#define HPET_CAP_TIMER_SIZE 0x00000020UL
|
|
||||||
#define HPET_CAP_TIMER_FSB_INT_DEL 0x00008000UL
|
|
||||||
|
|
||||||
#define HPET_GET_CAP_TIMER_ROUTE(timer) (((timer)->config & HPET_CAP_TIMER_MASK) >> 32)
|
|
||||||
#define HPET_GET_CONF_TIMER_INT_ROUTE(timer) (((timer)->config & HPET_CONF_TIMER_INT_ROUTE_MASK) >> HPET_CONF_TIMER_INT_ROUTE_SHIFT)
|
#define HPET_GET_CONF_TIMER_INT_ROUTE(timer) (((timer)->config & HPET_CONF_TIMER_INT_ROUTE_MASK) >> HPET_CONF_TIMER_INT_ROUTE_SHIFT)
|
||||||
|
#define HPET_GET_CONF_TIMER_INT_IS_LEVEL(timer) (((timer)->config & HPET_CONF_TIMER_INT_TYPE))
|
||||||
|
|
||||||
#define ACPI_HPET_SIGNATURE "HPET"
|
#define ACPI_HPET_SIGNATURE "HPET"
|
||||||
|
|
||||||
@ -83,16 +84,16 @@ struct hpet_regs {
|
|||||||
/* Level Tigger: 0 = off, 1 = set by hardware, timer is active */
|
/* Level Tigger: 0 = off, 1 = set by hardware, timer is active */
|
||||||
/* Edge Trigger: ignored */
|
/* Edge Trigger: ignored */
|
||||||
/* Writing 0 will not clear these. Must write 1 again. */
|
/* Writing 0 will not clear these. Must write 1 again. */
|
||||||
volatile uint64 reserved3[25];
|
uint64 reserved3[25];
|
||||||
|
|
||||||
union {
|
union {
|
||||||
volatile uint64 counter64; /* R/W */
|
volatile uint64 counter64; /* R/W */
|
||||||
volatile uint32 counter32;
|
volatile uint32 counter32;
|
||||||
} u0;
|
} u0;
|
||||||
|
|
||||||
volatile uint64 reserved4;
|
uint64 reserved4;
|
||||||
|
|
||||||
volatile struct hpet_timer timer[1];
|
struct hpet_timer timer[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user