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