Subversion Repositories shark

Rev

Rev 303 | Rev 305 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pj 1
/* Project:     OSLib
2
 * Description: The OS Construction Kit
3
 * Date:                1.6.2000
4
 * Idea by:             Luca Abeni & Gerardo Lamastra
5
 *
6
 * OSLib is an SO project aimed at developing a common, easy-to-use
7
 * low-level infrastructure for developing OS kernels and Embedded
8
 * Applications; it partially derives from the HARTIK project but it
9
 * currently is independently developed.
10
 *
11
 * OSLib is distributed under GPL License, and some of its code has
12
 * been derived from the Linux kernel source; also some important
13
 * ideas come from studying the DJGPP go32 extender.
14
 *
15
 * We acknowledge the Linux Community, Free Software Foundation,
16
 * D.J. Delorie and all the other developers who believe in the
17
 * freedom of software and ideas.
18
 *
19
 * For legalese, check out the included GPL license.
20
 */
21
 
120 giacomo 22
/* Added Advanced Timer Code
23
 *
24
 * Date:   8.4.2003
25
 * Author: Giacomo Guidi <giacomo@gandalf.sssup.it>
26
 *
27
 */
28
 
2 pj 29
/*      Time Event routines     */
30
 
31
#include <ll/i386/stdlib.h>
32
#include <ll/i386/mem.h>
33
#include <ll/i386/error.h>
34
#include <ll/i386/hw-arch.h>
40 pj 35
#include <ll/i386/pic.h>
2 pj 36
#include <ll/i386/pit.h>
299 giacomo 37
#include <ll/i386/apic.h>
131 giacomo 38
#include <ll/i386/advtimer.h>
39
 
2 pj 40
#include <ll/sys/ll/ll-data.h>
41
#include <ll/sys/ll/ll-instr.h>
304 giacomo 42
#include <ll/sys/ll/ll-func.h>
2 pj 43
#include <ll/sys/ll/time.h>
44
#include <ll/sys/ll/event.h>
45
 
46
FILE(Event);
47
 
48
extern LL_ARCH ll_arch;
49
 
50
BYTE frc;
51
 
52
/* Timer 0 usec base tick */
53
DWORD ticksize;
54
 
55
/* Timer 0 loaded time constant (= ticksize * 1.197) */
56
WORD pit_time_const;
57
DWORD timermode;
58
 
59
static DWORD nts;               /* System tick in nanoSeconds... */
60
struct timespec actTime;        /* Time (in nanosecs)... */
61
extern int activeInt;
62
 
63
WORD lastTime;
64
struct pitspec globalCounter;
65
 
66
struct event eventlist[MAX_EVENT];
67
 
68
struct event *freeevents;
69
struct event *firstevent;
70
 
71
extern void *last_handler;
72
extern void (*evt_prol) (void);
73
extern void (*evt_epil) (void);
74
 
120 giacomo 75
extern unsigned char use_tsc;
299 giacomo 76
extern unsigned char use_apic;
77
extern signed long long apic_clk_per_msec;
120 giacomo 78
 
40 pj 79
void event_setlasthandler(void *p)
80
{
81
    last_handler = p;
82
}                                                                              
2 pj 83
 
84
void event_setprologue(void *p)
85
{
86
    evt_prol = p;
87
}
88
 
89
void event_setepilogue(void *p)
90
{
91
    evt_epil = p;
92
}
93
 
94
/* Switched to timespec */
95
int periodic_event_post(struct timespec time, void (*handler) (void *p),
96
                        void *par)
