All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] PCI serial card support
@ 2008-11-04  0:38 donald.d.dugger
  2008-11-04 15:39 ` Robert Millan
  2009-07-21  8:11 ` tony.gugo
  0 siblings, 2 replies; 29+ messages in thread
From: donald.d.dugger @ 2008-11-04  0:38 UTC (permalink / raw)
  To: grub-devel

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 <donald.d.dugger@intel.com>

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 <donald.d.dugger@intel.com>
+
+	* 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  <bean123ch@gmail.com>
 
 	* 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;



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-04  0:38 [PATCH] PCI serial card support donald.d.dugger
@ 2008-11-04 15:39 ` Robert Millan
  2008-11-04 18:24   ` Dugger, Donald D
  2008-11-04 18:26   ` Vesa Jääskeläinen
  2009-07-21  8:11 ` tony.gugo
  1 sibling, 2 replies; 29+ messages in thread
From: Robert Millan @ 2008-11-04 15:39 UTC (permalink / raw)
  To: The development of GRUB 2

On Mon, Nov 03, 2008 at 04:38:02PM -0800, donald.d.dugger@intel.com wrote:
> 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

Hi!

Is there no better way to do this than queriing the user?  Can you read this
info from the device itself, or from its PCI id?

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [PATCH] PCI serial card support
  2008-11-04 15:39 ` Robert Millan
@ 2008-11-04 18:24   ` Dugger, Donald D
  2008-11-05  9:58     ` Robert Millan
  2008-11-04 18:26   ` Vesa Jääskeläinen
  1 sibling, 1 reply; 29+ messages in thread
From: Dugger, Donald D @ 2008-11-04 18:24 UTC (permalink / raw)
  To: The development of GRUB 2

To my knowledge there is no way to query the device to discover this.  You can create an internal table that maps PCI ID to base baud[1] but now you are tied to the PCI subsystem and you get into issues of no output until after PCI enumeration is done, what happens if you have 2 different PCI cards installed, what happens if you find a serial card that isn't on the list, what about Express cards, etc.  I thought it would be easier to just add a parameter to specify it similar to being able to specify the I/O port.  The hope is that most of the PCI serial cards out there do use the standard base baud so most people wouldn't have to worry about this parameter but it is available if necessary.

Having said all of that, I see that there is some PCI support in grub2 so I can look into creating such a table.  Even if we go that route I think we should still add the `--base' parameter, for those situations where the table doesn't work.

[1]  This is what the Linux driver does but this table is only available relatively late in the kernel boot process.  For early printk's I've submitted a patch to the LKML to allow you to specify the base baud on the kernel command line as a companion to this patch.

--
Don Dugger
"Censeo Toto nos in Kansa esse decisse." - D. Gale
Donald.D.Dugger@intel.com
Ph: (303)443-3786 

>-----Original Message-----
>From: grub-devel-bounces+donald.d.dugger=intel.com@gnu.org 
>[mailto:grub-devel-bounces+donald.d.dugger=intel.com@gnu.org] 
>On Behalf Of Robert Millan
>Sent: Tuesday, November 04, 2008 8:40 AM
>To: The development of GRUB 2
>Subject: Re: [PATCH] PCI serial card support
>
>On Mon, Nov 03, 2008 at 04:38:02PM -0800, 
>donald.d.dugger@intel.com wrote:
>> 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
>
>Hi!
>
>Is there no better way to do this than queriing the user?  Can 
>you read this info from the device itself, or from its PCI id?
>
>--
>Robert Millan
>
>  The DRM opt-in fallacy: "Your data belongs to us. We will 
>decide when (and
>  how) you may access your data; but nobody's threatening your 
>freedom: we
>  still allow you to remove your data and not access it at all."
>
>
>_______________________________________________
>Grub-devel mailing list
>Grub-devel@gnu.org
>http://lists.gnu.org/mailman/listinfo/grub-devel
>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-04 15:39 ` Robert Millan
  2008-11-04 18:24   ` Dugger, Donald D
@ 2008-11-04 18:26   ` Vesa Jääskeläinen
  2008-11-04 18:38     ` Dugger, Donald D
  1 sibling, 1 reply; 29+ messages in thread
From: Vesa Jääskeläinen @ 2008-11-04 18:26 UTC (permalink / raw)
  To: The development of GRUB 2

Robert Millan wrote:
> On Mon, Nov 03, 2008 at 04:38:02PM -0800, donald.d.dugger@intel.com wrote:
>> 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
> 
> Is there no better way to do this than queriing the user?  Can you read this
> info from the device itself, or from its PCI id?

There are some serial boards where you have to give N * IO base
addresses in order to support all N COMs. Actually there are even more
complex cards than this one. Some supporting much higher than 921600 as
maximum speed. Some needing even different kinds of formulas in order to
get proper baud rates... But I think this should be good short term
solution. More complex cards can have their own driver then.

Thou "base" could be something different. As this is advanced feature it
could be something more descriptive and harder to type... in example
divbase, or maxbaud... Of course if we can detect some cards
automatically we can store some table for those. For detection of PCI
cases we could use PCI ID's.

> +  return ((base << 4) + (speed << 3)) / (speed << 4);

Interesting formula. However. Whats the big gain against base/speed ?
Perhaps I am missing something? This formula just gives +0.5 (rounding?)
for resulting value which is then rounded down with integer maths.




^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [PATCH] PCI serial card support
  2008-11-04 18:26   ` Vesa Jääskeläinen
