1/* Realtek RTL8169 Family Driver 2 * Copyright (C) 2004 Marcus Overhagen <marcus@overhagen.de>. All rights reserved. 3 * 4 * Permission to use, copy, modify and distribute this software and its 5 * documentation for any purpose and without fee is hereby granted, provided 6 * that the above copyright notice appear in all copies, and that both the 7 * copyright notice and this permission notice appear in supporting documentation. 8 * 9 * Marcus Overhagen makes no representations about the suitability of this software 10 * for any purpose. It is provided "as is" without express or implied warranty. 11 * 12 * MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 13 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS 14 * OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 15 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19#include <Errors.h> 20#include <OS.h> 21#include <string.h> 22 23#include "debug.h" 24#include "timer.h" 25 26#define MAX_TIMERS 8 27 28 29struct timer_info 30{ 31 timer_id id; 32 timer_function func; 33 void * cookie; 34 bigtime_t next_event; 35 bigtime_t interval; 36 bool periodic; 37}; 38 39 40static struct timer_info sTimerData[MAX_TIMERS]; 41static int sTimerCount; 42static timer_id sTimerNextId; 43static thread_id sTimerThread; 44static sem_id sTimerSem; 45static spinlock sTimerSpinlock; 46 47 48static int32 49timer_thread(void *cookie) 50{ 51 status_t status = 0; 52 53 do { 54 bigtime_t timeout; 55 bigtime_t now; 56 cpu_status cpu; 57 timer_function func; 58 void * cookie; 59 int i; 60 int index; 61 62 cpu = disable_interrupts(); 63 acquire_spinlock(&sTimerSpinlock); 64 65 now = system_time(); 66 cookie = 0; 67 func = 0; 68 69 // find timer with smallest event time 70 index = -1; 71 timeout = B_INFINITE_TIMEOUT; 72 for (i = 0; i < sTimerCount; i++) { 73 if (sTimerData[i].next_event < timeout) { 74 timeout = sTimerData[i].next_event; 75 index = i; 76 } 77 } 78 79 if (timeout < now) { 80 // timer is ready for execution, load func and cookie 81 ASSERT(index >= 0 && index < sTimerCount); 82 func = sTimerData[index].func; 83 cookie = sTimerData[index].cookie; 84 if (sTimerData[index].periodic) { 85 // periodic timer is ready, update the entry 86 sTimerData[index].next_event += sTimerData[index].interval; 87 } else { 88 // single shot timer is ready, delete the entry 89 if (index != (sTimerCount - 1) && sTimerCount != 1) { 90 memcpy(&sTimerData[index], &sTimerData[sTimerCount - 1], sizeof(struct timer_info)); 91 } 92 sTimerCount--; 93 } 94 } 95 96 release_spinlock(&sTimerSpinlock); 97 restore_interrupts(cpu); 98 99 // execute timer hook 100 if (timeout < now) { 101 ASSERT(func); 102 func(cookie); 103 continue; 104 } 105 106 status = acquire_sem_etc(sTimerSem, 1, B_ABSOLUTE_TIMEOUT, timeout); 107 } while (status != B_BAD_SEM_ID); 108 109 return 0; 110} 111 112 113timer_id 114create_timer(timer_function func, void *cookie, bigtime_t interval, uint32 flags) 115{ 116 cpu_status cpu; 117 timer_id id; 118 119 if (func == 0) 120 return -1; 121 122 // Attention: flags are not real flags, as B_PERIODIC_TIMER is 3 123 124 cpu = disable_interrupts(); 125 acquire_spinlock(&sTimerSpinlock); 126 127 if (sTimerCount < MAX_TIMERS) { 128 id = sTimerNextId; 129 sTimerData[sTimerCount].id = id; 130 sTimerData[sTimerCount].func = func; 131 sTimerData[sTimerCount].cookie = cookie; 132 sTimerData[sTimerCount].next_event = (flags == B_ONE_SHOT_ABSOLUTE_TIMER) ? interval : system_time() + interval; 133 sTimerData[sTimerCount].interval = interval; 134 sTimerData[sTimerCount].periodic = flags == B_PERIODIC_TIMER; 135 sTimerNextId++; 136 sTimerCount++; 137 } else { 138 id = -1; 139 } 140 141 release_spinlock(&sTimerSpinlock); 142 restore_interrupts(cpu); 143 144 if (id != -1) 145 release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE); 146 147 return id; 148} 149 150 151status_t 152delete_timer(timer_id id) 153{ 154 cpu_status cpu; 155 bool deleted; 156 int i; 157 158 deleted = false; 159 160 cpu = disable_interrupts(); 161 acquire_spinlock(&sTimerSpinlock); 162 163 for (i = 0; i < sTimerCount; i++) { 164 if (sTimerData[i].id == id) { 165 if (i != (sTimerCount - 1) && sTimerCount != 1) { 166 memcpy(&sTimerData[i], &sTimerData[sTimerCount - 1], sizeof(struct timer_info)); 167 } 168 sTimerCount--; 169 deleted = true; 170 break; 171 } 172 } 173 174 release_spinlock(&sTimerSpinlock); 175 restore_interrupts(cpu); 176 177 if (!deleted) 178 return B_ERROR; 179 180 release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE); 181 return B_OK; 182} 183 184 185status_t 186initialize_timer(void) 187{ 188 sTimerCount = 0; 189 sTimerNextId = 1; 190 B_INITIALIZE_SPINLOCK(&sTimerSpinlock); 191 192 sTimerThread = spawn_kernel_thread(timer_thread, "rtl8169 timer", 80, 0); 193 sTimerSem = create_sem(0, "rtl8169 timer"); 194 set_sem_owner(sTimerSem, B_SYSTEM_TEAM); 195 196 if (sTimerSem < 0 || sTimerThread < 0) { 197 delete_sem(sTimerSem); 198 kill_thread(sTimerThread); 199 return B_ERROR; 200 } 201 202 resume_thread(sTimerThread); 203 return B_OK; 204} 205 206 207status_t 208terminate_timer(void) 209{ 210 status_t thread_return_value; 211 212 delete_sem(sTimerSem); 213 return wait_for_thread(sTimerThread, &thread_return_value); 214} 215 216