⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 timer.c

📁 nucleus_arm.rar
💻 C
字号:
/*
* Timer functions						*
* v0.1: TDS								*
*       - basic routines				*
* v0.2: TDS (26.05.2004)				*
*		- timer queued sub procedures	*
*		- detection of timer controller *
* v0.3: Doug Gale (01.08.2004)					*
*		- delay(): Improved resolution			*
*		- delay(): Works with IRQ disabled		*
*		- delay(): Corrected duration of delay	*
*		- delay(): Yields unwanted CPU time		*
*		- Corrected disabling of interrupts		*
*/
#include <stdio.h>
#include <support.h>
#include <interrupts.h>
#include <drivers/pic.h>
#include <irqa.h>
#include <multi.h>
#include <drivers/timer.h>
#include <drivers/input.h>
#include <drivers/mem/mem.h>

volatile long long timer_ticks;

// Called in timer IRQ handler
void timer_tick(void)
{
	timer_ticks++;
}

// Wait the specified number of milliseconds
// If you wait less than 16.6ms, has 1 microsecond accuracy
// If you wait more than 16.6ms, has 16.6ms microsecond accuracy
// Works when interrupts are disabled
// Could wait slightly longer than requested
void delay(int x)
{
	dword tmp;
	
	if (x <= 166 || !interrupts_query()) {
		//
		// Short delay or interrupts are disabled

		// Convert milliseconds to microseconds
		tmp = 1000 * x;
		while (tmp--)
			outportb(0x80, 0);
	} else {
		//
		// Long delay, interrupts enabled, CPU efficient

		tmp = timer_ticks + ((x * 60) / 1000);
		while (timer_ticks <= tmp)
			multi_yield();
	}
}

#define TIMER_PORT	0x43
#define PIT_LOW		0x10
#define PIT_HIGH	0x20
#define PIT_BOTH	0x30

#define PIT_MODE_0	0x0	// One shot 
#define PIT_MODE_1	0x2	// No worky 
#define PIT_MODE_2	0x4	// forever 
#define PIT_MODE_3	0x6	// forever 
#define PIT_MODE_4	0x8	// No worky 
#define PIT_MODE_5	0xA	// No worky 

#define Timer_EMUL	0		// Timer is faulty or emulated by OS 
#define Timer_8253	1		// Timer is an 8253 
#define Timer_8254	2		// Timer is an 8254 
#define TIMER_60HZ	0x4DAE	// 60Hz
#define TIMER_30HZ	0x965C	// 30Hz
#define TIMER_20HZ	0xE90B	// 20Hz
#define TIMER_18HZ	0xFFFF	// 18.2Hz (standard count)

unsigned timer_get(int channel)
{
	unsigned tmp;
	
	outportb(TIMER_PORT, channel * 0x40);
	tmp  = inportb(channel + 0x40);
	tmp |= (inportb(channel + 0x40) << 8);
	return tmp;
}

void timer_set(int channel, unsigned value)
{
	outportb(TIMER_PORT, (channel*0x40) | PIT_BOTH | PIT_MODE_3);
	outportb((0x40+channel), (value & 0xFF));
	outportb((0x40+channel), (value >> 8));
}

// FIXME: 8253 is present only in old IBM XT

// detect type of Timer chip - 8253, 8254 or emulated
static unsigned timer_get_type(void)
{
	const word TestValue = 0x55AA;
	const word Backwards = (word)((LOWORD(TestValue) << 8) + HIWORD(TestValue));
	const word EXP_CSTAT = 0x30;	// Expected counter status
	int ints_were_enabled;

	byte port61;
    byte rdb_status1, rdb_status2;
    word rdb_count1, rdb_count2;
    byte timer_type;
    word i, j;
    
	timer_type = Timer_EMUL;
	
	ints_were_enabled = interrupts_disable();

	// turn off speaker & set gate2 input to low 
	port61 = inportb(0x61);
	outportb(0x61, port61 & 0xFC);
  	// program channel 2 to mode 0, two bytes, binary 
	outportb(0x43, 0xB0);
  	outportb(0x42, LOBYTE(TestValue));
 	outportb(0x42, HIBYTE(TestValue));
	// wait until the value of counter 0 changes 
	i = j = timer_get(0);
	while ((j = timer_get(0)) == i);
	i = j;
	while ((j = timer_get(0)) == i);
	// read value from counter 2, test if readout is stable
	i = timer_get(2);
	j = timer_get(2);
	// if not then the Timer is bad or emulated
	if ((i != j) || (i != TestValue))
		goto got_type;
	// readback command will reverse lo/hi flag on a 8053
	outportb(0x43, 0xC8);
  	rdb_status1 = inportb(0x42);
	rdb_count1 = inportb(0x42);
  	rdb_count1 = (inportb(0x42) << 8) + rdb_count1;
	i = timer_get(2);
	// read again to fix hi/lo flag
	outportb(0x43, 0xC8);
	rdb_status2 = inportb(0x42);
	rdb_count2 = inportb(0x42);
	rdb_count2 = (inportb(0x42) << 8) + rdb_count2;
	j = timer_get(2);
	if ((rdb_status1 != EXP_CSTAT) && (rdb_status2 != EXP_CSTAT) && (i == Backwards) && (j == TestValue))
        timer_type = Timer_8253;
	if ((rdb_status1 == EXP_CSTAT) && (rdb_status2 == EXP_CSTAT) && (i == TestValue) && (j == TestValue))
		timer_type = Timer_8254;
got_type:

	if (ints_were_enabled)
		interrupts_enable();

	return timer_type;
}

void timer_init(void)
{
	dprintf("timer: Checking type...");
	switch(timer_get_type())
	{
		case Timer_EMUL: dprintf("emulated!\n"); break;
		case Timer_8253: dprintf("8253\n"); break;
		case Timer_8254: dprintf("8254\n"); break;
		default: dprintf("unknown!\n"); break;
	}
	timer_ticks=0;
	timer_set(0, TIMER_60HZ);

	interrupt_install(INT_HARDWARE, 0, isr_timer);
	irq_enable(0);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -