Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/arch/x86/dell-uart-backlight-emulator/dell-uart-backlight-emulator.c
26285 views
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 <[email protected]>
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
}
164
165