@ 2008-11-04 18:38     ` Dugger, Donald D
  0 siblings, 0 replies; 29+ messages in thread
From: Dugger, Donald D @ 2008-11-04 18:38 UTC (permalink / raw)
  To: The development of GRUB 2


>
>There are some serial boards where you have to give N * IO 
>base addresses in order to support all N COMs. Actually there 
>are even more complex cards than this one. Some supporting 
>much higher than 921600 as maximum speed. Some needing even 
>different kinds of formulas in order to get proper baud 
>rates... But I think this should be good short term solution. 
>More complex cards can have their own driver then.

My goal was to support 1 port to be used as the serial console, I don't see a great need for grub to support all the ports on a multi-port card, leave that to the OS that gets booted.

Of course, it gets worse, I believe there are some cards that use a non-standard I/O register layout, if we want to support those it will indeed require a special driver.

>
>Thou "base" could be something different. As this is advanced 
>feature it could be something more descriptive and harder to 
>type... in example divbase, or maxbaud... Of course if we can 
>detect some cards automatically we can store some table for 
>those. For detection of PCI cases we could use PCI ID's.
>
>> +  return ((base << 4) + (speed << 3)) / (speed << 4);
>
>Interesting formula. However. Whats the big gain against base/speed ?
>Perhaps I am missing something? This formula just gives +0.5 
>(rounding?) for resulting value which is then rounded down 
>with integer maths.
>

I stole that formula from the Linux PCI serial driver.  My analysis matches yours, it only causes a round up of 1 for some cases where the base baud is not a multiple of 2.  Unfortunately, if you look at all the base bauds in the Linux driver, there are some weird ones where the round up will change the divisor so I would assume this formula is necessary.

--
Don Dugger
"Censeo Toto nos in Kansa esse decisse." - D. Gale
Donald.D.Dugger@intel.com
Ph: (303)443-3786 


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-04 18:24   ` Dugger, Donald D
@ 2008-11-05  9:58     ` Robert Millan
  2008-11-05 15:37       ` Dugger, Donald D
  0 siblings, 1 reply; 29+ messages in thread
From: Robert Millan @ 2008-11-05  9:58 UTC (permalink / raw)
  To: The development of GRUB 2

On Tue, Nov 04, 2008 at 10:24:38AM -0800, Dugger, Donald D wrote:
> You can create an internal table that maps PCI ID to base baud[1]

I'd prefer that a lot.  Users don't necessarily have an idea on what
magic value they need.

> but now you are tied to the PCI subsystem and you get into issues of no output until after PCI enumeration is done

At least with our current design, you can't get to serial output untill
GRUB has been completely brought up, so there's no early point in which
we'd be missing it.

> what happens if you have 2 different PCI cards installed,

Then serial.mod can handle multiple terminals (it already does, just not for
PCI cards) via `serial' command, and use the PCI calls to gather info about
them whenever they're to be used.

> what happens if you find a serial card that isn't on the list,

Does this issue happen with all serial cards, or just some?  If it happens
with all, I guess it could just issue an error and let the user know that
we need feedback on how to add this one?

> what about Express cards, etc.

What do you mean?

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [PATCH] PCI serial card support
  2008-11-05  9:58     ` Robert Millan
@ 2008-11-05 15:37       ` Dugger, Donald D
  2008-11-06 15:02         ` Robert Millan
  0 siblings, 1 reply; 29+ messages in thread
From: Dugger, Donald D @ 2008-11-05 15:37 UTC (permalink / raw)
  To: The development of GRUB 2


>-----Original Message-----
>...
>> what happens if you have 2 different PCI cards installed,
>
>Then serial.mod can handle multiple terminals (it already 
>does, just not for PCI cards) via `serial' command, and use 
>the PCI calls to gather info about them whenever they're to be used.
>

Hmmm, this is getting a litte more complex than I had hoped but
so be it.  The problem is that to do this you need more than just
a PCI ID to base_baud map, now you have to be able to enumerate
serial devices, both multi-port and multi-function, so you can
match different terminal ports to their resources.  The code to do
this is moderately complex but, fortunately, the code already
exists in the Linux driver, I can just copy that code.  I know that
that code needs sub-vendor and sub-device IDs which I don't think
are exposed by the current grub PCI code so I'll have to expand
the PCI code just a little.

My thought was that we leave units 0 - 3 as the legacy ports
(whether they exist or not) and then number the PCI serial
ports that we find as units 4 and up.  I have a patch for a
simple PCI ID to base_baud map, I'll to to work on expanding
that patch.

Also, I'd like to modify the `serial' command so that typing that
command with no arguments lists out the serial ports availale,
I think that would be a usefull capability.

>> what happens if you find a serial card that isn't on the list,
>
>Does this issue happen with all serial cards, or just some?  
>If it happens with all, I guess it could just issue an error 
>and let the user know that we need feedback on how to add this one?
>
>> what about Express cards, etc.
>
>What do you mean?

I don't know anything about Express cards, if they sit on the
PCI bus with normal BDF's then there is no problem, if they
interface through some other means then supporting them will
get interesting.

>
>--
>Robert Millan
>
>  The DRM opt-in fallacy: "Your data belongs to us. We will 
>decide when (and
>  how) you may access your data; but nobody's threatening your 
>freedom: we
>  still allow you to remove your data and not access it at all."
>
>
>_______________________________________________
>Grub-devel mailing list
>Grub-devel@gnu.org
>http://lists.gnu.org/mailman/listinfo/grub-devel
>



--
Don Dugger
"Censeo Toto nos in Kansa esse decisse." - D. Gale
Donald.D.Dugger@intel.com
Ph: (303)443-3786 


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-05 15:37       ` Dugger, Donald D
@ 2008-11-06 15:02         ` Robert Millan
  2008-11-06 15:28           ` Dugger, Donald D
  0 siblings, 1 reply; 29+ messages in thread
From: Robert Millan @ 2008-11-06 15:02 UTC (permalink / raw)
  To: The development of GRUB 2

On Wed, Nov 05, 2008 at 07:37:50AM -0800, Dugger, Donald D wrote:
> 
> Hmmm, this is getting a litte more complex than I had hoped but
> so be it.  The problem is that to do this you need more than just
> a PCI ID to base_baud map, now you have to be able to enumerate
> serial devices, both multi-port and multi-function, so you can
> match different terminal ports to their resources.  The code to do
> this is moderately complex but, fortunately, the code already
> exists in the Linux driver, I can just copy that code.

On one hand, the code might be GPLv2 only, and on the other GRUB
maintainers require copyright assignments.  So I'm afraid this is
likely not possible.

> Also, I'd like to modify the `serial' command so that typing that
> command with no arguments lists out the serial ports availale,
> I think that would be a usefull capability.

