1 /* 2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 /* 23 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 24 * 25 * IOTimerEventSource.cpp 26 * 27 * HISTORY 28 * 2-Feb-1999 Joe Liu (jliu) created. 29 * 1999-10-14 Godfrey van der Linden(gvdl) 30 * Revamped to use thread_call APIs 31 * 32 */ 33 34 #include <sys/cdefs.h> 35 36 __BEGIN_DECLS 37 #include <kern/thread_call.h> 38 __END_DECLS 39 40 #include <IOKit/assert.h> 41 #include <IOKit/system.h> 42 43 #include <IOKit/IOLib.h> 44 #include <IOKit/IOTimerEventSource.h> 45 #include <IOKit/IOWorkLoop.h> 46 47 #include <IOKit/IOTimeStamp.h> 48 49 #define super IOEventSource 50 OSDefineMetaClassAndStructors(IOTimerEventSource, IOEventSource) 51 OSMetaClassDefineReservedUnused(IOTimerEventSource, 0); 52 OSMetaClassDefineReservedUnused(IOTimerEventSource, 1); 53 OSMetaClassDefineReservedUnused(IOTimerEventSource, 2); 54 OSMetaClassDefineReservedUnused(IOTimerEventSource, 3); 55 OSMetaClassDefineReservedUnused(IOTimerEventSource, 4); 56 OSMetaClassDefineReservedUnused(IOTimerEventSource, 5); 57 OSMetaClassDefineReservedUnused(IOTimerEventSource, 6); 58 OSMetaClassDefineReservedUnused(IOTimerEventSource, 7); 59 60 bool IOTimerEventSource::checkForWork() { return false; } 61 62 // Timeout handler function. This function is called by the kernel when 63 // the timeout interval expires. 64 // 65 void IOTimerEventSource::timeout(void *self) 66 { 67 IOTimerEventSource *me = (IOTimerEventSource *) self; 68 69 if (me->enabled) { 70 Action doit = (Action) me->action; 71 72 if (doit) { 73 IOTimeStampConstant(IODBG_TIMES(IOTIMES_ACTION), 74 (unsigned int) doit, (unsigned int) me->owner); 75 me->closeGate(); 76 (*doit)(me->owner, me); 77 me->openGate(); 78 } 79 } 80 } 81 82 void IOTimerEventSource::setTimeoutFunc() 83 { 84 calloutEntry = (void *) thread_call_allocate((thread_call_func_t) timeout, 85 (thread_call_param_t) this); 86 } 87 88 bool IOTimerEventSource::init(OSObject *inOwner, Action inAction) 89 { 90 if (!super::init(inOwner, (IOEventSource::Action) inAction) ) 91 return false; 92 93 setTimeoutFunc(); 94 if (!calloutEntry) 95 return false; 96 97 return true; 98 } 99 100 IOTimerEventSource * 101 IOTimerEventSource::timerEventSource(OSObject *inOwner, Action inAction) 102 { 103 IOTimerEventSource *me = new IOTimerEventSource; 104 105 if (me && !me->init(inOwner, inAction)) { 106 me->free(); 107 return 0; 108 } 109 110 return me; 111 } 112 113 void IOTimerEventSource::free() 114 { 115 if (calloutEntry) { 116 cancelTimeout(); 117 thread_call_free((thread_call_t) calloutEntry); 118 } 119 120 super::free(); 121 } 122 123 void IOTimerEventSource::cancelTimeout() 124 { 125 thread_call_cancel((thread_call_t) calloutEntry); 126 AbsoluteTime_to_scalar(&abstime) = 0; 127 } 128 129 void IOTimerEventSource::enable() 130 { 131 super::enable(); 132 if (kIOReturnSuccess != wakeAtTime(abstime)) 133 super::disable(); // Problem re-scheduling timeout ignore enable 134 } 135 136 void IOTimerEventSource::disable() 137 { 138 thread_call_cancel((thread_call_t) calloutEntry); 139 super::disable(); 140 } 141 142 IOReturn IOTimerEventSource::setTimeoutTicks(UInt32 ticks) 143 { 144 return setTimeout(ticks, NSEC_PER_SEC/hz); 145 } 146 147 IOReturn IOTimerEventSource::setTimeoutMS(UInt32 ms) 148 { 149 return setTimeout(ms, kMillisecondScale); 150 } 151 152 IOReturn IOTimerEventSource::setTimeoutUS(UInt32 us) 153 { 154 return setTimeout(us, kMicrosecondScale); 155 } 156 157 IOReturn IOTimerEventSource::setTimeout(UInt32 interval, UInt32 scale_factor) 158 { 159 AbsoluteTime end; 160 161 clock_interval_to_deadline(interval, scale_factor, &end); 162 return wakeAtTime(end); 163 } 164 165 IOReturn IOTimerEventSource::setTimeout(mach_timespec_t interval) 166 { 167 AbsoluteTime end, nsecs; 168 169 clock_interval_to_absolutetime_interval 170 (interval.tv_nsec, kNanosecondScale, &nsecs); 171 clock_interval_to_deadline 172 (interval.tv_sec, NSEC_PER_SEC, &end); 173 ADD_ABSOLUTETIME(&end, &nsecs); 174 175 return wakeAtTime(end); 176 } 177 178 IOReturn IOTimerEventSource::setTimeout(AbsoluteTime interval) 179 { 180 AbsoluteTime end; 181 182 clock_get_uptime(&end); 183 ADD_ABSOLUTETIME(&end, &interval); 184 185 return wakeAtTime(end); 186 } 187 188 IOReturn IOTimerEventSource::wakeAtTimeTicks(UInt32 ticks) 189 { 190 return wakeAtTime(ticks, NSEC_PER_SEC/hz); 191 } 192 193 IOReturn IOTimerEventSource::wakeAtTimeMS(UInt32 ms) 194 { 195 return wakeAtTime(ms, kMillisecondScale); 196 } 197 198 IOReturn IOTimerEventSource::wakeAtTimeUS(UInt32 us) 199 { 200 return wakeAtTime(us, kMicrosecondScale); 201 } 202 203 IOReturn IOTimerEventSource::wakeAtTime(UInt32 abstime, UInt32 scale_factor) 204 { 205 AbsoluteTime end; 206 clock_interval_to_absolutetime_interval(abstime, scale_factor, &end); 207 208 return wakeAtTime(end); 209 } 210 211 IOReturn IOTimerEventSource::wakeAtTime(mach_timespec_t abstime) 212 { 213 AbsoluteTime end, nsecs; 214 215 clock_interval_to_absolutetime_interval 216 (abstime.tv_nsec, kNanosecondScale, &nsecs); 217 clock_interval_to_absolutetime_interval 218 (abstime.tv_sec, kSecondScale, &end); 219 ADD_ABSOLUTETIME(&end, &nsecs); 220 221 return wakeAtTime(end); 222 } 223 224 IOReturn IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime) 225 { 226 if (!action) 227 return kIOReturnNoResources; 228 229 abstime = inAbstime; 230 if ( enabled && AbsoluteTime_to_scalar(&abstime) ) 231 thread_call_enter_delayed((thread_call_t) calloutEntry, abstime); 232 233 return kIOReturnSuccess; 234 } 235