diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2008-05-18 17:12:06 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2008-05-18 17:12:06 -0400 |
commit | 5be049093df6206cd8fd3017731abcfd40084da5 (patch) | |
tree | a3c4f18b5c82e6971e7f61275dfc229b3008de58 | |
parent | c25886949524d1e1a9809cf1a9908b070b731c03 (diff) | |
download | seabios-hppa-5be049093df6206cd8fd3017731abcfd40084da5.zip seabios-hppa-5be049093df6206cd8fd3017731abcfd40084da5.tar.gz seabios-hppa-5be049093df6206cd8fd3017731abcfd40084da5.tar.bz2 |
Implement usleep using real time clock.
The old usleep implementation relied on ps2 port refresh bit which is
not very portable.
This patch also refactors some of the code in clock.c.
-rw-r--r-- | src/clock.c | 137 | ||||
-rw-r--r-- | src/cmos.h | 3 | ||||
-rw-r--r-- | src/system.c | 10 | ||||
-rw-r--r-- | src/util.c | 12 | ||||
-rw-r--r-- | src/util.h | 3 |
5 files changed, 109 insertions, 56 deletions
diff --git a/src/clock.c b/src/clock.c index 42b8c69..8d908a7 100644 --- a/src/clock.c +++ b/src/clock.c @@ -13,6 +13,18 @@ #define DEBUGF1(fmt, args...) bprintf(0, fmt , ##args) #define DEBUGF(fmt, args...) +// RTC register flags +#define RTC_A_UIP 0x80 +#define RTC_B_SET 0x80 +#define RTC_B_PIE 0x40 +#define RTC_B_AIE 0x20 +#define RTC_B_UIE 0x10 + + +/**************************************************************** + * Init + ****************************************************************/ + static void pit_setup() { @@ -53,6 +65,11 @@ init_rtc() inb_cmos(CMOS_STATUS_D); } + +/**************************************************************** + * Standard clock functions + ****************************************************************/ + static u8 rtc_updating() { @@ -183,7 +200,8 @@ handle_1a05(struct bregs *regs) outb_cmos(regs->dh, CMOS_RTC_MONTH); outb_cmos(regs->dl, CMOS_RTC_DAY_MONTH); outb_cmos(regs->ch, CMOS_CENTURY); - u8 val8 = inb_cmos(CMOS_STATUS_B) & 0x7f; // clear halt-clock bit + // clear halt-clock bit + u8 val8 = inb_cmos(CMOS_STATUS_B) & ~RTC_B_SET; outb_cmos(val8, CMOS_STATUS_B); regs->ah = 0; regs->al = val8; // AL = val last written to Reg B @@ -220,7 +238,7 @@ handle_1a06(struct bregs *regs) outb_cmos(regs->ch, CMOS_RTC_HOURS_ALARM); outb(inb(PORT_PIC2_DATA) & ~PIC2_IRQ8, PORT_PIC2_DATA); // enable IRQ 8 // enable Status Reg B alarm bit, clear halt clock bit - outb_cmos((val8 & 0x7f) | 0x20, CMOS_STATUS_B); + outb_cmos((val8 & ~RTC_B_SET) | RTC_B_AIE, CMOS_STATUS_B); set_success(regs); } @@ -240,7 +258,7 @@ handle_1a07(struct bregs *regs) // My assumption: RegB = (RegB & 01010111b) u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B // clear clock-halt bit, disable alarm bit - outb_cmos(val8 & 0x57, CMOS_STATUS_B); // disable alarm bit + outb_cmos(val8 & ~(RTC_B_SET|RTC_B_AIE), CMOS_STATUS_B); regs->ah = 0; regs->al = val8; // val last written to Reg B set_success(regs); @@ -309,41 +327,103 @@ handle_08() eoi_master_pic(); } -// Set Interval requested. -static void -handle_158300(struct bregs *regs) + +/**************************************************************** + * Periodic timer + ****************************************************************/ + +static int +set_usertimer(u32 msecs, u16 seg, u16 offset) { - if (GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING) { - // Interval already set. - DEBUGF("int15: Func 83h, failed, already waiting.\n" ); - set_code_fail(regs, RET_EUNSUPPORTED); - } + if (GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING) + return -1; + // Interval not already set. SET_BDA(rtc_wait_flag, RWS_WAIT_PENDING); // Set status byte. - u32 v = (regs->es << 16) | regs->bx; - SET_BDA(ptr_user_wait_complete_flag, v); - v = (regs->dx << 16) | regs->cx; - SET_BDA(user_wait_timeout, v); + SET_BDA(ptr_user_wait_complete_flag, (seg << 16) | offset); + SET_BDA(user_wait_timeout, msecs); // Unmask IRQ8 so INT70 will get through. u8 irqDisable = inb(PORT_PIC2_DATA); outb(irqDisable & ~PIC2_IRQ8, PORT_PIC2_DATA); // Turn on the Periodic Interrupt timer u8 bRegister = inb_cmos(CMOS_STATUS_B); - outb_cmos(bRegister | CSB_EN_ALARM_IRQ, CMOS_STATUS_B); + outb_cmos(bRegister | RTC_B_PIE, CMOS_STATUS_B); - set_success(regs); // XXX - no set ah? + return 0; +} + +static void +clear_usertimer() +{ + // Turn off status byte. + SET_BDA(rtc_wait_flag, 0); + // Clear the Periodic Interrupt. + u8 bRegister = inb_cmos(CMOS_STATUS_B); + outb_cmos(bRegister & ~RTC_B_PIE, CMOS_STATUS_B); +} + +// Sleep for n microseconds. +int +usleep(u32 count) +{ +#ifdef MODE16 + // In 16bit mode, use the rtc to wait for the specified time. + u8 statusflag = 0; + int ret = set_usertimer(count, GET_SEG(SS), (u32)&statusflag); + if (ret) + return -1; + irq_enable(); + while (!statusflag) + cpu_relax(); + irq_disable(); + return 0; +#else + // In 32bit mode, we need to call into 16bit mode to sleep. + struct bregs br; + memset(&br, 0, sizeof(br)); + br.ah = 0x86; + br.cx = count >> 16; + br.dx = count; + call16_int(0x15, &br); + if (br.flags & F_CF) + return -1; + return 0; +#endif +} + +#define RET_ECLOCKINUSE 0x83 + +// Wait for CX:DX microseconds. currently using the +// refresh request port 0x61 bit4, toggling every 15usec +void +handle_1586(struct bregs *regs) +{ + int ret = usleep((regs->cx << 16) | regs->dx); + if (ret) + set_code_fail(regs, RET_ECLOCKINUSE); + else + set_success(regs); +} + +// Set Interval requested. +static void +handle_158300(struct bregs *regs) +{ + int ret = set_usertimer((regs->cx << 16) | regs->dx, regs->es, regs->bx); + if (ret) + // Interval already set. + set_code_fail(regs, RET_EUNSUPPORTED); + else + set_success(regs); } // Clear interval requested static void handle_158301(struct bregs *regs) { - SET_BDA(rtc_wait_flag, 0); // Clear status byte - // Turn off the Periodic Interrupt timer - u8 bRegister = inb_cmos(CMOS_STATUS_B); - outb_cmos(bRegister & ~CSB_EN_ALARM_IRQ, CMOS_STATUS_B); - set_success(regs); // XXX - no set ah? + clear_usertimer(); + set_success(regs); } static void @@ -367,13 +447,13 @@ handle_1583(struct bregs *regs) void VISIBLE16 handle_70() { - debug_isr(); + //debug_isr(); // Check which modes are enabled and have occurred. u8 registerB = inb_cmos(CMOS_STATUS_B); u8 registerC = inb_cmos(CMOS_STATUS_C); - if (!(registerB & 0x60)) + if (!(registerB & (RTC_B_PIE|RTC_B_AIE))) goto done; if (registerC & 0x20) { // Handle Alarm Interrupt. @@ -393,17 +473,14 @@ handle_70() // Wait Interval (Int 15, AH=83) active. u32 time = GET_BDA(user_wait_timeout); // Time left in microseconds. if (time < 0x3D1) { - // Done waiting. + // Done waiting - write to specified flag byte. u32 segoff = GET_BDA(ptr_user_wait_complete_flag); u16 segment = segoff >> 16; u16 offset = segoff & 0xffff; - // Turn off status byte. - SET_BDA(rtc_wait_flag, 0); - // Clear the Periodic Interrupt. - outb_cmos(registerB & 0x37, CMOS_STATUS_B); - // Write to specified flag byte. u8 oldval = GET_FARVAR(segment, *(u8*)(offset+0)); SET_FARVAR(segment, *(u8*)(offset+0), oldval | 0x80); + + clear_usertimer(); } else { // Continue waiting. time -= 0x3D1; @@ -39,9 +39,6 @@ #define CMOS_BIOS_DISKTRANSFLAG 0x39 #define CMOS_BIOS_BOOTFLAG2 0x3d -// CMOS_STATUS_B bitdefs -#define CSB_EN_ALARM_IRQ (1<<5) - // CMOS_FLOPPY_DRIVE_TYPE bitdefs #define CFD_NO_DRIVE 0 #define CFD_360KB 1 diff --git a/src/system.c b/src/system.c index 72c0735..f7ff31e 100644 --- a/src/system.c +++ b/src/system.c @@ -83,16 +83,6 @@ handle_1552(struct bregs *regs) set_code_success(regs); } -// Wait for CX:DX microseconds. currently using the -// refresh request port 0x61 bit4, toggling every 15usec -static void -handle_1586(struct bregs *regs) -{ - irq_enable(); - usleep((regs->cx << 16) | regs->dx); - irq_disable(); -} - static void handle_1587(struct bregs *regs) { @@ -11,18 +11,6 @@ checksum(u8 *far_data, u32 len) return sum; } -// Sleep for n microseconds. currently using the -// refresh request port 0x61 bit4, toggling every 15usec -void -usleep(u32 count) -{ - count = count / 15; - u8 kbd = inb(PORT_PS2_CTRLB); - while (count) - if ((inb(PORT_PS2_CTRLB) ^ kbd) & KBD_REFRESH) - count--; -} - void * memset(void *s, int c, size_t n) { @@ -151,7 +151,9 @@ void lpt_setup(); // clock.c void timer_setup(); +int usleep(u32 count); void handle_1583(struct bregs *regs); +void handle_1586(struct bregs *regs); // apm.c void VISIBLE16 handle_1553(struct bregs *regs); @@ -161,7 +163,6 @@ void handle_1ab1(struct bregs *regs); // util.c u8 checksum(u8 *far_data, u32 len); -void usleep(u32 count); // rombios32.c void rombios32_init(void); |