source: svn/trunk/newcon3bcm2_21bu/magnum/basemodules/tmr/7552/btmr.c @ 2

Last change on this file since 2 was 2, checked in by jglee, 11 years ago

first commit

  • Property svn:executable set to *
File size: 94.4 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2005-2012, Broadcom Corporation
3 *     All Rights Reserved
4 *     Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT  BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * $brcm_Workfile: btmr.c $
11 * $brcm_Revision: Hydra_Software_Devel/34 $
12 * $brcm_Date: 2/21/12 2:19p $
13 *
14 * Module Description:
15 *  This is a magnum PI module used to control the hardware timers of a BCM7xxx part.
16 *  This provides a means to create/destroy and start/stop timers when required.
17 *
18 * Revision History:
19 *
20 * $brcm_Log: /magnum/basemodules/tmr/7401/btmr.c $
21 *
22 * Hydra_Software_Devel/34   2/21/12 2:19p erickson
23 * SW7425-2130: fix debug warnings
24 *
25 * Hydra_Software_Devel/33   8/26/11 5:03p rjlewis
26 * SW7425-1187: locking semaphore didn't lock enough.  Need to block all
27 * other creates without impeding recursive creates (so creating virtual
28 * timer can create the two physical timers needed to process virtual
29 * timers).
30 *
31 * Hydra_Software_Devel/32   8/25/11 12:39p rjlewis
32 * SW7425-1187: added compile options for handling missing destroy calls.
33 * Added mutexes to protect counts (fixes dual destroy fail).  Added
34 * tagged for destroy.  General cleanup.
35 *
36 * Hydra_Software_Devel/31   8/18/11 4:29p rjlewis
37 * SW7346-460: comment around a coverity issue.
38 *
39 * Hydra_Software_Devel/30   8/18/11 4:10p rjlewis
40 * SW7346-460: If create failed -- tell them where it was asked to be
41 * created.
42 *
43 * Hydra_Software_Devel/29   8/18/11 3:36p rjlewis
44 * SW7346-460: make sure free-run timer was created before trying to
45 * destroy.
46 *
47 * Hydra_Software_Devel/28   8/16/11 6:50p rjlewis
48 * SW7346-460: checked in with "never leave enabled" flag defined.
49 *
50 * Hydra_Software_Devel/27   8/16/11 6:35p rjlewis
51 * SW7346-460: changed destroy timer loop to fix coverity issue.
52 *
53 * Hydra_Software_Devel/26   8/10/11 3:58p rjlewis
54 * SW3548-2526: don't try to remove virtual timer from linked list twice
55 * on close with missing destroy.
56 *
57 * Hydra_Software_Devel/25   8/10/11 2:40p rjlewis
58 * SW3548-2526: don't include ANY std includes -- causes compile issues.
59 * Don't use stdlib functions (compile errors).  clarify that location is
60 * creation location.
61 *
62 * Hydra_Software_Devel/24   8/9/11 9:59a rjlewis
63 * SW3548-2526: Removed unused include that was causing build error on
64 * some platforms.
65 *
66 * Hydra_Software_Devel/23   8/8/11 2:54p rjlewis
67 * SW3548-2526: Merged in virtual timer branch. PR22129: SW3548-2526:
68 * incorrectly using unsigned long and uint32_t where unsigned correct.
69 * Missing leave critical in read.  fixed names of values to reflect
70 * where converted to ticks.  Fixed bug: not setting default timer
71 * register offset. SWDTV-5441: added support for secondary timer block.
72 * Fixed return variables from uint32 to uslongs. SW3548-2526: General
73 * clean-up SW3548-2526: general cleanup.  Added jump tables for
74 * virt/phys processing. Keep track of virtual timers.  Added _isr where
75 * required.  Uses one less phys timer. SW35230-935: update branch so I
76 * can continue virtual timer changes before merging back into main.
77 * SW7550-300: Read physical timers value instead of virtual to get the
78 * time elapsed before deciding where to place new timer. SW7550-197:
79 *
80 * Hydra_Software_Devel/PR22129/8   7/29/11 2:02p rjlewis
81 * SW3548-2526: incorrectly using unsigned long and uint32_t where
82 * unsigned correct. Missing leave critical in read.  fixed names of
83 * values to reflect where converted to ticks.  Fixed bug: not setting
84 * default timer register offset.
85 *
86 * Hydra_Software_Devel/PR22129/7   5/25/11 3:48p rjlewis
87 * SWDTV-5441: added support for secondary timer block.  Fixed return
88 * variables from uint32 to uslongs.
89 *
90 * Hydra_Software_Devel/PR22129/6   3/18/11 6:05p rjlewis
91 * SW3548-2526: General clean-up
92 *
93 * Hydra_Software_Devel/PR22129/5   3/16/11 11:17a rjlewis
94 * SW3548-2526: general cleanup.  Added jump tables for virt/phys
95 * processing. Keep track of virtual timers.  Added _isr where required.
96 * Uses one less phys timer.
97 *
98 * Hydra_Software_Devel/PR22129/4   2/9/11 3:42p rjlewis
99 * SW35230-935: update branch so I can continue virtual timer changes
100 * before merging back into main.
101 *
102 * Hydra_Software_Devel/22   8/17/10 5:46p rjlewis
103 * SW35230-935: Added support for tagged version of create (so we can find
104 * where timers are being created).
105 * Don't stop non-countdown timers so anyone using timer outside PI
106 * (exclusive & shared) won't hang.
107 * Cleaned up unregistering of callbacks on close.
108 * Cleaned up message debug prints and entry/exit prints.
109 *
110 * Hydra_Software_Devel/21   8/13/10 7:00p rjlewis
111 * SW3548-2526: fixed coverity issues where missing free on error after
112 * malloc.
113 *
114 * Hydra_Software_Devel/20   8/6/10 5:49p rjlewis
115 * SW3548-2526: merge virtual timers into main
116 *
117 * Hydra_Software_Devel/PR22129/3   3/12/10 5:16p rjlewis
118 * SW7550-300: Read physical timers value instead of virtual to get the
119 * time elapsed before deciding where to place new timer.
120 * SW7550-197: Timeing splice allowed timer to interrupt after I took it
121 * off the queue.  Need to stop it first THEN take it off the queue.
122 *
123 * Hydra_Software_Devel/PR22129/2   11/20/09 4:52p rjlewis
124 * SW3548-2526: rewote virtual timers to use separate hardware timers to
125 * control free-run versus count-down virtual timers.
126 *
127 * Hydra_Software_Devel/PR22129/1   1/30/07 11:57a rjlewis
128 * PR22129: added support for virtal timers.
129 *
130 * Hydra_Software_Devel/19   11/20/09 4:27p rjlewis
131 * SW7420-391: Added David's tagged to find where timers being used.  This
132 * also uses object definitions instead of magic values.
133 * SW7335-485: fixes bug in returning error on open when last timer fails
134 * to create callback interrupt.
135 *
136 * Hydra_Software_Devel/18   6/12/08 1:05p vsilyaev
137 * PR 43317: Properly report an error
138 *
139 * Hydra_Software_Devel/17   10/27/06 11:03a rjlewis
140 * PR25238: functions with no parameters need void as per ANSI.
141 *
142 * Hydra_Software_Devel/16   6/8/06 11:22a rjlewis
143 * PR18214: remove warning when not compiling for debug.
144 *
145 * Hydra_Software_Devel/8   4/28/06 1:41p rjlewis
146 * PR18214: added an ISR version of the read timer function.
147 *
148 * Hydra_Software_Devel/7   4/25/06 2:42p jgarrett
149 * PR 21220: Removing BCHP_INT_ID defines
150 *
151 * Hydra_Software_Devel/5   1/13/06 12:32p jgarrett
152 * PR 19007: Updating base modules for 7400
153 *
154 * Hydra_Software_Devel/Refsw_Devel_7400_A0/1   1/12/06 3:08p jgarrett
155 * PR 19007: Update timer for 7400
156 *
157 * Hydra_Software_Devel/4   1/10/06 11:26a rjlewis
158 * PR18214: remove warnings.
159 *
160 * Hydra_Software_Devel/3   12/13/05 3:39p rjlewis
161 * PR18588: Don't process the interrupt if timer never created.
162 *
163 * Hydra_Software_Devel/2   12/8/05 11:28a erickson
164 * PR18214: remove duplicate typedef. uclibc -pedantic doesn't like it.
165 *
166 * Hydra_Software_Devel/1   11/21/05 2:05p rjlewis
167 * PR18214: Initial version.
168 *
169 ***************************************************************************/
170#include "bstd.h"
171#include "bkni.h"
172#include "bkni_multi.h"
173#include "bint.h"
174#include "bchp_common.h"
175#include "bchp_timer.h"
176#include "bchp_int_id_timer.h"
177#include "blst_list.h" /* double linked list code */
178#include "btmr.h"
179
180/* Can't use std includes -- causes conflicts on some builds */
181/*#include <stdio.h>*/
182/*#include <string.h>*/
183
184#include "bdbg.h"
185BDBG_MODULE(btmr);
186
187/* Note:
188** This file contains two complete sets of timer control functions.
189** That is, there is one set to control exclusive and/or shared timers (phys_) and another to control virtual timers (virt_).
190** The published interface functions test which type of timer is being used and calls the appropriate set.
191*/
192
193/* Shared Timer Notes:
194** The concept of a shared timer was added prior to adding virtual timers.  This allowed users to request a physical timer
195** for reading only (delay operations) but share it with other requestors.  A physical timer is used for this purpose.
196** Since the address to this timer is returned to each requestor (that wants to read the time without using this PI)
197** it is possible for any of the users to stop the timer -- this would be bad!  When virtual timers were introduced it was
198** decided to keep the shared timer as there is firmware in ancillary processors/dsps that can't use the PI but can read the
199** timer registers.  This lets them use a timer without having to use a unique physical timer.
200*/
201
202/* Virtual Timer Notes:
203** This interface supports two types of virtual timers: stop-watch (or free-run) and count-down.
204** One physical timer is used for the virtual count-down timer and the shared timer is used to support the virtual free-run timers.
205** The physical timer for count-down timers is ONLY used to generate the interrupt.  All the time calculations are done
206** using the shared free-run timer (for both the virtual count-down and virtual free-run timers).
207**
208** When a count-down timer is pending, the physical timer counts the virtual count-down timer that has the smallest count-down period.
209** A sorted list of the count-down timers is managed.  When a count-down timer is added to the list it is added in the list
210** based on its timeout time before an item that has a larger timeout period.  The difference between that item and its
211** preceeding entry defines how long the timeout needs to be for that timer.
212**
213** The timer for free-run virtual timers is started at open time and the current time is used to provide the caller
214** with a virtual time value (using the time when the user created the virtual timer).
215*/
216
217/* TODO:
218** 1) Instead of using two timers to support virtual timers, try to use the free-run timer for the timeout by just letting it run
219** but set a new match value for the next timeout.  The pain would be in the inserting of a new virtual count-down timer that is
220** less (smaller timeout) than the one that is currently running.  To calculate the time already run would be a bit more math.
221** 2) Allow reading the registers for a virtual stop-watch timer (return the registers for the free-run timer used for supporting
222** the virtual timers).  Then convert the create request for a shared timer to a virtual stop-watch and delete the concept of a
223** shared timer from the documentation (depricated).
224** 3) BTMR_ReadTimer should not return status as it can never fail -- return value instead.  This would require a change to the PI.
225** 4) Change BTMR_ReadTimerMax to allow specifying a handle in case future timers blocks have different wrap points.
226*/
227
228/**** Compile-time options ****/
229
230#define _FAIL_ON_CLOSE_ /* enable to cause close to fail on resource leaks (timers not returned). */
231    /* The above is useful when users aren't looking at the error messages on close failures.
232    ** Without the fail the user can over-look the issue and not do something about it.
233    ** With this enable, BKNI_Fails will occur when handles are not returned on close!
234    */
235
236/*#define _DESTROY_ON_CLOSE_*/ /* enable to cause close to try to clean up the resource leaks. */
237    /* The above will try to destroy all the timers that were left pending.
238    ** The main benefit is that we'll return all the memory we allocated (on user's behalf) and will destroy any pending handles.
239    ** This means that if anyone tries to use any of the timer functions after the close that we'll assert on the handle.
240    ** Note that this is wasted effort if you enable the _FAIL_ON_CLOSE_ option aove.
241    */
242
243/* Define a minimum timeout period where its just not prudent to wait for the timer to timeout -- i.e. close enough!
244** The danger here is that if they create a timer with less than the minimum hold time then we'll continue to
245** process that timer in this loop.  So, if you want to use the MIN_HOLD you MUST ensure that no periodic timer gets
246** created with a timeout period less than this timeout or we'll just hang!
247** Note: this is different than the BTMR_MINIMUM_TIMEOUT value that decides a minimum value for periodic timers.
248*/
249#if 1
250#define BTMR_MIN_HOLD 27 /* this is microsecond->timer conversion value */
251#else
252#define BTMR_MIN_HOLD (27*5)
253#endif
254
255/**** Misc definitions ****/
256
257#define NumberOfTimers 4 /* this hardware has this many instances of this physical timer */
258/* Note: This definition should be made into a platform definition should any platform implement a different number of sequential timers. */
259
260#define TimerWrap     (1<<30)        /* timer wraps at this count (is 39.7 seconds) */
261#define MaxTimerValue (TimerWrap-1)  /* the max timer count is one less than the wrap point */
262
263#define TimerSelect(timer) (1<<(timer)) /* the timer is selected by the bit number */
264
265/* Don't print out path when printing out file name (paths are just so long -- makes reading log harder) */
266/* Note: can't default this because can't include <string.h> without generating compile errors on some builds */
267#if 0
268#include <string.h>
269/*char *strchr(const char *s, int c);*/
270/*char *strrchr(const char *s, int c);*/
271#define shortenFileName(file) if (strchr((file),'/')) (file) = strrchr((file),'/')+1;
272#else
273#define shortenFileName(file)
274#endif
275
276/* Forward reference */
277static BERR_Code _BTMR_CreateTimer(BTMR_Handle device, BTMR_TimerHandle *phTimer, const BTMR_TimerSettings *pSettings, const char *file, int line);
278static BERR_Code _BTMR_DestroyTimer(BTMR_TimerHandle timer, const char*file, int line);
279
280/* There are different entry points for each of the timer handler functions based on whether the timer is a physical or virtual timer.
281** Rather than make the decision each time the function is called I use a table to use the correct function.
282** This table gets set at the timer creation.
283*/
284typedef struct {
285    BERR_Code (*create)(BTMR_Handle device, BTMR_TimerHandle timer, const BTMR_TimerSettings *pSettings);
286    BERR_Code (*destroy_isr)(BTMR_TimerHandle timer);
287    BERR_Code (*start_isr)(BTMR_TimerHandle timer, unsigned startingValue);
288    BERR_Code (*stop_isr)(BTMR_TimerHandle timer);
289    unsigned (*read_isr)(BTMR_TimerHandle timer);
290} ProcessingFunctions;
291
292BDBG_OBJECT_ID(btmr_timer_t);
293
294/* This is the data associated with an individual timer.
295** An opaque pointer to one of these (handle) is returned on a successful create timer request.
296*/
297struct BTMR_P_TimerContext {
298    BDBG_OBJECT(btmr_timer_t)    /* used to check if structure is valid */
299
300    BTMR_Handle device;          /* the device handle for this timer (passed in on create) */
301    BTMR_TimerSettings Settings; /* the settings passed in for this timer (passed in on create) */
302    uint32_t initialValue;       /* how long should this timer run (passed in on start) */
303
304    BLST_D_ENTRY(BTMR_P_TimerContext) created; /* for linking queue of created timers */
305    const char *file; int line; /* this is location where timer was created (will help in tracking down missing destroys) */
306
307    BTMR_TimerRegisters Registers; /* the offsets to the control and status registers */
308
309    ProcessingFunctions *functions; /* the table of processing functions for this type of timer (virtual versus physical) */
310
311    int timerNumber;    /* this indicates which timer was allocated (-1 for virtual timers) */
312    uint32_t lastValue; /* this is the last value of the timer when it was stopped */
313    bool cbEnabled;     /* indicates that I enabled the interrupt in the create */
314
315    BLST_D_ENTRY(BTMR_P_TimerContext) link; /* for linking onto a virtual timeout queue */
316
317    uint32_t startingValue;  /* virtual timers need to record the value of the timer when it was started */
318    uint32_t adjustedValue;  /* how long should this timer run when put on virtual timeout (difference from the timer before it) */
319
320    bool running;     /* flag, so we know if the timer is already running -- shouldn't start a running or stop a stopped timer */
321    bool processing;  /* this timer is being processed so don't try to stop or delete */
322
323    volatile bool pleaseStop;  /* this periodic timer was stopped in the callback so don't restart it */
324    volatile bool pleaseStart; /* this count-down timer was started in the callback so restart it */
325    unsigned delayedValue;     /* the starting value when asked to (re)start from a call-back handler */
326};
327
328BDBG_OBJECT_ID(btmr_device_t);
329
330/* This is the data associated with the timer module (group of timers).
331** An opaque pointer to one of these (handle) is returned on a successful module open call.
332*/
333struct BTMR_P_Context {
334    BDBG_OBJECT(btmr_device_t) /* used to check if structure is valid */
335    BCHP_Handle hChip;         /* the chip handle (passed in on open) */
336    BREG_Handle hRegister;     /* the register handle (passed in on open) */
337    BINT_Handle hInterrupt;    /* the interrupt handle (passed in on open) */
338
339    BTMR_DeviceSettings Settings; /* this is the list of available timers -- provided on request */
340    uint32_t inUse;               /* bitmask which specifies which timers are already in use by this code */ 
341
342    BTMR_TimerHandle Timers[NumberOfTimers];      /* list of allocated timers (so we can stop/destroy them on close) */
343    BINT_CallbackHandle CbHandle[NumberOfTimers]; /* interrupt callbacks for each timer we control */
344
345    BINT_CallbackHandle alt_CbHandle; /* interrupt callbacks for secondary block if interrupt is handled as Level 3 */
346    unsigned int alt_CbEnabled; /* flag to indicate whether alternate callback is enabled (enable on 0->1 transition, disable on 1->0 transition) */
347
348    BTMR_TimerHandle SharedTimer;    /* timer for shared timer use */
349    BTMR_TimerHandle CountDownTimer; /* timer for managing virtual count-down timers */
350    BTMR_TimerHandle FreeRunTimer;   /* timer for managing virtual free-run timers */
351
352    BLST_D_HEAD(TOL,  BTMR_P_TimerContext) TimeoutList; /* the list of vitrual count-down/periodic timers waiting to timeout */
353    BLST_D_HEAD(TBPL, BTMR_P_TimerContext) ToBeProcessedList; /* the list of vitrual count-down/periodic timers waiting to be processed */
354
355    BKNI_MutexHandle create_destroy_mutex; /* semaphore to protect against re-entrant code */
356
357    unsigned int SharedCount;  /* count of users using this shared timer (destroy when count goes to 0) */
358    unsigned int VirtualCount; /* count of outstanding virtual timers (for displaying error on close) */
359
360    BLST_D_HEAD(VTCL, BTMR_P_TimerContext) VirtualCreateList; /* the list of vitrual timers created */
361};
362
363/*\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\*/
364
365/* The timers run at 27Mhz (27,000,000 times a second) and a microsecond is 1,000,000th of a second, so ... */
366#define ConversionFactor (27000000/1000000) /* <- yeah, I know, its 27 -- but the compiler will figure that out, right? */
367#define TimerToMicroSeconds(timerValue)   ((unsigned)((unsigned)(timerValue) / ConversionFactor))
368#define MicroSecondsToTimer(microSeconds) ((unsigned)((unsigned)(microSeconds) * ConversionFactor))
369
370/*\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\*/
371
372/* These are used to get the timer control/status register for specific timer set/number */
373#define CONTROL_REG(device, timer) \
374    (((device)->Settings.baseRegister + (BCHP_TIMER_TIMER0_CTRL-BCHP_TIMER_REG_START)) + ((int)(timer) * (BCHP_TIMER_TIMER1_CTRL-BCHP_TIMER_TIMER0_CTRL)))
375#define STATUS_REG(device, timer)   \
376    (((device)->Settings.baseRegister + (BCHP_TIMER_TIMER0_STAT-BCHP_TIMER_REG_START)) + ((int)(timer) * (BCHP_TIMER_TIMER1_STAT-BCHP_TIMER_TIMER0_STAT)))
377
378/* These are used to get the interrupt status and enable/disable the interrupts when using a secondary timer block */
379#define TIMER_IS_REG(device) \
380    ((device)->Settings.baseRegister + (BCHP_TIMER_TIMER_IS-BCHP_TIMER_REG_START))
381#define TIMER_IE_REG(device) \
382    ((device)->Settings.baseRegister + (BCHP_TIMER_TIMER_IE0-BCHP_TIMER_REG_START))
383
384/*\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\*/
385
386/* This allocates one of the unused timers and returns its timer number (returns -1 if none available) */
387/* We start from last to first in case someone uses a timer (assuming they picked 0) outside of this PI and didn't tell us! */
388static int SelectAnAvailableTimer_isr(BTMR_Handle device)
389{
390    int timer, selected=-1;
391    for (timer=NumberOfTimers-1; timer >= 0; timer--)
392    {
393        if (!(device->inUse & TimerSelect(timer))) 
394        {
395            device->inUse |= TimerSelect(timer); /* this timer is now in use (should anybody ask) */
396            selected = timer; /* this is the timer I've selected just for you */
397            break;
398        }
399    }
400    return selected;
401}
402
403/* This frees a specific (selected) timer (makes it available again) */
404static void ReleaseThisTimer_isr(BTMR_Handle device, int timerNumber)
405{
406    device->inUse &= ~TimerSelect(timerNumber); /* not in use anymore */
407}
408
409#if BDBG_DEBUG_BUILD
410static char *_GetTimerType(bool exclusive, BTMR_Type type)
411{
412    if (type == BTMR_Type_eSharedFreeRun) return "Shared";
413    if (exclusive)
414    {
415        switch (type) {
416            case BTMR_Type_eCountDown:     return "Exclusive/CountDown";
417            case BTMR_Type_ePeriodic:      return "Exclusive/Periodic";
418            case BTMR_Type_eStopWatch:     return "Exclusive/StopWatch";
419            default: return "Unknown";
420        }
421    }
422    else
423    {
424        switch (type) {
425            case BTMR_Type_eCountDown:     return "Virtual/CountDown";
426            case BTMR_Type_ePeriodic:      return "Virtual/Periodic";
427            case BTMR_Type_eStopWatch:     return "Virtual/StopWatch";
428            default: return "Unknown";
429        }
430    }
431}
432static char *GetTimerType(const BTMR_TimerSettings *pSettings) { return _GetTimerType(pSettings->exclusive, pSettings->type); }
433#endif /*BDBG_DEBUG_BUILD*/
434
435/*\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\*/
436
437/* This talks to the hardware to enable the specified timer */
438static void EnableTimer_isr(BTMR_TimerHandle timer)
439{
440    uint32_t control_value, timeout;
441    /*uint32_t was = BREG_Read32_isr(timer->device->hRegister, timer->Registers.control);*/
442
443    /* Note: we always use Free-run mode!
444    ** I haven't figured out the difference between a count-down and free-run timer.
445    ** They seem to function exactly the same (count up to matching value, interrupt, and restart at 0).
446    */
447   
448    if (timer->Settings.type == BTMR_Type_eStopWatch || timer->Settings.type == BTMR_Type_eSharedFreeRun) {
449        /* Stop-watch timers count up until they wrap */
450        /* Counts up from 0 to the maximum timer value that the timer can handle (then it resets to zero and continues to count up) */
451        timeout = MaxTimerValue;
452    } else {
453        /* Count-down and Periodic timers count up to matching value */
454        /* This is the same as if they STARTED at the initial value and counted down (since I can't get count-down mode to work) */
455        timeout = timer->initialValue;
456    }
457   
458    control_value = BCHP_MASK(TIMER_TIMER0_CTRL,ENA) | (BCHP_FIELD_DATA(TIMER_TIMER0_CTRL, TIMEOUT_VAL, timeout) & BCHP_MASK(TIMER_TIMER0_CTRL,TIMEOUT_VAL));
459
460    /*BDBG_MSG(("EnableTimer_isr: Writing 0x%08x (was 0x%08x) to control register (offset=%08x)", control_value, was, timer->Registers.control));*/
461    BREG_Write32_isr(timer->device->hRegister, timer->Registers.control, control_value);
462    timer->running = true;
463}
464
465/* This talks to the hardware to disable the specified timer */
466static void DisableTimer_isr(BTMR_TimerHandle timer)
467{
468    uint32_t control_value, was;
469
470    control_value = was = BREG_Read32_isr(timer->device->hRegister, timer->Registers.control);
471    control_value &= ~BCHP_MASK(TIMER_TIMER0_CTRL,ENA);
472
473    /*BDBG_MSG(("DisableTimer_isr: Writing 0x%08x (was 0x%08x) to control register (offset=%08x)", control_value, was, timer->Registers.control));*/
474    BREG_Write32_isr(timer->device->hRegister, timer->Registers.control, control_value);
475    timer->running = false;
476}   
477
478/* This is special case version that disables the timer BEFORE we have a timer structure created for this timer (i.e. at init time) */
479static void DisableTimerNumber(BTMR_Handle device, int timerNumber)
480{
481    uint32_t control_register = CONTROL_REG(device, timerNumber);
482    uint32_t control_value, was;
483
484    control_value = was = BREG_Read32_isr(device->hRegister, control_register);
485    control_value &= ~BCHP_MASK(TIMER_TIMER0_CTRL,ENA);
486
487    /*BDBG_MSG(("DisableTimerNumber: Writing 0x%08x (was 0x%08x) to control register (offset=%08x)", control_value, was, control_register));*/
488    BREG_Write32(device->hRegister, control_register, control_value);
489}       
490
491/* This talks to hardware to get the timer value */
492static uint32_t GetTimerValue_isr(BTMR_TimerHandle timer)
493{
494    uint32_t status_value = BREG_Read32_isr(timer->device->hRegister, timer->Registers.status);
495    status_value &= MaxTimerValue; /* bits 30&31 are reserved but are sometimes set for some reason */
496    return status_value;
497}
498
499/*
500*******************************************************************************************************
501*******************************************************************************************************
502** These are the set of PHYSICAL (exclusive or shared) timer functions (and their utility functions).
503*******************************************************************************************************
504*******************************************************************************************************
505*/
506
507static BERR_Code JustStartTimer_isr(BTMR_TimerHandle timer, uint32_t initialValue)
508{
509    /* We don't allow starting a running timer (why not?) -- you must stop it first (???) */
510    /* The problem here is that if they forgot to stop the timer and believe that this is actually
511    ** starting the timer then they aren't going to get what they expected and won't know why.
512    ** We have three choices here: 1) don't let them start a started timer, 2) stop the timer and restart
513    ** with the new parameters, or 3) just say okay and keep going.
514    */
515    if (timer->running) {
516#if 0
517        BDBG_ERR(("BTMR_StartTimer: timer already running!"));
518        return BERR_TRACE(BTMR_ERR_ALREADY_STARTED);
519#else
520        goto done; /* its already started -- success! (this is choice 3) */
521#endif
522    }
523
524    /* Can't use an initial value of zero for count-down and periodic timers! */
525    if ((timer->Settings.type == BTMR_Type_eCountDown || timer->Settings.type == BTMR_Type_ePeriodic) && !initialValue) {
526        BDBG_ERR(("BTMR_StartTimer: can't use zero initial value with Count-down and Periodic timers!"));
527        return BERR_TRACE(BTMR_ERR_NO_TIMEOUT_GIVEN);
528    }
529
530    /* We only have specific number of bits worth of timer value */
531    if (initialValue >= MaxTimerValue) {
532        BDBG_ERR(("BTMR_StartTimer: initial value too large!"));
533        return BERR_TRACE(BTMR_ERR_TIMEOUT_TOO_LARGE);
534    }
535
536    timer->initialValue = initialValue;
537    timer->lastValue = 0;
538   
539    EnableTimer_isr(timer);
540
541  done:
542    return BERR_SUCCESS;
543}
544
545static uint32_t JustReadTimer_isr(BTMR_TimerHandle timer)
546{
547    uint32_t runTime;
548   
549    /* Stopwatch (FreeRun) timers count up  -- just give them the value of the timer */
550    runTime = GetTimerValue_isr(timer);
551
552/*    printf("runtime = %d (0x%x) type=%s [initial = %d (0x%x)]\n",
553           runTime, runTime, GetTimerType(&timer->Settings), timer->initialValue, timer->initialValue);
554*/
555    /* Count-down and Periodic timers count down (but don't let it go negative) */
556    /* Note: we always use the hardware timer in a count UP mode (i.e. count up to matching value).
557    ** If free-run then reading the timer IS the count.  In count-down we want the value of the timer
558    ** (or what it WOULD be if it was really counting down).  Thus, we do some math and make sure its capped at zero.
559    */
560    if (runTime && (timer->Settings.type == BTMR_Type_eCountDown || timer->Settings.type == BTMR_Type_ePeriodic))
561        runTime = (timer->initialValue > runTime) ? (timer->initialValue - runTime) : 0;
562
563/*    printf("runtime = %d (0x%x) type=%s [initial = %d (0x%x)]\n",
564           runTime, runTime, GetTimerType(&timer->Settings), timer->initialValue, timer->initialValue);
565*/
566    return runTime;
567}
568
569static BERR_Code JustStopTimer_isr(BTMR_TimerHandle timer)
570{
571    /* Should I let them stop a stopped timer??? */
572    /* We have two choices here: 1) don't let them stop a stopped timer or 2) just say okay and keep going.  */
573    if (!timer->running) {
574#if 0
575        BDBG_ERR(("BTMR_StopTimer: timer already stopped!"));
576        return BERR_TRACE(BTMR_ERR_ALREADY_STOPPED);
577#else
578        goto done; /* its already stopped -- success! (this is choice 2) */
579#endif
580    }
581
582    /* We're going to save off the last value of the timer when they stopped it.
583    ** That way, if they read it AFTER it stopped we can tell them what it was.
584    ** I'm pretty sure this is required as reading the status after stopping returns zero!
585    */
586    timer->lastValue = JustReadTimer_isr(timer);
587
588    DisableTimer_isr(timer);
589
590  done:
591    return BERR_SUCCESS;
592}
593
594/*
595** This is my ISR function for the physical Timers!
596** Its registered at 'open' time, de-registered at 'close', enabled at 'create', and disabled at 'destroy'.
597** This performs the callbacks to the owner of the count-down or periodic timer.
598*/
599
600static void Physical_Timer_Isr(BTMR_Handle device, int timerNumber)
601{
602    BTMR_TimerHandle timer;
603    BTMR_TimerSettings *context;
604
605    /* We're supposed to use asserts to catch logic errors (not run-time errors).
606    ** So is getting an invalid handle or timer number a logic error??
607    ** We should never be given a timerNumber for a timer that we don't control.
608    */
609#if 1
610    BDBG_ASSERT(device);
611    BDBG_OBJECT_ASSERT(device, btmr_device_t);
612    BDBG_ASSERT((timerNumber >= 0) && (timerNumber < NumberOfTimers));
613#else
614    if (!device) {
615        BDBG_ERR(("device parameter is null in ISR!"));
616        return;
617    }
618    if (timerNumber < 0 || timerNumber >= NumberOfTimers) {
619        BDBG_ERR(("ISR received an invalid timer number (=%d)!", timerNumber));
620        return;
621    }
622#endif
623
624    /*BDBG_WRN(("Physical interrupt (timer %d)", timerNumber));*/
625
626#if 0
627    /* We should never get an interrupt for a timer we don't control with this PI */
628    if (device->Settings.timerMask & TimerSelect(timerNumber)) return;
629
630    /* We should never get an interrupt for a timer we didn't open */
631    if (!(device->inUse & TimerSelect(timerNumber))) return;
632#endif
633
634    /* Note: for the above cases, returning without handling the interrupt could mean we get called back forever, but not much else I can do... */
635
636    /* Its been reported that we can be called (once??) at startup before anyone has created a timer.
637    ** This is either an interrupt for a timer being used externally (and they neglected to indicate this in the open)
638    ** or the timer was running and it generated an interrupt before the timer is created (why?).
639    ** If we assert here they won't know why this it happening.  So don't use: BDBG_ASSERT(timer);
640    ** But ignoring it is not great either -- in this case we're getting called for an interrupt we're not controlling
641    ** and doing nothing with the interrupt.  I think this is the better choice (keeps the code from crashing).
642    */
643    timer = device->Timers[timerNumber];
644    if (!timer) {
645        BDBG_ERR(("timer is NULL in ISR!"));
646        return;
647    }
648
649    /* Note: we cannot validate the timer with the following assert:
650    **     BDBG_ASSERT(timer->running == true);
651    ** This is because we allow for exclusive timers that are created through the PI but not started and stopped via the PI. 
652    ** This means that if someone is using a timer outside of this PI and it causes an interrupt that I'll not know what to
653    ** do with the timer.  This is bad but there is no way to control this.
654    */
655
656    /* If the timer is being used externally, then I may not have an object created to handle this (unless we use this
657    ** timer in the PI too).  This will catch anyone using this without telling me in the Open.
658    */
659    BDBG_OBJECT_ASSERT(timer, btmr_timer_t);
660
661    JustStopTimer_isr(timer);
662    timer->lastValue = 0; /* count down timers always stop at zero */
663   
664    /* We flag this timer as processing in case they try to start/stop the timer in the call-back function */
665    timer->processing = true;
666    timer->running = false;
667
668    /* If we have a callback function for this timer, then its time to call it! */
669    /* Note: this is processing count-down timers so there had BETTER be a call-back function!!! */
670    /* We ALWAYS call back with the timer stopped! */
671    context = &timer->Settings;
672    if (context->cb_isr)
673        context->cb_isr(context->pParm1, context->parm2); 
674
675    /* We're done processing this timer so its okay to stop or delete it now */
676    timer->processing = false;
677   
678    /* Periodic timers continue to go off until stopped -- we stopped it earlier so start it up again! */
679    /* They may have asked us to stop the timer in the callback.  We delayed this until done processing the call-back. */
680    /* If they asked us to stop the timer then just don't start it back up. */
681    if (context->type == BTMR_Type_ePeriodic && !timer->pleaseStop) {
682        JustStartTimer_isr(timer, timer->initialValue);
683        timer->running = true;
684    }
685
686    /* If they requested a count-down timer to be restarted in the call-back then do it now. */
687    if (context->type == BTMR_Type_eCountDown && timer->pleaseStart) {
688        BTMR_StartTimer_isr(timer, timer->delayedValue);
689    }
690
691    /* Make sure these are cleared before leaving (in case they tried to start a periodic or stop a countdown) */
692    timer->pleaseStart = false;
693    timer->pleaseStop  = false;
694}
695
696/*
697** This PI supports two different timer blocks with two different interrupt methods.
698** The primary (TMR) has a separate level two interrupt register for determining which of the four timers generated the interrupt.
699** In the second method, this implementation is handled as a level three (the level one references a level two block).  All I am
700** told in this method is one (or more) of the timers went off but not which one.  I have to figure that out myself by checking
701** the level three timer interrupt status register and clearing the appropriate interrupt after processing.
702*/
703
704static void Physical_Timer_Selection_Isr(BTMR_Handle device)
705{
706    int timerNumber;
707    uint32_t status, mask=0;
708
709    /* This shouldn't be necessary because I didn't enable anything not being used, but ... */
710    for (timerNumber=0; timerNumber < NumberOfTimers; timerNumber++) mask |= (1<<timerNumber);
711
712    /* Figure out which one of the timers interrupted by reading the status register */
713    status = BREG_Read32_isr(device->hRegister, TIMER_IS_REG(device)) & mask;
714    if (!status) return;
715
716    /* Clear the level three interrupts I'm about to process -- I'll work off the copy.
717    ** By doing this before processing means that if any interrupt callback starts a timer that causes a NEW interrupt
718    ** we won't kill that interrupt before leaving.  We'll get called right back, but we'll allow other interrupts
719    ** to process before we do get called back.
720    */
721    BREG_Write32_isr(device->hRegister, TIMER_IS_REG(device), status);
722
723    /* Process each of the timers sequentially */
724    for (timerNumber=0; timerNumber < NumberOfTimers; timerNumber++)
725    {
726        if (status & (1<<timerNumber)) {
727            /* Note: this print could print a LOT! */
728            /*BDBG_MSG(("Processing interrupt for timer number (=%d)!", timerNumber));*/
729            Physical_Timer_Isr(device, timerNumber);
730        }
731    }
732
733    /* Note: when I return the level two interrupt status will be cleared */
734}
735
736/*\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\*/
737
738static BERR_Code phys_CreateTimer_isr(BTMR_Handle device, BTMR_TimerHandle timer, const BTMR_TimerSettings *pSettings)
739{
740    BERR_Code retCode = BERR_SUCCESS;
741    int timerNumber;
742   
743    /* First, we have to select an available timer from the list of the available timers */
744    BDBG_MSG(("BTMR_CreateTimer: looking for an available timer"));
745    timerNumber = SelectAnAvailableTimer_isr(device);
746    if (timerNumber < 0) {
747        BDBG_ERR(("BTMR_CreateTimer: No timers available for create!"));
748        retCode =  BERR_TRACE(BTMR_ERR_NO_TIMERS_AVAILABLE);
749        goto done;
750    }
751    BDBG_MSG(("BTMR_CreateTimer: Using timer %d", timerNumber));
752   
753    /* If they requested a callback (and are allowed to request a callback) then register for the interrupt! */
754    if (pSettings->cb_isr)
755    {
756        if (device->alt_CbHandle)
757        {
758            uint32_t status;
759
760            if (!device->alt_CbEnabled) 
761            {
762                /* This enables the level 2 interrupt for this timer */
763                retCode = BINT_EnableCallback_isr(device->alt_CbHandle);
764                if (retCode != BERR_SUCCESS) {
765                    retCode = BERR_TRACE(retCode);
766                    BDBG_ERR(("BTMR_CreateTimer: Enable Callback failed to register interrupt!"));
767                    ReleaseThisTimer_isr(device, timerNumber);
768                    goto done;
769                }
770
771                device->alt_CbEnabled++;
772            }
773
774            /* Enable the level 3 interrupt for this timer */
775            /* I have to do this myself since this is a level 3 interrupt */
776            status = BREG_Read32_isr(device->hRegister, TIMER_IE_REG(device));
777            status |= 1<<timerNumber;
778            BREG_Write32_isr(device->hRegister, TIMER_IE_REG(device), status);
779        } 
780        else 
781        {
782            retCode = BINT_EnableCallback_isr(device->CbHandle[timerNumber]);
783            if (retCode != BERR_SUCCESS) {
784                retCode = BERR_TRACE(retCode);
785                BDBG_ERR(("BTMR_CreateTimer: Enable Callback failed to register interrupt (timer=%d)!", timerNumber));
786                ReleaseThisTimer_isr(device, timerNumber);
787                goto done;
788            }
789        }
790
791        timer->cbEnabled = true; /* remember we enabled this so we can disable in destroy */
792        BDBG_MSG(("BTMR_CreateTimer: Enabled the callback for timer %d", timerNumber));
793    }
794
795    /* Physical timers have a timer value */
796    timer->timerNumber = timerNumber;
797
798    /* *** Special case: *** Ignore exclusive flag on shared timers!
799    ** This lets anyone using the shared timer get its registers and stop it without notifying the others sharing the timer.
800    ** This is bad, but necessary -- this lets us maximize the usage of the shared timer by hardware functions that need
801    ** exclusive access but promise not to stop the timer.
802    */
803    if (pSettings->type == BTMR_Type_eSharedFreeRun)
804        timer->Settings.exclusive = false;
805   
806    /* This is the offsets to the registers for this timer */
807    /* When exclusive or shared access is requested we'll return these to the user (this is how they control this timer) */
808    timer->Registers.control = CONTROL_REG(device, timerNumber);
809    timer->Registers.status  = STATUS_REG(device, timerNumber);
810
811    device->Timers[timerNumber] = timer; /* so we can destroy created timers on close */
812   
813    /* Just to be safe, make sure the timer isn't running until they specifically start it.
814    ** Note that this will stop an external timer that they forgot to include in the open mask.
815    ** Sorry, but there's nothing I can do about that ... you should have told me to exclude it.
816    */
817    DisableTimer_isr(timer);
818   
819    /* If they asked to create a Free Run timer then this is the first use of the shared timer */
820    /* Start it ourselves -- they should NOT stop it (or restart it). */
821    if (pSettings->type == BTMR_Type_eSharedFreeRun)
822    {
823        device->SharedTimer = timer;
824        device->SharedCount = 1;
825        JustStartTimer_isr(timer, 0);
826    }
827
828    BDBG_MSG(("BTMR_CreateTimer: Successfully created new physical timer!"));
829
830  done:
831    return (retCode);
832}
833static BERR_Code phys_CreateTimer(BTMR_Handle device, BTMR_TimerHandle timer, const BTMR_TimerSettings *pSettings)
834{
835    BERR_Code status;
836    BKNI_EnterCriticalSection();
837    status = phys_CreateTimer_isr(device, timer, pSettings);
838    BKNI_LeaveCriticalSection();
839    return status;
840}
841
842static BERR_Code phys_DestroyTimer_isr(BTMR_TimerHandle timer)
843{
844    BTMR_Handle device = timer->device;
845    int timerNumber = timer->timerNumber;
846   
847    /* If I enabled the callback in the create then I need to disable it now */
848    if (timer->cbEnabled) 
849    {
850        /* Don't leave the timer running -- we don't want any interrupts from this timer anymore */
851        /* Hack: because I give out the registers for the shared timer and the fact that they can
852        ** access those registers outside of this PI, I can't control how they use this timer.
853        ** If they try to read the timer after I stop it they could hang.  There is no way for me
854        ** to fix this or tell them this is happening.
855        */
856        if (timer->running) {
857            BDBG_MSG(("BTMR_DestroyTimer: stopping timer!"));
858            JustStopTimer_isr(timer);
859        }
860
861        if (device->alt_CbHandle)
862        {
863            uint32_t status;
864
865            device->alt_CbEnabled--;
866
867            /* Disable the level two interrupt if this is the last disable */
868            if (!device->alt_CbEnabled)
869                BINT_DisableCallback_isr(device->alt_CbHandle);
870
871            /* Disable the level 3 interrupt for this timer */
872            /* I have to do this myself since this is a level 3 interrupt */
873            status = BREG_Read32_isr(device->hRegister, TIMER_IE_REG(device));
874            status &= ~(1<<timerNumber);
875            BREG_Write32_isr(device->hRegister, TIMER_IE_REG(device), status);
876        }
877        else
878        {
879            BINT_DisableCallback_isr(device->CbHandle[timerNumber]);
880        }
881
882        timer->cbEnabled = false;
883        BDBG_MSG(("BTMR_DestroyTimer: Disabled the callback for timer %d", timerNumber));
884    }
885
886    /* On the last destroy we have no more shared timers -- will be re-created on next create */
887    if (timer->Settings.type == BTMR_Type_eSharedFreeRun) {
888        device->SharedTimer = NULL;
889        device->SharedCount = 0;
890        JustStopTimer_isr(timer);
891    }
892
893    device->Timers[timerNumber] = NULL; /* we're done with this timer -- its gone! */
894    ReleaseThisTimer_isr(device, timerNumber);
895   
896    BDBG_MSG(("BTMR_DestroyTimer: Successfully destroyed physical timer!"));
897    return BERR_SUCCESS;
898}
899#if 0
900static BERR_Code phys_DestroyTimer(BTMR_TimerHandle timer)
901{
902    BERR_Code status;
903    BKNI_EnterCriticalSection();
904    status = phys_DestroyTimer_isr(timer);
905    BKNI_LeaveCriticalSection();
906    return status;
907}
908#endif
909
910static BERR_Code phys_StartTimer_isr(BTMR_TimerHandle timer, unsigned startingValue)
911{
912    uint32_t initial;
913
914#if 0 /* exclusive used to mean controlled externally -- now it means not virtual and don't share it */
915    /* They are only supposed to call this function IF the timer is NOT exclusive */
916    if (timer->Settings.exclusive) {
917        BDBG_ERR(("BTMR_StartTimer: requested START operation on exclusive timer!"));
918        return BERR_TRACE(BTMR_ERR_EXCLUSIVE_TIMER);
919    }
920#endif
921   
922    /* Starting a shared timer could mess up the others sharing this timer */
923    if (timer->Settings.type == BTMR_Type_eSharedFreeRun) {
924        BDBG_ERR(("BTMR_StartTimer: requested START operation on shared timer!"));
925        return BERR_TRACE(BTMR_ERR_FREE_RUN_TIMER);
926    }
927
928    /* They talk microseconds, we talk timer ticks */
929    initial = MicroSecondsToTimer(startingValue);
930
931    return JustStartTimer_isr(timer, initial);
932}
933
934static BERR_Code phys_StopTimer_isr(BTMR_TimerHandle timer)
935{
936#if 0 /* exclusive used to mean controlled externally -- now it means not virtual and don't share it */
937    /* They are only supposed to call this function IF the timer is NOT exclusive */
938    if (timer->Settings.exclusive) {
939        BDBG_ERR(("BTMR_StopTimer: requested STOP operation on exclusive timer!"));
940        return BERR_TRACE(BTMR_ERR_EXCLUSIVE_TIMER);
941    }
942#endif
943   
944    /* Stopping a shared timer could mess up the others sharing this timer */
945    if (timer->Settings.type == BTMR_Type_eSharedFreeRun) {
946        BDBG_ERR(("BTMR_StopTimer: requested STOP operation on shared timer!"));
947        return BERR_TRACE(BTMR_ERR_FREE_RUN_TIMER);
948    }
949
950    return JustStopTimer_isr(timer);
951}
952
953static unsigned phys_ReadTimer_isr(BTMR_TimerHandle timer)
954{
955    uint32_t runTime;
956
957    /* Stopped timers return the value of the timer when it was stopped! */
958    if (!timer->running) {
959        runTime = timer->lastValue;
960        BDBG_MSG(("BTMR_ReadTimer: (phys) read time from stopped timer (value=%x)!", runTime));
961    } else {
962        runTime = JustReadTimer_isr(timer);
963    }
964 
965    /* Stopwatch timers are relative to the initial value they supplied */
966    if (timer->Settings.type == BTMR_Type_eStopWatch) {
967        runTime += timer->initialValue;
968        if (runTime >= TimerWrap) 
969            runTime -= TimerWrap;
970    }
971   
972    /* They talk microseconds, we talk timer ticks */
973    return TimerToMicroSeconds(runTime);
974}
975
976/* These are the functions used by physical timers */
977static const ProcessingFunctions physicalFunctions = { phys_CreateTimer, phys_DestroyTimer_isr, phys_StartTimer_isr, phys_StopTimer_isr, phys_ReadTimer_isr };
978
979/*
980***********************************************************************************
981***********************************************************************************
982** These are the set of VIRTUAL timer functions (and their utility functions).
983***********************************************************************************
984***********************************************************************************
985*/
986
987/* This uses the physical free-run timer to get the runtime of the virtual timer */
988static uint32_t JustReadVirtualTimer_isr(BTMR_TimerHandle timer)
989{
990    BTMR_Handle device = timer->device;
991    uint32_t currentTime, runTime, timeLeft;
992
993    /* Start off with whatever the timer is currently at (currentTime) */
994    /* This starts with whatever is in the actual timer (its counting up) */
995    currentTime = GetTimerValue_isr(device->FreeRunTimer);
996
997    /* Account for wrap by the physical timer */
998    if (currentTime > timer->startingValue)
999        runTime = currentTime - timer->startingValue;
1000    else
1001        runTime = (TimerWrap - timer->startingValue) + currentTime;
1002
1003    if (timer->Settings.type == BTMR_Type_eStopWatch)
1004    {
1005        /* Stop Watch timers return the time expired (run-time). */
1006        /* Stop-watch timers can be supplied with a starting value -- account for that time! */
1007        runTime += timer->initialValue;
1008        if (runTime >= TimerWrap) 
1009            runTime -= TimerWrap;
1010/*printf("SW: current=%x, starting=%x, runTime=%x, initial=%x\n", currentTime, timer->startingValue, runTime, timer->initialValue);*/
1011        return runTime;
1012    }
1013    else
1014    {
1015        /* Count-down timers return the time left to run. */
1016        /* Count-down timers count down to zero -- make sure it stops at zero! */
1017        timeLeft = (timer->initialValue > runTime) ? (timer->initialValue - runTime) : 0;
1018/*printf("CD: current=%x, starting=%x, runTime=%x, initial=%x, timeleft=%x\n", currentTime, timer->startingValue, runTime, timer->initialValue, timeLeft);*/
1019        return timeLeft;
1020    }
1021}
1022
1023/* A sorted list is kept for the virtual count-down timers.  The order determines who times out next! */
1024/* Each item on the list has an adjusted timeout value that is the time DIFFERENCE from the item before it. */
1025
1026/* This puts items onto the sorted time-out list (on start timer request).
1027** We use a physical timer to timeout the smallest virtual timeout reqest.  If the new item's timeout
1028** is smaller than the currently running timer (if any) then it will stop the physical timer,
1029** account for the time the timer already ran, and restart the timer with the new timeout.  The old
1030** (was running) timer's timeout value will be adjusted for time already processed (its already on the queue).
1031*/
1032static void PutTimerOnTimeoutQueue_isr(BTMR_Handle device, BTMR_TimerHandle timer)
1033{
1034    timer->adjustedValue = timer->initialValue;
1035
1036    /* There are three cases to consider here:
1037    ** 1) Empty list -- no timer currently running.
1038    ** 2) New head item -- new timeout is less than currently running timer's timeout value.
1039    ** 3) Other -- new timeout is larger than currently running timer's timeout value.
1040    */
1041   
1042    if (BLST_D_EMPTY(&device->TimeoutList))
1043    {
1044        /* 1) If list is empty, then this is a new timeout value -- just start the timer */
1045        BLST_D_INSERT_HEAD(&device->TimeoutList, timer, link);
1046        JustStartTimer_isr(device->CountDownTimer, timer->adjustedValue);
1047    }
1048    else
1049    {
1050        /* If the list is NOT empty then we need to add this timer to the list in the appropriate location */
1051        uint32_t timeLeft;
1052        BTMR_TimerHandle walker = BLST_D_FIRST(&device->TimeoutList);
1053       
1054        timeLeft = JustReadTimer_isr(device->CountDownTimer);
1055
1056        /* 2) Is the timeout of the new item is smaller than the remaining timeout of the currently running timer? */
1057        /* If so then we need to stop the timer, count off how must time has elapsed, and adjust the head item's timeout value. */
1058        if (timer->initialValue < timeLeft)
1059        {
1060            JustStopTimer_isr(device->CountDownTimer);
1061
1062            BLST_D_INSERT_BEFORE(&device->TimeoutList, walker, timer, link);
1063            walker->adjustedValue = timeLeft - timer->initialValue;
1064
1065            JustStartTimer_isr(device->CountDownTimer, timer->initialValue);
1066        }
1067        else
1068        {
1069            bool added = false;
1070            BTMR_TimerHandle last = walker;
1071
1072            /* Account for the timeout of the currently running (or soon to be running) timer */
1073            timer->adjustedValue -= timeLeft;
1074           
1075            /* 3) We need to find the best place to put this new timeout. We adjust his timeout value as we skip over items. */
1076            /* Once found, we insert him and adjust the timeout of the guy that comes after him to account for the new timeout */
1077            for (walker = BLST_D_NEXT(walker, link); walker; last = walker, walker = BLST_D_NEXT(walker, link))
1078            {
1079                if (timer->adjustedValue < walker->adjustedValue)
1080                {
1081                    BLST_D_INSERT_BEFORE(&device->TimeoutList, walker, timer, link);
1082                    walker->adjustedValue -= timer->adjustedValue;
1083                    added = true;
1084                    break;
1085                }
1086                timer->adjustedValue -= walker->adjustedValue;
1087            }
1088
1089            /* If the new item is larger timeout then all the others then it goes onto the end of the list! */
1090            if (!added) {
1091                BLST_D_INSERT_AFTER(&device->TimeoutList, last, timer, link);
1092            }
1093        }
1094    }
1095}
1096
1097/* This takes an item off the sorted timeout list (on stop timer request).
1098** If the item was the head then it stops the timer and starts the next item on the queue.
1099** This assumes that the hardware timer is already running with either this timer or another timer.
1100*/
1101static void TakeTimerOffTimeoutQueue_isr(BTMR_Handle device, BTMR_TimerHandle timer)
1102{
1103    BTMR_TimerHandle head, next;
1104   
1105    /* There are two cases to consider here:
1106    ** 1) We're removing the head entry (and need to reset the timer).
1107    ** 2) Other -- we're removing a scheduled timeout that hasn't been scheduled yet.
1108    */
1109
1110    head = BLST_D_FIRST(&device->TimeoutList);
1111    if (!head) {
1112        BDBG_ERR(("Told to delete timer from an empty timeout queue -- ignoring!"));
1113        /*BKNI_Fail();*/ /* I should really panic, right??? */
1114        return;
1115    }
1116    next = BLST_D_NEXT(timer, link);
1117   
1118    if (timer == head)
1119    {
1120        /* 1) If the item being deleted is the head item we have to account for the amount of time the timer has left to run... */
1121        uint32_t timeLeft = JustReadVirtualTimer_isr(timer);
1122
1123        JustStopTimer_isr(device->CountDownTimer);
1124
1125        BLST_D_REMOVE(&device->TimeoutList, timer, link);
1126
1127        /* Adjust any next item AND start up a new timer (if there is one) */
1128        if (next) {
1129            next->adjustedValue += timeLeft;
1130            JustStartTimer_isr(device->CountDownTimer, next->adjustedValue);
1131        }
1132    }
1133    else
1134    {
1135        BLST_D_REMOVE(&device->TimeoutList, timer, link);
1136
1137        /* 2) If the item being deleted is NOT the head item then we only need to adjust the next guy's timeout value */
1138        if (next)
1139            next->adjustedValue += timer->adjustedValue;
1140    }
1141}
1142
1143/*
1144** This is my ISR function for the virtual count-down timers!
1145** This is registered as the callback for the physical timer used to process the virtual count-down timers.
1146** It is registered at at 'create' and disabled at 'destroy'.
1147** This performs the callbacks to the owner of the virtual timer.
1148** This is called back from the hardware ISR so this is run at ISR level.
1149*/
1150
1151static void Virtual_Timer_Isr(BTMR_Handle device)
1152{
1153    BTMR_TimerHandle timer, last;
1154    BTMR_TimerSettings *context;
1155
1156    /* Not getting a device means we have a logic error in our physical timer processing */
1157    BDBG_ASSERT(device);
1158    /* We should never be called here when there are no virtual timers running! */
1159    BDBG_ASSERT(!BLST_D_EMPTY(&device->TimeoutList));
1160    /* There should never be anything on the "to do" list */
1161    BDBG_ASSERT(BLST_D_EMPTY(&device->ToBeProcessedList));
1162
1163    /* The timer should already be stopped, but ... */
1164    JustStopTimer_isr(device->CountDownTimer);
1165
1166    /*BDBG_WRN(("Virtual timer interrupt"));*/
1167
1168    /* This is called from the registered hardware ISR for this timer (for the CountDownTimer).
1169    ** It stopped the timer as part of the ISR processing.
1170    ** The timer only interrupts if it counted up to its adjusted value.
1171    */
1172
1173    /* This interrupt occured because we have (at least) one count-down timer running and the next timer
1174    ** to timeout (smallest timeout) just timed out.  We pull off ALL the timers that expired (could be
1175    ** more than one) and queue them up for processing.  The benefit of delaying the processing is that
1176    ** a timer's callback function will not impact us from starting up the next virtual timer.
1177    */
1178    timer = BLST_D_FIRST(&device->TimeoutList);
1179    BDBG_ASSERT(timer);
1180    last = NULL;
1181
1182    do {
1183        BLST_D_REMOVE_HEAD(&device->TimeoutList, link);
1184
1185        if (BLST_D_EMPTY(&device->ToBeProcessedList))
1186            BLST_D_INSERT_HEAD(&device->ToBeProcessedList, timer, link);
1187        else
1188            BLST_D_INSERT_AFTER(&device->ToBeProcessedList, last, timer, link);
1189
1190        /* We flag this timer as processing in case they try to start/stop the timer in the call-back function */
1191        timer->processing = true;
1192        timer->running = false;
1193
1194        /* We don't need to physically stop the timer as it doesn't really exist */
1195        timer->lastValue = 0; /* count down timers always stop at zero */
1196
1197        last = timer;
1198        timer = BLST_D_FIRST(&device->TimeoutList);
1199
1200    } while (timer && timer->adjustedValue <= BTMR_MIN_HOLD);
1201
1202    /* If there is another timer waiting to start -- well, then start it! */
1203    if (timer) JustStartTimer_isr(device->CountDownTimer, timer->adjustedValue);
1204
1205    /* We now have a list of timers that need to be processed (i.e. process the call-back).
1206    ** If its a periodic timer, put it back onto the timer list.
1207    ** We do this as a separate pass so that we can get the timer running again (with the next timer) as soon as possible.
1208    ** This way, the callback from a timer will not effect the time of the next timer.
1209    ** This will however affect the start time of a periodic timer -- we'll restart the timer after the call-back returns.
1210    */
1211    while ((timer = BLST_D_FIRST(&device->ToBeProcessedList)))
1212    {
1213        BLST_D_REMOVE_HEAD(&device->ToBeProcessedList, link);
1214
1215        /* This timer expired!  Let the owner know it expired! */
1216        /* If we have a callback function for this timer, then its time to call it! */
1217        /* Note: this is processing count-down timers so there had BETTER be a call-back function!!! */
1218        context = &timer->Settings;
1219        if (context->cb_isr)
1220            context->cb_isr(context->pParm1, context->parm2); 
1221
1222        /* We're done processing this timer so its okay to stop or delete it now */
1223        timer->processing = false;
1224
1225        /* Periodic timers continue to go off until stopped -- start it up again! */
1226        /* They may have asked us to stop the timer in the callback.  We delayed this until done processing the call-back. */
1227        /* If they asked us to stop the timer then just don't start it back up. */
1228        if (context->type == BTMR_Type_ePeriodic && !timer->pleaseStop) {
1229            timer->startingValue = GetTimerValue_isr(device->FreeRunTimer);
1230            PutTimerOnTimeoutQueue_isr(device, timer);
1231            timer->running = true;
1232        }
1233
1234        /* If they requested a count-down timer to be restarted in the call-back then do it now. */
1235        if (context->type == BTMR_Type_eCountDown && timer->pleaseStart) {
1236            BTMR_StartTimer_isr(timer, timer->delayedValue);
1237        }
1238
1239        /* Make sure these are cleared before leaving (in case they tried to start a periodic or stop a countdown) */
1240        timer->pleaseStop  = false;
1241        timer->pleaseStart = false;
1242    }
1243}
1244
1245/*\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\*/
1246
1247/* Create the (two) timers we need to handle virtual timers */
1248/* This is used in the open call when requested to allocate these timers statically or in create call for dynamic when these are actually needed. */
1249static BERR_Code CreateUtilityTimers(BTMR_Handle device)
1250{
1251    /* If we've already created the timers needed for supporting virtual timers then nothing to do */
1252    if (device->CountDownTimer) return BERR_SUCCESS;
1253
1254    BDBG_MSG(("Creating utility timers ..."));
1255
1256    /* We need one physical timer in order to use virtual count-down timers.
1257    ** This timer will be controlled by our call back function (runs at ISR time).
1258    */
1259    {
1260        BTMR_TimerSettings settings = { BTMR_Type_eCountDown, (BTMR_CallbackFunc)Virtual_Timer_Isr, NULL, 0, true };
1261        settings.pParm1 = device; /* needs to be set at runtime */
1262        if (_BTMR_CreateTimer(device, &device->CountDownTimer, &settings, "CountDown", 0) != BERR_SUCCESS) {
1263            BDBG_ERR(("Failed to create physical timer needed for supporting virtual count-down timers!"));
1264            return BERR_TRACE(BTMR_ERR_NO_TIMERS_AVAILABLE);
1265        }
1266        BLST_D_INIT(&device->TimeoutList);
1267        BLST_D_INIT(&device->ToBeProcessedList);
1268        BDBG_MSG(("Created physical timer needed for supporting virtual CD timers (using timer %d)!", device->CountDownTimer->timerNumber));
1269    }
1270   
1271    /* We'll use THE one shared timer in order to use virtual stop-watch (free-run) timers.
1272    ** This just runs the timer and uses the timer value to generate a current time value.
1273    ** Note: if a shared timer was allocated previously then this will use that shared timer.
1274    ** If no shared timer was previously created then this call will create THE shared timer.
1275    */
1276    {
1277        BTMR_TimerSettings settings = { BTMR_Type_eSharedFreeRun, NULL, NULL, 0, true };
1278        settings.pParm1 = device; /* needs to be set at runtime */
1279        if (_BTMR_CreateTimer(device, &device->FreeRunTimer, &settings, "FreeRun", 0) != BERR_SUCCESS) {
1280            _BTMR_DestroyTimer(device->CountDownTimer, "CountDown", 0);
1281            device->CountDownTimer = NULL;
1282            BDBG_ERR(("Failed to create shared timer needed for supporting virtual free-run timers!"));
1283            return BERR_TRACE(BTMR_ERR_NO_TIMERS_AVAILABLE);
1284        }
1285        BDBG_MSG(("Created (shared) timer needed for supporting virtual FR timers (using timer %d)!", device->FreeRunTimer->timerNumber));
1286    }
1287
1288    return BERR_SUCCESS;
1289}
1290
1291/* Destroy the timers we created for handling the virtual timers */
1292static void DestroyUtilityTimers(BTMR_Handle device)
1293{
1294    /* If the timers were never created than nothing to destroy */
1295    if (!device->CountDownTimer) return;
1296
1297    BDBG_MSG(("Destroying utility timers ..."));
1298
1299    if (device->CountDownTimer) {
1300        _BTMR_DestroyTimer(device->CountDownTimer, "CountDown", 0);
1301        device->CountDownTimer = NULL;
1302    }
1303    if (device->FreeRunTimer) {
1304        _BTMR_DestroyTimer(device->FreeRunTimer, "FreeRun", 0);
1305        device->FreeRunTimer = NULL;
1306    }
1307    BDBG_MSG(("Destroyed timers needed for supporting virtual timers!"));
1308}
1309
1310/* This is used by open to clean up on error and close to disable level two interrupts */
1311static void DestroyCallbacks(BTMR_Handle device)
1312{
1313    int timerNumber;
1314
1315    /* The first thing we want to do is stop any running timers and make sure we won't be getting anymore interrupts */
1316    for (timerNumber=0; timerNumber<NumberOfTimers; timerNumber++)
1317    {
1318        /* Skip timers we don't control (excluded in the open) */
1319        if (device->Settings.timerMask & TimerSelect(timerNumber)) continue;
1320
1321        /* If we created the callback in the open, make sure we don't have any pending interrupts */
1322        if (device->Settings.interruptNumber)
1323        {
1324            if (device->alt_CbHandle) {
1325                /*BINT_ClearCallback(device->alt_CbHandle);*/ /* not necessary -- destroy handles this */
1326                BINT_DisableCallback(device->alt_CbHandle);
1327                BINT_DestroyCallback(device->alt_CbHandle);
1328                device->alt_CbHandle = NULL;
1329                device->alt_CbEnabled = 0;
1330            }
1331        }
1332        else
1333        {
1334            if (device->CbHandle[timerNumber]) {
1335                /*BINT_ClearCallback(device->CbHandle[timerNumber]);*/ /* not necessary -- destroy handles this */
1336                BINT_DisableCallback(device->CbHandle[timerNumber]);
1337                BINT_DestroyCallback(device->CbHandle[timerNumber]);
1338                device->CbHandle[timerNumber] = NULL;
1339            }
1340        }
1341
1342        /* If the callback is enabled for this timer then it isn't anymore */
1343        if (device->Timers[timerNumber])
1344            device->Timers[timerNumber]->cbEnabled = false;
1345    }
1346}
1347
1348/*\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\*/
1349
1350static BERR_Code virt_CreateTimer_isr(BTMR_Handle device, BTMR_TimerHandle timer, const BTMR_TimerSettings *pSettings)
1351{
1352    BERR_Code retCode = BERR_SUCCESS;
1353
1354    BSTD_UNUSED(pSettings); /* the phys version needs the settings, the virt version does not */
1355 
1356    /* Virtual timers don't have an actual timer number -- only physical timers do */
1357    timer->timerNumber = -1;
1358
1359    BDBG_MSG(("BTMR_CreateTimer: Successfully created new virtual timer!"));
1360    BLST_D_INSERT_HEAD(&device->VirtualCreateList, timer, created);
1361    device->VirtualCount++;
1362
1363    return (retCode);
1364}
1365static BERR_Code virt_CreateTimer(BTMR_Handle device, BTMR_TimerHandle timer, const BTMR_TimerSettings *pSettings)
1366{
1367    BERR_Code status;
1368
1369    /* We need some utility timers for handling virtual timers, so create them on first use */
1370    /* Note: This will succeed if they already exist (i.e. allocated statically in Open) */
1371    if (device->VirtualCount == 0) {
1372        if (CreateUtilityTimers(device) != BERR_SUCCESS) {
1373            return BERR_TRACE(BTMR_ERR_NO_TIMERS_AVAILABLE);
1374        }
1375    }
1376
1377    BKNI_EnterCriticalSection();
1378    status = virt_CreateTimer_isr(device, timer, pSettings);
1379    BKNI_LeaveCriticalSection();
1380    return status;
1381}
1382
1383static BERR_Code virt_DestroyTimer_isr(BTMR_TimerHandle timer)
1384{
1385    BTMR_Handle device = timer->device;
1386
1387    /* It would be bad to free up a timer that is running -- it could be linked onto a list, etc.
1388    ** We have to make sure its stopped before we delete it!
1389    ** Don't use virt_StopTimer_isr as the processing tests gets done in the higher level functions.
1390    */
1391    if (timer->running) BTMR_StopTimer_isr(timer);
1392   
1393    BDBG_MSG(("BTMR_DestroyTimer: Successfully destroyed virtual timer!"));
1394    BLST_D_REMOVE(&device->VirtualCreateList, timer, created);
1395    device->VirtualCount--;
1396
1397    return BERR_SUCCESS;
1398}
1399#if 0
1400static BERR_Code virt_DestroyTimer(BTMR_TimerHandle timer)
1401{
1402    BERR_Code status;
1403    BTMR_Handle device = timer->device;
1404
1405#if 0
1406    /* We created some utility timers needed for processing virtual timers.
1407    ** If this is the last virtual timer then we don't need these anymore.
1408    */
1409    if (device->VirtualCount == 1)
1410        DestroyUtilityTimers(device);
1411#endif
1412
1413    BKNI_EnterCriticalSection();
1414    status = virt_DestroyTimer_isr(timer);
1415    BKNI_LeaveCriticalSection();
1416    return status;
1417}
1418#endif
1419
1420static BERR_Code virt_StartTimer_isr(BTMR_TimerHandle timer, unsigned startingValue)
1421{
1422    BTMR_Handle device = timer->device;
1423
1424    /* Should I let them start a running timer??? */
1425    /* The problem here is that if they forgot to stop the timer and believe that this is actually
1426    ** starting the timer then they aren't going to get what they expected and won't know why.
1427    ** We have three choices here: 1) don't let them start a started timer, 2) stop the timer and restart
1428    ** with the new parameters, or 3) just say okay and keep going.
1429    */
1430    if (timer->running) 
1431    {
1432#if 0
1433        BDBG_ERR(("BTMR_StartTimer: timer already started!"));
1434        return BERR_TRACE(BTMR_ERR_ALREADY_STARTED);
1435#else
1436        goto done; /* its already started -- success! (this is choice 3) */
1437#endif
1438    }
1439   
1440    /* They talk microseconds, we talk timer ticks */
1441    timer->initialValue = MicroSecondsToTimer(startingValue);
1442
1443    /* We'll use the free running timer to provide time values when user tries to read the current time */
1444    timer->startingValue = GetTimerValue_isr(device->FreeRunTimer);
1445    timer->lastValue = 0;
1446   
1447    /* If its a free run timer then its already running -- we use the physical free run timer for the time calculations.
1448    ** If its a count-down type timer then we need to use the physical count-down timer to do the timing.
1449    ** That timer is shared by other count-down type timers so we queue it up for processing.
1450    */
1451    if (timer->Settings.type == BTMR_Type_eCountDown || timer->Settings.type == BTMR_Type_ePeriodic)
1452        PutTimerOnTimeoutQueue_isr(device, timer);
1453 
1454    timer->running = true;
1455
1456  done:
1457    return BERR_SUCCESS;
1458}
1459
1460static BERR_Code virt_StopTimer_isr(BTMR_TimerHandle timer)
1461{
1462    BTMR_Handle device = timer->device;
1463
1464    /* Should I let them stop a stopped timer??? */
1465    /* We have two choices here: 1) don't let them stop a stopped timer or 2) just say okay and keep going.  */
1466    if (!timer->running)
1467    {
1468#if 0
1469        BDBG_ERR(("BTMR_StopTimer: timer already stopped!"));
1470        return BERR_TRACE(BTMR_ERR_ALREADY_STOPPED);
1471#else
1472        goto done; /* its already stopped -- success! (this is choice 2) */
1473#endif
1474    }
1475 
1476    timer->lastValue = JustReadVirtualTimer_isr(timer);
1477   
1478    /* If its a free-run timer then we save a "last" (stopped) value above.
1479    ** If its a count-down type timer then its either running, queued to be run, or stopped.
1480    ** Regardless, we just dequeue the item so that it doesn't continue to run.
1481    */
1482    if (timer->Settings.type == BTMR_Type_eCountDown || timer->Settings.type == BTMR_Type_ePeriodic)
1483        TakeTimerOffTimeoutQueue_isr(device, timer);
1484
1485    timer->running = false;
1486
1487  done:
1488    return BERR_SUCCESS;
1489}
1490
1491static unsigned virt_ReadTimer_isr(BTMR_TimerHandle timer)
1492{
1493    uint32_t runTime;
1494
1495    /* Stopped timers return the value of the timer when it was stopped! */
1496    if (!timer->running) {
1497        runTime = timer->lastValue;
1498        BDBG_MSG(("BTMR_ReadTimer: (virt) read time from stopped timer (value=%x)!", runTime));
1499    } else {
1500        runTime = JustReadVirtualTimer_isr(timer);
1501    }
1502
1503    /* They talk microseconds, we talk timer ticks */
1504    return TimerToMicroSeconds(runTime);
1505}
1506
1507/* These are the functions used by virtual timers */
1508static const ProcessingFunctions virtualFunctions = { virt_CreateTimer, virt_DestroyTimer_isr, virt_StartTimer_isr, virt_StopTimer_isr, virt_ReadTimer_isr };
1509
1510/*
1511***********************************************************************************
1512***********************************************************************************
1513** These are the set of published timer functions (available for external use).
1514***********************************************************************************
1515***********************************************************************************
1516*/
1517
1518BERR_Code BTMR_Open(BTMR_Handle *phDevice,
1519                    BCHP_Handle hChip, BREG_Handle hRegister, BINT_Handle hInterrupt,
1520                    const BTMR_DeviceSettings *pOpenSettings)
1521{
1522    BTMR_Handle device;
1523    BERR_Code retCode = BERR_SUCCESS;
1524    int timerNumber, timersInitialized = 0;
1525
1526    /* Sanity check on the handles we've been given */
1527    BDBG_ENTER(BTMR_Open);
1528    BDBG_ASSERT(phDevice);
1529    BDBG_ASSERT(hRegister);
1530    BDBG_ASSERT(hInterrupt);
1531    /* Note: They don't have to give me the settings, I'll just use the default */
1532   
1533    /* Some say I shouldn't mess with the return variable unless I return success... */
1534    *phDevice = NULL; /* just to be sure caller doesn't use it */
1535
1536    device = (BTMR_Handle) BKNI_Malloc(sizeof(*device));
1537    if (device == NULL)
1538    {
1539        BDBG_ERR(("BTMR_Open: Memory allocation failed!"));
1540        retCode =  BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
1541        goto done;
1542    }
1543
1544    BKNI_Memset(device, 0, sizeof(*device));
1545    BDBG_OBJECT_SET(device, btmr_device_t);
1546
1547    retCode = BKNI_CreateMutex(&device->create_destroy_mutex);
1548    if (retCode != BERR_SUCCESS) 
1549    {
1550        BDBG_ERR(("BTMR_Open: Mutext (create_destroy) allocation failed!"));
1551        retCode = BERR_TRACE(retCode);
1552        goto error2;
1553    }
1554
1555    device->hChip      = hChip;
1556    device->hRegister  = hRegister;
1557    device->hInterrupt = hInterrupt;
1558
1559    if (pOpenSettings)
1560        BKNI_Memcpy(&device->Settings, pOpenSettings, sizeof(BTMR_DeviceSettings));
1561    else
1562        BTMR_GetDefaultDeviceSettings(&device->Settings);
1563
1564    /* Default this to the default timer set (in case they didn't use get defaults) */
1565    if (!device->Settings.baseRegister) {
1566        device->Settings.baseRegister = BCHP_TIMER_REG_START;
1567        device->Settings.interruptNumber = 0;
1568    }
1569
1570    BDBG_MSG(("BTMR_Open: device=%p using MASK %#x (pOpenSettings=%p)", (void*)device, device->Settings.timerMask, pOpenSettings));
1571    BDBG_CASSERT(NumberOfTimers==4); /* note: you have to fix the table below when changing the number of timers */
1572       
1573    /* If this timer block uses a level three interrupt then we have ONE callback for all the timers */
1574    /* Level two interrupts have their own individual interrupts */
1575    if (device->Settings.interruptNumber)
1576    {
1577        BDBG_MSG(("Interrupt number specified (using level 3)"));
1578
1579        for (timerNumber=0; timerNumber<NumberOfTimers; timerNumber++) 
1580        {
1581            /* We only setup a callback for the timers we're supposed to control (i.e. ones NOT reserved) */
1582            if (device->Settings.timerMask & TimerSelect(timerNumber)) {
1583                BDBG_WRN(("Timer %u is reserved (skipping)", timerNumber));
1584                continue;
1585            }
1586
1587            /* Make sure this timer is not running from a previous run (if they ^C out before) */
1588            DisableTimerNumber(device, timerNumber);
1589
1590            timersInitialized++;  /* got at least one! */
1591        }
1592
1593        if (timersInitialized) 
1594        {
1595            BERR_Code result;
1596
1597            /* This is where we setup the interrupt callback for the timers. */
1598            /* Note: we have to fail if we couldn't enable the level two interrupt for all these timers */
1599            result = BINT_CreateCallback(&device->alt_CbHandle, hInterrupt, device->Settings.interruptNumber,
1600                                      (BINT_CallbackFunc)Physical_Timer_Selection_Isr, (void *)device, 0);
1601            if (result != BERR_SUCCESS) {
1602                BDBG_ERR(("BTMR_Open: Create Callback for interrupt failed!"));
1603                goto error2;
1604            }
1605
1606            BINT_ClearCallback(device->alt_CbHandle);
1607        }
1608    }
1609    else
1610    {
1611        BDBG_MSG(("Interrupt number not specified (using level 1)"));
1612
1613        /* Create a callback for each of the timers we're controlling (but enable later) */
1614        for (timerNumber=0; timerNumber<NumberOfTimers; timerNumber++)
1615        {
1616            BERR_Code result;
1617            BINT_Id intId=0;
1618
1619            /* We only setup a callback for the timers we're supposed to control (i.e. ones NOT reserved) */
1620            if (device->Settings.timerMask & TimerSelect(timerNumber)) {
1621                BDBG_WRN(("Timer %u is reserved (skipping)", timerNumber));
1622                continue;
1623            }
1624       
1625            /* Make sure this timer is not running from a previous run (if they ^C out before) */
1626            DisableTimerNumber(device, timerNumber);
1627
1628            /*TODO: think of a way to set the intId value without having to resort to using the separate masks? */
1629
1630            switch (timerNumber) {
1631                case 0: intId = BCHP_INT_ID_TMR0TO; break;
1632                case 1: intId = BCHP_INT_ID_TMR1TO; break;
1633                case 2: intId = BCHP_INT_ID_TMR2TO; break;
1634                case 3: intId = BCHP_INT_ID_TMR3TO; break;
1635            }
1636
1637            /* This is where we setup the interrupt callback for the timers WE control. */
1638            /* Note: we don't have to fail just because we can't setup this call back -- just make it un-available! */
1639            result = BINT_CreateCallback(&device->CbHandle[timerNumber], hInterrupt, intId,
1640                                      (BINT_CallbackFunc)Physical_Timer_Isr, (void *)device, timerNumber);
1641            if (result != BERR_SUCCESS) {
1642                BDBG_ERR(("BTMR_Open: Create Callback for interrupt failed (timer=%d)!", timerNumber));
1643                device->Settings.timerMask |= TimerSelect(timerNumber);
1644                device->CbHandle[timerNumber] = NULL;
1645                continue;
1646            }
1647
1648            /* Make sure this interrupt is clear long before we enable it in the create funtion */
1649            /* Note: the comments for the create says is clears this, but an extra call shouldn't hurt */
1650            BINT_ClearCallback(device->CbHandle[timerNumber]);
1651            timersInitialized++;  /* got at least one! */
1652        }   
1653    }
1654
1655    /* Its possible that all of the timers are being used outside of this driver or that we couldn't create the callback for
1656    ** any of the timers that we will control.  This means we can't create the timers we need to support virtual timers!
1657    ** This can either be considered an error or return success and then fail whenever someone wants to create a timer.
1658    ** I think this should be an error!
1659    */
1660    if (!timersInitialized) {
1661        BDBG_ERR(("BTMR_Open: failed to initialize any physical timers (all physical timers are being used externally)!"));
1662        retCode = BERR_TRACE(BTMR_ERR_NO_TIMERS_AVAILABLE);
1663        goto error2;
1664    }
1665   
1666    /* Assume that any timer reserved is already "in use" */
1667    device->inUse = device->Settings.timerMask;
1668
1669    /* If using static utility timers, create the physical timers we need to handle virtual timers */
1670    /* Otherwise, we'll create the timers needed when someone requests a virtual timer */
1671    if (device->Settings.preallocUtilTimers && CreateUtilityTimers(device) != BERR_SUCCESS) {
1672        BDBG_ERR(("BTMR_Open: failed to create utility timers needed to support virtual timers!"));
1673        retCode = BERR_TRACE(BTMR_ERR_NO_TIMERS_AVAILABLE);
1674        goto error1;
1675    }
1676
1677    BLST_D_INIT(&device->VirtualCreateList);
1678
1679    *phDevice = device; /* here's your handle for creating timers! */
1680    goto done;
1681
1682  error1:
1683    DestroyCallbacks(device);
1684
1685  error2:
1686    if (device->create_destroy_mutex)  BKNI_DestroyMutex(device->create_destroy_mutex);
1687    BDBG_OBJECT_DESTROY(device, btmr_device_t);
1688    BKNI_Free(device);
1689
1690  done:
1691    BDBG_LEAVE(BTMR_Open);
1692    return (retCode);
1693}
1694
1695BERR_Code BTMR_Close(BTMR_Handle device)
1696{
1697    int timerNumber, timersLeftOpen;
1698    BTMR_TimerHandle timer;
1699   
1700    BDBG_ENTER(BTMR_Close);
1701    BDBG_OBJECT_ASSERT(device, btmr_device_t);
1702
1703    BDBG_MSG(("BTMR_Close: device=%p", (void*)device));
1704
1705    /* When our close is called, modules with outstanding timers should have already destroyed them.
1706    ** But that doesn't mean they did.  There are a couple of things we can do about this:
1707    ** 1) indicate that there were virtual timers left open and clean them up.
1708    ** 2) indicate there are outstanding shared timers (no clean-up necessary).
1709    ** 3) indicate that there are pending exclusive timers left open and clean them up.
1710    ** The clean-up is only so that we don't get yelled at for closing with allocated memory pending.
1711    ** We allocated it for someone else, but it'll still be our name on the error message and problem report.
1712    ** Use the compile flags to not do the cleanup (_DESTROY_ON_CLOSE_) or not be so nice about it (_FAIL_ON_CLOSE_).
1713    */
1714
1715    /* Disable any interrupts and callbacks associated with the registered interrupt */
1716    DestroyCallbacks(device);
1717
1718    /* From this point on we won't be getting any interrupts from any timers we control! */
1719
1720    /* Don't leave any of the timers running (not that it'll hurt anything).
1721    ** Note: if someone is still using this timer, even though it should be closed, this could cause a problem if he enters a wait loop.
1722    */
1723    BKNI_EnterCriticalSection();
1724    for (timerNumber=0; timerNumber<NumberOfTimers; timerNumber++)
1725    {
1726        /* Skip timers we don't control and stop the ones we do */
1727        if (device->Settings.timerMask & TimerSelect(timerNumber)) continue;
1728        if (device->Timers[timerNumber]) JustStopTimer_isr(device->Timers[timerNumber]);
1729    }
1730    BKNI_LeaveCriticalSection();
1731
1732    /* If we have outstanding virtual timers then we allocated context for each one.
1733    ** The owner was supposed to destroy the timer before the close was called, but ...
1734    ** We should probably make this into a fail at some point (but not yet)!
1735    */
1736    if (device->VirtualCount) 
1737    {
1738        BDBG_ERR(("BTMR_Close: called with %d outstanding virtual timers (resource leak)!", device->VirtualCount));
1739        timer = BLST_D_FIRST(&device->VirtualCreateList);
1740        while (timer)
1741        {
1742            BTMR_TimerHandle next = BLST_D_NEXT(timer, created);
1743            BDBG_ERR(("BTMR_Close: virtual timer created but never destroyed (created: %s,%d)", timer->file, timer->line));
1744#ifdef _DESTROY_ON_CLOSE_
1745            BTMR_DestroyTimer(timer);
1746#endif
1747            timer = next;
1748        }
1749#ifdef _FAIL_ON_CLOSE_
1750        BKNI_Fail();
1751#endif
1752    }
1753
1754    /* We may have statically allocated a shared or virtual timer as part of the open.  Free them up now. */
1755    DestroyUtilityTimers(device);
1756
1757    /* This is just informative.
1758    ** Unlike virtual timers (where we created context) all the shared timers use the same context so we can't keep track of who created them.
1759    ** So its not important that we clean these up other than to make sure the timer is stopped.
1760    */
1761    if (device->SharedCount) {
1762        BDBG_ERR(("BTMR_Close: called with %d outstanding shared timers (resource leak)!", device->SharedCount));
1763        device->SharedCount = 1; /* hack to make sure we really destroy the timer below (gets done on 1->0 transition) */
1764#ifdef _FAIL_ON_CLOSE_
1765        BKNI_Fail();
1766#endif
1767    }
1768
1769    /*
1770    ** Note: At this point, we've cleaned up after ourselves.  We've also done some clean up after others (virtual and shared timers).
1771    ** The only thing left to do is clean up any pending exclusive timers that did not get freed up before calling close.
1772    ** This is not something we're required to do, but this will prevent someone from thinking the TMR code exited with allocated memory.
1773    */
1774
1775    timersLeftOpen = 0;
1776    for (timerNumber=0; timerNumber<NumberOfTimers; timerNumber++)
1777    {
1778        /* Destroy any existing timers (frees resources used in create) */
1779        /* Note: this doesn't prevent someone that didn't destroy their timer from attempting to continue to use it... */
1780        if ((timer = device->Timers[timerNumber]))
1781        {
1782            /* Special case the shared timer -- it won't correctly reflect who created but didn't destroy */
1783            if (timer->Settings.type == BTMR_Type_eSharedFreeRun) {
1784                BDBG_ERR(("BTMR_Close: physical timer created but never destroyed"));
1785            } else {
1786                BDBG_ERR(("BTMR_Close: physical timer created but never destroyed (created: %s,%d)", timer->file, timer->line));
1787            }
1788#ifdef _DESTROY_ON_CLOSE_
1789            BTMR_DestroyTimer(timer);
1790#endif
1791            timersLeftOpen++;
1792        }
1793    }
1794    if (timersLeftOpen) {
1795        BDBG_ERR(("BTMR_Close: called with %d outstanding physical timers pending (resource leak)!", timersLeftOpen));
1796#ifdef _FAIL_ON_CLOSE_
1797        BKNI_Fail();
1798#endif
1799    }
1800 
1801    BKNI_DestroyMutex(device->create_destroy_mutex);
1802
1803    /* Mark it invalid in case he tries to give it to me again (close twice) */
1804    /* Note: this probably won't happen as the memory will be reassigned and stepped on, but ... */
1805    BDBG_OBJECT_DESTROY(device, btmr_device_t);
1806    BKNI_Free(device);
1807
1808    BDBG_LEAVE(BTMR_Close);
1809    return BERR_SUCCESS;
1810}
1811
1812static const BTMR_DeviceSettings DefaultDeviceSettings = { 
1813    0,                    /* don't reserve any timers for private use */
1814    false,                /* dynamically allocate timer(s) needed for virtual timers */
1815    BCHP_TIMER_REG_START, /* default to primary TMR block */
1816    0                     /* use default interrupt numbers */
1817};
1818
1819BERR_Code BTMR_GetDefaultDeviceSettings(BTMR_DeviceSettings *pSettings)
1820{
1821    BDBG_ASSERT(pSettings); /* don't write results to zero */
1822
1823    BKNI_Memcpy(pSettings, &DefaultDeviceSettings, sizeof(BTMR_DeviceSettings));
1824
1825#if 0 && defined(BCHP_WKTMR_REG_START)
1826    /* Don't use timer 3 on chips that are lacking WKTMR support, the kernel may be using it */
1827    /* This should be handled outside of this PI (in the open call) but might be easier to handle it here. */
1828    pSettings->timerMask |= 1<<3;   
1829    BDBG_ERR(("Setting mask to %p", pSettings->timerMask));
1830#endif
1831
1832    return BERR_SUCCESS;
1833}
1834
1835/* We need to recursively create timers when dynamically creating the utility timers needed for processing virtual timers.
1836** Because the CreateTimer function is re-entrant, this could allow us to try to crete the utility timers from two different tasks.
1837** A semaphore was added to mutually exclude the timer creates from occurring at the same time.  This function allows us to
1838** recursively enter the CreateTimer and by-pass the locking semaphore.
1839*/
1840static BERR_Code _BTMR_CreateTimer(BTMR_Handle device, BTMR_TimerHandle *phTimer, const BTMR_TimerSettings *pSettings, const char *file, int line)
1841{
1842    BERR_Code errCode = BERR_SUCCESS;
1843    BTMR_TimerHandle timer;
1844
1845    /* If they want to use the Shared Free Run timer (and it already exists) -- give it to them! */
1846    if (pSettings->type == BTMR_Type_eSharedFreeRun && device->SharedTimer)
1847    {
1848        device->SharedCount++;          /* one more user sharing this timer! */
1849        *phTimer = device->SharedTimer; /* here's your handle for using this timer! */
1850        BDBG_MSG(("BTMR_CreateTimer: NOT creating THE timer for shared timer [already created, count=%d] (%s,%d)!", device->SharedCount, file, line));
1851        return BERR_SUCCESS;
1852    }
1853   
1854    /* If not shared (or shared doesn't yet exist) then this is a new timer and we need a handle for further use */
1855    timer = (BTMR_TimerHandle) BKNI_Malloc(sizeof(*timer));
1856    if (timer == NULL)
1857    {
1858        BDBG_ERR(("BTMR_CreateTimer: Memory allocation failed!"));
1859        return BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
1860    }
1861
1862    BKNI_Memset(timer, 0, sizeof(*timer));
1863    BDBG_OBJECT_SET(timer, btmr_timer_t);
1864
1865    /*
1866    ** We'd like to enforce the use of virtual timers here by over-riding the exclusive setting to false.
1867    ** But that might break someone's code that really does want to manipulate the timer outside of this PI.
1868    ** That is something you can't do with Virtual Timers (could I fake this???).
1869    ** So don't do this!
1870    */
1871
1872    /* Use the appropriate processing functions for this timer based on the requested type */
1873    if (pSettings->exclusive || pSettings->type == BTMR_Type_eSharedFreeRun)
1874        timer->functions = (ProcessingFunctions*)&physicalFunctions;
1875    else
1876        timer->functions = (ProcessingFunctions*)&virtualFunctions;
1877
1878    timer->device = device;
1879    BKNI_Memcpy(&timer->Settings, pSettings, sizeof(BTMR_TimerSettings));
1880
1881    timer->file = file; /* remember where this timer was created */
1882    timer->line = line; /* so we can tell the user on exit where an un-destroyed timer was created */
1883
1884    BDBG_MSG(("BTMR_CreateTimer: creating %s(%d) timer (%s,%d)", GetTimerType(pSettings), pSettings->type, file, line));
1885    errCode = timer->functions->create(device, timer, pSettings);
1886    if (errCode) {
1887        BDBG_ERR(("BTMR_CreateTimer: failed to create  %s(%d) timer (at %s,%d)", GetTimerType(pSettings), pSettings->type, file, line));
1888        BKNI_Free(timer);
1889        return BERR_TRACE(errCode);
1890    }
1891
1892    *phTimer = timer; /* here's your handle for using this timer! */
1893
1894    return BERR_SUCCESS;
1895}
1896
1897BERR_Code BTMR_CreateTimer_tagged(BTMR_Handle device, BTMR_TimerHandle *phTimer, const BTMR_TimerSettings *pSettings, const char *file, int line)
1898{
1899    BERR_Code errCode = BERR_SUCCESS;
1900
1901    BDBG_ENTER(BTMR_CreateTimer);
1902    BDBG_OBJECT_ASSERT(device, btmr_device_t);
1903    BDBG_ASSERT(phTimer);   /* this is where I put his handle -- don't write to zero */
1904    BDBG_ASSERT(pSettings); /* this is the timer settings -- he MUST give me some settings */
1905
1906    /* Some say I shouldn't mess with the return variable unless I return success... */
1907    *phTimer = NULL; /* just to be sure caller doesn't use it -- you don't have a timer till I give you one! */
1908   
1909    shortenFileName(file);
1910
1911#if 1
1912    /*
1913    ** Now I COULD be nice and let them provide a callback when not expected (I just won't call it)
1914    ** or not provide a callback when I do expect it (nothing provided then nothing to call) but ...
1915    */
1916    if (pSettings->type == BTMR_Type_eStopWatch || pSettings->type == BTMR_Type_eSharedFreeRun)
1917    {
1918        /* StopWatch and FreeRun timers DON'T GET callbacks! Only used for sampling */
1919        if (pSettings->cb_isr) {
1920            BDBG_ERR(("BTMR_CreateTimer: StopWatch timer supplied with call back routine -- illegal!"));
1921            return BERR_TRACE(BERR_INVALID_PARAMETER);
1922        }
1923    }
1924    else
1925    {
1926        /* Count-down and Periodic timers MUST supply a callback! */
1927        if (!pSettings->cb_isr) {
1928            BDBG_ERR(("BTMR_CreateTimer: Count-down or Periodic timer NOT supplied with call back routine -- illegal!"));
1929            return BERR_TRACE(BERR_INVALID_PARAMETER);
1930        }
1931    }
1932#endif
1933   
1934    /*
1935    ** We have a re-entrancy issue with creating and destroying timers.
1936    ** Multiple processes can try to create/destroy a timer that can cause the Shared Timer and Virtual Timer counts to get stepped on.
1937    ** Because much of the work of creating a timer gets done at _isr level (in Critical Section) we have to block almost the entire
1938    ** create/destroy process.
1939    */
1940
1941    BKNI_AcquireMutex(device->create_destroy_mutex);
1942    errCode = _BTMR_CreateTimer(device, phTimer, pSettings, file, line);
1943    BKNI_ReleaseMutex(device->create_destroy_mutex);
1944
1945    BDBG_LEAVE(BTMR_CreateTimer);
1946    return errCode;
1947}
1948
1949/* We need to recursively destroy timers.
1950** This can happen when we're destroying the utility timers that are no longer needed after deleting the last virtual timer.
1951*/
1952static BERR_Code _BTMR_DestroyTimer(BTMR_TimerHandle timer, const char*file, int line)
1953{
1954    BERR_Code errCode = BERR_SUCCESS;
1955    BTMR_Handle device;
1956
1957    BDBG_OBJECT_ASSERT(timer, btmr_timer_t);
1958    BSTD_UNUSED(file);
1959    BSTD_UNUSED(line);
1960
1961    device = timer->device;
1962
1963    /* Shared Free Run timers only get destroyed on last destroy */
1964    if (timer->Settings.type == BTMR_Type_eSharedFreeRun && device->SharedCount > 1) 
1965    {
1966        BDBG_MSG(("BTMR_DestroyTimer: NOT deleting THE shared timer [still in use by others, count=%d] (%s,%d)!", device->SharedCount, file, line));
1967        device->SharedCount--;
1968        return BERR_SUCCESS;
1969    }
1970
1971    /* The shared timer reflects the first one to create one, not necessarily the one destroying it */
1972    BDBG_MSG(("BTMR_DestroyTimer: destroying %s timer %d (%s,%d)", GetTimerType(&timer->Settings), timer->timerNumber, file, line));
1973    if (timer->Settings.type != BTMR_Type_eSharedFreeRun)
1974    {
1975        BDBG_MSG(("BTMR_DestroyTimer:   destroying %s timer %d (created: %s,%d)", 
1976            GetTimerType(&timer->Settings), timer->timerNumber, timer->file, timer->line));
1977    }
1978
1979    BKNI_EnterCriticalSection();
1980    errCode = timer->functions->destroy_isr(timer);
1981    BKNI_LeaveCriticalSection();
1982
1983    /* Mark it as invalid in case he tries to give it to me again (destroy twice, or operation after destroy) */
1984    /* Note: this probably won't happen as the memory will be reassigned and stepped on, but ... */
1985    BDBG_OBJECT_DESTROY(timer, btmr_timer_t);
1986    BKNI_Free(timer);
1987
1988    return errCode;
1989}
1990
1991BERR_Code BTMR_DestroyTimer_tagged(BTMR_TimerHandle timer, const char*file, int line)
1992{
1993    BERR_Code errCode = BERR_SUCCESS;
1994    BTMR_Handle device;
1995
1996    BDBG_ENTER(BTMR_DestroyTimer);
1997    BDBG_OBJECT_ASSERT(timer, btmr_timer_t);
1998
1999    device = timer->device;
2000    shortenFileName(file);
2001
2002    /* You are not allowed to delete a timer from within the count-down or periodic timer's callback function.
2003    ** This is just a bad thing to do.  Besides, the call-back is running from ISR and this isn't an _isr routine.
2004    */
2005    if (timer->processing) {
2006        BDBG_ERR(("BTMR_DestroyTimer: request to destroy timer from a timer callback operation!"));
2007        return BERR_TRACE(BTMR_ERR_DELETE_FROM_ISR);
2008    }
2009
2010    BKNI_AcquireMutex(device->create_destroy_mutex);
2011    errCode = _BTMR_DestroyTimer(timer, file, line);
2012    BKNI_ReleaseMutex(device->create_destroy_mutex);
2013
2014    BDBG_LEAVE(BTMR_DestroyTimer);
2015    return errCode;
2016}
2017
2018BERR_Code BTMR_GetTimerRegisters(BTMR_TimerHandle timer, BTMR_TimerRegisters *pRegisters)
2019{
2020    BDBG_ENTER(BTMR_GetTimerRegisters);
2021    BDBG_OBJECT_ASSERT(timer, btmr_timer_t);
2022    BDBG_ASSERT(pRegisters); /* don't write results to zero */
2023
2024    /*BDBG_MSG(("Getting the registers for timer number %d (%s)", timer->timerNumber, GetTimerType(&timer->Settings)));*/
2025
2026    /* They are only supposed to call this function IF the timer was created as exclusive.
2027    ** Special case: we allow anyone using shared timer to also get its registers.
2028    ** We NEVER allow them to get the register values of a virtual timer (they don't exist).
2029    */
2030    if (!timer->Settings.exclusive && !(timer->Settings.type == BTMR_Type_eSharedFreeRun)) {
2031        BDBG_ERR(("BTMR_GetTimerRegisters: asked for registers to non-exclusive/non-shared timer!"));
2032        return BERR_TRACE(BTMR_ERR_EXCLUSIVE_OPERATION);
2033    }
2034   
2035    BKNI_Memcpy(pRegisters, &timer->Registers, sizeof(BTMR_TimerRegisters));
2036
2037    BDBG_LEAVE(BTMR_GetTimerRegisters);
2038    return BERR_SUCCESS;
2039}
2040
2041static const BTMR_TimerSettings DefaultTimerSettings =  { BTMR_Type_eStopWatch, NULL, NULL, 0, false };
2042
2043BERR_Code BTMR_GetDefaultTimerSettings(BTMR_TimerSettings *pSettings)
2044{
2045    BDBG_ASSERT(pSettings); /* don't write results to zero */
2046
2047    BKNI_Memcpy(pSettings, &DefaultTimerSettings, sizeof(BTMR_TimerSettings));
2048    return BERR_SUCCESS;
2049}
2050
2051/* This gets the current settings for THIS timer as opposed to the above that gets the default for ANY timer */
2052BERR_Code BTMR_GetTimerSettings(BTMR_TimerHandle timer, BTMR_TimerSettings *pSettings)
2053{
2054    BDBG_OBJECT_ASSERT(timer, btmr_timer_t);
2055    BDBG_ASSERT(pSettings); /* don't write results to zero */
2056
2057    BKNI_Memcpy(pSettings, &timer->Settings, sizeof(BTMR_TimerSettings));
2058    return BERR_SUCCESS;
2059}
2060
2061BERR_Code BTMR_StartTimer_isr(BTMR_TimerHandle timer, unsigned startingValue)
2062{
2063    BDBG_OBJECT_ASSERT(timer, btmr_timer_t);
2064
2065    /* If this was called from the count-down timer's callback function then we don't actually start it here.
2066    ** This could mess up the processing in the interrupt service routines.  So just mark it to be started.
2067    ** Note: we'll get called back here for virtual timers but with "processing" set to false this time.
2068    ** Also note that we can't provide proper status for this request because it doesn't happen until later.
2069    */
2070    if (timer->processing) {
2071        timer->delayedValue = startingValue;
2072        timer->pleaseStart = true;
2073        return BERR_SUCCESS;
2074    }
2075
2076    /* What should I do with a zero timer request?  Ignore request?  Error?  Make believe the timer expired (i.e. callback)? */
2077    if (!startingValue && (timer->Settings.type == BTMR_Type_eCountDown || timer->Settings.type == BTMR_Type_ePeriodic)) {
2078        BDBG_ERR(("BTMR_StartTimer: request to start count-down timer but given a zero count -- don't know what to do with that!!"));
2079        return BERR_TRACE(BTMR_ERR_NO_TIMEOUT_GIVEN);
2080    }
2081   
2082    /* A periodic timer with too small a timeout will cause a hang (timer continuously times out) */
2083    if (startingValue < BTMR_MINIMUM_TIMEOUT && timer->Settings.type == BTMR_Type_ePeriodic) {
2084        BDBG_ERR(("BTMR_StartTimer: request to start periodic timer with too small a timeout -- will cause a interrupt hang!!"));
2085        return BERR_TRACE(BTMR_ERR_TIMEOUT_TOO_SMALL);
2086    }
2087
2088    /* We can't allow a periodic timer to start up with a timeout less than our minimum.
2089    ** This would allow us to continue to add the timer to the timeout list and then immediately time it out (and hang).
2090    ** Note: this is different than the MINIMUM_TIMEOUT value (and check) above.
2091    */
2092    if (startingValue < BTMR_MIN_HOLD && timer->Settings.type == BTMR_Type_ePeriodic)
2093        startingValue = BTMR_MIN_HOLD + 1;
2094
2095    BDBG_MSG(("BTMR_StartTimer: starting %s timer %d (initial=%08x)", GetTimerType(&timer->Settings), timer->timerNumber, startingValue));
2096    return timer->functions->start_isr(timer, startingValue);
2097}
2098BERR_Code BTMR_StartTimer(BTMR_TimerHandle timer, unsigned startingValue)
2099{
2100    BERR_Code result;
2101    BDBG_ENTER(BTMR_StartTimer);
2102    BKNI_EnterCriticalSection();
2103    result = BTMR_StartTimer_isr(timer, startingValue);
2104    BKNI_LeaveCriticalSection();
2105    BDBG_LEAVE(BTMR_StartTimer);
2106    return result;
2107}
2108
2109BERR_Code BTMR_StopTimer_isr(BTMR_TimerHandle timer)
2110{
2111    BDBG_OBJECT_ASSERT(timer, btmr_timer_t);
2112
2113    /* If this was called from the count-down timer's callback function then we don't actually stop it here.
2114    ** This could mess up the processing in the interrupt service routines.  So just mark it to be stopped.
2115    ** Note that we can't provide proper status for this request because it doesn't happen until later.
2116    */
2117    if (timer->processing) {
2118        timer->pleaseStop = true;
2119        return BERR_SUCCESS;
2120    }
2121
2122    BDBG_MSG(("BTMR_StopTimer: stopping %s timer %d", GetTimerType(&timer->Settings), timer->timerNumber));
2123    return timer->functions->stop_isr(timer);
2124}
2125BERR_Code BTMR_StopTimer(BTMR_TimerHandle timer)
2126{
2127    BERR_Code result;
2128    BDBG_ENTER(BTMR_StopTimer);
2129    BKNI_EnterCriticalSection();
2130    result = BTMR_StopTimer_isr(timer);
2131    BKNI_LeaveCriticalSection();
2132    BDBG_LEAVE(BTMR_StopTimer);
2133    return result;
2134}
2135
2136BERR_Code BTMR_ReadTimer_isr(BTMR_TimerHandle timer, unsigned *pValue)
2137{
2138    BDBG_OBJECT_ASSERT(timer, btmr_timer_t);
2139    if (pValue) *pValue = timer->functions->read_isr(timer);
2140    return BERR_SUCCESS;
2141}
2142BERR_Code BTMR_ReadTimer(BTMR_TimerHandle timer, unsigned *pValue)
2143{
2144    BERR_Code result;
2145    BDBG_ENTER(BTMR_ReadTimer);
2146    BKNI_EnterCriticalSection();
2147    result = BTMR_ReadTimer_isr(timer, pValue);
2148    BKNI_LeaveCriticalSection();
2149    BDBG_LEAVE(BTMR_ReadTimer);
2150    return result;
2151}
2152
2153/* Note: we passed in a handle in case we ever have different wraps for different timer blocks */
2154unsigned BTMR_ReadTimerMax(void)
2155{
2156    return TimerToMicroSeconds(MaxTimerValue);
2157}
2158
2159/* End of File */
2160
Note: See TracBrowser for help on using the repository browser.