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 "fwdebug.h" 25 #include "timer.h" 26 27 #define MAX_TIMERS 8 28 29 30 struct timer_info 31 { 32 timer_id id; 33 timer_function func; 34 void * cookie; 35 bigtime_t next_event; 36 bigtime_t interval; 37 bool periodic; 38 }; 39 40 41 static struct timer_info sTimerData[MAX_TIMERS]; 42 static int sTimerCount; 43 static timer_id sTimerNextId; 44 static thread_id sTimerThread; 45 static sem_id sTimerSem; 46 static spinlock sTimerSpinlock; 47 48 49 static int32 50 timer_thread(void *cookie) 51 { 52 status_t status = 0; 53 54 do { 55 bigtime_t timeout; 56 bigtime_t now; 57 cpu_status cpu; 58 timer_function func; 59 void * cookie; 60 int i; 61 int index; 62 63 cpu = disable_interrupts(); 64 acquire_spinlock(&sTimerSpinlock); 65 66 now = system_time(); 67 cookie = 0; 68 func = 0; 69 70 // find timer with smallest event time 71 index = -1; 72 timeout = B_INFINITE_TIMEOUT; 73 for (i = 0; i < sTimerCount; i++) { 74 if (sTimerData[i].next_event < timeout) { 75 timeout = sTimerData[i].next_event; 76 index = i; 77 } 78 } 79 80 if (timeout < now) { 81 // timer is ready for execution, load func and cookie 82 ASSERT(index >= 0 && index < sTimerCount); 83 func = sTimerData[index].func; 84 cookie = sTimerData[index].cookie; 85 if (sTimerData[index].periodic) { 86 // periodic timer is ready, update the entry 87 sTimerData[index].next_event += sTimerData[index].interval; 88 } else { 89 // single shot timer is ready, delete the entry 90 if (index != (sTimerCount - 1) && sTimerCount != 1) { 91 memcpy(&sTimerData[index], &sTimerData[sTimerCount - 1], sizeof(struct timer_info)); 92 } 93 sTimerCount--; 94 } 95 } 96 97 release_spinlock(&sTimerSpinlock); 98 restore_interrupts(cpu); 99 100 // execute timer hook 101 if (timeout < now) { 102 ASSERT(func); 103 func(cookie); 104 continue; 105 } 106 107 status = acquire_sem_etc(sTimerSem, 1, B_ABSOLUTE_TIMEOUT, timeout); 108 } while (status != B_BAD_SEM_ID); 109 110 return 0; 111 } 112 113 114 timer_id 115 create_timer(timer_function func, void *cookie, bigtime_t interval, uint32 flags) 116 { 117 cpu_status cpu; 118 timer_id id; 119 120 if (func == 0) 121 return -1; 122 123 // Attention: flags are not real flags, as B_PERIODIC_TIMER is 3 124 125 cpu = disable_interrupts(); 126 acquire_spinlock(&sTimerSpinlock); 127 128 if (sTimerCount < MAX_TIMERS) { 129 id = sTimerNextId; 130 sTimerData[sTimerCount].id = id; 131 sTimerData[sTimerCount].func = func; 132 sTimerData[sTimerCount].cookie = cookie; 133 sTimerData[sTimerCount].next_event = (flags == B_ONE_SHOT_ABSOLUTE_TIMER) ? interval : system_time() + interval; 134 sTimerData[sTimerCount].interval = interval; 135 sTimerData[sTimerCount].periodic = flags == B_PERIODIC_TIMER; 136 sTimerNextId++; 137 sTimerCount++; 138 } else { 139 id = -1; 140 } 141 142 release_spinlock(&sTimerSpinlock); 143 restore_interrupts(cpu); 144 145 if (id != -1) 146 release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE); 147 148 return id; 149 } 150 151 152 status_t 153 delete_timer(timer_id id) 154 { 155 cpu_status cpu; 156 bool deleted; 157 int i; 158 159 deleted = false; 160 161 cpu = disable_interrupts(); 162 acquire_spinlock(&sTimerSpinlock); 163 164 for (i = 0; i < sTimerCount; i++) { 165 if (sTimerData[i].id == id) { 166 if (i != (sTimerCount - 1) && sTimerCount != 1) { 167 memcpy(&sTimerData[i], &sTimerData[sTimerCount - 1], sizeof(struct timer_info)); 168 } 169 sTimerCount--; 170 deleted = true; 171 break; 172 } 173 } 174 175 release_spinlock(&sTimerSpinlock); 176 restore_interrupts(cpu); 177 178 if (!deleted) 179 return B_ERROR; 180 181 release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE); 182 return B_OK; 183 } 184 185 186 status_t 187 initialize_timer(void) 188 { 189 sTimerCount = 0; 190 sTimerNextId = 1; 191 B_INITIALIZE_SPINLOCK(&sTimerSpinlock); 192 193 sTimerThread = spawn_kernel_thread(timer_thread, "firewire timer", 80, 0); 194 sTimerSem = create_sem(0, "firewire timer"); 195 set_sem_owner(sTimerSem, B_SYSTEM_TEAM); 196 197 if (sTimerSem < 0 || sTimerThread < 0) { 198 delete_sem(sTimerSem); 199 kill_thread(sTimerThread); 200 return B_ERROR; 201 } 202 203 resume_thread(sTimerThread); 204 return B_OK; 205 } 206 207 208 status_t 209 terminate_timer(void) 210 { 211 status_t thread_return_value; 212 213 delete_sem(sTimerSem); 214 return wait_for_thread(sTimerThread, &thread_return_value); 215 } 216 217