From 4006d229e50204c93c1aa04c58385ce2e66d597e Mon Sep 17 00:00:00 2001 From: Alexey Zaytsev Date: Sat, 1 Dec 2007 07:07:01 +0300 Subject: [PATCH] Introduce the new timer subsystem. Timer subsystem initialization code in core/timer.c Split the BIOS and RTDSC timer drivers from i386_timer.c Split arch/i386/firmware/pcbios/bios.c into the RTSDC timer driver and arch/i386/core/nap.c Split the headers properly: include/unistd.h - delay functions to be used by the gPXE core and drivers. include/gpxe/timer.h - the fimer subsystem interface to be used by the timer drivers and currticks() to be used by the code gPXE subsystems. include/latch.h - removed include/timer.h - scheduled for removal. Some driver are using currticks, which is only for core subsystems. Signed-off-by: Alexey Zaytsev --- src/arch/i386/core/i386_timer.c | 213 +++++++-------------------- src/arch/i386/core/nap.c | 12 ++ src/arch/i386/drivers/timer_bios.c | 57 +++++++ src/arch/i386/drivers/timer_rtdsc.c | 90 +++++++++++ src/arch/i386/firmware/pcbios/bios.c | 55 ------- src/arch/i386/include/bits/timer2.h | 8 + src/config.h | 5 +- src/core/config.c | 11 ++ src/core/misc.c | 12 -- src/core/timer.c | 107 ++++++++++++-- src/include/gpxe/timer.h | 32 ++++ src/include/timer.h | 70 +++------ src/include/unistd.h | 8 +- 13 files changed, 384 insertions(+), 296 deletions(-) create mode 100644 src/arch/i386/core/nap.c create mode 100644 src/arch/i386/drivers/timer_bios.c create mode 100644 src/arch/i386/drivers/timer_rtdsc.c delete mode 100644 src/arch/i386/firmware/pcbios/bios.c create mode 100644 src/arch/i386/include/bits/timer2.h create mode 100644 src/include/gpxe/timer.h diff --git a/src/arch/i386/core/i386_timer.c b/src/arch/i386/core/i386_timer.c index 8d3a629ad..8f90ae05a 100644 --- a/src/arch/i386/core/i386_timer.c +++ b/src/arch/i386/core/i386_timer.c @@ -1,18 +1,58 @@ -/* A couple of routines to implement a low-overhead timer for drivers */ - - /* +/* + * arch/i386/core/i386_timer.c + * + * Use the "System Timer 2" to implement the udelay callback in + * the BIOS timer driver. Also used to calibrate the clock rate + * in the RTDSC timer driver. + * * 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 2, or (at * your option) any later version. */ -#include "timer.h" -#include "latch.h" -#include -#include +#include +#include +#include +#include -void __load_timer2(unsigned int ticks) +/* Timers tick over at this rate */ +#define TIMER2_TICK_RATE 1193180U + +/* Parallel Peripheral Controller Port B */ +#define PPC_PORTB 0x61 + +/* Meaning of the port bits */ +#define PPCB_T2OUT 0x20 /* Bit 5 */ +#define PPCB_SPKR 0x02 /* Bit 1 */ +#define PPCB_T2GATE 0x01 /* Bit 0 */ + +/* Ports for the 8254 timer chip */ +#define TIMER2_PORT 0x42 +#define TIMER_MODE_PORT 0x43 + +/* Meaning of the mode bits */ +#define TIMER0_SEL 0x00 +#define TIMER1_SEL 0x40 +#define TIMER2_SEL 0x80 +#define READBACK_SEL 0xC0 + +#define LATCH_COUNT 0x00 +#define LOBYTE_ACCESS 0x10 +#define HIBYTE_ACCESS 0x20 +#define WORD_ACCESS 0x30 + +#define MODE0 0x00 +#define MODE1 0x02 +#define MODE2 0x04 +#define MODE3 0x06 +#define MODE4 0x08 +#define MODE5 0x0A + +#define BINARY_COUNT 0x00 +#define BCD_COUNT 0x01 + +static void load_timer2(unsigned int ticks) { /* * Now let's take care of PPC channel 2 @@ -35,162 +75,15 @@ void __load_timer2(unsigned int ticks) outb(ticks >> 8, TIMER2_PORT); } -static int __timer2_running(void) +static int timer2_running(void) { return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0); } -#if !defined(CONFIG_TSC_CURRTICKS) -static void setup_timers(void) +void i386_timer2_udelay(unsigned int usecs) { - return; + load_timer2((usecs * TIMER2_TICK_RATE)/USECS_IN_SEC); + while (timer2_running()) + ; } -void load_timer2(unsigned int ticks) -{ - return __load_timer2(ticks); -} - -int timer2_running(void) -{ - return __timer2_running(); -} - -void ndelay(unsigned int nsecs) -{ - waiton_timer2((nsecs * CLOCK_TICK_RATE)/1000000000); -} -void udelay(unsigned int usecs) -{ - waiton_timer2((usecs * TICKS_PER_MS)/1000); -} -#endif /* !defined(CONFIG_TSC_CURRTICKS) */ - -#if defined(CONFIG_TSC_CURRTICKS) - -#define rdtsc(low,high) \ - __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) - -#define rdtscll(val) \ - __asm__ __volatile__ ("rdtsc" : "=A" (val)) - - -/* Number of clock ticks to time with the rtc */ -#define LATCH 0xFF - -#define LATCHES_PER_SEC ((CLOCK_TICK_RATE + (LATCH/2))/LATCH) -#define TICKS_PER_LATCH ((LATCHES_PER_SEC + (TICKS_PER_SEC/2))/TICKS_PER_SEC) - -static void sleep_latch(void) -{ - __load_timer2(LATCH); - while(__timer2_running()); -} - -/* ------ Calibrate the TSC ------- - * Time how long it takes to excute a loop that runs in known time. - * And find the convertion needed to get to CLOCK_TICK_RATE - */ - - -static unsigned long long calibrate_tsc(void) -{ - unsigned long startlow, starthigh; - unsigned long endlow, endhigh; - - rdtsc(startlow,starthigh); - sleep_latch(); - rdtsc(endlow,endhigh); - - /* 64-bit subtract - gcc just messes up with long longs */ - __asm__("subl %2,%0\n\t" - "sbbl %3,%1" - :"=a" (endlow), "=d" (endhigh) - :"g" (startlow), "g" (starthigh), - "0" (endlow), "1" (endhigh)); - - /* Error: ECPUTOOFAST */ - if (endhigh) - goto bad_ctc; - - endlow *= TICKS_PER_LATCH; - return endlow; - - /* - * The CTC wasn't reliable: we got a hit on the very first read, - * or the CPU was so fast/slow that the quotient wouldn't fit in - * 32 bits.. - */ -bad_ctc: - printf("bad_ctc\n"); - return 0; -} - -static unsigned long clocks_per_tick; -static void setup_timers(void) -{ - if (!clocks_per_tick) { - clocks_per_tick = calibrate_tsc(); - /* Display the CPU Mhz to easily test if the calibration was bad */ - printf("CPU %ld Mhz\n", (clocks_per_tick/1000 * TICKS_PER_SEC)/1000); - } -} - -unsigned long currticks(void) -{ - unsigned long clocks_high, clocks_low; - unsigned long currticks; - /* Read the Time Stamp Counter */ - rdtsc(clocks_low, clocks_high); - - /* currticks = clocks / clocks_per_tick; */ - __asm__("divl %1" - :"=a" (currticks) - :"r" (clocks_per_tick), "0" (clocks_low), "d" (clocks_high)); - - - return currticks; -} - -static unsigned long long timer_timeout; -static int __timer_running(void) -{ - unsigned long long now; - rdtscll(now); - return now < timer_timeout; -} - -void udelay(unsigned int usecs) -{ - unsigned long long now; - rdtscll(now); - timer_timeout = now + usecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000)); - while(__timer_running()); -} -void ndelay(unsigned int nsecs) -{ - unsigned long long now; - rdtscll(now); - timer_timeout = now + nsecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000*1000)); - while(__timer_running()); -} - -void load_timer2(unsigned int timer2_ticks) -{ - unsigned long long now; - unsigned long clocks; - rdtscll(now); - clocks = timer2_ticks * ((clocks_per_tick * TICKS_PER_SEC)/CLOCK_TICK_RATE); - timer_timeout = now + clocks; -} - -int timer2_running(void) -{ - return __timer_running(); -} - -#endif /* RTC_CURRTICKS */ - -struct init_fn timer_init_fn __init_fn ( INIT_NORMAL ) = { - .initialise = setup_timers, -}; diff --git a/src/arch/i386/core/nap.c b/src/arch/i386/core/nap.c new file mode 100644 index 000000000..12bb5699c --- /dev/null +++ b/src/arch/i386/core/nap.c @@ -0,0 +1,12 @@ + +#include +#include + +/************************************************************************** + * Save power by halting the CPU until the next interrupt + **************************************************************************/ +void cpu_nap ( void ) { + __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" + "hlt\n\t" + "cli\n\t" ) : : ); +} diff --git a/src/arch/i386/drivers/timer_bios.c b/src/arch/i386/drivers/timer_bios.c new file mode 100644 index 000000000..f9caf8d9a --- /dev/null +++ b/src/arch/i386/drivers/timer_bios.c @@ -0,0 +1,57 @@ +/* + * Etherboot routines for PCBIOS firmware. + * + * Body of routines taken from old pcbios.S + */ + +#include +#include +#include +#include +#include +#include + +/* A bit faster actually, but we don't care. */ +#define TIMER2_TICKS_PER_SEC 18 + +/* + * Use direct memory access to BIOS variables, longword 0040:006C (ticks + * today) and byte 0040:0070 (midnight crossover flag) instead of calling + * timeofday BIOS interrupt. + */ + +static tick_t bios_currticks ( void ) { + static int days = 0; + uint32_t ticks; + uint8_t midnight; + + /* Re-enable interrupts so that the timer interrupt can occur */ + __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" + "nop\n\t" + "nop\n\t" + "cli\n\t" ) : : ); + + get_real ( ticks, BDA_SEG, 0x006c ); + get_real ( midnight, BDA_SEG, 0x0070 ); + + if ( midnight ) { + midnight = 0; + put_real ( midnight, BDA_SEG, 0x0070 ); + days += 0x1800b0; + } + + return ( (days + ticks) * (USECS_IN_SEC / TIMER2_TICKS_PER_SEC) ); +} + +static int bios_ts_init(void) +{ + DBG("BIOS timer installed\n"); + return 0; +} + +struct timer bios_ts __timer ( 02 ) = { + .init = bios_ts_init, + .udelay = i386_timer2_udelay, + .currticks = bios_currticks, +}; + diff --git a/src/arch/i386/drivers/timer_rtdsc.c b/src/arch/i386/drivers/timer_rtdsc.c new file mode 100644 index 000000000..1cd2abead --- /dev/null +++ b/src/arch/i386/drivers/timer_rtdsc.c @@ -0,0 +1,90 @@ + +#include +#include +#include +#include +#include +#include + + +#define rdtsc(low,high) \ + __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) + +#define rdtscll(val) \ + __asm__ __volatile__ ("rdtsc" : "=A" (val)) + +static unsigned long long calibrate_tsc(void) +{ + uint32_t startlow, starthigh; + uint32_t endlow, endhigh; + + rdtsc(startlow,starthigh); + i386_timer2_udelay(USECS_IN_MSEC/2); + rdtsc(endlow,endhigh); + + /* 64-bit subtract - gcc just messes up with long longs */ + /* XXX ORLY? Check it. */ + __asm__("subl %2,%0\n\t" + "sbbl %3,%1" + :"=a" (endlow), "=d" (endhigh) + :"g" (startlow), "g" (starthigh), + "0" (endlow), "1" (endhigh)); + + /* Error: ECPUTOOFAST */ + if (endhigh) + goto bad_ctc; + + endlow *= MSECS_IN_SEC*2; + return endlow; + + /* + * The CTC wasn't reliable: we got a hit on the very first read, + * or the CPU was so fast/slow that the quotient wouldn't fit in + * 32 bits.. + */ +bad_ctc: + return 0; +} +static uint32_t clocks_per_second = 0; + +static tick_t rtdsc_currticks(void) +{ + uint32_t clocks_high, clocks_low; + uint32_t currticks; + + /* Read the Time Stamp Counter */ + rdtsc(clocks_low, clocks_high); + + /* currticks = clocks / clocks_per_tick; */ + __asm__("divl %1" + :"=a" (currticks) + :"r" (clocks_per_second/USECS_IN_SEC), "0" (clocks_low), "d" (clocks_high)); + + return currticks; +} + +static int rtdsc_ts_init(void) +{ + + struct cpuinfo_x86 cpu_info; + + get_cpuinfo(&cpu_info); + if (cpu_info.features & X86_FEATURE_TSC) { + clocks_per_second = calibrate_tsc(); + if (clocks_per_second) { + DBG("RTDSC Ticksource installed. CPU running at %ld Mhz\n", + clocks_per_second/(1000*1000)); + return 0; + } + } + + printf("RTDSC timer not available on this machine.\n"); + return 1; +} + +struct timer rtdsc_ts __timer (01) = { + .init = rtdsc_ts_init, + .udelay = generic_currticks_udelay, + .currticks = rtdsc_currticks, +}; + diff --git a/src/arch/i386/firmware/pcbios/bios.c b/src/arch/i386/firmware/pcbios/bios.c deleted file mode 100644 index bcbe98a88..000000000 --- a/src/arch/i386/firmware/pcbios/bios.c +++ /dev/null @@ -1,55 +0,0 @@ -/* Etherboot routines for PCBIOS firmware. - * - * Body of routines taken from old pcbios.S - */ - -#include -#include -#include - -#define CF ( 1 << 0 ) - -/************************************************************************** -CURRTICKS - Get Time -Use direct memory access to BIOS variables, longword 0040:006C (ticks -today) and byte 0040:0070 (midnight crossover flag) instead of calling -timeofday BIOS interrupt. -**************************************************************************/ -#if defined(CONFIG_TSC_CURRTICKS) -#undef CONFIG_BIOS_CURRTICKS -#else -#define CONFIG_BIOS_CURRTICKS 1 -#endif -#if defined(CONFIG_BIOS_CURRTICKS) -unsigned long currticks ( void ) { - static uint32_t days = 0; - uint32_t ticks; - uint8_t midnight; - - /* Re-enable interrupts so that the timer interrupt can occur - */ - __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" - "nop\n\t" - "nop\n\t" - "cli\n\t" ) : : ); - - get_real ( ticks, BDA_SEG, 0x006c ); - get_real ( midnight, BDA_SEG, 0x0070 ); - - if ( midnight ) { - midnight = 0; - put_real ( midnight, BDA_SEG, 0x0070 ); - days += 0x1800b0; - } - return ( days + ticks ); -} -#endif /* CONFIG_BIOS_CURRTICKS */ - -/************************************************************************** -CPU_NAP - Save power by halting the CPU until the next interrupt -**************************************************************************/ -void cpu_nap ( void ) { - __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" - "hlt\n\t" - "cli\n\t" ) : : ); -} diff --git a/src/arch/i386/include/bits/timer2.h b/src/arch/i386/include/bits/timer2.h new file mode 100644 index 000000000..83923b299 --- /dev/null +++ b/src/arch/i386/include/bits/timer2.h @@ -0,0 +1,8 @@ +#ifndef BITS_TIMER2_H +#define BITS_TIMER2_H + +#include + +void i386_timer2_udelay(unsigned int usecs); + +#endif diff --git a/src/config.h b/src/config.h index 9aa9e8fdf..af0df1b69 100644 --- a/src/config.h +++ b/src/config.h @@ -18,11 +18,14 @@ */ #define CONSOLE_FIRMWARE /* Default BIOS console */ -#undef CONSOLE_SERIAL /* Serial port */ +#define CONSOLE_SERIAL /* Serial port */ #undef CONSOLE_DIRECT_VGA /* Direct access to VGA card */ #undef CONSOLE_BTEXT /* Who knows what this does? */ #undef CONSOLE_PC_KBD /* Direct access to PC keyboard */ +#define TIMER_BIOS +#define TIMER_RTDSC + /* @END general.h */ /* @BEGIN serial.h diff --git a/src/core/config.c b/src/core/config.c index d5accecfe..f3e17b62e 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -74,6 +74,17 @@ REQUIRE_OBJECT ( pc_kbd ); REQUIRE_OBJECT ( syslog ); #endif +/* + * Timers + */ + +#ifdef TIMER_BIOS +REQUIRE_OBJECT ( timer_bios ); +#endif + +#ifdef TIMER_RTDSC +REQUIRE_OBJECT ( timer_rtdsc ); +#endif /* * Drag in all requested protocols * diff --git a/src/core/misc.c b/src/core/misc.c index 4219a36c5..fcf0aeab3 100644 --- a/src/core/misc.c +++ b/src/core/misc.c @@ -7,18 +7,6 @@ MISC Support Routines #include #include -/************************************************************************** -SLEEP -**************************************************************************/ -unsigned int sleep(unsigned int secs) -{ - unsigned long tmo; - - for (tmo = currticks()+secs*TICKS_PER_SEC; currticks() < tmo; ) { - } - return 0; -} - /************************************************************************** INET_ATON - Convert an ascii x.x.x.x to binary form **************************************************************************/ diff --git a/src/core/timer.c b/src/core/timer.c index c56e53109..da53e0539 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -1,27 +1,104 @@ -/* A couple of routines to implement a low-overhead timer for drivers */ - - /* +/* + * core/timer.c + * + * Copyright (C) 2007 Alexey Zaytsev + * * 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 2, or (at - * your option) any later version. + * published by the Free Software Foundation; either version 2 of the + * License, or 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "timer.h" +#include +#include +#include +#include +#include -/* Machine Independant timer helper functions */ +static struct timer ts_table[0] + __table_start ( struct timer, timers ); +static struct timer ts_table_end[0] + __table_end ( struct timer, timers ); + + +static struct timer *used_ts = NULL; + +/* + * This function may be used in custom timer driver. + * + * This udelay implementation works well if you've got a + * fast currticks(). + */ +void generic_currticks_udelay(unsigned int usecs) +{ + tick_t t; + + t = currticks(); + while (t + usecs > currticks()) + ; /* xxx: Relax the cpu some way. */ +} + + +static void timer_init(void) +{ + struct timer *ts; + + for (ts = ts_table; ts < ts_table_end; ts++) { + if (ts->init && !ts->init()) { + used_ts = ts; + break; + } + } + + if (!used_ts) { + printf("No timer available. This should never happen. Expect gPXE to die soon.\n"); + /* Panic */ + } + +} + +struct init_fn ts_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = timer_init, +}; + +/* Functions for public use. */ + +tick_t currticks(void) +{ + tick_t ct; + assert(used_ts); + + ct = used_ts->currticks(); + DBG("currticks: %ld seconds and %06ld microseconds\n", ct/USECS_IN_SEC, ct%USECS_IN_SEC); + + return ct; +} + +void udelay(unsigned int usecs) +{ + used_ts->udelay(usecs); +} void mdelay(unsigned int msecs) { - unsigned int i; - for(i = 0; i < msecs; i++) { - udelay(1000); - } + while(msecs--) + used_ts->udelay(USECS_IN_MSEC); } -void waiton_timer2(unsigned int ticks) +unsigned int sleep(unsigned int secs) { - load_timer2(ticks); - while(timer2_running()) { - } + while (secs--) + mdelay(MSECS_IN_SEC); + + return 0; } + diff --git a/src/include/gpxe/timer.h b/src/include/gpxe/timer.h new file mode 100644 index 000000000..4a4cf5b2f --- /dev/null +++ b/src/include/gpxe/timer.h @@ -0,0 +1,32 @@ +#ifndef GPXE_TIMER_H +#define GPXE_TIMER_H + +#include + +typedef uint32_t tick_t; + +#define MSECS_IN_SEC (1000) +#define USECS_IN_SEC (1000*1000) +#define USECS_IN_MSEC (1000) + +#define TICKS_PER_SEC USECS_IN_SEC + +tick_t currticks(void); + +void generic_currticks_udelay(unsigned int usecs); + +struct timer { + /* Returns zero on successful initialisation. */ + int (*init) (void); + + /* Return the current time, int mictoseconds since the beginning. */ + tick_t (*currticks) (void); + + /* Sleep for a few useconds. */ + void (*udelay) (unsigned int useconds); +}; + +#define __timer(order) __table (struct timer, timers, order) + +#endif /* GPXE_TIMER_H */ + diff --git a/src/include/timer.h b/src/include/timer.h index 0044d0c07..cd1b2821a 100644 --- a/src/include/timer.h +++ b/src/include/timer.h @@ -1,61 +1,27 @@ -/* Defines for routines to implement a low-overhead timer for drivers */ - - /* - * 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 2, or (at - * your option) any later version. - */ - -#ifndef TIMER_H +#ifndef TIMER_H #define TIMER_H -/* Ports for the 8254 timer chip */ -#define TIMER2_PORT 0x42 -#define TIMER_MODE_PORT 0x43 +/* + * This file should be removed as soon as there are no + * currticks() abusers. + */ -/* Meaning of the mode bits */ -#define TIMER0_SEL 0x00 -#define TIMER1_SEL 0x40 -#define TIMER2_SEL 0x80 -#define READBACK_SEL 0xC0 +#include +/* +#warning Please fix me. I'm abusing the deprecated include/timer.h +*/ +#include -#define LATCH_COUNT 0x00 -#define LOBYTE_ACCESS 0x10 -#define HIBYTE_ACCESS 0x20 -#define WORD_ACCESS 0x30 +/* Duplicates include/gpxe/timer.h */ +typedef uint32_t tick_t; -#define MODE0 0x00 -#define MODE1 0x02 -#define MODE2 0x04 -#define MODE3 0x06 -#define MODE4 0x08 -#define MODE5 0x0A +#define MSECS_IN_SEC (1000) +#define USECS_IN_SEC (1000*1000) +#define USECS_IN_MSEC (1000) -#define BINARY_COUNT 0x00 -#define BCD_COUNT 0x01 +#define TICKS_PER_SEC USECS_IN_SEC -/* Timers tick over at this rate */ -#define CLOCK_TICK_RATE 1193180U -#define TICKS_PER_MS (CLOCK_TICK_RATE/1000) +tick_t currticks(void); -/* Parallel Peripheral Controller Port B */ -#define PPC_PORTB 0x61 +#endif -/* Meaning of the port bits */ -#define PPCB_T2OUT 0x20 /* Bit 5 */ -#define PPCB_SPKR 0x02 /* Bit 1 */ -#define PPCB_T2GATE 0x01 /* Bit 0 */ - -/* Ticks must be between 0 and 65535 (0 == 65536) - because it is a 16 bit counter */ -extern void load_timer2(unsigned int ticks); -extern inline int timer2_running(void); -extern void waiton_timer2(unsigned int ticks); - -extern void ndelay(unsigned int nsecs); -extern void udelay(unsigned int usecs); -extern void mdelay(unsigned int msecs); - - -#endif /* TIMER_H */ diff --git a/src/include/unistd.h b/src/include/unistd.h index 35dcf5845..7c44a0ced 100644 --- a/src/include/unistd.h +++ b/src/include/unistd.h @@ -4,7 +4,7 @@ #include #include -extern unsigned int sleep ( unsigned int seconds ); +unsigned int sleep ( unsigned int seconds ); extern int execv ( const char *command, char * const argv[] ); /** @@ -22,4 +22,10 @@ extern int execv ( const char *command, char * const argv[] ); rc; \ } ) +void udelay(unsigned int usecs); +void mdelay(unsigned int msecs); + +#define usleep(x) udelay(x) + + #endif /* _UNISTD_H */