I'm thinking that it's somewhat odd that selection of serial port is
done through the "serial" command instead of though the generic
"terminal" one (I think this interface was inherited from GRUB Legacy).

How would everyone feel about changing that?  So typing "terminal" could
list serial0, serial1, etc.

> I don't know anything about Express cards, if they sit on the
> PCI bus with normal BDF's then there is no problem, if they
> interface through some other means then supporting them will
> get interesting.

Since this is for a legacy interface, I doubt there will be vendors
manufacturing PCI Express cards for it.  USB is much more suitable for
compatibility.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [PATCH] PCI serial card support
  2008-11-06 15:02         ` Robert Millan
@ 2008-11-06 15:28           ` Dugger, Donald D
  2008-11-06 16:06             ` Robert Millan
  0 siblings, 1 reply; 29+ messages in thread
From: Dugger, Donald D @ 2008-11-06 15:28 UTC (permalink / raw)
  To: The development of GRUB 2

Bummer, I forgot about v2 vs. v3.  This means we have
a significant problem.  I can create a table to do the
base baud mapping without too much difficulty, there
are only about 153 non-standard devices to worry about,
it wouldn't be that hard to create a table for these
devices.

Automatically trying to identify the appropriate I/O
address for all the PCI cards out there is a much more
diffcult task that I don't want to try and do from
scratch.  The problem is that there are no standards
for which PCI BAR registers are used for which ports
on the serial cards.  The Linux driver has over 600
lines of customized code for over 100 different devices
to do this task.  Trying to duplicate that code from
scratch is rather unfeasible.

We're back to having the user manually specify the
I/O addres, then we can heuristically identify the
base baud with the ability to mnaually specify the
base baud if necessary.

--
Don Dugger
"Censeo Toto nos in Kansa esse decisse." - D. Gale
Donald.D.Dugger@intel.com
Ph: (303)443-3786

>-----Original Message-----
>From: grub-devel-bounces+donald.d.dugger=intel.com@gnu.org
>[mailto:grub-devel-bounces+donald.d.dugger=intel.com@gnu.org]
>On Behalf Of Robert Millan
>Sent: Thursday, November 06, 2008 8:02 AM
>To: The development of GRUB 2
>Subject: Re: [PATCH] PCI serial card support
>
>On Wed, Nov 05, 2008 at 07:37:50AM -0800, Dugger, Donald D wrote:
>>
>> Hmmm, this is getting a litte more complex than I had hoped
>but so be
>> it.  The problem is that to do this you need more than just a PCI ID
>> to base_baud map, now you have to be able to enumerate
>serial devices,
>> both multi-port and multi-function, so you can match different
>> terminal ports to their resources.  The code to do this is
>moderately
>> complex but, fortunately, the code already exists in the
>Linux driver,
>> I can just copy that code.
>
>On one hand, the code might be GPLv2 only, and on the other
>GRUB maintainers require copyright assignments.  So I'm afraid
>this is likely not possible.
>
>> Also, I'd like to modify the `serial' command so that typing that
>> command with no arguments lists out the serial ports
>availale, I think
>> that would be a usefull capability.
>
>I'm thinking that it's somewhat odd that selection of serial
>port is done through the "serial" command instead of though
>the generic "terminal" one (I think this interface was
>inherited from GRUB Legacy).
>
>How would everyone feel about changing that?  So typing
>"terminal" could list serial0, serial1, etc.
>
>> I don't know anything about Express cards, if they sit on
>the PCI bus
>> with normal BDF's then there is no problem, if they
>interface through
>> some other means then supporting them will get interesting.
>
>Since this is for a legacy interface, I doubt there will be
>vendors manufacturing PCI Express cards for it.  USB is much
>more suitable for compatibility.
>
>--
>Robert Millan
>
>  The DRM opt-in fallacy: "Your data belongs to us. We will
>decide when (and
>  how) you may access your data; but nobody's threatening your
>freedom: we
>  still allow you to remove your data and not access it at all."
>
>
>_______________________________________________
>Grub-devel mailing list
>Grub-devel@gnu.org
>http://lists.gnu.org/mailman/listinfo/grub-devel
>



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-06 15:28           ` Dugger, Donald D
@ 2008-11-06 16:06             ` Robert Millan
  2008-11-06 16:30               ` Dugger, Donald D
  0 siblings, 1 reply; 29+ messages in thread
From: Robert Millan @ 2008-11-06 16:06 UTC (permalink / raw)
  To: The development of GRUB 2

On Thu, Nov 06, 2008 at 07:28:57AM -0800, Dugger, Donald D wrote:
> The Linux driver has over 600
> lines of customized code for over 100 different devices
> to do this task.  Trying to duplicate that code from
> scratch is rather unfeasible.

Before we continue, did you check if that code in particular is GPLv2 only
or "or later"?  I think most drivers in Linux are in fact "or later".

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [PATCH] PCI serial card support
  2008-11-06 16:06             ` Robert Millan
@ 2008-11-06 16:30               ` Dugger, Donald D
  2008-11-06 17:00                 ` Dugger, Donald D
  0 siblings, 1 reply; 29+ messages in thread
From: Dugger, Donald D @ 2008-11-06 16:30 UTC (permalink / raw)
  To: The development of GRUB 2

To quote from the driver, `drivers/serial/8250_pci.c':

/*
 *  linux/drivers/char/8250_pci.c
 *
 *  Probe module for 8250/16550-type PCI serial ports.
 *
 *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
 *
 *  Copyright (C) 2001 Russell King, All Rights Reserved.
 *
 * This program 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 2 of the License.
 */

Looks like version 2 to me.

--
Don Dugger
"Censeo Toto nos in Kansa esse decisse." - D. Gale
Donald.D.Dugger@intel.com
Ph: (303)443-3786 

>-----Original Message-----
>From: grub-devel-bounces+donald.d.dugger=intel.com@gnu.org 
>[mailto:grub-devel-bounces+donald.d.dugger=intel.com@gnu.org] 
>On Behalf Of Robert Millan
>Sent: Thursday, November 06, 2008 9:07 AM
>To: The development of GRUB 2
>Subject: Re: [PATCH] PCI serial card support
>
>On Thu, Nov 06, 2008 at 07:28:57AM -0800, Dugger, Donald D wrote:
>> The Linux driver has over 600
>> lines of customized code for over 100 different devices to do this 
>> task.  Trying to duplicate that code from scratch is rather 
>> unfeasible.
>
>Before we continue, did you check if that code in particular 
>is GPLv2 only or "or later"?  I think most drivers in Linux 
>are in fact "or later".
>
>--
>Robert Millan
>
>  The DRM opt-in fallacy: "Your data belongs to us. We will 
>decide when (and
>  how) you may access your data; but nobody's threatening your 
>freedom: we
>  still allow you to remove your data and not access it at all."
>
>
>_______________________________________________
>Grub-devel mailing list
>Grub-devel@gnu.org
>http://lists.gnu.org/mailman/listinfo/grub-devel
>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [PATCH] PCI serial card support
  2008-11-06 16:30               ` Dugger, Donald D
