Hi,

The following diff is to support serial console on efiboot.

It uses ACPI UID to identify the port number (com0, com1 and so on) of
probed serial interface.  But I'm not sure wether com0-com3 are always
mapped UID 0-3 as expected.  Though I think this is good enough.

Comment?

diff --git a/sys/arch/amd64/stand/efiboot/conf.c 
b/sys/arch/amd64/stand/efiboot/conf.c
index 0b2933d4cff..913a33e77a6 100644
--- a/sys/arch/amd64/stand/efiboot/conf.c
+++ b/sys/arch/amd64/stand/efiboot/conf.c
@@ -85,6 +85,7 @@ int ndevs = nitems(devsw);
 
 struct consdev constab[] = {
        { efi_cons_probe, efi_cons_init, efi_cons_getc, efi_cons_putc },
+       { efi_com_probe, efi_com_init, efi_com_getc, efi_com_putc },
        { NULL }
 };
 struct consdev *cn_tab = constab;
diff --git a/sys/arch/amd64/stand/efiboot/efiboot.c 
b/sys/arch/amd64/stand/efiboot/efiboot.c
index d668258989f..613ede425b6 100644
--- a/sys/arch/amd64/stand/efiboot/efiboot.c
+++ b/sys/arch/amd64/stand/efiboot/efiboot.c
@@ -501,10 +501,171 @@ efi_cons_getshifts(dev_t dev)
        return (0);
 }
 
-/* XXX: serial console is not supported yet */
 int com_addr = -1;
 int com_speed = -1;
 
+static SERIAL_IO_INTERFACE     *serios[4];
+const int                       comports[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+
+void
+efi_com_probe(struct consdev *cn)
+{
+       EFI_GUID                 serio_guid = SERIAL_IO_PROTOCOL;
+       EFI_HANDLE              *handles = NULL;
+       SERIAL_IO_INTERFACE     *serio;
+       EFI_STATUS               status;
+       EFI_DEVICE_PATH         *dp, *dp0;
+       EFI_DEV_PATH_PTR         dpp;
+       UINTN                    sz;
+       int                      i, uid = -1;
+
+       sz = 0;
+       status = EFI_CALL(BS->LocateHandle, ByProtocol, &serio_guid, 0, &sz, 0);
+       if (status == EFI_BUFFER_TOO_SMALL) {
+               handles = alloc(sz);
+               status = EFI_CALL(BS->LocateHandle, ByProtocol, &serio_guid,
+                   0, &sz, handles);
+       }
+       if (handles == NULL || EFI_ERROR(status))
+               panic("could not get handles of serial i/o");
+
+       for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
+               /*
+                * Identify port number of the handle.  This assumes ACPI
+                * UID 0-4 map to legacy COM[1-4] and they use the legacy
+                * port address.
+                */
+               status = EFI_CALL(BS->HandleProtocol, handles[i], &devp_guid,
+                   (void **)&dp0);
+               if (EFI_ERROR(status))
+                       continue;
+               uid = -1;
+               for (dp = dp0; !IsDevicePathEnd(dp);
+                   dp = NextDevicePathNode(dp)) {
+                       dpp = (EFI_DEV_PATH_PTR)dp;
+                       if (DevicePathType(dp) == ACPI_DEVICE_PATH &&
+                           DevicePathSubType(dp) == ACPI_DP)
+                               if (dpp.Acpi->HID == 0x50141d0 /* PNP0501 */) {
+                                       uid = dpp.Acpi->UID;
+                                       break;
+                               }
+               }
+               if (uid < 0)
+                       continue;
+
+               /* Prepare SERIAL_IO_INTERFACE */
+               status = EFI_CALL(BS->HandleProtocol, handles[i], &serio_guid,
+                   (void **)&serio);
+               if (EFI_ERROR(status))
+                       continue;
+               if (uid < nitems(serios))
+                       serios[uid] = serio;
+       }
+       free(handles, sz);
+
+       for (i = 0; i < nitems(serios); i++) {
+               if (serios[i] != NULL)
+                   printf(" com%d", i);
+       }
+       cn->cn_pri = CN_LOWPRI;
+       cn->cn_dev = makedev(8, 0);
+}
+
+int
+efi_valid_com(dev_t dev)
+{
+       return (0 <= minor(dev) && minor(dev) < nitems(serios) &&
+           serios[minor(dev)] != NULL);
+}
+
+int
+comspeed(dev_t dev, int sp)
+{
+       EFI_STATUS               status;
+       SERIAL_IO_INTERFACE     *serio = serios[minor(dev)];
+
+       if (!efi_valid_com(dev))
+               return (-1);
+
+       if (sp > 0 && serio->Mode->BaudRate != sp) {
+               status = EFI_CALL(serio->SetAttributes, serio,
+                   sp, serio->Mode->ReceiveFifoDepth,
+                   serio->Mode->Timeout, serio->Mode->Parity,
+                   serio->Mode->DataBits, serio->Mode->StopBits);
+               if (EFI_ERROR(status)) {
+                       painc("com%d: SetAttribute() failed with status=%d\n",
+                           minor(dev), status);
+               }
+               com_speed = serio->Mode->BaudRate;
+       }
+       com_speed = sp;
+
+       return (serio->Mode->BaudRate);
+}
+
+void
+efi_com_init(struct consdev *cn)
+{
+       if (!efi_valid_com(cn->cn_dev))
+               panic("com%d is not probed", minor(cn->cn_dev));
+
+       if (com_speed == -1)
+               comspeed(cn->cn_dev, 9600); /* default speed is 9600 baud */
+
+       com_addr = comports[minor(cn->cn_dev)];
+}
+
+int
+efi_com_getc(dev_t dev)
+{
+       EFI_STATUS               status;
+       SERIAL_IO_INTERFACE     *serio;
+       UINTN                    sz;
+       u_char                   buf[1];
+       static u_char            lastchar = 0;
+
+       if (!efi_valid_com(dev & 0x7f))
+               panic("com%d is not probed", minor(dev));
+       serio = serios[minor(dev & 0x7f)];
+
+       if (lastchar != 0) {
+               int r = lastchar;
+               if ((dev & 0x80) == 0)
+                       lastchar = 0;
+               return (r);
+       }
+
+       for (;;) {
+               sz = 1;
+               status = EFI_CALL(serio->Read, serio, &sz, buf);
+               if (status == EFI_SUCCESS && sz > 0)
+                       break;
+               if (status != EFI_TIMEOUT && EFI_ERROR(status))
+                       panic("Error reading from serial status=%d", status);
+               if (dev & 0x80)
+                       return (0);
+       }
+
+       if (dev & 0x80)
+               lastchar = buf[0];
+
+       return (buf[0]);
+}
+
+void
+efi_com_putc(dev_t dev, int c)
+{
+       SERIAL_IO_INTERFACE     *serio;
+       UINTN                    sz = 1;
+       u_char                   buf[1];
+
+       if (!efi_valid_com(dev))
+               panic("com%d is not probed", minor(dev));
+       serio = serios[minor(dev)];
+       buf[0] = c;
+       EFI_CALL(serio->Write, serio, &sz, buf);
+}
+
 /***********************************************************************
  * Miscellaneous
  ***********************************************************************/
