#include #include #include #include #include #include size_t read_fw(const char *filename, uint8_t **fw_buf) { int fw_fd, r; size_t read_bytes = 0; size_t bufsize = 0; const size_t blocksize = 1024; fw_fd = open(filename, O_RDONLY); if (fw_fd < 0) { perror(filename); return 0; } *fw_buf = NULL; do { if (bufsize - read_bytes < blocksize) { bufsize += blocksize; *fw_buf = realloc(*fw_buf, bufsize); if (fw_buf == NULL) { perror("realloc"); abort(); } } r = read(fw_fd, *fw_buf + read_bytes, bufsize - read_bytes); if (r > 0) read_bytes += r; } while (r > 0); if (r < 0) perror("read"); if (read_bytes == 0) fprintf(stderr, "Warning: no data is read\n"); close(fw_fd); if (r < 0 || read_bytes == 0) { free(*fw_buf); *fw_buf = NULL; return 0; } return read_bytes; } typedef struct { uint8_t report_id; uint8_t device_index; uint8_t addr; union { uint8_t params[3]; uint8_t params_l[16]; }; } HidppReport; int fw_update(int fd, uint8_t device_index, uint8_t *fw, size_t fw_len) { HidppReport report; report.report_id = 0x10; report.device_index = device_index; report.addr = 0xE2; report.params[0]; // TODO: refactor ltunify to allow re-using its feature discovery functionality. // TODO: [ix feat] find HID++ version, confirm >= 0x0200 // TODO: [ix feat] discover DFU feature // TODO: print: ask user to restart device // TODO: [ix notif] wait for device connect // TODO: [ix feat req] send "DFU" to DFU feature // TODO: [ix feat resp] confirm DFU enablement // TODO: [ff SHORT_REG req] write "LT" ix to f0 // TODO: [DJ ix notif resp] Link-loss notif (0x42) // TODO: [ff SHORT_REG resp] write must be succesful // TODO: [ff SHORT_REG] read f0 and confirm it says LT ix // TODO: [ix 82 E2] send magic packet (+verify) // TODO: [ix 82 E2] send firmware (+check toggle) // TODO: [ix 82 E2] send verify (+check toggle) // TODO: [ff SHORT_REG req] send "XIT // TODO: [ix notif] expect re-connection (0x41, proto 5) // TODO: (optional): ask user to restart device, confirm notif // TODO: print: success return 1; } int main(int argc, char **argv) { uint8_t *fw = NULL; size_t fw_len; int hid_fd = -1; int r = 0; uint8_t device_index; if (argc <= 3) { fprintf(stderr, "Usage: %s /dev/hidrawX device_index flash-file\n", argv[0]); return 1; } device_index = atoi(argv[2]); if (!(device_index >= 1 && device_index <= 6)) { fprintf(stderr, "device_index must be between 1 and 6 (inclusive)\n"); return 1; } if ((fw_len = read_fw(argv[3], &fw)) == 0) { return 1; } printf("Firmware size: %zu\n", fw_len); hid_fd = open(argv[1], O_RDWR); if (hid_fd >= 0) { r = fw_update(hid_fd, device_index, fw, fw_len); } else { perror(argv[1]); r = 1; } if (hid_fd >= 0) close(hid_fd); free(fw); return r; }