From patchwork Tue Jul 25 16:05:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hans de Goede X-Patchwork-Id: 9862483 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 49D5B602B1 for ; Tue, 25 Jul 2017 16:05:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4613B28688 for ; Tue, 25 Jul 2017 16:05:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3AD99286F6; Tue, 25 Jul 2017 16:05:47 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 72BD628688 for ; Tue, 25 Jul 2017 16:05:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752637AbdGYQFp (ORCPT ); Tue, 25 Jul 2017 12:05:45 -0400 Received: from mx1.redhat.com ([209.132.183.28]:38040 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752540AbdGYQFn (ORCPT ); Tue, 25 Jul 2017 12:05:43 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1632CC0B7885; Tue, 25 Jul 2017 16:05:43 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 1632CC0B7885 Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=hdegoede@redhat.com Received: from dhcp-45-79.space.revspace.nl.com (ovpn-116-128.ams2.redhat.com [10.36.116.128]) by smtp.corp.redhat.com (Postfix) with ESMTP id 208838D56B; Tue, 25 Jul 2017 16:05:41 +0000 (UTC) From: Hans de Goede To: Bartlomiej Zolnierkiewicz , Jean Delvare Cc: Hans de Goede , linux-fbdev@vger.kernel.org Subject: [PATCH v5] video/console: Add dmi quirk table for x86 systems which need fbcon rotation Date: Tue, 25 Jul 2017 18:05:38 +0200 Message-Id: <20170725160538.1983-1-hdegoede@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 25 Jul 2017 16:05:43 +0000 (UTC) Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Some x86 clamshell design devices use portrait tablet screens and a display engine which cannot rotate in hardware, so we need to rotate the fbcon to compensate. This commit adds a DMI based quirk table which is initially populated with 4 such devices: The Asus T100HA, GPD Pocket, the GPD win and the I.T.Works TW891, so that the console comes up in the right orientation on these devices OOTB. Unfortunately these (cheap) devices also typically have quite generic DMI data, so we match on a combination of DMI data, screen resolution and a list of known BIOS dates to avoid false positives. Suggested-by: Jean Delvare Signed-off-by: Hans de Goede Reviewed-by: Jean Delvare --- Changes in v2: -Extend the commit message explaining why dmi_check_system does not work and this commit exports and uses dmi_matches instead Changes in v3: -The exporting of dmi_matches has been split out in a separate patch -Use u32 for width/height in struct fbcon_dmi_rotate_data to match the type of fb_var_screeninfo.xres / .yres Changes in v4: -Use dmi_first_match instead of exporting dmi_matches -Use DMI_EXACT_MATCH -Add the Asus T100HA to the list of devices needing rotation Changes in v5: -Add Reviewed-by: Jean Delvare -Add extra BIOS-date to known GDP pocket BIOS dates --- drivers/video/console/Makefile | 3 + drivers/video/console/fbcon.c | 12 ++- drivers/video/console/fbcon.h | 7 +- drivers/video/console/fbcon_dmi_quirks.c | 131 +++++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 drivers/video/console/fbcon_dmi_quirks.c diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile index 43bfa48..32ee2ad 100644 --- a/drivers/video/console/Makefile +++ b/drivers/video/console/Makefile @@ -15,5 +15,8 @@ ifeq ($(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION),y) obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \ fbcon_ccw.o endif +ifeq ($(CONFIG_DMI),y) +obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon_dmi_quirks.o +endif obj-$(CONFIG_FB_STI) += sticore.o diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 12ded23..3db5ac2 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -135,7 +135,7 @@ static char fontname[40]; static int info_idx = -1; /* console rotation */ -static int initial_rotation; +static int initial_rotation = -1; static int fbcon_has_sysfs; static const struct consw fb_con; @@ -954,7 +954,10 @@ static const char *fbcon_startup(void) ops->cur_rotate = -1; ops->cur_blink_jiffies = HZ / 5; info->fbcon_par = ops; - p->con_rotate = initial_rotation; + if (initial_rotation != -1) + p->con_rotate = initial_rotation; + else + p->con_rotate = fbcon_platform_get_rotate(info); set_blitting_type(vc, info); if (info->fix.type != FB_TYPE_TEXT) { @@ -1091,7 +1094,10 @@ static void fbcon_init(struct vc_data *vc, int init) ops = info->fbcon_par; ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); - p->con_rotate = initial_rotation; + if (initial_rotation != -1) + p->con_rotate = initial_rotation; + else + p->con_rotate = fbcon_platform_get_rotate(info); set_blitting_type(vc, info); cols = vc->vc_cols; diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 7aaa4ea..60e25e1 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -261,5 +261,10 @@ extern void fbcon_set_rotate(struct fbcon_ops *ops); #define fbcon_set_rotate(x) do {} while(0) #endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */ -#endif /* _VIDEO_FBCON_H */ +#ifdef CONFIG_DMI +int fbcon_platform_get_rotate(struct fb_info *info); +#else +#define fbcon_platform_get_rotate(i) FB_ROTATE_UR +#endif /* CONFIG_DMI */ +#endif /* _VIDEO_FBCON_H */ diff --git a/drivers/video/console/fbcon_dmi_quirks.c b/drivers/video/console/fbcon_dmi_quirks.c new file mode 100644 index 0000000..5b45ed2 --- /dev/null +++ b/drivers/video/console/fbcon_dmi_quirks.c @@ -0,0 +1,131 @@ +/* + * fbcon_dmi_quirks.c -- DMI based quirk detection for fbcon + * + * Copyright (C) 2017 Hans de Goede + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include "fbcon.h" + +/* + * Some x86 clamshell design devices use portrait tablet screens and a display + * engine which cannot rotate in hardware, so we need to rotate the fbcon to + * compensate. Unfortunately these (cheap) devices also typically have quite + * generic DMI data, so we match on a combination of DMI data, screen resolution + * and a list of known BIOS dates to avoid false positives. + */ + +struct fbcon_dmi_rotate_data { + int width; + int height; + const char * const *bios_dates; + int rotate; +}; + +static const struct fbcon_dmi_rotate_data rotate_data_asus_t100ha = { + .width = 800, + .height = 1280, + .rotate = FB_ROTATE_CCW, +}; + +static const struct fbcon_dmi_rotate_data rotate_data_gpd_pocket = { + .width = 1200, + .height = 1920, + .bios_dates = (const char * const []){ "05/26/2017", "07/05/2017", + NULL }, + .rotate = FB_ROTATE_CW, +}; + +static const struct fbcon_dmi_rotate_data rotate_data_gpd_win = { + .width = 720, + .height = 1280, + .bios_dates = (const char * const []){ + "10/25/2016", "11/18/2016", "02/21/2017", + "03/20/2017", NULL }, + .rotate = FB_ROTATE_CW, +}; + +static const struct fbcon_dmi_rotate_data rotate_data_itworks_tw891 = { + .width = 800, + .height = 1280, + .bios_dates = (const char * const []){ "10/16/2015", NULL }, + .rotate = FB_ROTATE_CW, +}; + +static const struct dmi_system_id rotate_data[] = { + { /* Asus T100HA */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100HAN"), + }, + .driver_data = (void *)&rotate_data_asus_t100ha, + }, { /* + * GPD Pocket, note that the the DMI data is less generic then + * it seems, devices with a board-vendor of "AMI Corporation" + * are quite rare, as are devices which have both board- *and* + * product-id set to "Default String" + */ + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"), + DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"), + }, + .driver_data = (void *)&rotate_data_gpd_pocket, + }, { /* GPD Win (same note on DMI match as GPD Pocket) */ + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"), + DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"), + }, + .driver_data = (void *)&rotate_data_gpd_win, + }, { /* I.T.Works TW891 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "TW891"), + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "TW891"), + }, + .driver_data = (void *)&rotate_data_itworks_tw891, + }, + {} +}; + +int fbcon_platform_get_rotate(struct fb_info *info) +{ + const struct dmi_system_id *match; + const struct fbcon_dmi_rotate_data *data; + const char *bios_date; + int i; + + for (match = dmi_first_match(rotate_data); + match; + match = dmi_first_match(match + 1)) { + data = match->driver_data; + + if (data->width != info->var.xres || + data->height != info->var.yres) + continue; + + if (!data->bios_dates) + return data->rotate; + + bios_date = dmi_get_system_info(DMI_BIOS_DATE); + if (!bios_date) + continue; + + for (i = 0; data->bios_dates[i]; i++) { + if (!strcmp(data->bios_dates[i], bios_date)) + return data->rotate; + } + } + + return FB_ROTATE_UR; +}