* grub-core/term/ns8250.c (do_real_config): Set port->broken to 0.

(serial_hw_put): Wait based on real time rather than port reads. Don't
	roken ports.
	* include/grub/serial.h (grub_serial_port): New field broken.
This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-10-16 17:29:12 +02:00
parent 5f8b440b6b
commit 24977b4451
3 changed files with 31 additions and 5 deletions

View file

@ -1,3 +1,10 @@
2010-10-16 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/term/ns8250.c (do_real_config): Set port->broken to 0.
(serial_hw_put): Wait based on real time rather than port reads. Don't
roken ports.
* include/grub/serial.h (grub_serial_port): New field broken.
2010-10-16 Robert Millan <rmh@gnu.org> 2010-10-16 Robert Millan <rmh@gnu.org>
* grub-core/kern/emu/misc.c * grub-core/kern/emu/misc.c

View file

@ -23,6 +23,7 @@
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/cpu/io.h> #include <grub/cpu/io.h>
#include <grub/mm.h> #include <grub/mm.h>
#include <grub/time.h>
#ifdef GRUB_MACHINE_PCBIOS #ifdef GRUB_MACHINE_PCBIOS
#include <grub/machine/memory.h> #include <grub/machine/memory.h>
@ -90,6 +91,8 @@ do_real_config (struct grub_serial_port *port)
if (port->configured) if (port->configured)
return; return;
port->broken = 0;
divisor = serial_get_divisor (port->config.speed); divisor = serial_get_divisor (port->config.speed);
/* Turn off the interrupt. */ /* Turn off the interrupt. */
@ -145,17 +148,29 @@ serial_hw_fetch (struct grub_serial_port *port)
static void static void
serial_hw_put (struct grub_serial_port *port, const int c) serial_hw_put (struct grub_serial_port *port, const int c)
{ {
unsigned int timeout = 100000; grub_uint64_t endtime;
do_real_config (port); do_real_config (port);
if (port->broken > 5)
endtime = grub_get_time_ms ();
else if (port->broken > 1)
endtime = grub_get_time_ms () + 50;
else
endtime = grub_get_time_ms () + 200;
/* Wait until the transmitter holding register is empty. */ /* Wait until the transmitter holding register is empty. */
while ((grub_inb (port->port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0) while ((grub_inb (port->port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 0)
{ {
if (--timeout == 0) if (grub_get_time_ms () > endtime)
{
port->broken++;
/* There is something wrong. But what can I do? */ /* There is something wrong. But what can I do? */
return; return;
} }
}
if (port->broken)
port->broken--;
grub_outb (c, port->port + UART_TX); grub_outb (c, port->port + UART_TX);
} }

View file

@ -71,8 +71,12 @@ struct grub_serial_port
when malloc isn't available it's a union. when malloc isn't available it's a union.
*/ */
union union
{
struct
{ {
grub_port_t port; grub_port_t port;
int broken;
};
struct struct
{ {
grub_usb_device_t usbdev; grub_usb_device_t usbdev;