serial.c 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2023 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/serial.h>
  19. #include <grub/term.h>
  20. #include <grub/types.h>
  21. #include <grub/pci.h>
  22. #include <grub/mm.h>
  23. #include <grub/misc.h>
  24. static int
  25. find_pciserial (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused)), void *data __attribute__ ((unused)))
  26. {
  27. grub_pci_address_t cmd_addr, class_addr, bar_addr;
  28. struct grub_serial_port *port;
  29. grub_uint32_t class, bar;
  30. grub_uint16_t cmdreg;
  31. grub_err_t err;
  32. cmd_addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
  33. cmdreg = grub_pci_read (cmd_addr);
  34. class_addr = grub_pci_make_address (dev, GRUB_PCI_REG_REVISION);
  35. class = grub_pci_read (class_addr);
  36. bar_addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
  37. bar = grub_pci_read (bar_addr);
  38. /* 16550 compatible MODEM or SERIAL. */
  39. if (((class >> 16) != GRUB_PCI_CLASS_COMMUNICATION_MODEM &&
  40. (class >> 16) != GRUB_PCI_CLASS_COMMUNICATION_SERIAL) ||
  41. ((class >> 8) & 0xff) != GRUB_PCI_SERIAL_16550_COMPATIBLE)
  42. return 0;
  43. if ((bar & GRUB_PCI_ADDR_SPACE_MASK) != GRUB_PCI_ADDR_SPACE_IO)
  44. return 0;
  45. port = grub_zalloc (sizeof (*port));
  46. if (port == NULL)
  47. return 0;
  48. port->name = grub_xasprintf ("pci,%02x:%02x.%x",
  49. grub_pci_get_bus (dev),
  50. grub_pci_get_device (dev),
  51. grub_pci_get_function (dev));
  52. if (port->name == NULL)
  53. goto fail;
  54. grub_pci_write (cmd_addr, cmdreg | GRUB_PCI_COMMAND_IO_ENABLED);
  55. port->driver = &grub_ns8250_driver;
  56. port->port = bar & GRUB_PCI_ADDR_IO_MASK;
  57. err = grub_serial_config_defaults (port);
  58. if (err != GRUB_ERR_NONE)
  59. {
  60. grub_print_error ();
  61. goto fail;
  62. }
  63. err = grub_serial_register (port);
  64. if (err != GRUB_ERR_NONE)
  65. goto fail;
  66. return 0;
  67. fail:
  68. grub_free (port->name);
  69. grub_free (port);
  70. return 0;
  71. }
  72. void
  73. grub_pciserial_init (void)
  74. {
  75. grub_pci_iterate (find_pciserial, NULL);
  76. }