diff --git a/libexec/rc/rc.conf b/libexec/rc/rc.conf index af7b6ff6302e..706806b90b63 100644 --- a/libexec/rc/rc.conf +++ b/libexec/rc/rc.conf @@ -71,6 +71,10 @@ local_startup="${_localbase}/etc/rc.d" # startup script dirs. script_name_sep=" " # Change if your startup scripts' names contain spaces rc_conf_files="/etc/rc.conf /etc/rc.conf.local" +# List of UEFI and kenv(1) variables to synchronize. +uefivars_variables='LoaderRotate' # Space separated list of names of variables +uefivars_kenv_LoaderRotate='screen.rotate' # List kenv(1) keys, one per UEFI variable + # ZFS support zfs_enable="NO" # Set to YES to automatically mount ZFS file systems zfskeys_enable="NO" # Set YES to autoload ZFS encryption keys @@ -719,8 +723,12 @@ devfs_set_rulesets="" # A list of /mount/dev=ruleset_name settings to devfs_load_rulesets="YES" # Enable to always load the default rulesets performance_cx_lowest="NONE" # Online CPU idle state performance_cpu_freq="NONE" # Online CPU frequency +performance_tz0_active="NONE" # Online forced active cooling zone +performance_tz0_PSV="NONE" # Online passive cooling threshold economy_cx_lowest="Cmax" # Offline CPU idle state economy_cpu_freq="NONE" # Offline CPU frequency +economy_tz0_active="NONE" # Offline forced active cooling zone +economy_tz0_PSV="NONE" # Offline passive cooling threshold virecover_enable="YES" # Perform housekeeping for the vi(1) editor ugidfw_enable="NO" # Load mac_bsdextended(4) rules on boot bsdextended_script="/etc/rc.bsdextended" # Default mac_bsdextended(4) diff --git a/libexec/rc/rc.d/Makefile b/libexec/rc/rc.d/Makefile index 40a1a212ca3a..a9e8067fc691 100644 --- a/libexec/rc/rc.d/Makefile +++ b/libexec/rc/rc.d/Makefile @@ -202,6 +202,10 @@ BSNMPPACKAGE= bsnmp CONFS+= ccd .endif +.if ${MK_EFI} != "no" +CONFS+= uefivars +.endif + .if ${MK_FTP} != "no" CONFS+= ftpd .endif diff --git a/libexec/rc/rc.d/power_profile b/libexec/rc/rc.d/power_profile index b7de08063437..9061f5f29b46 100755 --- a/libexec/rc/rc.d/power_profile +++ b/libexec/rc/rc.d/power_profile @@ -80,6 +80,14 @@ case ${state} in esac # Set the various sysctls based on the profile's values. +node="hw.acpi.thermal.tz0._PSV" +eval value=\$${profile}_tz0_PSV +sysctl_set + +node="hw.acpi.thermal.tz0.active" +eval value=\$${profile}_tz0_active +sysctl_set + node="hw.acpi.cpu.cx_lowest" highest_value="C1" lowest_value="Cmax" diff --git a/libexec/rc/rc.d/uefivars b/libexec/rc/rc.d/uefivars new file mode 100755 index 000000000000..18d20cec7aa1 --- /dev/null +++ b/libexec/rc/rc.d/uefivars @@ -0,0 +1,71 @@ +#!/bin/sh +# +# Copyright (c) 2003 The FreeBSD Project. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +# PROVIDE: uefivars +# REQUIRE: kld +# KEYWORD: shutdown + +. /etc/rc.subr + +name="uefivars" +desc="Synchronize UEFI with kenv(1) variables" +start_cmd="uefivars_start" +stop_cmd="uefivars_start" + +efivar="/usr/sbin/efivar -q" +freebsd_guid='cfee69ad-a0de-47a9-93a8-f63106f8ae99' +iconv="/usr/bin/iconv -t UCS-2-INTERNAL" +kenv="/bin/kenv -q" + +uefivars_start() +{ + local var kenv_key kenv_value UEFI_value + for var in $uefivars_variables + do + eval kenv_key=\$uefivars_kenv_$var + kenv_value=`$kenv $kenv_key` + if [ -z "$kenv_value" ] + then + debug "DELETE LoaderRotate" + # Delete UEFI variables without corresponding kenv(1) key. + $efivar -D ${freebsd_guid}-${var} + else + # Update UEFI variables that differ from $kenv_value. + UEFI_value=`$efivar -p -N -u ${freebsd_guid}-${var}` + if [ "$kenv_value" != "$UEFI_value" ] + then + debug "UPDATE LoaderRotate $config_value" + echo -n $kenv_value | $iconv | \ + $efivar -w ${freebsd_guid}-${var} + fi + fi + done +} + +load_rc_config $name +run_rc_command "$1" diff --git a/share/man/man4/acpi_thermal.4 b/share/man/man4/acpi_thermal.4 index d1cf8ee60ef2..05aeba12b6db 100644 --- a/share/man/man4/acpi_thermal.4 +++ b/share/man/man4/acpi_thermal.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 17, 2007 +.Dd July 31, 2022 .Dt ACPI_THERMAL 4 .Os .Sh NAME @@ -84,6 +84,9 @@ Current temperature for this zone. .It Va hw.acpi.thermal.tz%d._PSV Temperature to start passive cooling by throttling down CPU, etc. This value can be overridden by the user. +.It Va hw.acpi.thermal.tz%d._CR3 +Temperature to start critical suspend to RAM (S3). +This value can be overridden by the user. .It Va hw.acpi.thermal.tz%d._HOT Temperature to start critical suspend to disk (S4). This value can be overridden by the user. diff --git a/share/man/man4/usb_quirk.4 b/share/man/man4/usb_quirk.4 index 892c85aa6fba..9f21b6563a0c 100644 --- a/share/man/man4/usb_quirk.4 +++ b/share/man/man4/usb_quirk.4 @@ -76,6 +76,8 @@ device should be ignored by ums class does not identify properly .It UQ_MS_LEADING_BYTE mouse sends an unknown leading byte +.It UQ_MS_NO_SETPROTO +device should not receive "SetProtocol" requests .It UQ_MS_REVZ mouse has Z-axis reversed .It UQ_MS_VENDOR_BTN diff --git a/share/man/man4/vt.4 b/share/man/man4/vt.4 index 3d930ab4f710..6759164fe54a 100644 --- a/share/man/man4/vt.4 +++ b/share/man/man4/vt.4 @@ -358,6 +358,24 @@ To set black and white colors of console palette .Pp .Dl kern.vt.color.0.rgb="10,10,10" .Dl kern.vt.color.15.rgb="#f0f0f0" +.Pp +The mode option +.Sy rotate +is also supported, with values 0, 90, 180, and 270 representing the degrees +counterclockwise to rotate the display. Follow an optional connector name +and mode with a comma and the mode option. For example, +to set the default rotation for all output connectors 90 degrees clockwise: +.Pp +.Dl kern.vt.fb.default_mode=",rotate=270" +.Pp +This option is only supported by +.Cm vt_fb +when it is paired with a KMS video driver, and in most cases the +.Pp +.Dl screen.rotate=90 +.Pp +.Xr loader.conf 5 +setting, which will work with and without KMS, is more appropriate. .Sh SEE ALSO .Xr kbdcontrol 1 , .Xr login 1 , diff --git a/stand/common/gfx_fb.c b/stand/common/gfx_fb.c index 3e163de265ed..f8c1b11f0e29 100644 --- a/stand/common/gfx_fb.c +++ b/stand/common/gfx_fb.c @@ -773,6 +773,282 @@ gfxfb_shadow_fill(uint32_t *BltBuffer, } } +#if defined(EFI) +/* + * Rotate a UEFI Blt buffer of pixels by the specified angle (0,90,180,270) clockwise. + * Returns NULL if no rotation is performed, or a pointer to a static buffer + * containing the rotated data. + * We build the rotated buffer with Delta = 0 since there's no way to know what + * it should be if the rotation is 90 or 270 degrees. + */ +static EFI_GRAPHICS_OUTPUT_BLT_PIXEL * +RotateBuffer(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *inbuf, + UINTN angle, UINTN SourceX, UINTN SourceY, + UINTN Width, UINTN Height, + UINTN Delta) +{ + EFI_GRAPHICS_OUTPUT *gop = gfx_state.tg_private; + UINTN srcWidth, destOffset, srcOffset; + static EFI_GRAPHICS_OUTPUT_BLT_PIXEL *outbuf = NULL; + + if (angle != 90 && angle != 180 && angle != 270) + return NULL; + + if (outbuf == NULL && + (outbuf = malloc(gop->Mode->Info->VerticalResolution * + gop->Mode->Info->HorizontalResolution * + sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) == NULL) + return NULL; + + srcWidth = Width; + if (Delta != 0) + srcWidth = Delta; + + /* Check for out-of-bounds access. */ + if (srcWidth < SourceX + Width || + srcWidth > gop->Mode->Info->HorizontalResolution || + SourceX + Width > gop->Mode->Info->HorizontalResolution || + SourceY + Height > gop->Mode->Info->VerticalResolution) + return NULL; + + for (UINTN y = 0; y < Height; y++) { + for (UINTN x = 0; x < Width; x++) { + srcOffset = (SourceX + x) + (SourceY + y) * srcWidth; + switch ((int)angle) { + case 0: /* For reference */ + destOffset = (SourceX + x) + (SourceY + y) * Width; + break; + case 90: + destOffset = (SourceY + ((Height - 1) - y)) + + (SourceX + x) * Height; + break; + case 180: + destOffset = (SourceX + ((Width - 1) - x)) + + (SourceY + ((Height - 1) - y)) * Width; + break; + case 270: + destOffset = (SourceY + y) + + (SourceX + ((Width - 1) - x)) * Height; + break; + } + outbuf[destOffset] = inbuf[srcOffset]; + } + } + return (outbuf); +} + +/* Macros to facilitate rotation. */ +#define SWITCH_VALIDATE +#ifdef SWITCH_VALIDATE +#define SWITCH(DIR, AXIS, ORIENT, EXTENT) \ + if (Panel##DIR##AXIS + Rotated##EXTENT > \ + gop->Mode->Info->ORIENT##Resolution - 1) \ + Panel##DIR##AXIS = 0; \ + else \ + Panel##DIR##AXIS = (gop->Mode->Info->ORIENT##Resolution - 1) - \ + (Panel##DIR##AXIS + Rotated##EXTENT) +#define NO_SWITCH(DIR, AXIS, ORIENTATION) \ + if (Panel##DIR##AXIS > gop->Mode->Info->ORIENTATION##Resolution - 1) \ + Panel##DIR##AXIS = gop->Mode->Info->ORIENTATION##Resolution - 1 +#else +#define SWITCH(DIR, AXIS, ORIENT, EXTENT) \ + Panel##DIR##AXIS = (gop->Mode->Info->ORIENT##Resolution - 1) - \ + (Panel##DIR##AXIS + Rotated##EXTENT) +#define NO_SWITCH(DIR, AXIS, ORIENTATION) +#endif +#define SWITCH_SRC_X SWITCH(Src, X, Horizontal, Width) +#define SWITCH_DST_X SWITCH(Dst, X, Horizontal, Width) +#define SWITCH_SRC_Y SWITCH(Src, Y, Vertical, Height) +#define SWITCH_DST_Y SWITCH(Dst, Y, Vertical, Height) +#define NO_SWITCH_SRC_X NO_SWITCH(Src, X, Horizontal) +#define NO_SWITCH_DST_X NO_SWITCH(Dst, X, Horizontal) +#define NO_SWITCH_SRC_Y NO_SWITCH(Src, Y, Vertical) +#define NO_SWITCH_DST_Y NO_SWITCH(Dst, Y, Vertical) + +/* + * Perhaps better implemented as a separate UEFI gop layer (c.f. + * https://github.com/apop2/GopRotate), this rotation layer resides in the + * loader itself, above the UEFI, and will rotate gop->Blt() requests by the + * specified angle. It is more complex than a simple rotation because the + * gop->Blt interface is complex; using the gop direct bitmap interface would be + * simpler but would require more changes to the loader graphics code. + */ +EFI_STATUS +BltRot(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, + EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + UINTN SourceX, UINTN SourceY, + UINTN DestinationX, UINTN DestinationY, + UINTN Width, UINTN Height, + UINTN Delta) +{ + EFI_STATUS status; + EFI_GRAPHICS_OUTPUT *gop = gfx_state.tg_private; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *PanelBuffer, *unrotatedBuffer; + static EFI_GRAPHICS_OUTPUT_BLT_PIXEL *transformBuffer = NULL; + UINTN PanelSrcX, PanelSrcY, PanelDstX, PanelDstY, RotatedWidth, RotatedHeight; + UINTN destWidth; + + /* + * Translate logical: + * BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height + * to physical: + * PanelBuffer, PanelSrcX, PanelSrcY, PanelDstX, PanelDstY, RotatedWidth, + * RotatedHeight + * corresponding to the display hardware. + * + * Typically DestinationX = 0, DestinationY= 0 will correspond to the upper left + * pixel of the display in its mounted orientation, whereas PanelDstX = 0, + * PanelDstY = 0 will correspond to the hardware panel 0,0 coordinate. + */ + PanelSrcX = SourceX, PanelSrcY = SourceY; + PanelDstX = DestinationX, PanelDstY = DestinationY; + RotatedWidth = Width, RotatedHeight = Height; + PanelBuffer = BltBuffer; + + switch (BltOperation) { + /* + * Not only do we need to rotate the coordinates, we also need to rotate + * the origin of the BltBuffer transfer box (which itself must be + * rotated). + */ + case EfiBltBufferToVideo: + if (rotation == 0 || + (PanelBuffer = RotateBuffer(BltBuffer, rotation, SourceX, SourceY, + Width, Height, Delta)) == NULL) { + PanelBuffer = BltBuffer; + break; + } + Delta = 0; /* PanelBuffer is built with no delta */ + /* Fallthrough */ + + /* Rotate the coordinates to the panel coordinates. */ + case EfiBltVideoFill: + if (rotation == 90 || rotation == 270) { + PanelDstX = DestinationY, PanelDstY = DestinationX; + RotatedWidth = Height, RotatedHeight = Width; + } + switch (rotation) { + case 0: + break; + case 90: + SWITCH_DST_X; + NO_SWITCH_DST_Y; + break; + case 180: + SWITCH_DST_X; + SWITCH_DST_Y; + break; + case 270: + NO_SWITCH_DST_X; + SWITCH_DST_Y; + break; + } + break; + + /* Rotate the coordinates to and from the panel coordinates. */ + case EfiBltVideoToVideo: + if (rotation == 90 || rotation == 270) { + PanelSrcX = SourceY, PanelSrcY = SourceX; + PanelDstX = DestinationY, PanelDstY = DestinationX; + RotatedWidth = Height, RotatedHeight = Width; + } + switch (rotation) { + case 90: + SWITCH_SRC_X; + SWITCH_DST_X; + NO_SWITCH_SRC_Y; + NO_SWITCH_DST_Y; + break; + case 180: + SWITCH_SRC_X; + SWITCH_DST_X; + SWITCH_SRC_Y; + SWITCH_DST_Y; + break; + case 270: + NO_SWITCH_SRC_X; + NO_SWITCH_DST_X; + SWITCH_SRC_Y; + SWITCH_DST_Y; + break; + } + break; + + /* Rotate the coordinates from the panel coordinates. */ + case EfiBltVideoToBltBuffer: + if (rotation == 0 || + (transformBuffer == NULL && + (transformBuffer = malloc(gop->Mode->Info->HorizontalResolution * + gop->Mode->Info->VerticalResolution * + sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) == NULL)) + break; + + PanelBuffer = transformBuffer; + if (rotation == 90 || rotation == 270) { + PanelSrcX = SourceY, PanelSrcY = SourceX; + RotatedWidth = Height, RotatedHeight = Width; + } + switch (rotation) { + case 90: + SWITCH_SRC_X; + NO_SWITCH_SRC_Y; + break; + case 180: + SWITCH_SRC_X; + SWITCH_SRC_Y; + break; + case 270: + NO_SWITCH_SRC_X; + SWITCH_SRC_Y; + break; + } + break; + } + + status = gop->Blt(gop, PanelBuffer, BltOperation, + PanelSrcX, PanelSrcY, PanelDstX, PanelDstY, + RotatedWidth, RotatedHeight, Delta); + if (EFI_ERROR(status)) + return (status); + + /* Unless we need to unrotate and merge data into BltBuffer, we are done. */ + if (BltOperation != EfiBltVideoToBltBuffer || PanelBuffer == BltBuffer) + return (status); + + /* + * Until this point, on rotation failure we simply pass the data + * unrotated. From here on, we return an error (which will likely cause + * loader failure). + */ + unrotatedBuffer = RotateBuffer(PanelBuffer, 360 - rotation, + DestinationX, DestinationY, Width, Height, Delta); + if (unrotatedBuffer == NULL) + return (EFI_OUT_OF_RESOURCES); + + /* + * It is not obvious what the correct reconstruction of a non-zero delta + * should be. This is likely to work correctly. + */ + destWidth = Width; + if (Delta != 0) + destWidth = Delta; + + /* Check for out-of-bounds access. */ + if (destWidth < DestinationX + Width || + destWidth > gop->Mode->Info->HorizontalResolution || + DestinationX + Width > gop->Mode->Info->HorizontalResolution || + DestinationY + Height > gop->Mode->Info->VerticalResolution) + return (EFI_INVALID_PARAMETER); + + for (UINTN y = DestinationY; y < DestinationY + Height; y++) { + for (UINTN x = DestinationX; x < DestinationX + Width; x++) { + BltBuffer[x + y * destWidth] = unrotatedBuffer[x + y * Width]; + } + } + return (status); +} +#endif + int gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation, uint32_t SourceX, uint32_t SourceY, @@ -796,28 +1072,26 @@ gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation, tpl = BS->RaiseTPL(TPL_NOTIFY); switch (BltOperation) { case GfxFbBltVideoFill: - gfxfb_shadow_fill(BltBuffer, DestinationX, - DestinationY, Width, Height); - status = gop->Blt(gop, BltBuffer, EfiBltVideoFill, + status = BltRot(BltBuffer, EfiBltVideoFill, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta); break; case GfxFbBltVideoToBltBuffer: - status = gop->Blt(gop, BltBuffer, + status = BltRot(BltBuffer, EfiBltVideoToBltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta); break; case GfxFbBltBufferToVideo: - status = gop->Blt(gop, BltBuffer, EfiBltBufferToVideo, + status = BltRot(BltBuffer, EfiBltBufferToVideo, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta); break; case GfxFbBltVideoToVideo: - status = gop->Blt(gop, BltBuffer, EfiBltVideoToVideo, + status = BltRot(BltBuffer, EfiBltVideoToVideo, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta); break; diff --git a/stand/common/gfx_fb.h b/stand/common/gfx_fb.h index f5747e065daf..fb5a4c588515 100644 --- a/stand/common/gfx_fb.h +++ b/stand/common/gfx_fb.h @@ -259,6 +259,9 @@ struct text_pixel { extern const int cons_to_vga_colors[NCOLORS]; +/* Set by freebsd-LoaderRotate UEFI variable, determines rotation of framebuffer. */ +extern uint32_t rotation; + /* Screen buffer to track changes on the terminal screen. */ extern struct text_pixel *screen_buffer; bool is_same_pixel(struct text_pixel *, struct text_pixel *); diff --git a/stand/defaults/loader.conf.5 b/stand/defaults/loader.conf.5 index 23a65935c95a..47c21f99a917 100644 --- a/stand/defaults/loader.conf.5 +++ b/stand/defaults/loader.conf.5 @@ -23,7 +23,7 @@ .\" SUCH DAMAGE. .\" .\" $FreeBSD$ -.Dd July 31, 2021 +.Dd August 3, 2022 .Dt LOADER.CONF 5 .Os .Sh NAME @@ -308,6 +308,16 @@ If EDID is not available, the default resolution is 800x600 (if available). .Va screen.width , .Va screen.depth are set by loader when loader is using framebuffer mode to draw the screen. +.It Va screen.rotate +Sets the rotation of the framebuffer console to 0, 90, 180, or 270 degrees clockwise. +If KMS is present, the rotation may be performed in hardware, +and an additional value, "AUTO", is supported which will often detect the +correct rotation. +.Pp +This option will also rotate the screen of the EFI boot loader; because the rotation +setting for the EFI loader is stored in the EFI itself during shutdown based upon the +value present in the current kernel environment, +it will take a second reboot to pass a change to the loader. .It Va efi_max_resolution .It Va vbe_max_resolution Specify the maximum desired resolution for the EFI or VBE framebuffer console. diff --git a/stand/efi/libefi/env.c b/stand/efi/libefi/env.c index 77e232343040..97fc3b70ef81 100644 --- a/stand/efi/libefi/env.c +++ b/stand/efi/libefi/env.c @@ -469,7 +469,7 @@ efi_print_mem_type(const CHAR16 *varnamearg __unused, uint8_t *data, /* * Print FreeBSD variables. - * We have LoaderPath and LoaderDev as CHAR16 strings. + * We have LoaderRotate, LoaderPath and LoaderDev as CHAR16 strings. */ static int efi_print_freebsd(const CHAR16 *varnamearg, uint8_t *data, @@ -481,7 +481,8 @@ efi_print_freebsd(const CHAR16 *varnamearg, uint8_t *data, if (ucs2_to_utf8(varnamearg, &var) != 0) return (CMD_ERROR); - if (strcmp("LoaderPath", var) == 0 || + if (strcmp("LoaderRotate", var) == 0 || + strcmp("LoaderPath", var) == 0 || strcmp("LoaderDev", var) == 0) { printf(" = "); printf("%S", (CHAR16 *)data); diff --git a/stand/efi/loader/bootinfo.c b/stand/efi/loader/bootinfo.c index a6b722b947e9..df5dd4727bb5 100644 --- a/stand/efi/loader/bootinfo.c +++ b/stand/efi/loader/bootinfo.c @@ -186,8 +186,17 @@ bi_load_efi_data(struct preloaded_file *kfp, bool exit_bs) efifb.fb_addr = gfx_state.tg_fb.fb_addr; efifb.fb_size = gfx_state.tg_fb.fb_size; - efifb.fb_height = gfx_state.tg_fb.fb_height; - efifb.fb_width = gfx_state.tg_fb.fb_width; + /* + * If we have rotated the framebuffer height and width, rotate them back + * before passing them to the kernel + */ + if (rotation == 90 || rotation == 270) { + efifb.fb_height = gfx_state.tg_fb.fb_width; + efifb.fb_width = gfx_state.tg_fb.fb_height; + } else { + efifb.fb_height = gfx_state.tg_fb.fb_height; + efifb.fb_width = gfx_state.tg_fb.fb_width; + } efifb.fb_stride = gfx_state.tg_fb.fb_stride; efifb.fb_mask_red = gfx_state.tg_fb.fb_mask_red; efifb.fb_mask_green = gfx_state.tg_fb.fb_mask_green; @@ -329,6 +338,7 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp, bool exit_bs) vm_offset_t size; char *rootdevname; int howto; + char *autorotate, strbuf[4]; bool is64 = sizeof(long) == 8; #if defined(LOADER_FDT_SUPPORT) vm_offset_t dtbp; @@ -351,6 +361,17 @@ bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp, bool exit_bs) #endif howto = bi_getboothowto(args); + /* + * If screen.rotate="AUTO", pass the current rotation to the kernel to + * use until the autodetection completes. + */ + if (rotation != 0 && + (autorotate = getenv("screen.rotate")) != NULL && + strncasecmp(autorotate, "auto", 5) == 0) { + snprintf(strbuf, sizeof(strbuf), "%d", rotation); + setenv("screen.autorotate", strbuf, 1); + } + /* * Allow the environment variable 'rootdev' to override the supplied * device. This should perhaps go to MI code and/or have $rootdev diff --git a/stand/efi/loader/framebuffer.c b/stand/efi/loader/framebuffer.c index 9dfe547d7557..fafbc374eab7 100644 --- a/stand/efi/loader/framebuffer.c +++ b/stand/efi/loader/framebuffer.c @@ -42,7 +42,9 @@ __FBSDID("$FreeBSD$"); #include #include "bootstrap.h" +#include "efichar.h" #include "framebuffer.h" +#include "gfx_fb.h" static EFI_GUID conout_guid = EFI_CONSOLE_OUT_DEVICE_GUID; EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; @@ -55,6 +57,9 @@ static EFI_HANDLE gop_handle; /* Cached EDID. */ struct vesa_edid_info *edid_info = NULL; +/* Angle to rotate boot console display. */ +uint32_t rotation = 0; + static EFI_GRAPHICS_OUTPUT *gop; static EFI_UGA_DRAW_PROTOCOL *uga; @@ -146,11 +151,42 @@ efifb_from_gop(struct efi_fb *efifb, EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode, EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info) { int result; + size_t len = 0; + efi_char *buf; + char *angle = NULL; + EFI_STATUS rv; + + /* + * Use the UEFI variable freebsd-LoaderRotate to rotate the framebuffer + * to match the panel orientation. We use a UEFI variable because + * the framebuffer is set up very early in the boot process, before + * loader variables (even the early /boot/efi/EFI/FreeBSD/loader.env + * variables) are set up. + * + * It is intended that an rc.d script shall use the screen.rotate loader + * variable to update freebsd-LoaderRotate for the next boot. + */ + if (efi_freebsd_getenv("LoaderRotate", NULL, &len) == EFI_BUFFER_TOO_SMALL) + if ((buf = calloc(len + 1, sizeof(efi_char)))) { + if (efi_freebsd_getenv("LoaderRotate", buf, &len) == EFI_SUCCESS) + if (ucs2_to_utf8(buf, &angle) == 0) { + rotation = strtol(angle, NULL, 0); + free(angle); + } + free(buf); + } + if (rotation != 90 && rotation != 180 && rotation != 270) + rotation = 0; efifb->fb_addr = mode->FrameBufferBase; efifb->fb_size = mode->FrameBufferSize; - efifb->fb_height = info->VerticalResolution; - efifb->fb_width = info->HorizontalResolution; + if (rotation == 90 || rotation == 270) { + efifb->fb_width = info->VerticalResolution; + efifb->fb_height = info->HorizontalResolution; + } else { + efifb->fb_height = info->VerticalResolution; + efifb->fb_width = info->HorizontalResolution; + } efifb->fb_stride = info->PixelsPerScanLine; result = efifb_mask_from_pixfmt(efifb, info->PixelFormat, &info->PixelInformation); diff --git a/stand/lua/config.lua b/stand/lua/config.lua index 9ef7c0796f46..7fff5c2ba38a 100644 --- a/stand/lua/config.lua +++ b/stand/lua/config.lua @@ -63,7 +63,7 @@ local MSG_FAILSYN_EOLVAR = "Unescaped $ at end of line" local MSG_FAILSYN_BADVAR = "Malformed variable expression at position '%d'" local MODULEEXPR = '([-%w_]+)' -local QVALEXPR = '"(.*)"' +local QVALEXPR = '"([^"]*)"' local QVALREPL = QVALEXPR:gsub('%%', '%%%%') local WORDEXPR = "([-%w%d][-%w%d_.]*)" local WORDREPL = WORDEXPR:gsub('%%', '%%%%') diff --git a/stand/lua/menu.lua b/stand/lua/menu.lua index 400dbf3d469b..4a326cb54bb9 100644 --- a/stand/lua/menu.lua +++ b/stand/lua/menu.lua @@ -58,6 +58,9 @@ local function bootenvSet(env) loader.setenv("vfs.root.mountfrom", env) loader.setenv("currdev", env .. ":") config.reload() + if loader.getenv("kernelname") ~= nil then + loader.perform("unload") + end end local function multiUserPrompt() diff --git a/stand/lua/password.lua b/stand/lua/password.lua index 8edd4edd7ec3..3aea8e80bae6 100644 --- a/stand/lua/password.lua +++ b/stand/lua/password.lua @@ -135,6 +135,7 @@ function password.check() local pwd = loader.getenv("password") if pwd ~= nil then core.autoboot() + loader.setenv("autoboot_delay", "NO") -- The autoboot sequence was interrupted, so we'll need to -- prompt for a password. Put the screen back into a known -- good state, otherwise we're drawing back a couple lines diff --git a/sys/dev/acpica/acpi_thermal.c b/sys/dev/acpica/acpi_thermal.c index 9ff86ae8d827..8d3cfbedc7cb 100644 --- a/sys/dev/acpica/acpi_thermal.c +++ b/sys/dev/acpica/acpi_thermal.c @@ -60,7 +60,7 @@ ACPI_MODULE_NAME("THERMAL") #define TZ_NOTIFY_TEMPERATURE 0x80 /* Temperature changed. */ #define TZ_NOTIFY_LEVELS 0x81 /* Cooling levels changed. */ #define TZ_NOTIFY_DEVICES 0x82 /* Device lists changed. */ -#define TZ_NOTIFY_CRITICAL 0xcc /* Fake notify that _CRT/_HOT reached. */ +#define TZ_NOTIFY_CRITICAL 0xcc /* Fake notify that _CRT/_HOT/_CR3 reached. */ /* Check for temperature changes every 10 seconds by default */ #define TZ_POLLRATE 10 @@ -78,6 +78,7 @@ struct acpi_tz_zone { ACPI_BUFFER al[TZ_NUMLEVELS]; int crt; int hot; + int cr3; ACPI_BUFFER psl; int psv; int tc1; @@ -97,8 +98,9 @@ struct acpi_tz_softc { int tz_thflags; /*Current temp-related flags*/ #define TZ_THFLAG_NONE 0 #define TZ_THFLAG_PSV (1<<0) -#define TZ_THFLAG_HOT (1<<2) -#define TZ_THFLAG_CRT (1<<3) +#define TZ_THFLAG_CR3 (1<<2) +#define TZ_THFLAG_HOT (1<<3) +#define TZ_THFLAG_CRT (1<<4) int tz_flags; #define TZ_FLAG_NO_SCP (1<<0) /*No _SCP method*/ #define TZ_FLAG_GETPROFILE (1<<1) /*Get power_profile in timeout*/ @@ -282,6 +284,10 @@ acpi_tz_attach(device_t dev) OID_AUTO, "_PSV", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, offsetof(struct acpi_tz_softc, tz_zone.psv), acpi_tz_temp_sysctl, "IK", "passive cooling temp setpoint"); + SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), + OID_AUTO, "_CR3", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, + offsetof(struct acpi_tz_softc, tz_zone.cr3), acpi_tz_temp_sysctl, "IK", + "too warm temp setpoint (standby now)"); SYSCTL_ADD_PROC(&sc->tz_sysctl_ctx, SYSCTL_CHILDREN(sc->tz_sysctl_tree), OID_AUTO, "_HOT", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, offsetof(struct acpi_tz_softc, tz_zone.hot), acpi_tz_temp_sysctl, "IK", @@ -421,6 +427,7 @@ acpi_tz_establish(struct acpi_tz_softc *sc) } acpi_tz_getparam(sc, "_CRT", &sc->tz_zone.crt); acpi_tz_getparam(sc, "_HOT", &sc->tz_zone.hot); + acpi_tz_getparam(sc, "_CR3", &sc->tz_zone.cr3); sc->tz_zone.psl.Length = ACPI_ALLOCATE_BUFFER; sc->tz_zone.psl.Pointer = NULL; AcpiEvaluateObject(sc->tz_handle, "_PSL", NULL, &sc->tz_zone.psl); @@ -438,6 +445,7 @@ acpi_tz_establish(struct acpi_tz_softc *sc) */ acpi_tz_sanity(sc, &sc->tz_zone.crt, "_CRT"); acpi_tz_sanity(sc, &sc->tz_zone.hot, "_HOT"); + acpi_tz_sanity(sc, &sc->tz_zone.cr3, "_CR3"); acpi_tz_sanity(sc, &sc->tz_zone.psv, "_PSV"); for (i = 0; i < TZ_NUMLEVELS; i++) acpi_tz_sanity(sc, &sc->tz_zone.ac[i], "_ACx"); @@ -495,6 +503,7 @@ acpi_tz_get_temperature(struct acpi_tz_softc *sc) static void acpi_tz_monitor(void *Context) { + struct acpi_softc *acpi_sc; struct acpi_tz_softc *sc; struct timespec curtime; int temp; @@ -545,6 +554,8 @@ acpi_tz_monitor(void *Context) newflags = TZ_THFLAG_NONE; if (sc->tz_zone.psv != -1 && temp >= sc->tz_zone.psv) newflags |= TZ_THFLAG_PSV; + if (sc->tz_zone.cr3 != -1 && temp >= sc->tz_zone.cr3) + newflags |= TZ_THFLAG_CR3; if (sc->tz_zone.hot != -1 && temp >= sc->tz_zone.hot) newflags |= TZ_THFLAG_HOT; if (sc->tz_zone.crt != -1 && temp >= sc->tz_zone.crt) @@ -595,7 +606,7 @@ acpi_tz_monitor(void *Context) /* XXX (de)activate any passive cooling that may be required. */ /* - * If the temperature is at _HOT or _CRT, increment our event count. + * If the temperature is at _CR3, _HOT or _CRT, increment our event count. * If it has occurred enough times, shutdown the system. This is * needed because some systems will report an invalid high temperature * for one poll cycle. It is suspected this is due to the embedded @@ -604,13 +615,18 @@ acpi_tz_monitor(void *Context) * * If we're almost at that threshold, notify the user through devd(8). */ - if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) { + if ((newflags & (TZ_THFLAG_CR3 | TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) { sc->tz_validchecks++; if (sc->tz_validchecks == TZ_VALIDCHECKS) { device_printf(sc->tz_dev, "WARNING - current temperature (%d.%dC) exceeds safe limits\n", TZ_KELVTOC(sc->tz_temperature)); - shutdown_nice(RB_POWEROFF); + if ((newflags & (TZ_THFLAG_HOT | TZ_THFLAG_CRT)) != 0) + shutdown_nice(RB_POWEROFF); + else { + acpi_sc = acpi_device_get_parent_softc(sc->tz_dev); + acpi_ReqSleepState(acpi_sc, ACPI_STATE_S3); + } } else if (sc->tz_validchecks == TZ_NOTIFYCOUNT) acpi_UserNotify("Thermal", sc->tz_handle, TZ_NOTIFY_CRITICAL); } else { @@ -1006,51 +1022,68 @@ acpi_tz_thread(void *arg) static int acpi_tz_cpufreq_restore(struct acpi_tz_softc *sc) { - device_t dev; - int error; + device_t *devs; + int devcount, error, n; if (!sc->tz_cooling_updated) return (0); - if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) + + if ((error = devclass_get_devices(devclass_find("cpufreq"), &devs, &devcount))) { + free(devs, M_TEMP); return (ENXIO); + } + ACPI_VPRINT(sc->tz_dev, acpi_device_get_parent_softc(sc->tz_dev), "temperature %d.%dC: resuming previous clock speed (%d MHz)\n", TZ_KELVTOC(sc->tz_temperature), sc->tz_cooling_saved_freq); - error = CPUFREQ_SET(dev, NULL, CPUFREQ_PRIO_KERN); + for (n = 0; n < devcount; n++) { + if ((error = CPUFREQ_SET(devs[n], NULL, CPUFREQ_PRIO_KERN))) { + /* + * If you find yourself here: cf_set_method() in kern_cpu.c + * requires CPUFREQ_GET() be run before CPUFREQ_SET(), otherwise on + * a restore sc->curr_level.total_set.freq = CPUFREQ_VAL_UNKNOWN, + * and then if it hasn't been updated the next save/restore will fail. + */ + device_printf(sc->tz_dev, "cpu%d: failed to restore cpufreq priority\n", n); + break; + } + } if (error == 0) sc->tz_cooling_updated = FALSE; + + free(devs, M_TEMP); return (error); } static int acpi_tz_cpufreq_update(struct acpi_tz_softc *sc, int req) { - device_t dev; + device_t *devs; struct cf_level *levels; - int num_levels, error, freq, desired_freq, perf, i; + int num_levels, error, freq, desired_freq, perf, devcount, i, n; levels = malloc(CPUFREQ_MAX_LEVELS * sizeof(*levels), M_TEMP, M_NOWAIT); if (levels == NULL) return (ENOMEM); /* - * Find the main device, cpufreq0. We don't yet support independent - * CPU frequency control on SMP. + * Find the main device, cpufreq0. We make plans based upon cpu0, and + * change all the cpu frequencies to the same level. */ - if ((dev = devclass_get_device(devclass_find("cpufreq"), 0)) == NULL) { - error = ENXIO; + if ((error = devclass_get_devices(devclass_find("cpufreq"), &devs, &devcount))) { + free(devs, M_TEMP); goto out; } - /* Get the current frequency. */ - error = CPUFREQ_GET(dev, &levels[0]); + /* Get the current frequency for cpu0. */ + error = CPUFREQ_GET(devs[0], &levels[0]); if (error) goto out; freq = levels[0].total_set.freq; - /* Get the current available frequency levels. */ + /* Get the current available frequency levels for cpu0. */ num_levels = CPUFREQ_MAX_LEVELS; - error = CPUFREQ_LEVELS(dev, levels, &num_levels); + error = CPUFREQ_LEVELS(devs[0], levels, &num_levels); if (error) { if (error == E2BIG) printf("cpufreq: need to increase CPUFREQ_MAX_LEVELS\n"); @@ -1111,8 +1144,22 @@ acpi_tz_cpufreq_update(struct acpi_tz_softc *sc, int req) TZ_KELVTOC(sc->tz_temperature), (freq > levels[i].total_set.freq) ? "de" : "in", freq, levels[i].total_set.freq); - error = CPUFREQ_SET(dev, &levels[i], CPUFREQ_PRIO_KERN); - if (error == 0 && !sc->tz_cooling_updated) { + + /* Change all the cpus to the chosen frequency. */ + for (n = 0; n < devcount; n++) { + /* CPUFREQ_SET() fails occasionally without this. */ + if ((error = CPUFREQ_GET(devs[n], &levels[0]))) + goto out; + + if ((error = CPUFREQ_LEVELS(devs[n], levels, &num_levels))) { + if (error == E2BIG) + printf("cpufreq: need to increase CPUFREQ_MAX_LEVELS\n"); + goto out; + } + if ((error = CPUFREQ_SET(devs[n], &levels[i], CPUFREQ_PRIO_KERN))) + goto out; + } + if (!sc->tz_cooling_updated) { sc->tz_cooling_saved_freq = freq; sc->tz_cooling_updated = TRUE; } @@ -1121,6 +1168,7 @@ acpi_tz_cpufreq_update(struct acpi_tz_softc *sc, int req) out: if (levels) free(levels, M_TEMP); + free(devs, M_TEMP); return (error); } diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c index ab42f0ea1283..f2e7e0a126a8 100644 --- a/sys/dev/usb/input/ukbd.c +++ b/sys/dev/usb/input/ukbd.c @@ -964,7 +964,8 @@ ukbd_probe(device_t dev) return (ENXIO); if (hid_is_keyboard(d_ptr, d_len)) { - if (hid_is_mouse(d_ptr, d_len)) { + if (hid_is_mouse(d_ptr, d_len) && + !usb_test_quirk(uaa, UQ_UMS_IGNORE)) { /* * NOTE: We currently don't support USB mouse * and USB keyboard on the same USB endpoint. diff --git a/sys/dev/usb/input/ums.c b/sys/dev/usb/input/ums.c index 5ddba1311762..220d4e6884f1 100644 --- a/sys/dev/usb/input/ums.c +++ b/sys/dev/usb/input/ums.c @@ -592,13 +592,15 @@ ums_attach(device_t dev) usb_callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0); /* - * Force the report (non-boot) protocol. + * Force the report (non-boot) protocol unless + * UQ_MS_NO_SETPROTO is set. * * Mice without boot protocol support may choose not to implement * Set_Protocol at all; Ignore any error. */ - err = usbd_req_set_protocol(uaa->device, NULL, - uaa->info.bIfaceIndex, 1); + if (!usb_test_quirk(uaa, UQ_MS_NO_SETPROTO)) + err = usbd_req_set_protocol(uaa->device, NULL, + uaa->info.bIfaceIndex, 1); err = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex, sc->sc_xfer, ums_config, diff --git a/sys/dev/usb/quirk/usb_quirk.c b/sys/dev/usb/quirk/usb_quirk.c index bb02b90ba4bd..973ec549607e 100644 --- a/sys/dev/usb/quirk/usb_quirk.c +++ b/sys/dev/usb/quirk/usb_quirk.c @@ -649,6 +649,7 @@ static const char *usb_quirk_str[USB_QUIRK_MAX] = { [UQ_UMS_IGNORE] = "UQ_UMS_IGNORE", [UQ_MS_BAD_CLASS] = "UQ_MS_BAD_CLASS", [UQ_MS_LEADING_BYTE] = "UQ_MS_LEADING_BYTE", + [UQ_MS_NO_SETPROTO] = "UQ_MS_NO_SETPROTO", [UQ_MS_REVZ] = "UQ_MS_REVZ", [UQ_MS_VENDOR_BTN] = "UQ_MS_VENDOR_BTN", [UQ_NO_STRINGS] = "UQ_NO_STRINGS", diff --git a/sys/dev/usb/quirk/usb_quirk.h b/sys/dev/usb/quirk/usb_quirk.h index 399c8d3f65b4..62c96bd147a7 100644 --- a/sys/dev/usb/quirk/usb_quirk.h +++ b/sys/dev/usb/quirk/usb_quirk.h @@ -54,6 +54,7 @@ enum { UQ_UMS_IGNORE, /* device should be ignored by ums class */ UQ_MS_BAD_CLASS, /* doesn't identify properly */ UQ_MS_LEADING_BYTE, /* mouse sends an unknown leading byte */ + UQ_MS_NO_SETPROTO, /* device should not receive SetProtocol requests */ UQ_MS_REVZ, /* mouse has Z-axis reversed */ UQ_MS_VENDOR_BTN, /* mouse has buttons in vendor usage page */ UQ_NO_STRINGS, /* string descriptors are broken */ diff --git a/sys/dev/vt/hw/fb/vt_fb.c b/sys/dev/vt/hw/fb/vt_fb.c index 2f6c4c3939d5..33e76f903b8c 100644 --- a/sys/dev/vt/hw/fb/vt_fb.c +++ b/sys/dev/vt/hw/fb/vt_fb.c @@ -162,11 +162,22 @@ vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) { struct fb_info *info; uint32_t c; - u_int o; + u_int o, row, col; info = vd->vd_softc; c = info->fb_cmap[color]; - o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); + + /* Rotations */ + if (info->fb_flags & FB_FLAG_ROTATE_90) + row = x, col = y; + else + row = y, col = x; + if (info->fb_flags & FB_FLAG_ROTATE_180) + row = (info->fb_height - 1) - row; + if (!(info->fb_flags & FB_FLAG_ROTATE_90) != + !(info->fb_flags & FB_FLAG_ROTATE_180)) + col = (info->fb_width - 1) - col; + o = info->fb_stride * row + col * FBTYPE_GET_BYTESPP(info); if (info->fb_flags & FB_FLAG_NOWRITE) return; @@ -266,7 +277,7 @@ vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) { struct fb_info *info; - uint32_t fgc, bgc, cc, o; + uint32_t fgc, bgc, cc, o, row, col; int bpp, bpl, xi, yi; int bit, byte; @@ -299,7 +310,18 @@ vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, /* Skip pixel write, if mask bit not set. */ if (mask != NULL && (mask[byte] & bit) == 0) continue; - o = (y + yi) * info->fb_stride + (x + xi) * bpp; + + /* Rotations */ + if (info->fb_flags & FB_FLAG_ROTATE_90) + row = x + xi, col = y + yi; + else + row = y + yi, col = x + xi; + if (info->fb_flags & FB_FLAG_ROTATE_180) + row = (info->fb_height - 1) - row; + if (!(info->fb_flags & FB_FLAG_ROTATE_90) != + !(info->fb_flags & FB_FLAG_ROTATE_180)) + col = (info->fb_width - 1) - col; + o = row * info->fb_stride + col * bpp; o += vd->vd_transpose; cc = pattern[byte] & bit ? fgc : bgc; @@ -459,15 +481,64 @@ vt_fb_init(struct vt_device *vd) { struct fb_info *info; u_int margin; - int bg, err; + int angle = 0, bg, err; term_color_t c; + char *rotation, strbuf[4]; info = vd->vd_softc; - vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height); - margin = (info->fb_height - vd->vd_height) >> 1; - vd->vd_transpose = margin * info->fb_stride; - vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width); - margin = (info->fb_width - vd->vd_width) >> 1; + + /* + * If we have been passed a rotation, and screen.rotate="AUTO", change + * screen.rotate to the autodetected rotation for use during the next + * reboot. + */ + if (info->fb_flags & FB_FLAG_ROTATE_NODEFAULT) { + if ((rotation = kern_getenv("screen.rotate")) != NULL && + strncasecmp(rotation, "auto", 5) == 0) { + if (info->fb_flags & FB_FLAG_ROTATE_90) + angle += 90; + if (info->fb_flags & FB_FLAG_ROTATE_180) + angle += 180; + snprintf(strbuf, sizeof(strbuf), "%d", angle); + kern_setenv("screen.rotate", strbuf); + } + freeenv(rotation); + } + + /* Default angle to rotate console clockwise, in 90 degree increments. */ + if (!(info->fb_flags & FB_FLAG_ROTATE_NODEFAULT)) { + if ((TUNABLE_INT_FETCH("screen.autorotate", &angle) == 0)) + TUNABLE_INT_FETCH("screen.rotate", &angle); + info->fb_flags &= ~FB_FLAG_ROTATE_MASK; + switch (angle) { + case 270: + info->fb_flags |= FB_FLAG_ROTATE_270; + break; + case 180: + info->fb_flags |= FB_FLAG_ROTATE_180; + break; + case 90: + info->fb_flags |= FB_FLAG_ROTATE_90; + break; + default: + info->fb_flags |= FB_FLAG_ROTATE_0; + break; + } + } + + if (info->fb_flags & FB_FLAG_ROTATE_90) { /* +/-90 degrees rotation */ + vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_width); + vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_height); + margin = (info->fb_height - vd->vd_width) >> 1; + vd->vd_transpose = margin * info->fb_stride; + margin = (info->fb_width - vd->vd_height) >> 1; + } else { + vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height); + vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width); + margin = (info->fb_height - vd->vd_height) >> 1; + vd->vd_transpose = margin * info->fb_stride; + margin = (info->fb_width - vd->vd_width) >> 1; + } vd->vd_transpose += margin * (info->fb_bpp / NBBY); vd->vd_video_dev = info->fb_video_dev; diff --git a/sys/kern/kern_ntptime.c b/sys/kern/kern_ntptime.c index a8418248abd7..500aefb61096 100644 --- a/sys/kern/kern_ntptime.c +++ b/sys/kern/kern_ntptime.c @@ -1074,6 +1074,10 @@ static void start_periodic_resettodr(void *arg __unused) { + EVENTHANDLER_REGISTER(power_resume, periodic_resettodr, NULL, + EVENTHANDLER_PRI_ANY); + EVENTHANDLER_REGISTER(power_suspend_early, shutdown_resettodr, NULL, + EVENTHANDLER_PRI_FIRST); EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_resettodr, NULL, SHUTDOWN_PRI_FIRST); callout_init(&resettodr_callout, 1); diff --git a/sys/sys/fbio.h b/sys/sys/fbio.h index 931ef689fc1f..d573811044bc 100644 --- a/sys/sys/fbio.h +++ b/sys/sys/fbio.h @@ -143,9 +143,15 @@ struct fb_info { void *fb_priv; /* First argument for read/write. */ const char *fb_name; uint32_t fb_flags; -#define FB_FLAG_NOMMAP 1 /* mmap unsupported. */ -#define FB_FLAG_NOWRITE 2 /* disable writes for the time being */ -#define FB_FLAG_MEMATTR 4 /* override memattr for mmap */ +#define FB_FLAG_NOMMAP 0x01 /* mmap unsupported. */ +#define FB_FLAG_NOWRITE 0x02 /* disable writes for the time being */ +#define FB_FLAG_MEMATTR 0x04 /* override memattr for mmap */ +#define FB_FLAG_ROTATE_0 0x00 /* rotate fb 0 degrees clockwise */ +#define FB_FLAG_ROTATE_90 0x08 /* rotate fb 90 degrees clockwise */ +#define FB_FLAG_ROTATE_180 0x10 /* rotate fb 180 degrees clockwise */ +#define FB_FLAG_ROTATE_270 (FB_FLAG_ROTATE_90 | FB_FLAG_ROTATE_180) +#define FB_FLAG_ROTATE_MASK 0x18 +#define FB_FLAG_ROTATE_NODEFAULT 0x20 /* do not load console defaults */ vm_memattr_t fb_memattr; int fb_stride; int fb_bpp; /* bits per pixel */