1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Dell AIO Serial Backlight board emulator for testing
4 * the Linux dell-uart-backlight driver.
6 * Copyright (C) 2024 Hans de Goede <hansg@kernel.org>
14 #include <sys/ioctl.h>
16 #include <sys/types.h>
24 static unsigned char dell_uart_checksum(unsigned char *buf
, int len
)
26 unsigned char val
= 0;
34 /* read() will return -1 on SIGINT / SIGTERM causing the mainloop to cleanly exit */
35 void signalhdlr(int signum
)
39 int main(int argc
, char *argv
[])
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;
48 fprintf(stderr
, "Invalid or missing arguments\n");
49 fprintf(stderr
, "Usage: %s <serial-port>\n", argv
[0]);
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
));
59 ret
= tcgetattr(serial_fd
, &tty
);
61 fprintf(stderr
, "Error getting tcattr: %s\n", strerror(errno
));
66 cfsetspeed(&tty
, 9600);
68 tty
.c_cflag
&= ~CSTOPB
;
69 tty
.c_cflag
&= ~CRTSCTS
;
70 tty
.c_cflag
|= CLOCAL
| CREAD
;
72 ret
= tcsetattr(serial_fd
, TCSANOW
, &tty
);
74 fprintf(stderr
, "Error setting tcattr: %s\n", strerror(errno
));
78 sigaction(SIGINT
, &sigact
, 0);
79 sigaction(SIGTERM
, &sigact
, 0);
82 while (read(serial_fd
, &buf
[idx
], 1) == 1) {
85 /* 3 MSB bits: cmd-len + 01010 SOF marker */
86 case 0x6a: len
= 3; break;
87 case 0x8a: len
= 4; break;
89 fprintf(stderr
, "Error unexpected first byte: 0x%02x\n", buf
[0]);
90 continue; /* Try to sync up with sender */
94 /* Process msg when len bytes have been received */
95 if (idx
!= (len
- 1)) {
100 /* Reset idx for next command */
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",
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
);
116 case 0x8a0b: /* cmd = 0x0b, set brightness */
118 fprintf(stderr
, "Error invalid brightness param: %d\n", buf
[2]);
124 printf("Set brightness %d\n", brightness
);
126 case 0x6a0c: /* cmd = 0x0c, get brightness */
128 response
[2] = brightness
;
129 printf("Get brightness, reply: %d\n", brightness
);
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]);
138 printf("Set power %d\n", buf
[2]);
141 fprintf(stderr
, "Error unknown cmd 0x%04x\n",
142 (buf
[0] << 8) | buf
[1]);
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",
159 tcsetattr(serial_fd
, TCSANOW
, &saved_tty
);