/** * USB debuggign tool for Pinephone keyboard * * Copyright (C) 2021 Ondřej Jirman * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common.c" int kb_open(void) { int ret, fd; // first check if keyboard USB device is available, if it is // we need to first switch to bootloader mode fd = open_usb_dev(0x04f3, 0xb001); if (fd >= 0) { struct usbdevfs_disconnect_claim dc = { .interface = 0, }; ret = ioctl(fd, USBDEVFS_DISCONNECT_CLAIM, &dc); syscall_error(ret < 0, "USBDEVFS_DISCONNECT_CLAIM failed"); } return fd; } static int usb_fd = -1; int command(uint8_t req[8]) { int ret; struct usbdevfs_urb urb = { .type = USBDEVFS_URB_TYPE_INTERRUPT, .endpoint = 0x01, // .flags = USBDEVFS_URB_ZERO_PACKET, .buffer = req, .buffer_length = 8, .actual_length = 8, }; ret = handle_urb(usb_fd, &urb, 100); if (ret) return ret; debug("CMD:"); for (int i = 0; i < urb.actual_length; i++) debug(" %02hhx", req[i]); debug("\n"); return 0; } int response(uint8_t res[8]) { int ret; struct usbdevfs_urb urb = { .type = USBDEVFS_URB_TYPE_INTERRUPT, .endpoint = 0x82, .flags = USBDEVFS_URB_SHORT_NOT_OK, .buffer = res, .buffer_length = 8, .actual_length = 0, }; ret = handle_urb(usb_fd, &urb, 100); if (ret) return ret; if (urb.actual_length != 8) error("Status response size invalid, must be 8 bytes, got %d", urb.actual_length); debug("RES:"); for (int i = 0; i < urb.actual_length; i++) debug(" %02hhx", res[i]); debug("\n"); return 0; } int read_stdout(void) { int ret; uint8_t buf[64]; struct usbdevfs_urb urb = { .type = USBDEVFS_URB_TYPE_INTERRUPT, .endpoint = 0x83, .buffer = buf, .buffer_length = 64, .actual_length = 0, }; ret = handle_urb(usb_fd, &urb, 10); if (ret) return ret; debug("STD%d:", urb.actual_length); for (int i = 0; i < urb.actual_length; i++) debug(" %02hhx", buf[i]); debug("\n"); if (urb.actual_length > 0) { ssize_t rv = xwrite(1, buf, urb.actual_length); if (rv < 0) return -1; } return 0; } int read_keys(uint8_t buf[12]) { int ret; struct usbdevfs_urb urb = { .type = USBDEVFS_URB_TYPE_INTERRUPT, .endpoint = 0x84, .flags = USBDEVFS_URB_SHORT_NOT_OK, .buffer = buf, .buffer_length = 12, .actual_length = 0, }; ret = handle_urb(usb_fd, &urb, 10); if (ret) return ret; return 0; } void print_bitmap(uint8_t* map) { // printf("\033[H"); for (int r = 0; r < 6; r++) { if (r == 0) { printf(" C"); for (int c = 0; c < 12; c++) printf("%-3d", c + 1); printf("\n"); } printf("R%d", r + 1); for (int c = 0; c < 12; c++) printf(" %s", map[c] & (1u << r) ? "X" : "."); printf("\n"); } } int main(int ac, char* av[]) { int ret; uint8_t keys[12]; usb_fd = kb_open(); if (usb_fd < 0) error("Failed to open the keyboard"); while (1) { ret = read_stdout(); if (ret < 0 && errno != 110) syscall_error(true, "read_stdout failed"); ret = read_keys(keys); if (ret < 0 && errno != 110) syscall_error(true, "read_keys failed"); if (ret == 0) print_bitmap(keys); } return 0; }