File Index
Files and directories
Sign in
FILE

dell-uart-backlight-emulator.c

File preview with syntax highlighting.

linux-6.19.14/tools/arch/x86/dell-uart-backlight-emulator/dell-uart-backlight-emulator.c 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
 21int serial_fd;
 22int brightness = 50;
 23
 24static 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 */
 35void signalhdlr(int signum)
 36{
 37}
 38
 39int 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;
158out_restore:
159	tcsetattr(serial_fd, TCSANOW, &saved_tty);
160out_close:
161	close(serial_fd);
162	return ret;
163}
~/ Read-only file preview.