Subversion Repositories shark

Rev

Rev 502 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/* Project:     OSLib
 * Description: The OS Construction Kit
 * Date:                1.6.2000
 * Idea by:             Luca Abeni & Gerardo Lamastra
 *
 * OSLib is an SO project aimed at developing a common, easy-to-use
 * low-level infrastructure for developing OS kernels and Embedded
 * Applications; it partially derives from the HARTIK project but it
 * currently is independently developed.
 *
 * OSLib is distributed under GPL License, and some of its code has
 * been derived from the Linux kernel source; also some important
 * ideas come from studying the DJGPP go32 extender.
 *
 * We acknowledge the Linux Community, Free Software Foundation,
 * D.J. Delorie and all the other developers who believe in the
 * freedom of software and ideas.
 *
 * For legalese, check out the included GPL license.
 */


/* Added Advanced Timer Code
 *
 * Date:   8.4.2003
 * Author: Giacomo Guidi <giacomo@gandalf.sssup.it>
 *
 */


/*      Time Event routines     (one shot mode) */

#include <ll/i386/stdlib.h>
#include <ll/i386/mem.h>
#include <ll/i386/pit.h>
#include <ll/i386/apic.h>
#include <ll/i386/advtimer.h>
#include <ll/i386/error.h>
#include <ll/i386/64bit.h>

#include <ll/sys/ll/ll-data.h>
#include <ll/sys/ll/ll-func.h>
#include <ll/sys/ll/time.h>
#include <ll/sys/ll/event.h>

#include <tracer.h>
extern unsigned short int currCtx;

FILE(EventOneShot);

extern int activeInt;
int activeEvent;

extern BYTE frc;

extern struct event eventlist[MAX_EVENT];
extern WORD lastTime;
extern struct pitspec globalCounter;

extern struct event *freeevents;
extern struct event *firstevent;

extern void (*evt_prol) (void);
extern void (*evt_epil) (void);

extern unsigned int apic_clk_per_msec;
extern unsigned char use_tsc, use_apic;

/* Switched to timespec */
int oneshot_event_post(struct timespec time, void (*handler) (void *p), void *par)
{
        struct event *p;
        struct event *p1, *t;
        struct timespec now, tmp;
        int done;
        DWORD tnext;

        TRACER_LOGEVENT(FTrace_EVT_timer_post, 0, 0);

        if (!freeevents) {
                message("NO FREE EVENTS !\n");
                ll_abort(20);
                return -1;
        }
        /* Extract from the ``free events'' queue */
        p = freeevents;
        freeevents = p->next;

        /* Fill the event fields */
        p->handler = handler;
        TIMESPEC_ASSIGN(&(p->time), &time);
        p->par = par;

        /* ...And insert it in the event queue!!! */

        t = NULL;
        done = 0;
        /* walk through list, finding spot, adjusting ticks parameter */
        for (p1 = firstevent; p1; p1 = t->next) {
                if (TIMESPEC_A_GT_B((&time), (&p1->time))) {
                t = p1;
                } else
                break;
        }

        /* adjust next entry */
        if (t) {
                t->next = p;
        } else {
                firstevent = p;
                if (!activeEvent) {
                        if (!use_tsc) {
                                ll_gettime(TIME_NEW, &now);
                        } else {
                                ll_read_timespec(&now);
                        }
                        if (TIMESPEC_A_GT_B(&now, &(firstevent->time))) {
                                NULL_TIMESPEC(&tmp);
                        } else {
                                SUBTIMESPEC(&(firstevent->time), &now, &tmp);
                        }
                        tnext = TIMESPEC2USEC(&tmp);
                        if (!use_apic) {
                                mul32div32to32(tnext,1193182,1000000,tnext);
                                pit_setconstant(0, tnext);
                        } else {
                                mul32div32to32(tnext,apic_clk_per_msec,1000,tnext);
                                set_APIC_timer(tnext);
                        }
                }
        }
        p->next = p1;

        return p->index;
}

