grub-devel
[Top][All Lists]
Advanced

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

Re: [PATCH] PCI serial card support


From: n0ano
Subject: Re: [PATCH] PCI serial card support
Date: Fri, 14 Nov 2008 12:24:58 -0700
User-agent: Mutt/1.4.2.1i

On Thu, Nov 13, 2008 at 08:05:37PM +0200, Vesa J??skel?inen wrote:
> Hi Don,
> 
> Thanks for the patch!
> 

Here is a new patch incorporating your comments.

(Still waiting on legal about the copyright assignment, I'm sure it'll
happen - someday.)

Signed-off-by: Donald D. Dugger <address@hidden>

-- 
Don Dugger
"Censeo Toto nos in Kansa esse decisse." - D. Gale
address@hidden
Ph: 303/443-3786

diffstat pci_serial-grub-1113.patch
 ChangeLog                           |   14 +
 include/grub/i386/pc/serial.h       |   10 +
 include/grub/i386/pc/serial_table.h |   86 ++++++++++
 include/grub/i386/pci.h             |   16 ++
 include/grub/pci.h                  |    6 
 include/grub/pci_ids.h              |   29 +++
 term/i386/pc/serial.c               |  288 +++++++++++++++++++++++++-----------
 7 files changed, 368 insertions(+), 81 deletions(-)

Index: include/grub/i386/pci.h
===================================================================
--- include/grub/i386/pci.h     (revision 1911)
+++ include/grub/i386/pci.h     (working copy)
@@ -32,4 +32,20 @@
   return grub_inl (GRUB_PCI_DATA_REG);
 }
 
+static inline grub_uint32_t
+grub_pci_read_config(unsigned int bus, unsigned int dev, unsigned int func, 
unsigned int off)
+{
+  grub_pci_address_t addr;
+
+  addr = grub_pci_make_address (bus, dev, func, off);
+  return grub_pci_read (addr);
+}
+
+static inline grub_uint32_t
+grub_pci_get_bar(unsigned int bus, unsigned int dev, unsigned int func, 
unsigned int bar)
+{
+
+  return grub_pci_read_config(bus, dev, func, 4 + bar) & ~3;
+}
+
 #endif /* GRUB_CPU_PCI_H */
Index: include/grub/i386/pc/serial.h
===================================================================
--- include/grub/i386/pc/serial.h       (revision 1911)
+++ 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
@@ -64,4 +67,11 @@
 /* Turn on DTR, RTS, and OUT2.  */
 #define UART_ENABLE_MODEM      0x0B
 
+/* Serial device types */
+#define SERIAL_LEGACY  0
+#define SERIAL_PCI     1
+#define SERIAL_USB     2
+
+void grub_serial_add(int type, unsigned int id, unsigned int base, unsigned 
int port);
+
 #endif /* ! GRUB_SERIAL_MACHINE_HEADER */
