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:
Stefano Ceccherini 2011-10-19 12:40:12 +00:00
parent bcf13367d4
commit 276a254c1c
2 changed files with 67 additions and 43 deletions

View File

@ -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;
} }

View File

@ -37,6 +37,11 @@
/* 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
@ -45,12 +50,8 @@
#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];
}; };