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: Wed, 12 Nov 2008 11:58:03 -0700
User-agent: Mutt/1.4.2.1i

On Sun, Nov 09, 2008 at 10:57:30PM +0100, Robert Millan wrote:
> On Sat, Nov 08, 2008 at 06:58:19PM -0700, address@hidden wrote:
> > I think this is pretty much what I'm in the middle of doing.  I want to
> > put the infrastructure in place so that we can handle an arbitrary PCI
> > device but I will only put the actual code in to handle the PCI card that
> > I have (the only one I can test).
> > 
> > What I'm doing is creating a table that matches the tuple (vendor id,
> > device id, subsystem vendor id, subsystem device id, device type, device
> > type mask) to a base baud and a configuration function.  The default
> > configuration function does nothing so the table only provides the base
> > baud.  We can add config functions for different cards as time goes by.
> 

Finally, here is the patch that adds an infrastructure to support
multiple serial devices (legacy & PCI, we can think about USB for
the future but that will be harder).

This patch creates a table with an entry for each serial device
in the system.  It attempts to fill in appropriate defaults for
each entry.  Right now it should determine the base baud for most
PCI devices but it can only find the I/O port for the Titan PCI
serial card that I have to test.

The command `serial' will print out the table, flagging the
currently selected serial entry, e.g.:

grub> serial
Available serial units:
* 0: legacy   COM1 0x0000   9600/115200  8N1
  1: legacy   COM2 0x0000   9600/115200  8N1
  2: legacy   COM3 0x0000   9600/115200  8N1
  3: legacy   COM4 0x0000   9600/115200  8N1
  4:    pci 1:00.0 0xe880   9600/921600  8N1

Note that unit 0 (the legacy COM1 port) is currently the selected
unit.  Since my machine doesn't have any legacy serial devices
(note the 0x0000 for the I/O port) this device won't work.  The
command `serial -u 4' will select the PCI device and, since all
the defaults are correct, that device will work.  You can override
all defaults with the serial command so, to duplicate the defaults
for the PCI device, you would use the command:

serial -u 4 -p 0xe880 -s 9600 -b 921600 -w 8 -r n -t 1

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

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

diffstat /isis/homeb/intel/patch.d/pci_serial-grub-1112a.patch 
 ChangeLog                     |   10 
 include/grub/i386/pc/serial.h |    8 
 include/grub/pci_serial_ids.h |  642 ++++++++++++++++++++++++++++++++++++++++++
 term/i386/pc/serial.c         |  291 +++++++++++++------
 4 files changed, 870 insertions(+), 81 deletions(-)