@ 2008-11-06 17:00                 ` Dugger, Donald D
  2008-11-07 16:07                   ` n0ano
  0 siblings, 1 reply; 29+ messages in thread
From: Dugger, Donald D @ 2008-11-06 17:00 UTC (permalink / raw)
  To: The development of GRUB 2

Hmm, I just realized that the word `either' is interesting, it could
mean that the intent was to use either v2 or v3 and the v3 part got
dropped by mistake.  I'll ask for a clarification on the LKML to see
for sure.

--
Don Dugger
"Censeo Toto nos in Kansa esse decisse." - D. Gale
Donald.D.Dugger@intel.com
Ph: (303)443-3786 

>-----Original Message-----
>From: grub-devel-bounces+donald.d.dugger=intel.com@gnu.org 
>[mailto:grub-devel-bounces+donald.d.dugger=intel.com@gnu.org] 
>On Behalf Of Dugger, Donald D
>Sent: Thursday, November 06, 2008 9:30 AM
>To: The development of GRUB 2
>Subject: RE: [PATCH] PCI serial card support
>
>To quote from the driver, `drivers/serial/8250_pci.c':
>
>/*
> *  linux/drivers/char/8250_pci.c
> *
> *  Probe module for 8250/16550-type PCI serial ports.
> *
> *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
> *
> *  Copyright (C) 2001 Russell King, All Rights Reserved.
> *
> * This program 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 2 of the License.
> */
>
>Looks like version 2 to me.
>
>--
>Don Dugger
>"Censeo Toto nos in Kansa esse decisse." - D. Gale 
>Donald.D.Dugger@intel.com
>Ph: (303)443-3786 
>
>>-----Original Message-----
>>From: grub-devel-bounces+donald.d.dugger=intel.com@gnu.org
>>[mailto:grub-devel-bounces+donald.d.dugger=intel.com@gnu.org]
>>On Behalf Of Robert Millan
>>Sent: Thursday, November 06, 2008 9:07 AM
>>To: The development of GRUB 2
>>Subject: Re: [PATCH] PCI serial card support
>>
>>On Thu, Nov 06, 2008 at 07:28:57AM -0800, Dugger, Donald D wrote:
>>> The Linux driver has over 600
>>> lines of customized code for over 100 different devices to do this 
>>> task.  Trying to duplicate that code from scratch is rather 
>>> unfeasible.
>>
>>Before we continue, did you check if that code in particular is GPLv2 
>>only or "or later"?  I think most drivers in Linux are in fact "or 
>>later".
>>
>>--
>>Robert Millan
>>
>>  The DRM opt-in fallacy: "Your data belongs to us. We will 
>decide when 
>>(and
>>  how) you may access your data; but nobody's threatening your
>>freedom: we
>>  still allow you to remove your data and not access it at all."
>>
>>
>>_______________________________________________
>>Grub-devel mailing list
>>Grub-devel@gnu.org
>>http://lists.gnu.org/mailman/listinfo/grub-devel
>>
>
>_______________________________________________
>Grub-devel mailing list
>Grub-devel@gnu.org
>http://lists.gnu.org/mailman/listinfo/grub-devel
>


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-06 17:00                 ` Dugger, Donald D
@ 2008-11-07 16:07                   ` n0ano
  2008-11-07 16:52                     ` Vesa Jääskeläinen
  0 siblings, 1 reply; 29+ messages in thread
From: n0ano @ 2008-11-07 16:07 UTC (permalink / raw)
  To: The development of GRUB 2; +Cc: Russell King, Theodore Tso

Bad news, I heard back from the two people who wrote the PCI serial
code for Linux (Russell King & Ted Tso) and they both agree that,
no matter how the ambiguity got into the Linux source files, their
intent was that the code was GPL v2 only.

That being the case, we can't use the code and I don't want to try
and re-write it from scratch so we're back to having the user manually
specify the I/O port address but at least I can create a PCI ID table
to map the base baud.

On Thu, Nov 06, 2008 at 09:00:22AM -0800, Dugger, Donald D wrote:
> Hmm, I just realized that the word `either' is interesting, it could
> mean that the intent was to use either v2 or v3 and the v3 part got
> dropped by mistake.  I'll ask for a clarification on the LKML to see
> for sure.
> 
> --
> Don Dugger
> "Censeo Toto nos in Kansa esse decisse." - D. Gale
> Donald.D.Dugger@intel.com
> Ph: (303)443-3786 
> 
> >-----Original Message-----
> >From: grub-devel-bounces+donald.d.dugger=intel.com@gnu.org 
> >[mailto:grub-devel-bounces+donald.d.dugger=intel.com@gnu.org] 
> >On Behalf Of Dugger, Donald D
> >Sent: Thursday, November 06, 2008 9:30 AM
> >To: The development of GRUB 2
> >Subject: RE: [PATCH] PCI serial card support
> >
> >To quote from the driver, `drivers/serial/8250_pci.c':
> >
> >/*
> > *  linux/drivers/char/8250_pci.c
> > *
> > *  Probe module for 8250/16550-type PCI serial ports.
> > *
> > *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
> > *
> > *  Copyright (C) 2001 Russell King, All Rights Reserved.
> > *
> > * This program 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 2 of the License.
> > */
> >
> >Looks like version 2 to me.
> >
> >--
> >Don Dugger
> >"Censeo Toto nos in Kansa esse decisse." - D. Gale 
> >Donald.D.Dugger@intel.com
> >Ph: (303)443-3786 
> >
> >>-----Original Message-----
> >>From: grub-devel-bounces+donald.d.dugger=intel.com@gnu.org
> >>[mailto:grub-devel-bounces+donald.d.dugger=intel.com@gnu.org]
> >>On Behalf Of Robert Millan
> >>Sent: Thursday, November 06, 2008 9:07 AM
> >>To: The development of GRUB 2
> >>Subject: Re: [PATCH] PCI serial card support
> >>
> >>On Thu, Nov 06, 2008 at 07:28:57AM -0800, Dugger, Donald D wrote:
> >>> The Linux driver has over 600
> >>> lines of customized code for over 100 different devices to do this 
> >>> task.  Trying to duplicate that code from scratch is rather 
> >>> unfeasible.
> >>
> >>Before we continue, did you check if that code in particular is GPLv2 
> >>only or "or later"?  I think most drivers in Linux are in fact "or 
> >>later".
> >>
> >>--
> >>Robert Millan
> >>
> >>  The DRM opt-in fallacy: "Your data belongs to us. We will 
> >decide when 
> >>(and
> >>  how) you may access your data; but nobody's threatening your
> >>freedom: we
> >>  still allow you to remove your data and not access it at all."
> >>
> >>
> >>_______________________________________________
> >>Grub-devel mailing list
> >>Grub-devel@gnu.org
> >>http://lists.gnu.org/mailman/listinfo/grub-devel
> >>
> >
> >_______________________________________________
> >Grub-devel mailing list
> >Grub-devel@gnu.org
> >http://lists.gnu.org/mailman/listinfo/grub-devel
> >
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel

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



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-07 16:07                   ` n0ano
@ 2008-11-07 16:52                     ` Vesa Jääskeläinen
  2008-11-08 11:25                       ` Robert Millan
  0 siblings, 1 reply; 29+ messages in thread
