pinephone-keyboard/usb-debugger.c
Ondrej Jirman 6a5fe581b9 Implement flashing over I2C and user/stock firmware support
I2C register layout changed a bit to make various operations easier
to implement in FW and for the user.

Flashing/debugging tools now share more code. Firmware is now more
configurable (it's now possible to compile-out various features).

Self-testing for column-shorts is implemented.

Firmware is optimized for low power consumption.
2021-06-28 15:09:47 +02:00

187 lines
3.6 KiB
C

/**
* USB debuggign tool for Pinephone keyboard
*
* Copyright (C) 2021 Ondřej Jirman <megi@xff.cz>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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;
}