Index: include/grub/pci_serial_ids.h
===================================================================
--- include/grub/pci_serial_ids.h       (revision 0)
+++ include/grub/pci_serial_ids.h       (revision 0)
@@ -0,0 +1,642 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000,2001,2002,2003,2004,2005,2007  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_COMMUNICATION_SERIAL 0x0700
+#define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702
+#define PCI_CLASS_COMMUNICATION_MODEM  0x0703
+
+#define PCI_VENDOR_ID_DELL             0x1028
+#define PCI_DEVICE_ID_DELL_RACIII      0x0008
+#define PCI_DEVICE_ID_DELL_RAC4                0x0012
+
+#define PCI_VENDOR_ID_SGI              0x10a9
+#define PCI_DEVICE_ID_SGI_IOC3         0x0003
+
+#define PCI_VENDOR_ID_PLX              0x10b5
+#define PCI_DEVICE_ID_PLX_ROMULUS      0x106a
+#define PCI_DEVICE_ID_PLX_SPCOM800     0x1076
+#define PCI_DEVICE_ID_PLX_1077         0x1077
+#define PCI_DEVICE_ID_PLX_SPCOM200     0x1103
+#define PCI_DEVICE_ID_PLX_9030          0x9030
+#define PCI_DEVICE_ID_PLX_9050         0x9050
+#define PCI_SUBVENDOR_ID_KEYSPAN       0x11a9
+#define PCI_SUBVENDOR_ID_KEYSPAN_SX2   0x5334
+
+#define PCI_VENDOR_ID_V3               0x11b0
+#define PCI_DEVICE_ID_V3_V960          0x0001
+#define PCI_DEVICE_ID_V3_V351          0x0002
+
+#define PCI_VENDOR_ID_SPECIALIX                0x11cb
+#define PCI_SUBDEVICE_ID_SPECIALIX_SPEED4 0xa004
+#define PCI_SUBVENDOR_ID_CONNECT_TECH                  0x12c4
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232          0x0001
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232          0x0002
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232          0x0003
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ                0x000C
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232   0x0300
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1     0x0310
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2     0x0311
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2       0x0320
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485   0x0330
+#define PCI_SUBVENDOR_ID_CHASE_PCIFAST         0x12E0
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST4                0x0031
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST8                0x0021
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16       0x0011
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC    0x0041
+#define PCI_SUBVENDOR_ID_CHASE_PCIRAS          0x124D
+#define PCI_SUBDEVICE_ID_CHASE_PCIRAS4         0xF001
+#define PCI_SUBDEVICE_ID_CHASE_PCIRAS8         0xF010
+
+#define PCI_VENDOR_ID_SIIG             0x131f
+#define PCI_DEVICE_ID_SIIG_1S_10x_550  0x1000
+#define PCI_DEVICE_ID_SIIG_1S_10x_650  0x1001
+#define PCI_DEVICE_ID_SIIG_1S_10x_850  0x1002
+#define PCI_DEVICE_ID_SIIG_2S_10x_550  0x1030
+#define PCI_DEVICE_ID_SIIG_2S_10x_650  0x1031
+#define PCI_DEVICE_ID_SIIG_2S_10x_850  0x1032
+#define PCI_DEVICE_ID_SIIG_4S_10x_550  0x1050
+#define PCI_DEVICE_ID_SIIG_4S_10x_650  0x1051
+#define PCI_DEVICE_ID_SIIG_4S_10x_850  0x1052
+#define PCI_DEVICE_ID_SIIG_1S_20x_550  0x2000
+#define PCI_DEVICE_ID_SIIG_1S_20x_650  0x2001
+#define PCI_DEVICE_ID_SIIG_1S_20x_850  0x2002
+#define PCI_DEVICE_ID_SIIG_2S_20x_550  0x2030
+#define PCI_DEVICE_ID_SIIG_2S_20x_650  0x2031
+#define PCI_DEVICE_ID_SIIG_2S_20x_850  0x2032
+#define PCI_DEVICE_ID_SIIG_4S_20x_550  0x2050
+#define PCI_DEVICE_ID_SIIG_4S_20x_650  0x2051
+#define PCI_DEVICE_ID_SIIG_4S_20x_850  0x2052
+#define PCI_DEVICE_ID_SIIG_8S_20x_550  0x2080
+#define PCI_DEVICE_ID_SIIG_8S_20x_650  0x2081
+#define PCI_DEVICE_ID_SIIG_8S_20x_850  0x2082
+
+#define PCI_VENDOR_ID_EXAR             0x13a8
+#define PCI_DEVICE_ID_EXAR_XR17C152    0x0152
+#define PCI_DEVICE_ID_EXAR_XR17C154    0x0154
+#define PCI_DEVICE_ID_EXAR_XR17C158    0x0158
+
+#define PCI_VENDOR_ID_LAVA             0x1407
+#define PCI_DEVICE_ID_LAVA_OCTO_A      0x0180
+#define PCI_DEVICE_ID_LAVA_OCTO_B      0x0181
+#define PCI_DEVICE_ID_LAVA_PORT_PLUS   0x0200
+#define PCI_DEVICE_ID_LAVA_QUAD_A      0x0201
+#define PCI_DEVICE_ID_LAVA_QUAD_B      0x0202
+#define PCI_DEVICE_ID_LAVA_PORT_650    0x0600
+
+#define PCI_VENDOR_ID_TIMEDIA          0x1409
+#define PCI_DEVICE_ID_TIMEDIA_1889     0x7168
+
+#define PCI_VENDOR_ID_OXSEMI           0x1415
+#define PCI_DEVICE_ID_OXSEMI_16PCI954  0x9501
+#define PCI_DEVICE_ID_OXSEMI_16PCI95N  0x9511
+#define PCI_DEVICE_ID_OXSEMI_16PCI954PP        0x9513
+#define PCI_DEVICE_ID_OXSEMI_16PCI952  0x9521
+#define PCI_DEVICE_ID_OXSEMI_16PCI952PP        0x9523
+
+#define PCI_VENDOR_ID_TITAN            0x14D2
+#define PCI_DEVICE_ID_TITAN_100L       0x8010
+#define PCI_DEVICE_ID_TITAN_200L       0x8020
+#define PCI_DEVICE_ID_TITAN_400L       0x8040
+#define PCI_DEVICE_ID_TITAN_800L       0x8080
+#define PCI_DEVICE_ID_TITAN_100                0xA001
+#define PCI_DEVICE_ID_TITAN_200                0xA005
+#define PCI_DEVICE_ID_TITAN_400                0xA003
+#define PCI_DEVICE_ID_TITAN_800B       0xA004
+
+#define PCI_VENDOR_ID_PANACOM          0x14d4
+#define PCI_DEVICE_ID_PANACOM_QUADMODEM        0x0400
+#define PCI_DEVICE_ID_PANACOM_DUALMODEM        0x0402
+
+#define PCI_VENDOR_ID_MAINPINE         0x1522
+
+#define PCI_VENDOR_ID_PASEMI           0x1959
+
+#define PCI_VENDOR_ID_KORENIX          0x1982
+#define PCI_DEVICE_ID_KORENIX_JETCARDF0        0x1600
+#define PCI_DEVICE_ID_KORENIX_JETCARDF1        0x16ff
+
+#define PCI_VENDOR_ID_INTEL            0x8086
+#define PCI_DEVICE_ID_INTEL_80960_RP   0x1960
+
+#define PCI_VENDOR_ID_COMPUTONE                0x8e0e
+#define PCI_DEVICE_ID_COMPUTONE_PG     0x0302
+#define PCI_SUBVENDOR_ID_COMPUTONE     0x8e0e
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG4 0x0001
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG8 0x0002
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG6 0x0003
+
+#define PCI_SUBVENDOR_ID_EXSYS         0xd84d
+#define PCI_SUBDEVICE_ID_EXSYS_4055    0x4055
+
+#define PCI_VENDOR_ID_SBSMODULARIO     0x124B
+#define PCI_SUBVENDOR_ID_SBSMODULARIO  0x124B
+
+#define PCI_DEVICE_ID_OCTPRO           0x0001
+#define PCI_SUBDEVICE_ID_OCTPRO232     0x0108
+#define PCI_SUBDEVICE_ID_OCTPRO422     0x0208
+#define PCI_SUBDEVICE_ID_POCTAL232     0x0308
+#define PCI_SUBDEVICE_ID_POCTAL422     0x0408
+
+#define PCI_BDF(b,d,f) ((b << 8) | (d << 3) | f)
+
+static unsigned int
+pci_get_bar(unsigned int bus, unsigned int dev, unsigned int func, unsigned 
int bar)
+{
+  grub_pci_address_t addr;
+
+  addr = grub_pci_make_address (bus, dev, func, 4 + bar);
+  return grub_pci_read (addr) & ~3;
+}
+
+static void
+titan(unsigned int bus, unsigned int dev, unsigned int func, unsigned int 
bbaud)
+{
+  unsigned int port;
+
+  port = pci_get_bar(bus, dev, func, 1);
+  grub_serial_add(SERIAL_PCI, 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, 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_V3, PCI_DEVICE_ID_V3_V960,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               1382400, generic },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               1382400, generic },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+               1382400, generic },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+               1382400, generic },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+               1382400, generic },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+               1382400, generic },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ, 0, 0,
+               1250000, generic },
+       {       PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_KEYSPAN,
+               PCI_SUBVENDOR_ID_KEYSPAN_SX2, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+               PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+               PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+               PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_SUBVENDOR_ID_EXSYS,
+               PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
+               0x10b5, 0x106a, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
+               0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               1843200, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0x950a,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               1130000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc101,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc105,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc11b,    /* OXPCIe952 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc11f,    /* OXPCIe952 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc120,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc124,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc138,    /* OXPCIe952 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc13d,    /* OXPCIe952 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc140,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc141,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc144,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc145,    /* OXPCIe952 1 Legacy UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc158,    /* OXPCIe952 2 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc15d,    /* OXPCIe952 2 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc208,    /* OXPCIe954 4 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc20d,    /* OXPCIe954 4 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc308,    /* OXPCIe958 8 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc30d,    /* OXPCIe958 8 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc40b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc40f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc41b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc41f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc42b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc42f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc43b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc43f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc44b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc44f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc45b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc45f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc46b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc46f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc47b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc47f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc48b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc48f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc49b,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc49f,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4ab,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4af,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4bb,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4bf,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4cb,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, 0xc4cf,    /* OXPCIe200 1 Native UART */
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 
Super-G3 Fax */
+               PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 
Super-G3 Fax */
+               PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 
Super-G3 Fax */
+               PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 
Super-G3 Fax */
+               PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0,
+               4000000, generic },
+       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO232, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO422, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL232, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+               PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL422, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, titan },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, titan },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, titan },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, titan },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, titan },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, titan },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, titan },
+       {       PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, titan },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
+               0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
+               0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+               PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
+               0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+               PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               460800, generic },
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+               0x1204, 0x0004, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+               0x1208, 0x0004, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1,
+               0x1208, 0x0004, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RAC4,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               1382400, generic },
+       {       PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RACIII,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               1382400, generic },
+       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80960_RP,
+               0xE4BF, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+               0xFF00, 0, 0, 0,
+               458333, generic },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485, 0, 0,
+               1843200, generic },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2, 0, 0,
+               1843200, generic },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1, 0, 0,
+               1843200, generic },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_SUBVENDOR_ID_CONNECT_TECH,
+               PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232, 0, 0,
+               1843200, generic },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C152,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C154,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17C158,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               921600, generic },
+       {       PCI_VENDOR_ID_PASEMI, 0xa004,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               8333333, generic },
+       /*
+        * Generic entries that define the defaults
+        */
+       {       PCI_ANY_ID, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00,
+               115200, generic },
+       {       PCI_ANY_ID, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMMUNICATION_MODEM << 8, 0xffff00,
+               115200, generic },
+       {       PCI_ANY_ID, PCI_ANY_ID,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+               115200, generic },
+       {
+               0, 0, 0, 0, 0, 0, 0, generic },
+};
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,9 @@
 /* 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
+
 #endif /* ! GRUB_SERIAL_MACHINE_HEADER */