From: Vesa Jääskeläinen @ 2008-11-07 16:52 UTC (permalink / raw)
  To: The development of GRUB 2

n0ano@n0ano.com wrote:
> Bad news, I heard back from the two people who wrote the PCI serial
> code for Linux (Russell King & Ted Tso) and they both agree that,
> no matter how the ambiguity got into the Linux source files, their
> intent was that the code was GPL v2 only.
> 
> That being the case, we can't use the code and I don't want to try
> and re-write it from scratch so we're back to having the user manually
> specify the I/O port address but at least I can create a PCI ID table
> to map the base baud.

Ok. Then I would suggest that only simple change is made at this time to
support it. So we start from scratch on that implementation. Anyway...
it can be improved later on.



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-07 16:52                     ` Vesa Jääskeläinen
@ 2008-11-08 11:25                       ` Robert Millan
  2008-11-08 12:23                         ` Vesa Jääskeläinen
  0 siblings, 1 reply; 29+ messages in thread
From: Robert Millan @ 2008-11-08 11:25 UTC (permalink / raw)
  To: The development of GRUB 2

On Fri, Nov 07, 2008 at 06:52:21PM +0200, Vesa Jääskeläinen wrote:
> n0ano@n0ano.com wrote:
> > Bad news, I heard back from the two people who wrote the PCI serial
> > code for Linux (Russell King & Ted Tso) and they both agree that,
> > no matter how the ambiguity got into the Linux source files, their
> > intent was that the code was GPL v2 only.
> > 
> > That being the case, we can't use the code and I don't want to try
> > and re-write it from scratch so we're back to having the user manually
> > specify the I/O port address but at least I can create a PCI ID table
> > to map the base baud.
> 
> Ok. Then I would suggest that only simple change is made at this time to
> support it. So we start from scratch on that implementation. Anyway...
> it can be improved later on.

Why not use PCI ID to support this particular card?  This way Donald doesn't
have to support all cards, but the base is laid out so more cards can be added
in the future.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-08 11:25                       ` Robert Millan
@ 2008-11-08 12:23                         ` Vesa Jääskeläinen
  2008-11-08 12:45                           ` Robert Millan
  0 siblings, 1 reply; 29+ messages in thread
From: Vesa Jääskeläinen @ 2008-11-08 12:23 UTC (permalink / raw)
  To: The development of GRUB 2

Robert Millan wrote:
> On Fri, Nov 07, 2008 at 06:52:21PM +0200, Vesa Jääskeläinen wrote:
>> n0ano@n0ano.com wrote:
>>> Bad news, I heard back from the two people who wrote the PCI serial
>>> code for Linux (Russell King & Ted Tso) and they both agree that,
>>> no matter how the ambiguity got into the Linux source files, their
>>> intent was that the code was GPL v2 only.
>>>
>>> That being the case, we can't use the code and I don't want to try
>>> and re-write it from scratch so we're back to having the user manually
>>> specify the I/O port address but at least I can create a PCI ID table
>>> to map the base baud.
>> Ok. Then I would suggest that only simple change is made at this time to
>> support it. So we start from scratch on that implementation. Anyway...
>> it can be improved later on.
> 
> Why not use PCI ID to support this particular card?  This way Donald doesn't
> have to support all cards, but the base is laid out so more cards can be added
> in the future.

I have nothing against that. But in any case I think there has to be
this override functionality support. Just make it a bit harder for user
to type so they know it is advanced feature :). Making these transparent
for user is always a plus.

I just feel that it might be a bit overkill to chain this module to pci
module. Of course you can dynamically check if PCI module is there and
then ask identification information from there. If you make it other way
around so that some other module references to serial module and then
just registers new serial device there then that is better of course.

isnmod pciserial [device location in system, or if omitted, autodetect]?




^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-08 12:23                         ` Vesa Jääskeläinen
@ 2008-11-08 12:45                           ` Robert Millan
  2008-11-08 14:00                             ` Vesa Jääskeläinen
  2008-11-09  1:58                             ` n0ano
  0 siblings, 2 replies; 29+ messages in thread
