Author: jackburton Date: 2011-10-19 14:40:12 +0200 (Wed, 19 Oct 2011) New Revision: 42882 Changeset: https://dev.haiku-os.org/changeset/42882 Modified: haiku/trunk/src/add-ons/kernel/drivers/timer/hpet.cpp haiku/trunk/src/add-ons/kernel/drivers/timer/hpet.h Log: 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. Modified: haiku/trunk/src/add-ons/kernel/drivers/timer/hpet.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/timer/hpet.cpp 2011-10-19 11:11:53 UTC (rev 42881) +++ haiku/trunk/src/add-ons/kernel/drivers/timer/hpet.cpp 2011-10-19 12:40:12 UTC (rev 42882) @@ -14,6 +14,7 @@ #include <ACPI.h> #include <PCI.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -38,6 +39,7 @@ int number; int32 irq; sem_id sem; + hpet_timer* timer; }; //////////////////////////////////////////////////////////////////////////////// @@ -92,7 +94,7 @@ #define MIN_TIMEOUT 1 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: if (relativeTimeout < MIN_TIMEOUT) @@ -116,7 +118,7 @@ static status_t -hpet_clear_hardware_timer(volatile hpet_timer *timer) +hpet_clear_hardware_timer(hpet_timer *timer) { // Disable timer interrupt timer->config &= ~HPET_CONF_TIMER_INT_ENABLE; @@ -129,12 +131,14 @@ { //dprintf("HPET timer_interrupt!!!!\n"); hpet_timer_cookie* hpetCookie = (hpet_timer_cookie*)arg; + hpet_timer* timer = &sHPETRegs->timer[hpetCookie->number]; - // clear interrupt status 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; - hpet_clear_hardware_timer(&sHPETRegs->timer[hpetCookie->number]); + hpet_clear_hardware_timer(timer); release_sem_etc(hpetCookie->sem, 1, B_DO_NOT_RESCHEDULE); return B_HANDLED_INTERRUPT; @@ -159,7 +163,7 @@ hpet_set_legacy(bool enabled) { 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; } @@ -197,7 +201,7 @@ dprintf("\tTimer type: %s\n", timer->config & HPET_CONF_TIMER_TYPE ? "Periodic" : "OneShot"); 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", HPET_GET_CONF_TIMER_INT_ROUTE(timer)); @@ -213,7 +217,7 @@ static status_t 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); @@ -226,9 +230,10 @@ } } - if (interrupt == -1) + if (interrupt == -1) { + dprintf("hpet_init_timer(): timer can't be routed to any interrupt!") return B_ERROR; - + } // Non-periodic mode timer->config &= ~HPET_CONF_TIMER_TYPE; @@ -287,10 +292,9 @@ sHPETPeriod = HPET_GET_PERIOD(sHPETRegs); TRACE(("hpet_init: HPET is at %p.\n" - "\tVendor ID: %llx, rev: %llx, period: %lld\n" - "\tin legacy mode: %s\n", + "\tVendor ID: %llx, rev: %llx, period: %lld\n", 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); if (status != B_OK) @@ -302,8 +306,10 @@ uint32 numTimers = HPET_GET_NUM_TIMERS(sHPETRegs) + 1; - TRACE(("hpet_init: HPET supports %lu timers, and is %s bits wide.\n", - numTimers, HPET_IS_64BIT(sHPETRegs) ? "64" : "32")); + TRACE(("hpet_init: HPET supports %lu timers, is %s bits wide, " + "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", sHPETRegs->config, sHPETRegs->interrupt_status)); @@ -428,27 +434,44 @@ return B_BUSY; } + 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)); - int timerNumber = 2; + if (hpetCookie == NULL) { + delete_sem(sem); + atomic_add(&sOpenCount, -1); + return B_NO_MEMORY; + } + 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); hpet_set_enabled(false); 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)); - return status; - } hpet_set_enabled(true); *cookie = hpetCookie; - if (status != B_OK) + if (status != B_OK) { + delete_sem(sem); + free(hpetCookie); atomic_add(&sOpenCount, -1); - + } return status; } Modified: haiku/trunk/src/add-ons/kernel/drivers/timer/hpet.h =================================================================== --- haiku/trunk/src/add-ons/kernel/drivers/timer/hpet.h 2011-10-19 11:11:53 UTC (rev 42881) +++ haiku/trunk/src/add-ons/kernel/drivers/timer/hpet.h 2011-10-19 12:40:12 UTC (rev 42882) @@ -12,20 +12,20 @@ /* Doing it this way is Required since the HPET only supports 32/64-bit aligned reads. */ /* 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_WIDTH 0x0000000000002000ULL +#define HPET_CAP_MASK_WIDTH 0x0000000000002000ULL #define HPET_CAP_MASK_LEGACY 0x0000000000008000ULL #define HPET_CAP_MASK_VENDOR_ID 0x00000000FFFF0000ULL #define HPET_CAP_MASK_PERIOD 0xFFFFFFFF00000000ULL /* Retrieve Global Capabilities */ -#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_IS_64BIT(regs) (((regs)->capabilities & HPET_CAP_MASK_WIDTH) >> 13) +#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_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_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_VENDOR_ID(regs) (((regs)->capabilities & HPET_CAP_MASK_VENDOR_ID) >> 16) +#define HPET_GET_PERIOD(regs) (((regs)->capabilities & HPET_CAP_MASK_PERIOD) >> 32) /* Global Config Register Masks */ #define HPET_CONF_MASK_ENABLED 0x00000001 @@ -37,20 +37,21 @@ /* Timer Configuration and Capabilities*/ #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_SHIFT 9 -#define HPET_CONF_TIMER_INT_TYPE 0x00000002UL -#define HPET_CONF_TIMER_INT_ENABLE 0x00000004UL -#define HPET_CONF_TIMER_TYPE 0x00000008UL -#define HPET_CONF_TIMER_VAL_SET 0x00000040UL -#define HPET_CONF_TIMER_32MODE 0x00000100UL -#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_CONF_TIMER_INT_TYPE 0x00000002UL +#define HPET_CONF_TIMER_INT_ENABLE 0x00000004UL +#define HPET_CONF_TIMER_TYPE 0x00000008UL +#define HPET_CONF_TIMER_VAL_SET 0x00000040UL +#define HPET_CONF_TIMER_32MODE 0x00000100UL +#define HPET_CONF_TIMER_FSB_ENABLE 0x00004000UL #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" @@ -83,16 +84,16 @@ /* Level Tigger: 0 = off, 1 = set by hardware, timer is active */ /* Edge Trigger: ignored */ /* Writing 0 will not clear these. Must write 1 again. */ - volatile uint64 reserved3[25]; + uint64 reserved3[25]; union { volatile uint64 counter64; /* R/W */ volatile uint32 counter32; } u0; - volatile uint64 reserved4; + uint64 reserved4; - volatile struct hpet_timer timer[1]; + struct hpet_timer timer[1]; };