Index: ChangeLog
===================================================================
--- ChangeLog   (revision 1911)
+++ ChangeLog   (working copy)
@@ -1,3 +1,13 @@
+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/pci_serial_ids.h: map serial PCI IDs to base baud
+
 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,7 +27,12 @@
 #include <grub/arg.h>
 #include <grub/terminfo.h>
 #include <grub/cpu/io.h>
+#include <grub/mm.h>
+#include <grub/pci.h>
 
+void grub_serial_add(int type, unsigned int id, unsigned int base, unsigned 
int port);
+#include <grub/pci_serial_ids.h>
+
 #define TEXT_WIDTH     80
 #define TEXT_HEIGHT    25
 
@@ -48,22 +53,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 +80,94 @@
 #define GRUB_SERIAL_PORT_NUM (sizeof(serial_hw_io_addr)/(serial_hw_io_addr[0]))
 #endif
 
+char *serial_types[] = {
+       "legacy",
+       "   pci",
+       "   usb"
+};
+
+static void
+serial_pr_type(int i, struct serial_dev *p)
+{
+
+  grub_printf("%c%2d: %s ", (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;
+}
+
+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 +182,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 +195,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 +305,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 +343,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 +569,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 +611,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 +627,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 +641,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 +677,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 +696,57 @@
   return hwiniterr;
 }
 
+static int
+serial_pci_scan (int bus, int dev, int func, grub_pci_id_t pciid)
+{
+  struct pci_device_id *p;
+  grub_pci_address_t addr;
+  unsigned int w, vid, did, ss_vid, ss_did, class;
+
+  vid = pciid & 0xffff;
+  did = pciid >> 16;
+  addr = grub_pci_make_address (bus, dev, func, 2);
+  w = grub_pci_read (addr);
+  class = (w >> 16) | ((w >> 8) & 0xff);
+  addr = grub_pci_make_address (bus, dev, func, 11);
+  w = grub_pci_read (addr);
+  ss_vid = w & 0xffff;
+  ss_did = w >> 16;
+  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;
+
   (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++)
+    grub_serial_add(SERIAL_LEGACY, i, UART_BASE_BAUD, serial_hw_get_port(i));
+  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]