From: Robert Millan @ 2008-11-08 12:45 UTC (permalink / raw)
  To: The development of GRUB 2

On Sat, Nov 08, 2008 at 02:23:32PM +0200, Vesa Jääskeläinen wrote:
> > 
> > Why not use PCI ID to support this particular card?  This way Donald doesn't
> > have to support all cards, but the base is laid out so more cards can be added
> > in the future.
> 
> I have nothing against that. But in any case I think there has to be
> this override functionality support. Just make it a bit harder for user
> to type so they know it is advanced feature :).

How about implementing the flag but not listing it in --help output, and
not documenting it (oh wait, we didn't document serial.mod anyway ;-)) ?

> Of course you can dynamically check if PCI module is there and
> then ask identification information from there.

Sounds good.  But do we have support for "weak" symbol dependencies a la
dlym() ?

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-08 12:45                           ` Robert Millan
@ 2008-11-08 14:00                             ` Vesa Jääskeläinen
  2008-11-09  1:58                             ` n0ano
  1 sibling, 0 replies; 29+ messages in thread
From: Vesa Jääskeläinen @ 2008-11-08 14:00 UTC (permalink / raw)
  To: The development of GRUB 2

Robert Millan wrote:
> Sounds good.  But do we have support for "weak" symbol dependencies a la
> dlym() ?

I tried it once while traveling and you can dynamically check for
function symbols and then start using them if they are loaded. Thou... I
do not know how reference counting is then affected. So you probably
should either increment counters if used dyniamically or only use it
while inside function call.



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-08 12:45                           ` Robert Millan
  2008-11-08 14:00                             ` Vesa Jääskeläinen
@ 2008-11-09  1:58                             ` n0ano
  2008-11-09 21:57                               ` Robert Millan
  1 sibling, 1 reply; 29+ messages in thread
From: n0ano @ 2008-11-09  1:58 UTC (permalink / raw)
  To: The development of GRUB 2

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.

The user can always specify a specific I/O port and base baud for his/her
specific device, the table is really just a heuristic to provide a reasonable
default that can always be over-ridden.

Note that what I'm doing will make the serial module dependent upon the
pci module but I don't see that that's a big concern.  Pretty much any
modern machine will have a PCI bus so scanning it should not be a
problem.  Also, note that the legacy serial devices (I/O ports at
0x3f8 & 0x2f8) are going away, in the not too distant future the only
way to get serial output will be through PCI or USB.  Given that USB
controllers hang off the PCI bus I don't see an issue with having the
serial module require the pci module.

On Sat, Nov 08, 2008 at 01:45:44PM +0100, Robert Millan wrote:
> On Sat, Nov 08, 2008 at 02:23:32PM +0200, Vesa J????skel??inen wrote:
> > > 
> > > Why not use PCI ID to support this particular card?  This way Donald doesn't
> > > have to support all cards, but the base is laid out so more cards can be added
> > > in the future.
> > 
> > I have nothing against that. But in any case I think there has to be
> > this override functionality support. Just make it a bit harder for user
> > to type so they know it is advanced feature :).
> 
> How about implementing the flag but not listing it in --help output, and
> not documenting it (oh wait, we didn't document serial.mod anyway ;-)) ?
> 
> > Of course you can dynamically check if PCI module is there and
> > then ask identification information from there.
> 
> Sounds good.  But do we have support for "weak" symbol dependencies a la
> dlym() ?
> 
> -- 
> Robert Millan
> 
>   The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
>   how) you may access your data; but nobody's threatening your freedom: we
>   still allow you to remove your data and not access it at all."
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel

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



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-09  1:58                             ` n0ano
@ 2008-11-09 21:57                               ` Robert Millan
  2008-11-09 22:13                                 ` Vesa Jääskeläinen
                                                   ` (2 more replies)
  0 siblings, 3 replies; 29+ messages in thread
From: Robert Millan @ 2008-11-09 21:57 UTC (permalink / raw)
  To: The development of GRUB 2

On Sat, Nov 08, 2008 at 06:58:19PM -0700, n0ano@n0ano.com 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.

Nice!  Aside from base baud and configuration function, I assume we'd also
want to specify the I/O port?

> Note that what I'm doing will make the serial module dependent upon the
> pci module but I don't see that that's a big concern.  Pretty much any
> modern machine will have a PCI bus so scanning it should not be a
> problem.  Also, note that the legacy serial devices (I/O ports at
> 0x3f8 & 0x2f8) are going away, in the not too distant future the only
> way to get serial output will be through PCI or USB.  Given that USB
> controllers hang off the PCI bus I don't see an issue with having the
> serial module require the pci module.

If we want to soften the dependency on the pci module, I guess it can
always be done afterwards.  Vesa, what do you think?

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-09 21:57                               ` Robert Millan
@ 2008-11-09 22:13                                 ` Vesa Jääskeläinen
  2008-11-09 22:14                                 ` n0ano
  2008-11-12 18:58                                 ` n0ano
  2 siblings, 0 replies; 29+ messages in thread
From: Vesa Jääskeläinen @ 2008-11-09 22:13 UTC (permalink / raw)
  To: The development of GRUB 2

Robert Millan wrote:
> On Sat, Nov 08, 2008 at 06:58:19PM -0700, n0ano@n0ano.com wrote:
>> Note that what I'm doing will make the serial module dependent upon the
>> pci module but I don't see that that's a big concern.  Pretty much any
>> modern machine will have a PCI bus so scanning it should not be a
>> problem.  Also, note that the legacy serial devices (I/O ports at
>> 0x3f8 & 0x2f8) are going away, in the not too distant future the only
>> way to get serial output will be through PCI or USB.  Given that USB
>> controllers hang off the PCI bus I don't see an issue with having the
>> serial module require the pci module.
> 
> If we want to soften the dependency on the pci module, I guess it can
> always be done afterwards.  Vesa, what do you think?

Not an issue at this point. If it comes an issue then we can modify it.



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-09 21:57                               ` Robert Millan
  2008-11-09 22:13                                 ` Vesa Jääskeläinen
@ 2008-11-09 22:14                                 ` n0ano
  2008-11-12 18:58                                 ` n0ano
  2 siblings, 0 replies; 29+ messages in thread
From: n0ano @ 2008-11-09 22:14 UTC (permalink / raw)
  To: The development of GRUB 2

On Sun, Nov 09, 2008 at 10:57:30PM +0100, Robert Millan wrote:
>... 
> Nice!  Aside from base baud and configuration function, I assume we'd also
> want to specify the I/O port?

Yep, I/O port and base baud are the only two device specific items
we need since we don't do interrupts.  Doing a table for base baud
is easy, unfortunately identifying the I/O port is hard, that's the
one we'll have to develop over time.

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



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-09 21:57                               ` Robert Millan
  2008-11-09 22:13                                 ` Vesa Jääskeläinen
  2008-11-09 22:14                                 ` n0ano
@ 2008-11-12 18:58                                 ` n0ano
  2008-11-13 18:05                                   ` Vesa Jääskeläinen
  2 siblings, 1 reply; 29+ messages in thread
From: n0ano @ 2008-11-12 18:58 UTC (permalink / raw)
  To: The development of GRUB 2

On Sun, Nov 09, 2008 at 10:57:30PM +0100, Robert Millan wrote:
> On Sat, Nov 08, 2008 at 06:58:19PM -0700, n0ano@n0ano.com 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 <donald.d.dugger@intel.com>

-- 
Don Dugger
"Censeo Toto nos in Kansa esse decisse." - D. Gale
n0ano@n0ano.com
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 <donald.d.dugger@intel.com>
+
+	* 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  <rmh@aybabtu.com>
 
 	* 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. */
     {



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-12 18:58                                 ` n0ano
@ 2008-11-13 18:05                                   ` Vesa Jääskeläinen
  2008-11-13 20:13                                     ` n0ano
  2008-11-14 19:24                                     ` n0ano
  0 siblings, 2 replies; 29+ messages in thread
From: Vesa Jääskeläinen @ 2008-11-13 18:05 UTC (permalink / raw)
  To: The development of GRUB 2

Hi Don,

Thanks for the patch!

n0ano@n0ano.com wrote:
> On Sun, Nov 09, 2008 at 10:57:30PM +0100, Robert Millan wrote:
>> On Sat, Nov 08, 2008 at 06:58:19PM -0700, n0ano@n0ano.com 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

Why not hide the legacy comports if they are not there and we can auto
detect that?

That actually brings us to other issue. Should be have some kind of HW
dependant device path support that would be universal in grub?. Now if
user unplugs in example USB serial converter then the order will change
and can cause some problems.

> --- 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.

This seems to be new file. Please change copyright years to start from 2008.

Where did you get that device table?. Generated by yourself from pci
database?

Anyway. I think those vendor and device ID's should be in global file as
they are "universal" to any PCI device.

> --- term/i386/pc/serial.c	(revision 1911)
> +++ term/i386/pc/serial.c	(working copy)

> +#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>
> +

Please keep includes at same place.

Why is this prototype even here?. And should it be static?

> +char *serial_types[] = {
> +	"legacy",
> +	"   pci",
> +	"   usb"
> +};

static const

And please leave output formatting to actual printing.

> +  grub_printf("%c%2d: %s ", (p == serial_dev) ? '*' : ' ',
> +			   i, serial_types[p->type]);

What is p->type is not within range of serial_types?

> +char parity[] = {

static const

> +static int
> +serial_pci_scan (int bus, int dev, int func, grub_pci_id_t pciid)

> +  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;

This smells. Perhaps helper function or macro.

As a generic note. If this is generic information that is available on
every PCI device. Why not change PCI to iterate with structure.

Well... I didn't look too deep there this time. :)

Thanks,
Vesa Jääskeläinen



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-13 18:05                                   ` Vesa Jääskeläinen
@ 2008-11-13 20:13                                     ` n0ano
  2008-11-14 19:24                                     ` n0ano
  1 sibling, 0 replies; 29+ messages in thread
From: n0ano @ 2008-11-13 20:13 UTC (permalink / raw)
  To: The development of GRUB 2

On Thu, Nov 13, 2008 at 08:05:37PM +0200, Vesa J??skel?inen wrote:
> 
> Why not hide the legacy comports if they are not there and we can auto
> detect that?

I went back and forth on this.  I finally decided that COM1 to COM4 are
so firmly a part of the PC design I should leave them (note that if
GRUB_MACHINE_PCBIOS is not defined then these 4 I/O ports will be defined
whether or not they are there and I'll have to list them.).  If there's
a strong preference I can drop them if the BIOS doesn't define an I/O
port for them.

> 
> That actually brings us to other issue. Should be have some kind of HW
> dependant device path support that would be universal in grub?. Now if
> user unplugs in example USB serial converter then the order will change
> and can cause some problems.

Maybe.  Seems like a little bit of over engineering right now.

> 
> > --- 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.
> 
> This seems to be new file. Please change copyright years to start from 2008.
> 
> Where did you get that device table?. Generated by yourself from pci
> database?
> 
> Anyway. I think those vendor and device ID's should be in global file as
> they are "universal" to any PCI device.

It is now.  My understanding is that a data table is not copyrightable
(no expressive content) but, just to make sure there is no issue, I've
replaced this with a table of just the devices I know about.  I'll
create (a very small) generic PCI ID table, we can add on as time goes
by.

> 
> > --- term/i386/pc/serial.c	(revision 1911)
> > +++ term/i386/pc/serial.c	(working copy)
> 
> > +#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>
> > +
> 
> Please keep includes at same place.
> 
> Why is this prototype even here?. And should it be static?

Since the mapping table code calls this function the prototype
needs to be defined before the include of `pci_serial_ids.h'.
I'll move the prototype to `serial.h' and clean these two up.

> 
> > +char *serial_types[] = {
> > +	"legacy",
> > +	"   pci",
> > +	"   usb"
> > +};
> 
> static const
> 
> And please leave output formatting to actual printing.

sure.

> 
> > +  grub_printf("%c%2d: %s ", (p == serial_dev) ? '*' : ' ',
> > +			   i, serial_types[p->type]);
> 
> What is p->type is not within range of serial_types?

Then we have a more serious problem since `p->type' is only set
by the code to a value between 0 - 2.  Given that this could only
be wrong because of a code bug it seems silly to value check it.

> 
> > +char parity[] = {
> 
> static const
> 
> > +static int
> > +serial_pci_scan (int bus, int dev, int func, grub_pci_id_t pciid)
> 
> > +  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;
> 
> This smells. Perhaps helper function or macro.
> 
> As a generic note. If this is generic information that is available on
> every PCI device. Why not change PCI to iterate with structure.
> 
> Well... I didn't look too deep there this time. :)

I was trying not to re-write the PCI code too much, it is way to
hard coded right now but my goal was to get the serial support in
first.  I can certainly look into regularizing the PCI code a little
on the way.

Thanks for the comments, I'll get an updated patch out soon.


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



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-13 18:05                                   ` Vesa Jääskeläinen
  2008-11-13 20:13                                     ` n0ano
@ 2008-11-14 19:24                                     ` n0ano
  2008-11-22  2:53                                       ` Neo Jia
  1 sibling, 1 reply; 29+ messages in thread
From: n0ano @ 2008-11-14 19:24 UTC (permalink / raw)
  To: The development of GRUB 2

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 <donald.d.dugger@intel.com>

-- 
Don Dugger
"Censeo Toto nos in Kansa esse decisse." - D. Gale
n0ano@n0ano.com
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 <donald.d.dugger@intel.com>
+
+	* 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  <rmh@aybabtu.com>
 
 	* 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. */
     {



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-14 19:24                                     ` n0ano
@ 2008-11-22  2:53                                       ` Neo Jia
  2008-11-22  7:18                                         ` Vesa Jääskeläinen
  0 siblings, 1 reply; 29+ messages in thread
From: Neo Jia @ 2008-11-22  2:53 UTC (permalink / raw)
  To: The development of GRUB 2

hi,

Will the current GRUB 2 trunk from SVN repository contain the PCI
searil port card support?

I would like to try it out as my mb doesn't have a onboad serial port.

Thanks,
Neo

On Fri, Nov 14, 2008 at 11:24 AM,  <n0ano@n0ano.com> wrote:
> 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 <donald.d.dugger@intel.com>
>
> --
> Don Dugger
> "Censeo Toto nos in Kansa esse decisse." - D. Gale
> n0ano@n0ano.com
> 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 <donald.d.dugger@intel.com>
> +
> +       * 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  <rmh@aybabtu.com>
>
>        * 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. */
>     {
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>



-- 
I would remember that if researchers were not ambitious
probably today we haven't the technology we are using!



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-22  2:53                                       ` Neo Jia
@ 2008-11-22  7:18                                         ` Vesa Jääskeläinen
  0 siblings, 0 replies; 29+ messages in thread
From: Vesa Jääskeläinen @ 2008-11-22  7:18 UTC (permalink / raw)
  To: The development of GRUB 2

Neo Jia wrote:
> hi,
> 
> Will the current GRUB 2 trunk from SVN repository contain the PCI
> searil port card support?
> 
> I would like to try it out as my mb doesn't have a onboad serial port.

Hi Neo,

Not at this time. Please wait a bit until legal stuff has been completed
so it can be merged.

In meanwhile you can try to determine your IO base address and try it
out with serial's --port=0x<base address> argument. With luck you are fine.

Please report what kind of card you have and some details about it (in
example verbose dump of lspci with your serial card section included).

Thanks,
Vesa Jääskeläinen



^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH] PCI serial card support
  2008-11-04  0:38 [PATCH] PCI serial card support donald.d.dugger
  2008-11-04 15:39 ` Robert Millan
@ 2009-07-21  8:11 ` tony.gugo
  1 sibling, 0 replies; 29+ messages in thread
From: tony.gugo @ 2009-07-21  8:11 UTC (permalink / raw)
  To: grub-devel

I want to configure the OXPCIe954 to nDTR auto flow contorol (I want the RS-485 ports).
I add the following code at driver open com port.
WRITE_REGISTER_UCHAR(Port_Addr + 7, 0);
WRITE_REGISTER_UCHAR(Port_Addr + 0xA0 + 5, 0x30);

But the ports are not able to send and receive data. (If I use the oxford's device driver and set the port as RS-485, it works.)

Is there any register I forget to configure?

Thanks All.

--
This message was sent on behalf of tony.gugo@gmail.com at openSubscriber.com
http://www.opensubscriber.com/message/grub-devel@gnu.org/10640386.html



^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2009-07-21  8:11 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-04  0:38 [PATCH] PCI serial card support donald.d.dugger
2008-11-04 15:39 ` Robert Millan
2008-11-04 18:24   ` Dugger, Donald D
2008-11-05  9:58     ` Robert Millan
2008-11-05 15:37       ` Dugger, Donald D
2008-11-06 15:02         ` Robert Millan
2008-11-06 15:28           ` Dugger, Donald D
2008-11-06 16:06             ` Robert Millan
2008-11-06 16:30               ` Dugger, Donald D
2008-11-06 17:00                 ` Dugger, Donald D
2008-11-07 16:07                   ` n0ano
2008-11-07 16:52                     ` Vesa Jääskeläinen
2008-11-08 11:25                       ` Robert Millan
2008-11-08 12:23                         ` Vesa Jääskeläinen
2008-11-08 12:45                           ` Robert Millan
2008-11-08 14:00                             ` Vesa Jääskeläinen
2008-11-09  1:58                             ` n0ano
2008-11-09 21:57                               ` Robert Millan
2008-11-09 22:13                                 ` Vesa Jääskeläinen
2008-11-09 22:14                                 ` n0ano
2008-11-12 18:58                                 ` n0ano
2008-11-13 18:05                                   ` Vesa Jääskeläinen
2008-11-13 20:13                                     ` n0ano
2008-11-14 19:24                                     ` n0ano
2008-11-22  2:53                                       ` Neo Jia
2008-11-22  7:18                                         ` Vesa Jääskeläinen
2008-11-04 18:26   ` Vesa Jääskeläinen
2008-11-04 18:38     ` Dugger, Donald D
2009-07-21  8:11 ` tony.gugo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.