grub-devel
[Top][All Lists]
Advanced

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

Re: [PATCH] PCI serial card support


From: Neo Jia
Subject: Re: [PATCH] PCI serial card support
Date: Fri, 21 Nov 2008 18:53:19 -0800

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




reply via email to

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