grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] PCI serial card support


From: donald . d . dugger
Subject: [PATCH] PCI serial card support
Date: Mon, 3 Nov 2008 16:38:02 -0800

The problem with using a PCI serial card for the console is that many
PCI cards use a different crystal than the IBM PC standard.  This means
that serial drivers wind up computing the wrong divisor when trying to
set the baud rate.  This patch solves this problem by adding the `--base'
parameter to the `serial' command.  The allows you to set the base baud
(typically the highest baud rate supported by the device) so that PCI
cards with non-standard crystal frequencies can be supported.  For example,
the option I use with my PCI serial card is:

        serial --port=0xe880 --speed=115200 --base=921600

Signed-off-by: Don Dugger <address@hidden>

diffstat /isis/homeb/intel/patch.d/pci_serial-grub-1103.patch 
 ChangeLog                     |    8 +++++
 include/grub/i386/pc/serial.h |    3 ++
 term/i386/pc/serial.c         |   60 ++++++++++++++++--------------------------
 3 files changed, 35 insertions(+), 36 deletions(-)

----- cut here for pci_serial-grub-1103.patch -----
Index: include/grub/i386/pc/serial.h
===================================================================
--- include/grub/i386/pc/serial.h       (revision 1892)
+++ include/grub/i386/pc/serial.h       (working copy)
@@ -40,6 +40,9 @@
 #define UART_DATA_READY                0x01
 #define UART_EMPTY_TRANSMITTER 0x20
 
+/* Default base baud */
+#define UART_BASE_BAUD         115200
+
 /* The type of parity.  */
 #define UART_NO_PARITY         0x00
 #define UART_ODD_PARITY                0x08
Index: ChangeLog
===================================================================
--- ChangeLog   (revision 1892)
+++ ChangeLog   (working copy)
@@ -1,3 +1,11 @@
+2008-11-03  Don Dugger <address@hidden>
+
+       * term/i386/pc/serial.c: add `--base' parameter to serial command,
+       allows user to specify base baud for those UARTs that don't follow
+       the PC standard.
+       * include/grub/i386/pc/serial.h: define default base baud value
+       of 115200 (default for PCs).
+
 2008-11-03  Bean  <address@hidden>
 
        * kern/elf.c (grub_elf32_load): Revert to previous code.
Index: term/i386/pc/serial.c
===================================================================
--- term/i386/pc/serial.c       (revision 1892)
+++ term/i386/pc/serial.c       (working copy)
@@ -48,6 +48,7 @@
   {"word",   'w', 0, "Set the serial port word length", 0, ARG_TYPE_INT},
   {"parity", 'r', 0, "Set the serial port parity",      0, ARG_TYPE_STRING},
   {"stop",   't', 0, "Set the serial port stop bits",   0, ARG_TYPE_INT},
+  {"base",   'b', 0, "Set the serial port base baud",   0, ARG_TYPE_INT},
   {0, 0, 0, 0, 0, 0}
 };
 
@@ -55,7 +56,8 @@
 struct serial_port
 {
   unsigned short port;
-  unsigned short divisor;
+  unsigned int   speed;
+  unsigned int   base;
   unsigned short word_len;
   unsigned int   parity;
   unsigned short stop_bits;
@@ -210,35 +212,9 @@
 
 /* Convert speed to divisor.  */
 static unsigned short
-serial_get_divisor (unsigned int speed)
+serial_get_divisor (unsigned int speed, unsigned int base)
 {
-  unsigned int i;
-
-  /* The structure for speed vs. divisor.  */
-  struct divisor
-  {
-    unsigned int speed;
-    unsigned short div;
-  };
-
-  /* The table which lists common configurations.  */
-  /* 1843200 / (speed * 16)  */
-  static struct divisor divisor_tab[] =
-    {
-      { 2400,   0x0030 },
-      { 4800,   0x0018 },
-      { 9600,   0x000C },
-      { 19200,  0x0006 },
-      { 38400,  0x0003 },
-      { 57600,  0x0002 },
-      { 115200, 0x0001 }
-    };
-
-  /* Set the baud rate.  */
-  for (i = 0; i < sizeof (divisor_tab) / sizeof (divisor_tab[0]); i++)
-    if (divisor_tab[i].speed == speed)
-      return divisor_tab[i].div;
-  return 0;
+  return ((base << 4) + (speed << 3)) / (speed << 4);
 }
 
 /* The serial version of checkkey.  */
@@ -277,6 +253,7 @@
 serial_hw_init (void)
 {
   unsigned char status = 0;
+  unsigned short divisor;
 
   /* Turn off the interrupt.  */
   grub_outb (0, serial_settings.port + UART_IER);
@@ -285,8 +262,9 @@
   grub_outb (UART_DLAB, serial_settings.port + UART_LCR);
 
   /* Set the baud rate.  */
-  grub_outb (serial_settings.divisor & 0xFF, serial_settings.port + UART_DLL);
-  grub_outb (serial_settings.divisor >> 8, serial_settings.port + UART_DLH);
+  divisor = serial_get_divisor(serial_settings.speed, serial_settings.base);
+  grub_outb (divisor & 0xFF, serial_settings.port + UART_DLL);
+  grub_outb (divisor >> 8, serial_settings.port + UART_DLH);
 
   /* Set the line status.  */
   status |= (serial_settings.parity
@@ -511,11 +489,9 @@
   
   if (state[2].set)
     {
-      unsigned long speed;
 
-      speed = grub_strtoul (state[2].arg, 0, 0);
-      serial_settings.divisor = serial_get_divisor ((unsigned int) speed);
-      if (serial_settings.divisor == 0)
+      serial_settings.speed = (unsigned int )grub_strtoul (state[2].arg, 0, 0);
+      if (serial_settings.speed == 0)
        {
          serial_settings = backup_settings;
          return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
@@ -567,6 +543,17 @@
        }
     }
 
+  if (state[6].set)
+    {
+
+      serial_settings.base = grub_strtoul (state[6].arg, 0, 0);
+      if (serial_settings.base == 0)
+       {
+         serial_settings = backup_settings;
+         return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad base baud");
+       }
+    }
+
   /* Initialize with new settings.  */
   hwiniterr = serial_hw_init ();
   
@@ -606,7 +593,8 @@
                          "serial [OPTIONS...]", "Configure serial port.", 
options);
   /* Set default settings.  */
   serial_settings.port      = serial_hw_get_port (0);
-  serial_settings.divisor   = serial_get_divisor (9600);
+  serial_settings.speed     = 9600;
+  serial_settings.base      = UART_BASE_BAUD;
   serial_settings.word_len  = UART_8BITS_WORD;
   serial_settings.parity    = UART_NO_PARITY;
   serial_settings.stop_bits = UART_1_STOP_BIT;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]