Index: include/grub/i386/pc/serial_table.h
===================================================================
--- include/grub/i386/pc/serial_table.h (revision 0)
+++ include/grub/i386/pc/serial_table.h (revision 0)
@@ -0,0 +1,86 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static void
+titan(unsigned int bus, unsigned int dev, unsigned int func, unsigned int 
bbaud)
+{
+  unsigned int port;
+
+  port = grub_pci_get_bar(bus, dev, func, 1);
+  grub_serial_add(SERIAL_PCI, GRUB_PCI_BDF(bus, dev, func), bbaud, port);
+  return;
+}
+
+static void
+netmos(unsigned int bus, unsigned int dev, unsigned int func, unsigned int 
bbaud)
+{
+  unsigned int port;
+
+  port = grub_pci_get_bar(bus, dev, func, 0);
+  grub_serial_add(SERIAL_PCI, GRUB_PCI_BDF(bus, dev, func), bbaud, port);
+  return;
+}
+
+static void
+generic(unsigned int bus, unsigned int dev, unsigned int func, unsigned int 
bbaud)
+{
+
+  grub_serial_add(SERIAL_PCI, GRUB_PCI_BDF(bus, dev, func), bbaud, 0);
+  return;
+}
+
+/*
+ *  Table to map PCI ID to config routine.  Currently, the config routine
+ *    only sets the base baud but, utltimately, it should identify which
+ *    I/O port is associated with which serial port.
+ */
+static struct pci_device_id {
+  unsigned int vendor_id;
+  unsigned int device_id;
+  unsigned int ss_vendor;
+  unsigned int ss_device;
+  unsigned int dev_class;
+  unsigned int dev_class_mask;
+  unsigned int base_baud;
+  void         (*dev_config)(unsigned int bus, unsigned int dev,
+                             unsigned int func, unsigned int bbaud);
+} serial_pci_id[] = {
+       {       PCI_VENDOR_ID_TITAN, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, titan },
+       {       PCI_VENDOR_ID_NETMOS, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               115200, netmos },
+       /*
+        * Generic entries that define the defaults
+        */
+       {       PCI_ANY_ID, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMM_SERIAL << 8, 0xffff00,
+               115200, generic },
+       {       PCI_ANY_ID, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMM_SERIAL_16450 << 8, 0xffff00,
+               115200, generic },
+       {       PCI_ANY_ID, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMM_SERIAL_16550 << 8, 0xffff00,
+               115200, generic },
+       {
+               0, 0, 0, 0, 0, 0, 0, generic },
+};
Index: include/grub/pci_ids.h
===================================================================
--- include/grub/pci_ids.h      (revision 0)
+++ include/grub/pci_ids.h      (revision 0)
@@ -0,0 +1,29 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define PCI_ANY_ID     ((unsigned int)(~0))
+
+#define PCI_CLASS_COMM_SERIAL          0x0700
+#define PCI_CLASS_COMM_SERIAL_16450    0x0702
+#define PCI_CLASS_COMM_SERIAL_16550    0x0703
+
+#define PCI_VENDOR_ID_TITAN            0x14D2
+#define PCI_DEVICE_ID_TITAN_100L       0x8010
+
+#define PCI_VENDOR_ID_NETMOS           0x9710
+#define PCI_DEVICE_ID_NETMOS_9835      0x9835
Index: include/grub/pci.h
===================================================================
--- include/grub/pci.h  (revision 1911)
+++ include/grub/pci.h  (working copy)
@@ -35,6 +35,12 @@
 #define  GRUB_PCI_ADDR_MEM_MASK                ~0xf
 #define  GRUB_PCI_ADDR_IO_MASK         ~0x03
 
+#define  GRUB_PCI_BDF(b,d,f)           ((b << 8) | (d << 3) | f)
+
+#define  GRUB_PCI_VENDOR(id)           (id & 0xffff)
+#define  GRUB_PCI_DEVICE(id)           ((id >> 16) & 0xffff)
+#define  GRUB_PCI_DEVICE_CLASS(c)      ((c >> 16) | ((c >> 8) & 0xff))
+
 typedef grub_uint32_t grub_pci_id_t;
 typedef int (*grub_pci_iteratefunc_t) (int bus, int device, int func,
                                       grub_pci_id_t pciid);
Index: ChangeLog
===================================================================
--- ChangeLog   (revision 1911)
+++ ChangeLog   (working copy)
@@ -1,3 +1,17 @@
+2008-11-03  Don Dugger <address@hidden>
+
+       * term/i386/pc/serial.c: major changes to support multiple serial
+       devices, also add `--base' parameter to serial command allowing
+       user to specify base baud for those UARTs that don't follow
+       the PC standard and are not recognized
+       * include/grub/i386/pc/serial.h: define default base baud value
+       of 115200 (default for PCs) and serial device types.
+       * include/grub/i386/pc/serial_table.h: define base bauds for known
+       serial devices
+       * include/grub/pci_ids.h: start at a PCI IDs table
+       * include/grub/pci.h: add some helper functions
+       * include/grub/i386/pci.h: add some helper functions
+
 2008-11-12  Robert Millan  <address@hidden>
 
        * conf/i386-pc.rmk (kernel_img_SOURCES): Add `term/i386/vga_common.c'.
Index: term/i386/pc/serial.c
===================================================================
--- term/i386/pc/serial.c       (revision 1911)
+++ term/i386/pc/serial.c       (working copy)
@@ -27,6 +27,10 @@
 #include <grub/arg.h>
 #include <grub/terminfo.h>
 #include <grub/cpu/io.h>
+#include <grub/mm.h>
+#include <grub/pci.h>
+#include <grub/pci_ids.h>
+#include <grub/machine/serial_table.h>
 
 #define TEXT_WIDTH     80
 #define TEXT_HEIGHT    25
@@ -48,22 +52,24 @@
   {"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}
 };
 
