Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tools arch x86: Add dell-uart-backlight-emulator

Dell All In One (AIO) models released after 2017 use a backlight controller
board connected to an UART.

Add a small emulator to allow development and testing of
the drivers/platform/x86/dell/dell-uart-backlight.c driver for
this board, without requiring access to an actual Dell All In One.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20240513144603.93874-3-hdegoede@redhat.com

+229
+1
tools/arch/x86/dell-uart-backlight-emulator/.gitignore
··· 1 + dell-uart-backlight-emulator
+19
tools/arch/x86/dell-uart-backlight-emulator/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # Makefile for Intel Software Defined Silicon provisioning tool 3 + 4 + dell-uart-backlight-emulator: dell-uart-backlight-emulator.c 5 + 6 + BINDIR ?= /usr/bin 7 + 8 + override CFLAGS += -O2 -Wall 9 + 10 + %: %.c 11 + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) 12 + 13 + .PHONY : clean 14 + clean : 15 + @rm -f dell-uart-backlight-emulator 16 + 17 + install : dell-uart-backlight-emulator 18 + install -d $(DESTDIR)$(BINDIR) 19 + install -m 755 -p dell-uart-backlight-emulator $(DESTDIR)$(BINDIR)/dell-uart-backlight-emulator
+46
tools/arch/x86/dell-uart-backlight-emulator/README
··· 1 + Emulator for DELL0501 UART attached backlight controller 2 + -------------------------------------------------------- 3 + 4 + Dell All In One (AIO) models released after 2017 use a backlight controller 5 + board connected to an UART. 6 + 7 + In DSDT this uart port will be defined as: 8 + 9 + Name (_HID, "DELL0501") 10 + Name (_CID, EisaId ("PNP0501") 11 + 12 + With the DELL0501 indicating that we are dealing with an UART with 13 + the backlight controller board attached. 14 + 15 + This small emulator allows testing 16 + the drivers/platform/x86/dell/dell-uart-backlight.c driver without access 17 + to an actual Dell All In One. 18 + 19 + This requires: 20 + 1. A (desktop) PC with a 16550 UART on the motherboard and a standard DB9 21 + connector connected to this UART. 22 + 2. A DB9 NULL modem cable. 23 + 3. A second DB9 serial port, this can e.g. be a USB to serial converter 24 + with a DB9 connector plugged into the same desktop PC. 25 + 4. A DSDT overlay for the desktop PC replacing the _HID of the 16550 UART 26 + ACPI Device() with "DELL0501" and adding a _CID of "PNP0501", see 27 + DSDT.patch for an example of the necessary DSDT changes. 28 + 29 + With everything setup and the NULL modem cable connected between 30 + the 2 serial ports run: 31 + 32 + ./dell-uart-backlight-emulator <path-to-/dev/tty*S#-for-second-port> 33 + 34 + For example when using an USB to serial converter for the second port: 35 + 36 + ./dell-uart-backlight-emulator /dev/ttyUSB0 37 + 38 + And then (re)load the dell-uart-backlight driver: 39 + 40 + sudo rmmod dell-uart-backlight; sudo modprobe dell-uart-backlight dyndbg 41 + 42 + After this check "dmesg" to see if the driver correctly received 43 + the firmware version string from the emulator. If this works there 44 + should be a /sys/class/backlight/dell_uart_backlight/ directory now 45 + and writes to the brightness or bl_power files should be reflected 46 + by matching output from the emulator.
+163
tools/arch/x86/dell-uart-backlight-emulator/dell-uart-backlight-emulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Dell AIO Serial Backlight board emulator for testing 4 + * the Linux dell-uart-backlight driver. 5 + * 6 + * Copyright (C) 2024 Hans de Goede <hansg@kernel.org> 7 + */ 8 + #include <errno.h> 9 + #include <fcntl.h> 10 + #include <signal.h> 11 + #include <stdio.h> 12 + #include <stdlib.h> 13 + #include <string.h> 14 + #include <sys/ioctl.h> 15 + #include <sys/stat.h> 16 + #include <sys/types.h> 17 + #include <sys/un.h> 18 + #include <termios.h> 19 + #include <unistd.h> 20 + 21 + int serial_fd; 22 + int brightness = 50; 23 + 24 + static unsigned char dell_uart_checksum(unsigned char *buf, int len) 25 + { 26 + unsigned char val = 0; 27 + 28 + while (len-- > 0) 29 + val += buf[len]; 30 + 31 + return val ^ 0xff; 32 + } 33 + 34 + /* read() will return -1 on SIGINT / SIGTERM causing the mainloop to cleanly exit */ 35 + void signalhdlr(int signum) 36 + { 37 + } 38 + 39 + int main(int argc, char *argv[]) 40 + { 41 + struct sigaction sigact = { .sa_handler = signalhdlr }; 42 + unsigned char buf[4], csum, response[32]; 43 + const char *version_str = "PHI23-V321"; 44 + struct termios tty, saved_tty; 45 + int ret, idx, len = 0; 46 + 47 + if (argc != 2) { 48 + fprintf(stderr, "Invalid or missing arguments\n"); 49 + fprintf(stderr, "Usage: %s <serial-port>\n", argv[0]); 50 + return 1; 51 + } 52 + 53 + serial_fd = open(argv[1], O_RDWR | O_NOCTTY); 54 + if (serial_fd == -1) { 55 + fprintf(stderr, "Error opening %s: %s\n", argv[1], strerror(errno)); 56 + return 1; 57 + } 58 + 59 + ret = tcgetattr(serial_fd, &tty); 60 + if (ret == -1) { 61 + fprintf(stderr, "Error getting tcattr: %s\n", strerror(errno)); 62 + goto out_close; 63 + } 64 + saved_tty = tty; 65 + 66 + cfsetspeed(&tty, 9600); 67 + cfmakeraw(&tty); 68 + tty.c_cflag &= ~CSTOPB; 69 + tty.c_cflag &= ~CRTSCTS; 70 + tty.c_cflag |= CLOCAL | CREAD; 71 + 72 + ret = tcsetattr(serial_fd, TCSANOW, &tty); 73 + if (ret == -1) { 74 + fprintf(stderr, "Error setting tcattr: %s\n", strerror(errno)); 75 + goto out_restore; 76 + } 77 + 78 + sigaction(SIGINT, &sigact, 0); 79 + sigaction(SIGTERM, &sigact, 0); 80 + 81 + idx = 0; 82 + while (read(serial_fd, &buf[idx], 1) == 1) { 83 + if (idx == 0) { 84 + switch (buf[0]) { 85 + /* 3 MSB bits: cmd-len + 01010 SOF marker */ 86 + case 0x6a: len = 3; break; 87 + case 0x8a: len = 4; break; 88 + default: 89 + fprintf(stderr, "Error unexpected first byte: 0x%02x\n", buf[0]); 90 + continue; /* Try to sync up with sender */ 91 + } 92 + } 93 + 94 + /* Process msg when len bytes have been received */ 95 + if (idx != (len - 1)) { 96 + idx++; 97 + continue; 98 + } 99 + 100 + /* Reset idx for next command */ 101 + idx = 0; 102 + 103 + csum = dell_uart_checksum(buf, len - 1); 104 + if (buf[len - 1] != csum) { 105 + fprintf(stderr, "Error checksum mismatch got 0x%02x expected 0x%02x\n", 106 + buf[len - 1], csum); 107 + continue; 108 + } 109 + 110 + switch ((buf[0] << 8) | buf[1]) { 111 + case 0x6a06: /* cmd = 0x06, get version */ 112 + len = strlen(version_str); 113 + strcpy((char *)&response[2], version_str); 114 + printf("Get version, reply: %s\n", version_str); 115 + break; 116 + case 0x8a0b: /* cmd = 0x0b, set brightness */ 117 + if (buf[2] > 100) { 118 + fprintf(stderr, "Error invalid brightness param: %d\n", buf[2]); 119 + continue; 120 + } 121 + 122 + len = 0; 123 + brightness = buf[2]; 124 + printf("Set brightness %d\n", brightness); 125 + break; 126 + case 0x6a0c: /* cmd = 0x0c, get brightness */ 127 + len = 1; 128 + response[2] = brightness; 129 + printf("Get brightness, reply: %d\n", brightness); 130 + break; 131 + case 0x8a0e: /* cmd = 0x0e, set backlight power */ 132 + if (buf[2] != 0 && buf[2] != 1) { 133 + fprintf(stderr, "Error invalid set power param: %d\n", buf[2]); 134 + continue; 135 + } 136 + 137 + len = 0; 138 + printf("Set power %d\n", buf[2]); 139 + break; 140 + default: 141 + fprintf(stderr, "Error unknown cmd 0x%04x\n", 142 + (buf[0] << 8) | buf[1]); 143 + continue; 144 + } 145 + 146 + /* Respond with <total-len> <cmd> <data...> <csum> */ 147 + response[0] = len + 3; /* response length in bytes */ 148 + response[1] = buf[1]; /* ack cmd */ 149 + csum = dell_uart_checksum(response, len + 2); 150 + response[len + 2] = csum; 151 + ret = write(serial_fd, response, response[0]); 152 + if (ret != (response[0])) 153 + fprintf(stderr, "Error writing %d bytes: %d\n", 154 + response[0], ret); 155 + } 156 + 157 + ret = 0; 158 + out_restore: 159 + tcsetattr(serial_fd, TCSANOW, &saved_tty); 160 + out_close: 161 + close(serial_fd); 162 + return ret; 163 + }