void oneshot_wake_up(void)
{
        /* CHANGE the NAME, please... */
        struct event *p = NULL, *pp;
        struct timespec now, ttmp;
        WORD tmp;
        DWORD tnext;

        TRACER_LOGEVENT(FTrace_EVT_timer_wakeup_start, 0, 0);

        if (!use_tsc) {
                tmp = pit_read(frc);
                ADDPITSPEC((WORD) (lastTime - tmp), &globalCounter);
                lastTime = tmp;

                PITSPEC2TIMESPEC(&globalCounter, &now);
        } else {
                ll_read_timespec(&now);
        }

        if (firstevent != NULL) {
                activeEvent = 1;
                if (TIMESPEC_A_GT_B(&now, &(firstevent->time))) {
                        if (!activeInt && evt_prol != NULL) {
                                evt_prol();
                        }
                        activeInt++;

                        for (p = firstevent; p != NULL; p = pp) {
                                if ((p->time.tv_sec > now.tv_sec) ||
                                   ((p->time.tv_sec == now.tv_sec)
                                   && (p->time.tv_nsec > now.tv_nsec))) {
                                        break;
                                }
                                pp = p->next;
                                p->next = freeevents;
                                freeevents = p;
                                firstevent = pp;
                                p->handler(p->par);
                        }
       
                        if (activeInt == 1 && evt_epil != NULL) {
                                evt_epil();
                        }
                        activeInt--;
                }

                if (!use_tsc) {
                        tmp = pit_read(frc);
                        ADDPITSPEC((WORD) (lastTime - tmp), &globalCounter);
                        lastTime = tmp;
       
                        PITSPEC2TIMESPEC(&globalCounter, &now);
                } else {
                        ll_read_timespec(&now);
                }

                if (TIMESPEC_A_GT_B(&now, &(firstevent->time))) {
                        NULL_TIMESPEC(&ttmp);
                } else {
                        SUBTIMESPEC(&(firstevent->time), &now, &ttmp);
                }
                /*  SUBTIMESPEC(&(firstevent->time), &now, &ttmp); */
                tnext = TIMESPEC2USEC(&ttmp);
                if (!use_apic) {
                        mul32div32to32(tnext,1193182,1000000,tnext);
                        pit_setconstant(0, tnext);
                } else {
                        mul32div32to32(tnext,apic_clk_per_msec,1000,tnext);
                        set_APIC_timer(tnext);
                }
                activeEvent = 0;
        } else {
                if (!use_apic)
                        pit_setconstant(0, 0xFFFF);
                else
                        set_APIC_timer(0xFFFFFFFF);
        }

        TRACER_LOGEVENT(FTrace_EVT_timer_wakeup_end, (unsigned short int)currCtx, 0);
}

int oneshot_event_delete(int index)
{
        struct event *p1, *t;
        struct timespec tmp, now;
        DWORD tnext;
        int firstdeleted = FALSE;

        TRACER_LOGEVENT(FTrace_EVT_timer_delete, 0, 0);

        if (index == -1)
                return -1;
        t = NULL;
        /* walk through list, finding spot, adjusting ticks parameter */
       
        for (p1 = firstevent; (p1) && (index != p1->index); p1 = t->next) {
                t = p1;
        }
       
        if (p1 == NULL) {
                return -1;
        }
        if (t == NULL) {
                firstevent = p1->next;
                firstdeleted = TRUE;
        } else {
                t->next = p1->next;
        }
       
        p1->next = freeevents;
        freeevents = p1;
       
        if (!activeEvent) {
                if (firstevent == NULL) {
                        if (!use_apic)
                                pit_setconstant(0, 0xFFFF);
                        else
                                set_APIC_timer(0xFFFFFFFF);
                } else {
                        if (firstdeleted) {
                                if (!use_tsc)
                                        ll_gettime(TIME_NEW, &now);
                                else
                                        ll_read_timespec(&now);
                                if (TIMESPEC_A_GT_B(&now, &(firstevent->time))) {
                                        NULL_TIMESPEC(&tmp);
                                } else {
                                        SUBTIMESPEC(&(firstevent->time), &now, &tmp);
                                }
                                /*SUBTIMESPEC(&now, &(firstevent->time), &tmp); */
                                tnext = TIMESPEC2USEC(&tmp);
                                if (!use_apic) {
                                        mul32div32to32(tnext,1193182,1000000,tnext);
                                        pit_setconstant(0, tnext);
                                } else {
                                        mul32div32to32(tnext,apic_clk_per_msec,1000,tnext);
                                        set_APIC_timer(tnext);
                                }
                        }
                }
        }
        return 1;
}