-/* Serial port settings.  */
-struct serial_port
-{
+struct serial_dev {
+  int           type;
+  int           id;
   unsigned short port;
-  unsigned short divisor;
+  unsigned int  speed;
+  unsigned int  base;
   unsigned short word_len;
   unsigned int   parity;
   unsigned short stop_bits;
 };
+static struct serial_dev *serial_devices = (struct serial_dev *)0;
+static struct serial_dev *serial_dev;
+static int num_dev = 0;
 
-/* Serial port settings.  */
-static struct serial_port serial_settings;
-
 #ifdef GRUB_MACHINE_PCBIOS
 /* The BIOS data area.  */
 static const unsigned short *serial_hw_io_addr = (const unsigned short *) 
0x0400;
@@ -73,6 +79,94 @@
 #define GRUB_SERIAL_PORT_NUM (sizeof(serial_hw_io_addr)/(serial_hw_io_addr[0]))
 #endif
 
+static const char *serial_types[] = {
+       "legacy",
+       "pci",
+       "usb"
+};
+
+static void
+serial_pr_type(int i, struct serial_dev *p)
+{
+
+  grub_printf("%c%2d: %6.6s ", (p == serial_dev) ? '*' : ' ',
+                          i, serial_types[p->type]);
+  switch (p->type) {
+
+  case SERIAL_LEGACY:
+    grub_printf("  COM%d", p->id + 1);
+    break;
+
+  case SERIAL_PCI:
+    {
+      unsigned int b, d, f;
+
+      b = p->id >> 8;
+      d = (p->id >> 3) & 0x1f;
+      f = p->id & 7;
+      grub_printf("%d:%02x.%d", b, d, f);
+      break;
+    }
+
+  case SERIAL_USB:
+    grub_printf("    %2d", p->id);
+    break;
+
+  }
+
+  return;
+}
+
+static const char parity[] = {
+       'N',
+       'O',
+       '?',
+       'E'
+};
+
+static void
+serial_pr(void)
+{
+  int i;
+  struct serial_dev *p;
+
+  grub_printf("Available serial units:\n");
+  p = serial_devices;
+  for (i = 0; i < num_dev; i++) {
+    serial_pr_type(i, p);
+    grub_printf(" 0x%04x %6d/%-7d %d%c%d\n", p->port, p->speed, p->base,
+                                            p->word_len + 5,
+                                            parity[p->parity >> 3],
+                                            (p->stop_bits >> 2) + 1);
+    p++;
+  }
+}
+
+void
+grub_serial_add(int type, unsigned int id, unsigned int base, unsigned int 
port)
+{
+  int idx, unit;
+
+  unit = serial_dev - serial_devices;
+  idx = num_dev++;
+  if ((serial_devices = grub_realloc(serial_devices, num_dev * 
(sizeof(*serial_devices)))) == (struct serial_dev *)0) {
+    grub_error (GRUB_ERR_OUT_OF_MEMORY, "realloc of %d bytes failed\n", 
num_dev * (sizeof(*serial_devices)));
+    return;
+  }
+
+  serial_devices[idx].type     = type;
+  serial_devices[idx].id       = id;
+  serial_devices[idx].base     = base;
+  serial_devices[idx].port     = port;
+  serial_devices[idx].speed     = 9600;
+  serial_devices[idx].word_len  = UART_8BITS_WORD;
+  serial_devices[idx].parity    = UART_NO_PARITY;
+  serial_devices[idx].stop_bits = UART_1_STOP_BIT;
+  serial_dev = &serial_devices[unit];
+  
+  return;
+}
+
 /* Return the port number for the UNITth serial device.  */
 static inline unsigned short
 serial_hw_get_port (const unsigned int unit)
@@ -87,8 +181,8 @@
 static int
 serial_hw_fetch (void)
 {
-  if (grub_inb (serial_settings.port + UART_LSR) & UART_DATA_READY)
-    return grub_inb (serial_settings.port + UART_RX);
+  if (grub_inb (serial_dev->port + UART_LSR) & UART_DATA_READY)
+    return grub_inb (serial_dev->port + UART_RX);
 
   return -1;
 }
@@ -100,14 +194,14 @@
   unsigned int timeout = 100000;
 
   /* Wait until the transmitter holding register is empty.  */
-  while ((grub_inb (serial_settings.port + UART_LSR) & UART_EMPTY_TRANSMITTER) 
== 0)
+  while ((grub_inb (serial_dev->port + UART_LSR) & UART_EMPTY_TRANSMITTER) == 
0)
     {
       if (--timeout == 0)
         /* There is something wrong. But what can I do?  */
         return;
     }
 
-  grub_outb (c, serial_settings.port + UART_TX);
+  grub_outb (c, serial_dev->port + UART_TX);
 }
 
 static void
@@ -210,35 +304,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.  */
@@ -274,31 +342,36 @@
    WORD_LEN, PARITY and STOP_BIT_LEN are defined in the header file as
    macros.  */
 static grub_err_t