diff --git a/sys/arch/amd64/stand/efiboot/efiboot.h 
b/sys/arch/amd64/stand/efiboot/efiboot.h
index 84cbcb537a4..fb7abb7c5f4 100644
--- a/sys/arch/amd64/stand/efiboot/efiboot.h
+++ b/sys/arch/amd64/stand/efiboot/efiboot.h
@@ -17,14 +17,18 @@
  */
 
 void    efi_cleanup(void);
-void    efi_cons_probe (struct consdev *);
-void    efi_memprobe (void);
-void    efi_hardprobe (void);
-void    efi_diskprobe (void);
-void    efi_cons_init (struct consdev *);
-int     efi_cons_getc (dev_t);
-void    efi_cons_putc (dev_t, int);
+void    efi_cons_probe(struct consdev *);
+void    efi_memprobe(void);
+void    efi_hardprobe(void);
+void    efi_diskprobe(void);
+void    efi_cons_init(struct consdev *);
+int     efi_cons_getc(dev_t);
+void    efi_cons_putc(dev_t, int);
 int     efi_cons_getshifts(dev_t dev);
+void    efi_com_probe(struct consdev *);
+void    efi_com_init(struct consdev *);
+int     efi_com_getc(dev_t);
+void    efi_com_putc(dev_t, int);
 int     Xvideo_efi(void);
 int     Xexit_efi(void);
 void    efi_makebootargs(void);
diff --git a/sys/arch/amd64/stand/libsa/dev_i386.c 
b/sys/arch/amd64/stand/libsa/dev_i386.c
index ee1a11ca6b0..a2b55ec556d 100644
--- a/sys/arch/amd64/stand/libsa/dev_i386.c
+++ b/sys/arch/amd64/stand/libsa/dev_i386.c
@@ -182,10 +182,8 @@ ttydev(char *name)
 int
 cnspeed(dev_t dev, int sp)
 {
-#ifndef EFIBOOT
        if (major(dev) == 8)    /* comN */
                return comspeed(dev, sp);
-#endif
 
        /* pc0 and anything else */
        return 9600;

Reply via email to