X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fserial.c;h=21b4bd010586166bc4cfe8453a268147870403aa;hb=refs%2Fheads%2Fcoreboot;hp=8ca7e36781e7737b238b5103029c3a78dfb74656;hpb=913cc2e089536edc3b0c2199d5b1f38545c50b1b;p=seabios.git diff --git a/src/serial.c b/src/serial.c index 8ca7e36..21b4bd0 100644 --- a/src/serial.c +++ b/src/serial.c @@ -1,12 +1,13 @@ // 16bit code to handle serial and printer services. // -// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2008,2009 Kevin O'Connor // Copyright (C) 2002 MandrakeSoft S.A. // -// This file may be distributed under the terms of the GNU GPLv3 license. +// This file may be distributed under the terms of the GNU LGPLv3 license. -#include "biosvar.h" // struct bregs +#include "biosvar.h" // SET_BDA #include "util.h" // debug_enter +#include "bregs.h" // struct bregs /**************************************************************** @@ -16,25 +17,33 @@ static u16 detect_serial(u16 port, u8 timeout, u8 count) { - outb(0x02, port+1); - if (inb(port+1) != 0x02) + outb(0x02, port+SEROFF_IER); + u8 ier = inb(port+SEROFF_IER); + if (ier != 0x02) return 0; - if (inb(port+2) != 0x02) + u8 iir = inb(port+SEROFF_IIR); + if ((iir & 0x3f) != 0x02) return 0; - outb(0x00, port+1); + + outb(0x00, port+SEROFF_IER); SET_BDA(port_com[count], port); SET_BDA(com_timeout[count], timeout); return 1; } void -serial_setup() +serial_setup(void) { + if (! CONFIG_SERIAL) + return; + dprintf(3, "init serial\n"); + u16 count = 0; - count += detect_serial(0x3f8, 0x0a, count); - count += detect_serial(0x2f8, 0x0a, count); - count += detect_serial(0x3e8, 0x0a, count); - count += detect_serial(0x2e8, 0x0a, count); + count += detect_serial(PORT_SERIAL1, 0x0a, count); + count += detect_serial(PORT_SERIAL2, 0x0a, count); + count += detect_serial(PORT_SERIAL3, 0x0a, count); + count += detect_serial(PORT_SERIAL4, 0x0a, count); + dprintf(1, "Found %d serial ports\n", count); // Equipment word bits 9..11 determing # serial ports u16 eqb = GET_BDA(equipment_list_flags); @@ -45,108 +54,117 @@ static u16 getComAddr(struct bregs *regs) { if (regs->dx >= 4) { - set_fail(regs); + set_invalid(regs); return 0; } u16 addr = GET_BDA(port_com[regs->dx]); if (! addr) - set_fail(regs); + set_invalid(regs); return addr; } +// SERIAL - INITIALIZE PORT static void handle_1400(struct bregs *regs) { u16 addr = getComAddr(regs); if (!addr) return; - outb(inb(addr+3) | 0x80, addr+3); + outb(inb(addr+SEROFF_LCR) | 0x80, addr+SEROFF_LCR); if ((regs->al & 0xE0) == 0) { - outb(0x17, addr); - outb(0x04, addr+1); + outb(0x17, addr+SEROFF_DLL); + outb(0x04, addr+SEROFF_DLH); } else { u16 val16 = 0x600 >> ((regs->al & 0xE0) >> 5); - outb(val16 & 0xFF, addr); - outb(val16 >> 8, addr+1); + outb(val16 & 0xFF, addr+SEROFF_DLL); + outb(val16 >> 8, addr+SEROFF_DLH); } - outb(regs->al & 0x1F, addr+3); - regs->ah = inb(addr+5); - regs->al = inb(addr+6); + outb(regs->al & 0x1F, addr+SEROFF_LCR); + regs->ah = inb(addr+SEROFF_LSR); + regs->al = inb(addr+SEROFF_MSR); set_success(regs); } +// SERIAL - WRITE CHARACTER TO PORT static void handle_1401(struct bregs *regs) { u16 addr = getComAddr(regs); if (!addr) return; - u16 timer = GET_BDA(timer_counter); - u16 timeout = GET_BDA(com_timeout[regs->dx]); - while (((inb(addr+5) & 0x60) != 0x60) && (timeout)) { - u16 val16 = GET_BDA(timer_counter); - if (val16 != timer) { - timer = val16; - timeout--; + u32 end = calc_future_timer_ticks(GET_BDA(com_timeout[regs->dx])); + for (;;) { + u8 lsr = inb(addr+SEROFF_LSR); + if ((lsr & 0x60) == 0x60) { + // Success - can write data + outb(regs->al, addr+SEROFF_DATA); + // XXX - reread lsr? + regs->ah = lsr; + break; + } + if (check_timer(end)) { + // Timed out - can't write data. + regs->ah = lsr | 0x80; + break; } + yield(); } - if (timeout) - outb(regs->al, addr); - regs->ah = inb(addr+5); - if (!timeout) - regs->ah |= 0x80; set_success(regs); } +// SERIAL - READ CHARACTER FROM PORT static void handle_1402(struct bregs *regs) { u16 addr = getComAddr(regs); if (!addr) return; - u16 timer = GET_BDA(timer_counter); - u16 timeout = GET_BDA(com_timeout[regs->dx]); - while (((inb(addr+5) & 0x01) == 0) && (timeout)) { - u16 val16 = GET_BDA(timer_counter); - if (val16 != timer) { - timer = val16; - timeout--; + u32 end = calc_future_timer_ticks(GET_BDA(com_timeout[regs->dx])); + for (;;) { + u8 lsr = inb(addr+SEROFF_LSR); + if (lsr & 0x01) { + // Success - can read data + regs->al = inb(addr+SEROFF_DATA); + regs->ah = lsr; + break; } - } - if (timeout) { - regs->ah = 0; - regs->al = inb(addr); - } else { - regs->ah = inb(addr+5); + if (check_timer(end)) { + // Timed out - can't read data. + regs->ah = lsr | 0x80; + break; + } + yield(); } set_success(regs); } +// SERIAL - GET PORT STATUS static void handle_1403(struct bregs *regs) { u16 addr = getComAddr(regs); if (!addr) return; - regs->ah = inb(addr+5); - regs->al = inb(addr+6); + regs->ah = inb(addr+SEROFF_LSR); + regs->al = inb(addr+SEROFF_MSR); set_success(regs); } static void handle_14XX(struct bregs *regs) { - // Unsupported - set_fail(regs); + set_unimplemented(regs); } // INT 14h Serial Communications Service Entry Point void VISIBLE16 handle_14(struct bregs *regs) { - debug_enter(regs); - - irq_enable(); + debug_enter(regs, DEBUG_HDL_14); + if (! CONFIG_SERIAL) { + handle_14XX(regs); + return; + } switch (regs->ah) { case 0x00: handle_1400(regs); break; @@ -157,6 +175,9 @@ handle_14(struct bregs *regs) } } +// XXX - Baud Rate Generator Table +u8 BaudTable[16] VAR16FIXED(0xe729); + /**************************************************************** * LPT ports @@ -178,11 +199,16 @@ detect_parport(u16 port, u8 timeout, u8 count) } void -lpt_setup() +lpt_setup(void) { + if (! CONFIG_LPT) + return; + dprintf(3, "init lpt\n"); + u16 count = 0; - count += detect_parport(0x378, 0x14, count); - count += detect_parport(0x278, 0x14, count); + count += detect_parport(PORT_LPT1, 0x14, count); + count += detect_parport(PORT_LPT2, 0x14, count); + dprintf(1, "Found %d lpt ports\n", count); // Equipment word bits 14..15 determing # parallel ports u16 eqb = GET_BDA(equipment_list_flags); @@ -193,25 +219,15 @@ static u16 getLptAddr(struct bregs *regs) { if (regs->dx >= 3) { - set_fail(regs); + set_invalid(regs); return 0; } u16 addr = GET_BDA(port_lpt[regs->dx]); if (! addr) - set_fail(regs); + set_invalid(regs); return addr; } -static void -lpt_ret(struct bregs *regs, u16 addr, u16 timeout) -{ - u8 val8 = inb(addr+1); - regs->ah = (val8 ^ 0x48); - if (!timeout) - regs->ah |= 0x01; - set_success(regs); -} - // INT 17 - PRINTER - WRITE CHARACTER static void handle_1700(struct bregs *regs) @@ -219,17 +235,31 @@ handle_1700(struct bregs *regs) u16 addr = getLptAddr(regs); if (!addr) return; - u16 timeout = GET_BDA(lpt_timeout[regs->dx]) << 8; + + u32 end = calc_future_timer_ticks(GET_BDA(lpt_timeout[regs->dx])); outb(regs->al, addr); u8 val8 = inb(addr+2); outb(val8 | 0x01, addr+2); // send strobe - nop(); + udelay(5); outb(val8 & ~0x01, addr+2); - while (((inb(addr+1) & 0x40) == 0x40) && (timeout)) - timeout--; - lpt_ret(regs, addr, timeout); + for (;;) { + u8 v = inb(addr+1); + if (!(v & 0x40)) { + // Success + regs->ah = v ^ 0x48; + break; + } + if (check_timer(end)) { + // Timeout + regs->ah = (v ^ 0x48) | 0x01; + break; + } + yield(); + } + + set_success(regs); } // INT 17 - PRINTER - INITIALIZE PORT @@ -239,14 +269,14 @@ handle_1701(struct bregs *regs) u16 addr = getLptAddr(regs); if (!addr) return; - u16 timeout = GET_BDA(lpt_timeout[regs->dx]) << 8; u8 val8 = inb(addr+2); outb(val8 & ~0x04, addr+2); // send init - nop(); + udelay(5); outb(val8 | 0x04, addr+2); - lpt_ret(regs, addr, timeout); + regs->ah = inb(addr+1) ^ 0x48; + set_success(regs); } // INT 17 - PRINTER - GET STATUS @@ -256,25 +286,25 @@ handle_1702(struct bregs *regs) u16 addr = getLptAddr(regs); if (!addr) return; - u16 timeout = GET_BDA(lpt_timeout[regs->dx]) << 8; - - lpt_ret(regs, addr, timeout); + regs->ah = inb(addr+1) ^ 0x48; + set_success(regs); } static void handle_17XX(struct bregs *regs) { - // Unsupported - set_fail(regs); + set_unimplemented(regs); } // INT17h : Printer Service Entry Point void VISIBLE16 handle_17(struct bregs *regs) { - debug_enter(regs); - - irq_enable(); + debug_enter(regs, DEBUG_HDL_17); + if (! CONFIG_LPT) { + handle_17XX(regs); + return; + } switch (regs->ah) { case 0x00: handle_1700(regs); break;