-serial_hw_init (void)
+serial_hw_init (struct serial_dev *dev)
 {
   unsigned char status = 0;
+  unsigned short divisor;
 
+  if (dev->port == 0)
+    return GRUB_ERR_OUT_OF_RANGE;
+
   /* Turn off the interrupt.  */
-  grub_outb (0, serial_settings.port + UART_IER);
+  grub_outb (0, dev->port + UART_IER);
 
   /* Set DLAB.  */
-  grub_outb (UART_DLAB, serial_settings.port + UART_LCR);
+  grub_outb (UART_DLAB, dev->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(dev->speed, dev->base);
+  grub_outb (divisor & 0xFF, dev->port + UART_DLL);
+  grub_outb (divisor >> 8, dev->port + UART_DLH);
 
   /* Set the line status.  */
-  status |= (serial_settings.parity
-            | serial_settings.word_len
-            | serial_settings.stop_bits);
-  grub_outb (status, serial_settings.port + UART_LCR);
+  status |= (dev->parity
+            | dev->word_len
+            | dev->stop_bits);
+  grub_outb (status, dev->port + UART_LCR);
 
   /* Enable the FIFO.  */
-  grub_outb (UART_ENABLE_FIFO, serial_settings.port + UART_FCR);
+  grub_outb (UART_ENABLE_FIFO, dev->port + UART_FCR);
 
   /* Turn on DTR, RTS, and OUT2.  */
-  grub_outb (UART_ENABLE_MODEM, serial_settings.port + UART_MCR);
+  grub_outb (UART_ENABLE_MODEM, dev->port + UART_MCR);
 
   /* Drain the input buffer.  */
   while (grub_serial_checkkey () != -1)
@@ -495,31 +568,41 @@
                  int argc __attribute__ ((unused)),
                 char **args __attribute__ ((unused)))
 {
-  struct serial_port backup_settings = serial_settings;
+  int unit;
+  struct serial_dev dev;
   grub_err_t hwiniterr;
 
+  if ((state[0].set == 0) && (state[1].set == 0) && (state[2].set == 0) &&
+      (state[3].set == 0) && (state[4].set == 0) && (state[5].set == 0) &&
+      (state[6].set == 0)) {
+    serial_pr();
+    return GRUB_ERR_NONE;
+  }
+
+  dev = *serial_dev;
+  unit = serial_dev - serial_devices;
   if (state[0].set)
     {
-      unsigned int unit;
 
       unit = grub_strtoul (state[0].arg, 0, 0);
-      serial_settings.port = serial_hw_get_port (unit);
-      if (!serial_settings.port)
-       return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad unit number.");
+      if (unit >= num_dev)
+       {
+         return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad unit number.");
+       }
+      dev = serial_devices[unit];
     }
   
   if (state[1].set)
-    serial_settings.port = (unsigned short) grub_strtoul (state[1].arg, 0, 0);
+    {
+      dev.port = (unsigned short) grub_strtoul (state[1].arg, 0, 0);
+    }
   
   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)
+      dev.speed = (unsigned int )grub_strtoul (state[2].arg, 0, 0);
+      if (dev.speed == 0)
        {
-         serial_settings = backup_settings;
          return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad speed");
        }
     }
@@ -527,16 +610,15 @@
   if (state[3].set)
     {
       if (! grub_strcmp (state[3].arg, "5"))
-       serial_settings.word_len = UART_5BITS_WORD;
+       dev.word_len = UART_5BITS_WORD;
       else if (! grub_strcmp (state[3].arg, "6"))
-       serial_settings.word_len = UART_6BITS_WORD;
+       dev.word_len = UART_6BITS_WORD;
       else if (! grub_strcmp (state[3].arg, "7"))
-       serial_settings.word_len = UART_7BITS_WORD;
+       dev.word_len = UART_7BITS_WORD;
       else if (! grub_strcmp (state[3].arg, "8"))
-       serial_settings.word_len = UART_8BITS_WORD;
+       dev.word_len = UART_8BITS_WORD;
       else
        {
-         serial_settings = backup_settings;
          return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad word length");
        }
     }
@@ -544,14 +626,13 @@
   if (state[4].set)
     {
       if (! grub_strcmp (state[4].arg, "no"))
-       serial_settings.parity = UART_NO_PARITY;
+       dev.parity = UART_NO_PARITY;
       else if (! grub_strcmp (state[4].arg, "odd"))
-       serial_settings.parity = UART_ODD_PARITY;
+       dev.parity = UART_ODD_PARITY;
       else if (! grub_strcmp (state[4].arg, "even"))
-       serial_settings.parity = UART_EVEN_PARITY;
+       dev.parity = UART_EVEN_PARITY;
       else
        {
-         serial_settings = backup_settings;
          return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad parity");
        }
     }
