Author: imp
Date: Mon Feb  8 19:34:17 2016
New Revision: 295408
URL: https://svnweb.freebsd.org/changeset/base/295408

Log:
  Implement -P for boot loader. It's a bit easier to implement here than
  in boot1, like is normally done. When a keyboard appears in the UEFI
  device tree, assume -D -h, just like on a BIOS boot.
  
  # It is unclear if an ACPI keyboard appearing in the tree means there's
  # a real keyboard or not. A USB keyboard doesn't seem to appear unless
  # it is really there.
  
  Differential Revision: https://reviews.freebsd.org/D5223

Modified:
  head/sys/boot/efi/loader/main.c

Modified: head/sys/boot/efi/loader/main.c
==============================================================================
--- head/sys/boot/efi/loader/main.c     Mon Feb  8 19:24:13 2016        
(r295407)
+++ head/sys/boot/efi/loader/main.c     Mon Feb  8 19:34:17 2016        
(r295408)
@@ -66,6 +66,7 @@ EFI_GUID hoblist = HOB_LIST_TABLE_GUID;
 EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID;
 EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID;
 EFI_GUID fdtdtb = FDT_TABLE_GUID;
+EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL;
 
 #ifdef EFI_ZFS_BOOT
 static void efi_zfs_probe(void);
@@ -94,6 +95,88 @@ cp16to8(const CHAR16 *src, char *dst, si
                dst[i] = (char)src[i];
 }
 
+static int
+has_keyboard(void)
+{
+       EFI_STATUS status;
+       EFI_DEVICE_PATH *path;
+       EFI_HANDLE *hin, *hin_end, *walker;
+       UINTN sz;
+       int retval = 0;
+       
+       /*
+        * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and
+        * do the typical dance to get the right sized buffer.
+        */
+       sz = 0;
+       hin = NULL;
+       status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0);
+       if (status == EFI_BUFFER_TOO_SMALL) {
+               hin = (EFI_HANDLE *)malloc(sz);
+               status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz,
+                   hin);
+               if (EFI_ERROR(status))
+                       free(hin);
+       }
+       if (EFI_ERROR(status))
+               return retval;
+
+       /*
+        * Look at each of the handles. If it supports the device path protocol,
+        * use it to get the device path for this handle. Then see if that
+        * device path matches either the USB device path for keyboards or the
+        * legacy device path for keyboards.
+        */
+       hin_end = &hin[sz / sizeof(*hin)];
+       for (walker = hin; walker < hin_end; walker++) {
+               status = BS->HandleProtocol(*walker, &devid, (VOID **)&path);
+               if (EFI_ERROR(status))
+                       continue;
+
+               while (!IsDevicePathEnd(path)) {
+                       /*
+                        * Check for the ACPI keyboard node. All PNP3xx nodes
+                        * are keyboards of different flavors. Note: It is
+                        * unclear of there's always a keyboard node when
+                        * there's a keyboard controller, or if there's only one
+                        * when a keyboard is detected at boot.
+                        */
+                       if (DevicePathType(path) == ACPI_DEVICE_PATH &&
+                           (DevicePathSubType(path) == ACPI_DP ||
+                               DevicePathSubType(path) == ACPI_EXTENDED_DP)) {
+                               ACPI_HID_DEVICE_PATH  *acpi;
+
+                               acpi = (ACPI_HID_DEVICE_PATH *)(void *)path;
+                               if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 
0x300 &&
+                                   (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) {
+                                       retval = 1;
+                                       goto out;
+                               }
+                       /*
+                        * Check for USB keyboard node, if present. Unlike a
+                        * PS/2 keyboard, these definitely only appear when
+                        * connected to the system.
+                        */
+                       } else if (DevicePathType(path) == 
MESSAGING_DEVICE_PATH &&
+                           DevicePathSubType(path) == MSG_USB_CLASS_DP) {
+                               USB_CLASS_DEVICE_PATH *usb;
+                              
+                               usb = (USB_CLASS_DEVICE_PATH *)(void *)path;
+                               if (usb->DeviceClass == 3 && /* HID */
+                                   usb->DeviceSubClass == 1 && /* Boot devices 
*/
+                                   usb->DeviceProtocol == 1) { /* Boot 
keyboards */
+                                       retval = 1;
+                                       goto out;
+                               }
+                       }
+                       path = NextDevicePathNode(path);
+               }
+       }
+out:
+       free(hin);
+       return retval;
+}
+
 EFI_STATUS
 main(int argc, CHAR16 *argv[])
 {
@@ -104,6 +187,7 @@ main(int argc, CHAR16 *argv[])
        struct devsw *dev;
        uint64_t pool_guid;
        UINTN k;
+       int has_kbd;
 
        archsw.arch_autoload = efi_autoload;
        archsw.arch_getdev = efi_getdev;
@@ -115,6 +199,8 @@ main(int argc, CHAR16 *argv[])
        archsw.arch_zfs_probe = efi_zfs_probe;
 #endif
 
+       has_kbd = has_keyboard();
+
        /*
         * XXX Chicken-and-egg problem; we want to have console output
         * early, but some console attributes may depend on reading from
@@ -150,15 +236,19 @@ main(int argc, CHAR16 *argv[])
                                case 'D':
                                        howto |= RB_MULTIPLE;
                                        break;
-                               case 'm':
-                                       howto |= RB_MUTE;
-                                       break;
                                case 'h':
                                        howto |= RB_SERIAL;
                                        break;
+                               case 'm':
+                                       howto |= RB_MUTE;
+                                       break;
                                case 'p':
                                        howto |= RB_PAUSE;
                                        break;
+                               case 'P':
+                                       if (!has_kbd)
+                                               howto |= RB_SERIAL | 
RB_MULTIPLE;
+                                       break;
                                case 'r':
                                        howto |= RB_DFLTROOT;
                                        break;
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to