/* Realtek RTL8169 Family Driver * Copyright (C) 2004 Marcus Overhagen . All rights reserved. * * Permission to use, copy, modify and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies, and that both the * copyright notice and this permission notice appear in supporting documentation. * * Marcus Overhagen makes no representations about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * * MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS * OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "debug.h" #include "fwdebug.h" #include "timer.h" #define MAX_TIMERS 8 struct timer_info { timer_id id; timer_function func; void * cookie; bigtime_t next_event; bigtime_t interval; bool periodic; }; static struct timer_info sTimerData[MAX_TIMERS]; static int sTimerCount; static timer_id sTimerNextId; static thread_id sTimerThread; static sem_id sTimerSem; static spinlock sTimerSpinlock; static int32 timer_thread(void *cookie) { status_t status = 0; do { bigtime_t timeout; bigtime_t now; cpu_status cpu; timer_function func; void * cookie; int i; int index; cpu = disable_interrupts(); acquire_spinlock(&sTimerSpinlock); now = system_time(); cookie = 0; func = 0; // find timer with smallest event time index = -1; timeout = B_INFINITE_TIMEOUT; for (i = 0; i < sTimerCount; i++) { if (sTimerData[i].next_event < timeout) { timeout = sTimerData[i].next_event; index = i; } } if (timeout < now) { // timer is ready for execution, load func and cookie ASSERT(index >= 0 && index < sTimerCount); func = sTimerData[index].func; cookie = sTimerData[index].cookie; if (sTimerData[index].periodic) { // periodic timer is ready, update the entry sTimerData[index].next_event += sTimerData[index].interval; } else { // single shot timer is ready, delete the entry if (index != (sTimerCount - 1) && sTimerCount != 1) { memcpy(&sTimerData[index], &sTimerData[sTimerCount - 1], sizeof(struct timer_info)); } sTimerCount--; } } release_spinlock(&sTimerSpinlock); restore_interrupts(cpu); // execute timer hook if (timeout < now) { ASSERT(func); func(cookie); continue; } status = acquire_sem_etc(sTimerSem, 1, B_ABSOLUTE_TIMEOUT, timeout); } while (status != B_BAD_SEM_ID); return 0; } timer_id create_timer(timer_function func, void *cookie, bigtime_t interval, uint32 flags) { cpu_status cpu; timer_id id; if (func == 0) return -1; // Attention: flags are not real flags, as B_PERIODIC_TIMER is 3 cpu = disable_interrupts(); acquire_spinlock(&sTimerSpinlock); if (sTimerCount < MAX_TIMERS) { id = sTimerNextId; sTimerData[sTimerCount].id = id; sTimerData[sTimerCount].func = func; sTimerData[sTimerCount].cookie = cookie; sTimerData[sTimerCount].next_event = (flags == B_ONE_SHOT_ABSOLUTE_TIMER) ? interval : system_time() + interval; sTimerData[sTimerCount].interval = interval; sTimerData[sTimerCount].periodic = flags == B_PERIODIC_TIMER; sTimerNextId++; sTimerCount++; } else { id = -1; } release_spinlock(&sTimerSpinlock); restore_interrupts(cpu); if (id != -1) release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE); return id; } status_t delete_timer(timer_id id) { cpu_status cpu; bool deleted; int i; deleted = false; cpu = disable_interrupts(); acquire_spinlock(&sTimerSpinlock); for (i = 0; i < sTimerCount; i++) { if (sTimerData[i].id == id) { if (i != (sTimerCount - 1) && sTimerCount != 1) { memcpy(&sTimerData[i], &sTimerData[sTimerCount - 1], sizeof(struct timer_info)); } sTimerCount--; deleted = true; break; } } release_spinlock(&sTimerSpinlock); restore_interrupts(cpu); if (!deleted) return B_ERROR; release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE); return B_OK; } status_t initialize_timer(void) { sTimerCount = 0; sTimerNextId = 1; B_INITIALIZE_SPINLOCK(&sTimerSpinlock); sTimerThread = spawn_kernel_thread(timer_thread, "firewire timer", 80, 0); sTimerSem = create_sem(0, "firewire timer"); set_sem_owner(sTimerSem, B_SYSTEM_TEAM); if (sTimerSem < 0 || sTimerThread < 0) { delete_sem(sTimerSem); kill_thread(sTimerThread); return B_ERROR; } resume_thread(sTimerThread); return B_OK; } status_t terminate_timer(void) { status_t thread_return_value; delete_sem(sTimerSem); return wait_for_thread(sTimerThread, &thread_return_value); }