xref: /haiku/src/add-ons/kernel/bus_managers/firewire/timer.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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