97
{
98
    struct event *p;
99
    struct event *p1, *t;
100
 
101
    if (!freeevents) {
304 giacomo 102
        message("NO FREE EVENTS !\n");
103
        ll_abort(20);
2 pj 104
        return -1;
105
    }
106
 
107
    /* Extract from the ``free events'' queue */
108
    p = freeevents;
109
    freeevents = p->next;
110
 
111
    /* Fill the event fields */
112
    p->handler = handler;
113
    TIMESPEC_ASSIGN(&(p->time), &time);
114
    p->par = par;
115
 
116
    /* ...And insert it in the event queue!!! */
117
 
118
    t = NULL;
119
    /* walk through list, finding spot, adjusting ticks parameter */
120
    for (p1 = firstevent; p1; p1 = t->next) {
121
/*
122
                SUBTIMESPEC(&time, &(p1->time), &tmp);
123
                if ((tmp.tv_sec > 0) && (tmp.tv_nsec > 0)) {
124
*/
125
        if (TIMESPEC_A_GT_B(&time, &p1->time))
126
            t = p1;
127
        else
128
            break;
129
    }
130
 
131
    /* adjust next entry */
132
    if (t) {
133
        t->next = p;
134
    } else {
135
        firstevent = p;
136
    }
137
    p->next = p1;
138
 
139
    return p->index;
140
}
141
 
142
int periodic_event_delete(int index)
143
{
144
    struct event *p1, *t;
145
 
146
    t = NULL;
147
    /* walk through list, finding spot, adjusting ticks parameter */
148
    for (p1 = firstevent; (p1) && (index != p1->index); p1 = t->next) {
149
        t = p1;
150
    }
151
 
152
    if (p1 == NULL) {
153
        return -1;
154
    }
155
 
156
    if (t == NULL) {
157
        firstevent = p1->next;
158
    } else {
159
        t->next = p1->next;
160
    }
161
    p1->next = freeevents;
162
    freeevents = p1;
163
 
164
    return 1;
165
}
166
 
167
void periodic_wake_up(void)
168
{                               /* CHANGE the NAME, please... */
169
    struct event *p, *pp;
170
    WORD tmp;
171
 
120 giacomo 172
    if(!use_tsc) {
173
        tmp = pit_read(frc);
174
        ADDPITSPEC((WORD) (lastTime - tmp), &globalCounter);
175
        lastTime = tmp;
176
    }
177
 
2 pj 178
    activeInt++;
179
    if (activeInt == 1 && evt_prol != NULL) {
180
        evt_prol();
181
    }
182
 
120 giacomo 183
    if (!use_tsc) {
184
            ADDNANO2TIMESPEC(nts, &actTime);
185
    } else {
131 giacomo 186
            ll_read_timespec(&actTime);
120 giacomo 187
    }
188
 
2 pj 189
    for (p = firstevent; p != NULL; p = pp) {
190
/*
191
                SUBTIMESPEC(&(p->time), &actTime, &tmp);
192
                if ((tmp.tv_sec > 0) && (tmp.tv_nsec > 0)) {
193
                        break;
194
                } */
195
        if ((p->time.tv_sec > actTime.tv_sec) ||
196
            ((p->time.tv_sec == actTime.tv_sec)
197
             && (p->time.tv_nsec > actTime.tv_nsec))) {
198
            break;
199
        }
200
        pp = p->next;
201
        p->next = freeevents;
202
        freeevents = p;
203
        firstevent = pp;
204
        p->handler(p->par);
205
    }
206
 
207
    if (activeInt == 1 && evt_epil != NULL) {
208
        evt_epil();
209
    }
210
    activeInt--;
211
}
212
 
