xref: /haiku/src/add-ons/kernel/bus_managers/firewire/timer.cpp (revision d0f2d8282f3f59a1af7fe2d340d2af0cb36a9b20)
14535495dSIngo Weinhold /* Realtek RTL8169 Family Driver
24535495dSIngo Weinhold  * Copyright (C) 2004 Marcus Overhagen <marcus@overhagen.de>. All rights reserved.
34535495dSIngo Weinhold  *
44535495dSIngo Weinhold  * Permission to use, copy, modify and distribute this software and its
54535495dSIngo Weinhold  * documentation for any purpose and without fee is hereby granted, provided
64535495dSIngo Weinhold  * that the above copyright notice appear in all copies, and that both the
74535495dSIngo Weinhold  * copyright notice and this permission notice appear in supporting documentation.
84535495dSIngo Weinhold  *
94535495dSIngo Weinhold  * Marcus Overhagen makes no representations about the suitability of this software
104535495dSIngo Weinhold  * for any purpose. It is provided "as is" without express or implied warranty.
114535495dSIngo Weinhold  *
124535495dSIngo Weinhold  * MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
134535495dSIngo Weinhold  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
144535495dSIngo Weinhold  * OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
154535495dSIngo Weinhold  * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
164535495dSIngo Weinhold  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
174535495dSIngo Weinhold  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
184535495dSIngo Weinhold  */
194535495dSIngo Weinhold #include <Errors.h>
204535495dSIngo Weinhold #include <OS.h>
214535495dSIngo Weinhold #include <string.h>
224535495dSIngo Weinhold 
234535495dSIngo Weinhold #include "debug.h"
244535495dSIngo Weinhold #include "fwdebug.h"
254535495dSIngo Weinhold #include "timer.h"
264535495dSIngo Weinhold 
274535495dSIngo Weinhold #define MAX_TIMERS 8
284535495dSIngo Weinhold 
294535495dSIngo Weinhold 
304535495dSIngo Weinhold struct timer_info
314535495dSIngo Weinhold {
324535495dSIngo Weinhold 	timer_id 		id;
334535495dSIngo Weinhold 	timer_function	func;
344535495dSIngo Weinhold 	void *			cookie;
354535495dSIngo Weinhold 	bigtime_t		next_event;
364535495dSIngo Weinhold 	bigtime_t		interval;
374535495dSIngo Weinhold 	bool			periodic;
384535495dSIngo Weinhold };
394535495dSIngo Weinhold 
404535495dSIngo Weinhold 
414535495dSIngo Weinhold static struct timer_info	sTimerData[MAX_TIMERS];
424535495dSIngo Weinhold static int					sTimerCount;
434535495dSIngo Weinhold static timer_id				sTimerNextId;
444535495dSIngo Weinhold static thread_id			sTimerThread;
454535495dSIngo Weinhold static sem_id				sTimerSem;
464535495dSIngo Weinhold static spinlock				sTimerSpinlock;
474535495dSIngo Weinhold 
484535495dSIngo Weinhold 
494535495dSIngo Weinhold static int32
timer_thread(void * cookie)504535495dSIngo Weinhold timer_thread(void *cookie)
514535495dSIngo Weinhold {
524535495dSIngo Weinhold 	status_t status = 0;
534535495dSIngo Weinhold 
544535495dSIngo Weinhold 	do {
554535495dSIngo Weinhold 		bigtime_t timeout;
564535495dSIngo Weinhold 		bigtime_t now;
574535495dSIngo Weinhold 		cpu_status cpu;
584535495dSIngo Weinhold 		timer_function func;
594535495dSIngo Weinhold 		void * cookie;
604535495dSIngo Weinhold 		int i;
614535495dSIngo Weinhold 		int index;
624535495dSIngo Weinhold 
634535495dSIngo Weinhold 		cpu = disable_interrupts();
644535495dSIngo Weinhold 		acquire_spinlock(&sTimerSpinlock);
654535495dSIngo Weinhold 
664535495dSIngo Weinhold 		now = system_time();
674535495dSIngo Weinhold 		cookie = 0;
684535495dSIngo Weinhold 		func = 0;
694535495dSIngo Weinhold 
704535495dSIngo Weinhold 		// find timer with smallest event time
714535495dSIngo Weinhold 		index = -1;
724535495dSIngo Weinhold 		timeout = B_INFINITE_TIMEOUT;
734535495dSIngo Weinhold 		for (i = 0; i < sTimerCount; i++) {
744535495dSIngo Weinhold 			if (sTimerData[i].next_event < timeout) {
754535495dSIngo Weinhold 				timeout = sTimerData[i].next_event;
764535495dSIngo Weinhold 				index = i;
774535495dSIngo Weinhold 			}
784535495dSIngo Weinhold 		}
794535495dSIngo Weinhold 
804535495dSIngo Weinhold 		if (timeout < now) {
814535495dSIngo Weinhold 			// timer is ready for execution, load func and cookie
824535495dSIngo Weinhold 			ASSERT(index >= 0 && index < sTimerCount);
834535495dSIngo Weinhold 			func = sTimerData[index].func;
844535495dSIngo Weinhold 			cookie = sTimerData[index].cookie;
854535495dSIngo Weinhold 			if (sTimerData[index].periodic) {
864535495dSIngo Weinhold 				// periodic timer is ready, update the entry
874535495dSIngo Weinhold 				sTimerData[index].next_event += sTimerData[index].interval;
884535495dSIngo Weinhold 			} else {
894535495dSIngo Weinhold 				// single shot timer is ready, delete the entry
904535495dSIngo Weinhold 				if (index != (sTimerCount - 1) && sTimerCount != 1) {
914535495dSIngo Weinhold 					memcpy(&sTimerData[index], &sTimerData[sTimerCount - 1], sizeof(struct timer_info));
924535495dSIngo Weinhold 				}
934535495dSIngo Weinhold 				sTimerCount--;
944535495dSIngo Weinhold 			}
954535495dSIngo Weinhold 		}
964535495dSIngo Weinhold 
974535495dSIngo Weinhold 		release_spinlock(&sTimerSpinlock);
984535495dSIngo Weinhold 		restore_interrupts(cpu);
994535495dSIngo Weinhold 
1004535495dSIngo Weinhold 		// execute timer hook
1014535495dSIngo Weinhold 		if (timeout < now) {
1024535495dSIngo Weinhold 			ASSERT(func);
1034535495dSIngo Weinhold 			func(cookie);
1044535495dSIngo Weinhold 			continue;
1054535495dSIngo Weinhold 		}
1064535495dSIngo Weinhold 
1074535495dSIngo Weinhold 		status = acquire_sem_etc(sTimerSem, 1, B_ABSOLUTE_TIMEOUT, timeout);
1084535495dSIngo Weinhold 	} while (status != B_BAD_SEM_ID);
1094535495dSIngo Weinhold 
1104535495dSIngo Weinhold 	return 0;
1114535495dSIngo Weinhold }
1124535495dSIngo Weinhold 
1134535495dSIngo Weinhold 
1144535495dSIngo Weinhold timer_id
create_timer(timer_function func,void * cookie,bigtime_t interval,uint32 flags)1154535495dSIngo Weinhold create_timer(timer_function func, void *cookie, bigtime_t interval, uint32 flags)
1164535495dSIngo Weinhold {
1174535495dSIngo Weinhold 	cpu_status cpu;
1184535495dSIngo Weinhold 	timer_id id;
1194535495dSIngo Weinhold 
1204535495dSIngo Weinhold 	if (func == 0)
1214535495dSIngo Weinhold 		return -1;
1224535495dSIngo Weinhold 
1234535495dSIngo Weinhold 	// Attention: flags are not real flags, as B_PERIODIC_TIMER is 3
1244535495dSIngo Weinhold 
1254535495dSIngo Weinhold 	cpu = disable_interrupts();
1264535495dSIngo Weinhold 	acquire_spinlock(&sTimerSpinlock);
1274535495dSIngo Weinhold 
1284535495dSIngo Weinhold 	if (sTimerCount < MAX_TIMERS) {
1294535495dSIngo Weinhold 		id = sTimerNextId;
1304535495dSIngo Weinhold 		sTimerData[sTimerCount].id = id;
1314535495dSIngo Weinhold 		sTimerData[sTimerCount].func = func;
1324535495dSIngo Weinhold 		sTimerData[sTimerCount].cookie = cookie;
1334535495dSIngo Weinhold 		sTimerData[sTimerCount].next_event = (flags == B_ONE_SHOT_ABSOLUTE_TIMER) ? interval : system_time() + interval;
1344535495dSIngo Weinhold 		sTimerData[sTimerCount].interval = interval;
1354535495dSIngo Weinhold 		sTimerData[sTimerCount].periodic = flags == B_PERIODIC_TIMER;
1364535495dSIngo Weinhold 		sTimerNextId++;
1374535495dSIngo Weinhold 		sTimerCount++;
1384535495dSIngo Weinhold 	} else {
1394535495dSIngo Weinhold 		id = -1;
1404535495dSIngo Weinhold 	}
1414535495dSIngo Weinhold 
1424535495dSIngo Weinhold 	release_spinlock(&sTimerSpinlock);
1434535495dSIngo Weinhold 	restore_interrupts(cpu);
1444535495dSIngo Weinhold 
1454535495dSIngo Weinhold 	if (id != -1)
1464535495dSIngo Weinhold 		release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE);
1474535495dSIngo Weinhold 
1484535495dSIngo Weinhold 	return id;
1494535495dSIngo Weinhold }
1504535495dSIngo Weinhold 
1514535495dSIngo Weinhold 
1524535495dSIngo Weinhold status_t
delete_timer(timer_id id)1534535495dSIngo Weinhold delete_timer(timer_id id)
1544535495dSIngo Weinhold {
1554535495dSIngo Weinhold 	cpu_status cpu;
1564535495dSIngo Weinhold 	bool deleted;
1574535495dSIngo Weinhold 	int i;
1584535495dSIngo Weinhold 
1594535495dSIngo Weinhold 	deleted = false;
1604535495dSIngo Weinhold 
1614535495dSIngo Weinhold 	cpu = disable_interrupts();
1624535495dSIngo Weinhold 	acquire_spinlock(&sTimerSpinlock);
1634535495dSIngo Weinhold 
1644535495dSIngo Weinhold 	for (i = 0; i < sTimerCount; i++) {
1654535495dSIngo Weinhold 		if (sTimerData[i].id == id) {
1664535495dSIngo Weinhold 			if (i != (sTimerCount - 1) && sTimerCount != 1) {
1674535495dSIngo Weinhold 				memcpy(&sTimerData[i], &sTimerData[sTimerCount - 1], sizeof(struct timer_info));
1684535495dSIngo Weinhold 			}
1694535495dSIngo Weinhold 			sTimerCount--;
1704535495dSIngo Weinhold 			deleted = true;
1714535495dSIngo Weinhold 			break;
1724535495dSIngo Weinhold 		}
1734535495dSIngo Weinhold 	}
1744535495dSIngo Weinhold 
1754535495dSIngo Weinhold 	release_spinlock(&sTimerSpinlock);
1764535495dSIngo Weinhold 	restore_interrupts(cpu);
1774535495dSIngo Weinhold 
1784535495dSIngo Weinhold 	if (!deleted)
1794535495dSIngo Weinhold 		return B_ERROR;
1804535495dSIngo Weinhold 
1814535495dSIngo Weinhold 	release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE);
1824535495dSIngo Weinhold 	return B_OK;
1834535495dSIngo Weinhold }
1844535495dSIngo Weinhold 
1854535495dSIngo Weinhold 
1864535495dSIngo Weinhold status_t
initialize_timer(void)1874535495dSIngo Weinhold initialize_timer(void)
1884535495dSIngo Weinhold {
1894535495dSIngo Weinhold 	sTimerCount = 0;
1904535495dSIngo Weinhold 	sTimerNextId = 1;
191*e736a456SPawel Dziepak 	B_INITIALIZE_SPINLOCK(&sTimerSpinlock);
1924535495dSIngo Weinhold 
1934535495dSIngo Weinhold 	sTimerThread = spawn_kernel_thread(timer_thread, "firewire timer", 80, 0);
1944535495dSIngo Weinhold 	sTimerSem = create_sem(0, "firewire timer");
1954535495dSIngo Weinhold 	set_sem_owner(sTimerSem, B_SYSTEM_TEAM);
1964535495dSIngo Weinhold 
1974535495dSIngo Weinhold 	if (sTimerSem < 0 || sTimerThread < 0) {
1984535495dSIngo Weinhold 		delete_sem(sTimerSem);
1994535495dSIngo Weinhold 		kill_thread(sTimerThread);
2004535495dSIngo Weinhold 		return B_ERROR;
2014535495dSIngo Weinhold 	}
2024535495dSIngo Weinhold 
2034535495dSIngo Weinhold 	resume_thread(sTimerThread);
2044535495dSIngo Weinhold 	return B_OK;
2054535495dSIngo Weinhold }
2064535495dSIngo Weinhold 
2074535495dSIngo Weinhold 
2084535495dSIngo Weinhold status_t
terminate_timer(void)2094535495dSIngo Weinhold terminate_timer(void)
2104535495dSIngo Weinhold {
2114535495dSIngo Weinhold 	status_t thread_return_value;
2124535495dSIngo Weinhold 
2134535495dSIngo Weinhold 	delete_sem(sTimerSem);
2144535495dSIngo Weinhold 	return wait_for_thread(sTimerThread, &thread_return_value);
2154535495dSIngo Weinhold }
2164535495dSIngo Weinhold 
217