Path: blob/master/tools/arch/x86/dell-uart-backlight-emulator/dell-uart-backlight-emulator.c
26285 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Dell AIO Serial Backlight board emulator for testing3* the Linux dell-uart-backlight driver.4*5* Copyright (C) 2024 Hans de Goede <[email protected]>6*/7#include <errno.h>8#include <fcntl.h>9#include <signal.h>10#include <stdio.h>11#include <stdlib.h>12#include <string.h>13#include <sys/ioctl.h>14#include <sys/stat.h>15#include <sys/types.h>16#include <sys/un.h>17#include <termios.h>18#include <unistd.h>1920int serial_fd;21int brightness = 50;2223static unsigned char dell_uart_checksum(unsigned char *buf, int len)24{25unsigned char val = 0;2627while (len-- > 0)28val += buf[len];2930return val ^ 0xff;31}3233/* read() will return -1 on SIGINT / SIGTERM causing the mainloop to cleanly exit */34void signalhdlr(int signum)35{36}3738int main(int argc, char *argv[])39{40struct sigaction sigact = { .sa_handler = signalhdlr };41unsigned char buf[4], csum, response[32];42const char *version_str = "PHI23-V321";43struct termios tty, saved_tty;44int ret, idx, len = 0;4546if (argc != 2) {47fprintf(stderr, "Invalid or missing arguments\n");48fprintf(stderr, "Usage: %s <serial-port>\n", argv[0]);49return 1;50}5152serial_fd = open(argv[1], O_RDWR | O_NOCTTY);53if (serial_fd == -1) {54fprintf(stderr, "Error opening %s: %s\n", argv[1], strerror(errno));55return 1;56}5758ret = tcgetattr(serial_fd, &tty);59if (ret == -1) {60fprintf(stderr, "Error getting tcattr: %s\n", strerror(errno));61goto out_close;62}63saved_tty = tty;6465cfsetspeed(&tty, 9600);66cfmakeraw(&tty);67tty.c_cflag &= ~CSTOPB;68tty.c_cflag &= ~CRTSCTS;69tty.c_cflag |= CLOCAL | CREAD;7071ret = tcsetattr(serial_fd, TCSANOW, &tty);72if (ret == -1) {73fprintf(stderr, "Error setting tcattr: %s\n", strerror(errno));74goto out_restore;75}7677sigaction(SIGINT, &sigact, 0);78sigaction(SIGTERM, &sigact, 0);7980idx = 0;81while (read(serial_fd, &buf[idx], 1) == 1) {82if (idx == 0) {83switch (buf[0]) {84/* 3 MSB bits: cmd-len + 01010 SOF marker */85case 0x6a: len = 3; break;86case 0x8a: len = 4; break;87default:88fprintf(stderr, "Error unexpected first byte: 0x%02x\n", buf[0]);89continue; /* Try to sync up with sender */90}91}9293/* Process msg when len bytes have been received */94if (idx != (len - 1)) {95idx++;96continue;97}9899/* Reset idx for next command */100idx = 0;101102csum = dell_uart_checksum(buf, len - 1);103if (buf[len - 1] != csum) {104fprintf(stderr, "Error checksum mismatch got 0x%02x expected 0x%02x\n",105buf[len - 1], csum);106continue;107}108109switch ((buf[0] << 8) | buf[1]) {110case 0x6a06: /* cmd = 0x06, get version */111len = strlen(version_str);112strcpy((char *)&response[2], version_str);113printf("Get version, reply: %s\n", version_str);114break;115case 0x8a0b: /* cmd = 0x0b, set brightness */116if (buf[2] > 100) {117fprintf(stderr, "Error invalid brightness param: %d\n", buf[2]);118continue;119}120121len = 0;122brightness = buf[2];123printf("Set brightness %d\n", brightness);124break;125case 0x6a0c: /* cmd = 0x0c, get brightness */126len = 1;127response[2] = brightness;128printf("Get brightness, reply: %d\n", brightness);129break;130case 0x8a0e: /* cmd = 0x0e, set backlight power */131if (buf[2] != 0 && buf[2] != 1) {132fprintf(stderr, "Error invalid set power param: %d\n", buf[2]);133continue;134}135136len = 0;137printf("Set power %d\n", buf[2]);138break;139default:140fprintf(stderr, "Error unknown cmd 0x%04x\n",141(buf[0] << 8) | buf[1]);142continue;143}144145/* Respond with <total-len> <cmd> <data...> <csum> */146response[0] = len + 3; /* response length in bytes */147response[1] = buf[1]; /* ack cmd */148csum = dell_uart_checksum(response, len + 2);149response[len + 2] = csum;150ret = write(serial_fd, response, response[0]);151if (ret != (response[0]))152fprintf(stderr, "Error writing %d bytes: %d\n",153response[0], ret);154}155156ret = 0;157out_restore:158tcsetattr(serial_fd, TCSANOW, &saved_tty);159out_close:160close(serial_fd);161return ret;162}163164165