@@ -559,21 +640,32 @@
   if (state[5].set)
     {
       if (! grub_strcmp (state[5].arg, "1"))
-       serial_settings.stop_bits = UART_1_STOP_BIT;
+       dev.stop_bits = UART_1_STOP_BIT;
       else if (! grub_strcmp (state[5].arg, "2"))
-       serial_settings.stop_bits = UART_2_STOP_BITS;
+       dev.stop_bits = UART_2_STOP_BITS;
       else
        {
-         serial_settings = backup_settings;
          return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad number of stop bits");
        }
     }
 
+  if (state[6].set)
+    {
+
+      dev.base = grub_strtoul (state[6].arg, 0, 0);
+      if (dev.base == 0)
+       {
+         return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad base baud");
+       }
+    }
+
   /* Initialize with new settings.  */
-  hwiniterr = serial_hw_init ();
+  hwiniterr = serial_hw_init (&dev);
   
   if (hwiniterr == GRUB_ERR_NONE)
     {
+      serial_dev = &serial_devices[unit];
+      *serial_dev = dev;
       /* Register terminal if not yet registered.  */
       if (registered == 0)
        {
@@ -584,13 +676,13 @@
     }
   else
     {
+      grub_error(GRUB_ERR_BAD_ARGUMENT, "Bad settings, revert to prior 
device");
       /* Initialization with new settings failed.  */
       if (registered == 1)
        {
          /* If the terminal is registered, attempt to restore previous
             settings.  */
-         serial_settings = backup_settings;
-         if (serial_hw_init () != GRUB_ERR_NONE)
+         if (serial_hw_init (serial_dev) != GRUB_ERR_NONE)
            {
              /* If unable to restore settings, unregister terminal.  */
              grub_term_unregister_input (&grub_serial_term_input);
@@ -603,21 +695,55 @@
   return hwiniterr;
 }
 
+static int
+serial_pci_scan (int bus, int dev, int func, grub_pci_id_t pci_id)
+{
+  struct pci_device_id *p;
+  unsigned int w, vid, did, ss_vid, ss_did, class;
+
+  vid = GRUB_PCI_VENDOR(pci_id);
+  did = GRUB_PCI_DEVICE(pci_id);
+  class = GRUB_PCI_DEVICE_CLASS(grub_pci_read_config(bus, dev, func, 2));
+  w = grub_pci_read_config (bus, dev, func, 11);
+  ss_vid = GRUB_PCI_VENDOR(w);
+  ss_did = GRUB_PCI_DEVICE(w);
+  for (p = serial_pci_id; p->vendor_id; p++) {
+    if ((p->vendor_id == PCI_ANY_ID || p->vendor_id == vid) &&
+       (p->device_id == PCI_ANY_ID || p->device_id == did) &&
+       (p->ss_vendor == PCI_ANY_ID || p->ss_vendor == ss_vid) &&
+       (p->ss_device == PCI_ANY_ID || p->ss_device == ss_did) &&
+       !((p->dev_class ^ (class << 8)) & p->dev_class_mask)) {
+      (p->dev_config)(bus, dev, func, p->base_baud);
+      break;
+    }
+  }
+  return 0;
+}
+
 GRUB_MOD_INIT(serial)
 {
+  int i;
+  unsigned int port;
+
   (void) mod;                  /* To stop warning. */
+  grub_errno = 0;
   grub_register_command ("serial", grub_cmd_serial, GRUB_COMMAND_FLAG_BOTH,
                          "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.word_len  = UART_8BITS_WORD;
-  serial_settings.parity    = UART_NO_PARITY;
-  serial_settings.stop_bits = UART_1_STOP_BIT;
+  for (i = 0; i < GRUB_SERIAL_PORT_NUM; i++)
+    if ((port = serial_hw_get_port(i)) != 0)
+      grub_serial_add(SERIAL_LEGACY, i, UART_BASE_BAUD, port);
+  serial_dev = &serial_devices[0];
+
+  /*
+   *  Check for PCI serial card, set defaults appropriately if one exists
+   */
+  grub_pci_iterate (serial_pci_scan);
 }
 
 GRUB_MOD_FINI(serial)
 {
+  grub_free (serial_devices);
   grub_unregister_command ("serial");
   if (registered == 1)         /* Unregister terminal only if registered. */
     {




reply via email to

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