summaryrefslogtreecommitdiff
path: root/fw-update.c
blob: 5b70219286fa78979f8ed6b27854443a65216af5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

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;
}