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
timer_thread(void * cookie)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
create_timer(timer_function func,void * cookie,bigtime_t interval,uint32 flags)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
delete_timer(timer_id id)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
initialize_timer(void)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
terminate_timer(void)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