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