213
void event_init(struct ll_initparms *l)
214
{
215
    extern void ll_timer(void);
299 giacomo 216
    extern void ll_apic_timer(void);
2 pj 217
    int i;
218
    BYTE mask;
219
    TIME t;
299 giacomo 220
    DWORD apic_clk;
2 pj 221
 
265 giacomo 222
    if (use_tsc) ll_init_advtimer();
223
 
299 giacomo 224
    if (!use_apic)
225
      IDT_place(0x40,ll_timer);
226
    else
304 giacomo 227
      IDT_place(0x39,ll_apic_timer);
2 pj 228
 
229
    if (l->mode != LL_PERIODIC) {
120 giacomo 230
        message("One-shot mode\n");
2 pj 231
        t = 0;
299 giacomo 232
        if (!use_apic) {
233
          /* Mode: Binary/Mode 4/16 bit Time_const/Counter 0 */
234
          pit_init(0, TMR_MD4, 0xFFFF); /* Timer 0, Mode 4, constant 0xFFFF */
303 giacomo 235
        } else {
236
          set_APIC_timer(0xFFFFFFFF);
237
          enable_APIC_timer();
238
        }
2 pj 239
    } else {
240
        t = l->tick;
299 giacomo 241
 
242
        /* Translate the tick value in usec into a suitable time constant   */
2 pj 243
        /* for 8254 timer chip; the chip is driven with a 1.19718 MHz       */
244
        /* frequency; then the effective frequency is given by the base     */
245
        /* frequency divided for the time constant; the tick is the inverse */
246
        /* of this effective frequency (in usec!)                           */
247
        /* Time-Constant = f_base (MHz) * tick (usec)                       */
248
        /* If T-C == 0 -> T-C = 65536 (Max available)                       */
249
        ticksize = t;
265 giacomo 250
 
299 giacomo 251
        if (!use_apic) {
252
 
253
           t = (signed long long)(t) * 1193182 / 1000000;
2 pj 254
 
299 giacomo 255
           /* Only for security! This should cause timer overrun */
256
           /* While 0 would set maximum period on timer          */
257
          if (t == 0)
258
              t = 1;
259
          pit_time_const = (WORD) (t & 0xFFFF);
260
          /* Mode: Binary/Mode 2/16 bit Time_const/Counter 0 */
261
          pit_init(0, TMR_MD2, t);      /* Timer 0, Mode 2, Time constant t */
262
 
263
        } else {
2 pj 264
 
299 giacomo 265
          apic_clk = (signed long long)(t) * apic_clk_per_msec / 1000;
303 giacomo 266
          set_APIC_timer(apic_clk);
267
          enable_APIC_timer();
299 giacomo 268
 
269
        }
2 pj 270
    }
271
    timermode = l->mode;
301 giacomo 272
 
273
    if (!use_apic) {
299 giacomo 274
      if (ll_arch.x86.cpu > 4) {
301 giacomo 275
        /* Timer1: mode 0, time const 0... */
276
        pit_init(1, TMR_MD0, 0);
277
        frc = 1;
299 giacomo 278
      } else {
301 giacomo 279
        frc = 2;
280
        pit_init(2, TMR_MD0, 0);
281
        outp(0x61, 3);
299 giacomo 282
      }
2 pj 283
    }
284
 
301 giacomo 285
    mask = ll_in(0x21);
286
    mask &= 0xFE;               /* 0xFE = ~0x01 */
287
    ll_out(0x21, mask);
288
 
2 pj 289
    /* Init the event list... */
290
    for (i = 0; i < MAX_EVENT; i++) {
291
        if (i < MAX_EVENT - 1) {
292
            eventlist[i].next = &(eventlist[i + 1]);
293
        }
294
        eventlist[i].index = i;
295
    }
296
    eventlist[MAX_EVENT - 1].next = NULL;
297
    freeevents = &(eventlist[0]);
298
 
299
    evt_prol = NULL;
300
    evt_epil = NULL;
301
 
302
    /* Initialization of the time variables for periodic mode */
303
    nts = ticksize * 1000;
304
    NULL_TIMESPEC(&actTime);
120 giacomo 305
 
2 pj 306
    /* Initialization of the general time variables */
307
    NULLPITSPEC(&globalCounter);
308
    lastTime = 0;
309
 
310
    if (timermode == LL_PERIODIC) {
311
        event_post = periodic_event_post;
312
        event_delete = periodic_event_delete;
313
    } else {
314
        event_post = oneshot_event_post;
315
        event_delete = oneshot_event_delete;
316
    }
40 pj 317
 
318
    /* Last but not least... */
299 giacomo 319
    if (!use_apic) irq_unmask(0);
320
 
2 pj 321
}