/* Pilote pour le timer Intel 8253/8254 Programmable Interval Timer */ /* Copyright (C) 2008 Emmanuel Varoquaux This file is part of XOS. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #define DIVISOR (1193180 / TIMER_FREQUENCY) static volatile unsigned long ticks; static struct alarm_struct *first_alarm; /* Alarmes */ static void insert_alarm(struct alarm_struct *alarm) { struct alarm_struct *alm1, *alm2; alm1 = NULL; alm2 = first_alarm; while (alm2 && alm2->time <= alarm->time) alm1 = alm2, alm2 = alm2->next; alarm->previous = alm1; alarm->next = alm2; if (alm1) alm1->next = alarm; else first_alarm = alarm; if (alm2) alm2->previous = alarm; alarm->active = 1; } static void remove_alarm(struct alarm_struct *alarm) { if (alarm->previous) alarm->previous->next = alarm->next; else first_alarm = alarm->next; if (alarm->next) alarm->next->previous = alarm->previous; alarm->active = 0; } /* Interface */ void timer_init() { ticks = 0; first_alarm = NULL; outbp(0x34, 0x43); /* Compteur 0, LSB/MSB, mode 2, binaire */ outb(DIVISOR & 0xff, 0x40); /* LSB */ outb(DIVISOR >> 8, 0x40); /* MSB */ } void timer_print_info() { printk("Timer: Intel 8254 Programmable Interval Timer\n"); printk("Timer frequency set to %dHz.\n", TIMER_FREQUENCY); } void do_timer_interrupt(const struct interrupted_instruction_struct *interrupted_instruction) { struct alarm_struct *alm; /* le temps passe */ ticks++; /* alarmes */ while (first_alarm && first_alarm->time <= ticks) { alm = first_alarm; remove_alarm(alm); alm->handler(alm); } /* ordonnancement des processus */ preempt(interrupted_instruction); /* doit etre la derniere instruction du gestionnaire d'interruption !!! */ } void alarm_init(struct alarm_struct *alarm, void (*handler)(struct alarm_struct *)) { alarm->handler = handler; alarm->active = 0; /* Inutile d'itinialiser les autres membres. */ } void alarm_set(struct alarm_struct *alarm, unsigned long milliseconds) { int intr; disable_intr(intr); if (alarm->active) remove_alarm(alarm); alarm->time = ticks + milliseconds * TIMER_FREQUENCY / 1000; insert_alarm(alarm); restore_intr(intr); } unsigned long alarm_unset(struct alarm_struct *alarm) { int intr; unsigned long left; disable_intr(intr); if (alarm->active) { left = (alarm->time - ticks) * 1000 / TIMER_FREQUENCY; remove_alarm(alarm); } else left = 0; restore_intr(intr); return left; }