~tuomasjjrasanen/libm210/master

« back to all changes in this revision

Viewing changes to src/dev.c

  • Committer: Tuomas Jorma Juhani Räsänen
  • Date: 2011-12-22 19:02:26 UTC
  • Revision ID: git-v1:2df22e9635e3ed53ccdcdbc8f88bf1933422e058
Code formatting: clear whitespace, tabify, etc.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
  Copyright © 2011 Tuomas Jorma Juhani Räsänen
3
 
 
4
 
  This program is free software: you can redistribute it and/or modify
5
 
  it under the terms of the GNU General Public License as published by
6
 
  the Free Software Foundation, either version 3 of the License, or
7
 
  (at your option) any later version.
8
 
 
9
 
  This program is distributed in the hope that it will be useful,
10
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
  GNU General Public License for more details.
13
 
 
14
 
  You should have received a copy of the GNU General Public License
15
 
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 
*/
 
1
/* libm210
 
2
 * Copyright (C) 2011 Tuomas Jorma Juhani Räsänen
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation, either version 3 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
 */
17
17
 
18
18
#include <errno.h>
19
19
#include <fcntl.h>
39
39
#define M210_DEV_MAX_TIMEOUT_RETRIES 5
40
40
 
41
41
struct m210_dev {
42
 
        int fds[M210_DEV_USB_INTERFACE_COUNT];
 
42
        int fds[M210_DEV_USB_INTERFACE_COUNT];
43
43
};
44
44
 
45
45
struct m210_dev_packet {
46
 
        uint16_t num;
47
 
        uint8_t data[M210_DEV_PACKET_SIZE];
 
46
        uint16_t num;
 
47
        uint8_t data[M210_DEV_PACKET_SIZE];
48
48
} __attribute__((packed));
49
49
 
50
50
static struct hidraw_devinfo const DEVINFO_M210 = {
51
 
        BUS_USB,
52
 
        0x0e20,
53
 
        0x0101,
 
51
        BUS_USB,
 
52
        0x0e20,
 
53
        0x0101,
54
54
};
55
55
 
56
 
static enum m210_err
57
 
m210_dev_write(struct m210_dev const *const dev_ptr,
58
 
               uint8_t const *const bytes,
59
 
               size_t const bytes_size)
60
 
{
61
 
        enum m210_err err = M210_ERR_OK;
62
 
        size_t const request_size = bytes_size + 3;
63
 
        uint8_t *request = malloc(request_size);
64
 
 
65
 
        if (request == NULL) {
66
 
                err = M210_ERR_SYS;
67
 
                goto exit;
68
 
        }
69
 
 
70
 
        request[0] = 0x00;     /* Without this, response is not sent. Why?? */
71
 
        request[1] = 0x02;     /* report id */
72
 
        request[2] = bytes_size;
73
 
 
74
 
        /* Copy report paylod to the end of the request. */
75
 
        memcpy(request + 3, bytes, bytes_size);
76
 
 
77
 
        /* Send request to the interface 0. */
78
 
        if (write(dev_ptr->fds[0], request, request_size) == -1) {
79
 
                err = M210_ERR_SYS;
80
 
                goto exit;
81
 
        }
82
 
 
83
 
exit:
84
 
        free(request);
85
 
        return err;
86
 
}
87
 
 
88
 
static enum m210_err
89
 
m210_dev_read(struct m210_dev const *const dev_ptr,
90
 
              int const interface,
91
 
              void *const response,
92
 
              size_t const response_size)
93
 
{
94
 
        enum m210_err err = M210_ERR_OK;
95
 
        fd_set readfds;
96
 
        int const fd = dev_ptr->fds[interface];
97
 
        static struct timeval select_interval;
98
 
 
99
 
        memset(&select_interval, 0, sizeof(struct timeval));
100
 
        FD_ZERO(&readfds);
101
 
        FD_SET(fd, &readfds);
102
 
 
103
 
        select_interval.tv_usec = M210_DEV_READ_INTERVAL;
104
 
 
105
 
        switch (select(fd + 1, &readfds, NULL, NULL, &select_interval)) {
106
 
        case 0:
107
 
                err = M210_ERR_DEV_TIMEOUT;
108
 
                goto exit;
109
 
        case -1:
110
 
                err = M210_ERR_SYS;
111
 
                goto exit;
112
 
        default:
113
 
                break;
114
 
        }
115
 
 
116
 
        if (read(fd, response, response_size) == -1) {
117
 
                err = M210_ERR_SYS;
118
 
                goto exit;
119
 
        }
120
 
 
121
 
exit:
122
 
        return err;
123
 
}
124
 
 
125
 
static enum m210_err
126
 
m210_dev_find_hidraw_devnode(int const iface,
127
 
                             char *const path_ptr,
128
 
                             size_t const path_size)
129
 
{
130
 
        enum m210_err err = M210_ERR_OK;
131
 
        struct udev_list_entry *list_entry = NULL;
132
 
        struct udev_enumerate *enumerate = NULL;
133
 
        struct udev *udev = NULL;
134
 
 
135
 
        udev = udev_new();
136
 
        if (udev == NULL) {
137
 
                err = M210_ERR_SYS;
138
 
                goto exit;
139
 
        }
140
 
 
141
 
        enumerate = udev_enumerate_new(udev);
142
 
        if (enumerate == NULL) {
143
 
                err = M210_ERR_SYS;
144
 
                goto exit;
145
 
        }
146
 
 
147
 
        if (udev_enumerate_add_match_subsystem(enumerate, "hidraw")) {
148
 
                err = M210_ERR_SYS;
149
 
                goto exit;
150
 
        }
151
 
 
152
 
        if (udev_enumerate_scan_devices(enumerate)) {
153
 
                err = M210_ERR_SYS;
154
 
                goto exit;
155
 
        }
156
 
 
157
 
        list_entry = udev_enumerate_get_list_entry(enumerate);
158
 
 
159
 
        while (list_entry != NULL) {
160
 
                int ifn;
161
 
                uint16_t vendor;
162
 
                uint16_t product;
163
 
                char const *syspath;
164
 
                struct udev_device *device;
165
 
                char const *devnode;
166
 
                struct udev_device *parent;
167
 
 
168
 
                syspath =  udev_list_entry_get_name(list_entry);
169
 
                device = udev_device_new_from_syspath(udev, syspath);
170
 
                devnode = udev_device_get_devnode(device);
171
 
 
172
 
                /* Second parent: usb */
173
 
                parent = udev_device_get_parent(device);
174
 
                parent = udev_device_get_parent(parent);
175
 
 
176
 
                ifn = atoi(udev_device_get_sysattr_value(parent,
177
 
                                                         "bInterfaceNumber"));
178
 
                parent = udev_device_get_parent(parent);
179
 
                vendor = strtol(udev_device_get_sysattr_value(parent,
180
 
                                                              "idVendor"),
181
 
                                NULL, 16);
182
 
                product = strtol(udev_device_get_sysattr_value(parent,
183
 
                                                               "idProduct"),
184
 
                                 NULL, 16);
185
 
                if (vendor == DEVINFO_M210.vendor
186
 
                    && product == DEVINFO_M210.product
187
 
                    && iface == ifn) {
188
 
                        strncpy(path_ptr, devnode, path_size);
189
 
                        udev_device_unref(device);
190
 
                        goto exit;
191
 
                }
192
 
                list_entry = udev_list_entry_get_next(list_entry);
193
 
                udev_device_unref(device);
194
 
        }
195
 
        err = M210_ERR_NO_DEV;
196
 
exit:
197
 
        if (enumerate) {
198
 
                udev_enumerate_unref(enumerate);
199
 
        }
200
 
 
201
 
        if (udev) {
202
 
                udev_unref(udev);
203
 
        }
204
 
 
205
 
        return err;
206
 
}
207
 
 
208
 
static enum m210_err
209
 
m210_dev_accept_download(struct m210_dev const *const dev_ptr)
210
 
{
211
 
        uint8_t const bytes[] = {0xb6};
212
 
        return m210_dev_write(dev_ptr, bytes, sizeof(bytes));
213
 
}
214
 
 
215
 
static enum m210_err
216
 
m210_dev_reject_download(struct m210_dev const *const dev_ptr)
217
 
{
218
 
        uint8_t const bytes[] = {0xb7};
219
 
        return m210_dev_write(dev_ptr, bytes, sizeof(bytes));
220
 
}
221
 
 
222
 
static enum m210_err
223
 
m210_dev_connect_hidraw(struct m210_dev *const dev_ptr,
224
 
                        char *const *const hidraw_path_ptrs)
225
 
{
226
 
        enum m210_err err = M210_ERR_OK;
227
 
        int fds[M210_DEV_USB_INTERFACE_COUNT];
228
 
 
229
 
        for (size_t i = 0; i < M210_DEV_USB_INTERFACE_COUNT; ++i) {
230
 
                struct hidraw_devinfo devinfo;
231
 
                int fd = open(hidraw_path_ptrs[i], O_RDWR);
232
 
                if (fd == -1) {
233
 
                        err = M210_ERR_SYS;
234
 
                        goto exit;
235
 
                }
236
 
 
237
 
                if (ioctl(fd, HIDIOCGRAWINFO, &devinfo)) {
238
 
                        err = M210_ERR_SYS;
239
 
                        goto exit;
240
 
                }
241
 
 
242
 
                if (memcmp(&devinfo, &DEVINFO_M210,
243
 
                           sizeof(struct hidraw_devinfo)) != 0) {
244
 
                        err = M210_ERR_BAD_DEV;
245
 
                        goto exit;
246
 
                }
247
 
 
248
 
                fds[i] = fd;
249
 
        }
250
 
 
251
 
exit:
252
 
        if (!err) {
253
 
                memcpy(dev_ptr->fds, fds, sizeof(fds));
254
 
        }
255
 
        return err;
 
56
static enum m210_err m210_dev_write(struct m210_dev const *const dev_ptr,
 
57
                                    uint8_t const *const bytes,
 
58
                                    size_t const bytes_size)
 
59
{
 
60
        enum m210_err err = M210_ERR_OK;
 
61
        size_t const request_size = bytes_size + 3;
 
62
        uint8_t *request = malloc(request_size);
 
63
 
 
64
        if (request == NULL) {
 
65
                err = M210_ERR_SYS;
 
66
                goto out;
 
67
        }
 
68
 
 
69
        request[0] = 0x00;     /* Without this, response is not sent. Why?? */
 
70
        request[1] = 0x02;     /* report id */
 
71
        request[2] = bytes_size;
 
72
 
 
73
        /* Copy report paylod to the end of the request. */
 
74
        memcpy(request + 3, bytes, bytes_size);
 
75
 
 
76
        /* Send request to the interface 0. */
 
77
        if (write(dev_ptr->fds[0], request, request_size) == -1) {
 
78
                err = M210_ERR_SYS;
 
79
                goto out;
 
80
        }
 
81
 
 
82
out:
 
83
        free(request);
 
84
        return err;
 
85
}
 
86
 
 
87
static enum m210_err m210_dev_read(struct m210_dev const *const dev_ptr,
 
88
                                   int const interface,
 
89
                                   void *const response,
 
90
                                   size_t const response_size)
 
91
{
 
92
        enum m210_err err = M210_ERR_OK;
 
93
        fd_set readfds;
 
94
        int const fd = dev_ptr->fds[interface];
 
95
        static struct timeval select_interval;
 
96
 
 
97
        memset(&select_interval, 0, sizeof(struct timeval));
 
98
        FD_ZERO(&readfds);
 
99
        FD_SET(fd, &readfds);
 
100
 
 
101
        select_interval.tv_usec = M210_DEV_READ_INTERVAL;
 
102
 
 
103
        switch (select(fd + 1, &readfds, NULL, NULL, &select_interval)) {
 
104
        case 0:
 
105
                err = M210_ERR_DEV_TIMEOUT;
 
106
                goto out;
 
107
        case -1:
 
108
                err = M210_ERR_SYS;
 
109
                goto out;
 
110
        default:
 
111
                break;
 
112
        }
 
113
 
 
114
        if (read(fd, response, response_size) == -1) {
 
115
                err = M210_ERR_SYS;
 
116
                goto out;
 
117
        }
 
118
 
 
119
out:
 
120
        return err;
 
121
}
 
122
 
 
123
static enum m210_err m210_dev_find_hidraw_devnode(int const iface,
 
124
                                                  char *const path_ptr,
 
125
                                                  size_t const path_size)
 
126
{
 
127
        enum m210_err err = M210_ERR_OK;
 
128
        struct udev_list_entry *list_entry = NULL;
 
129
        struct udev_enumerate *enumerate = NULL;
 
130
        struct udev *udev = NULL;
 
131
 
 
132
        udev = udev_new();
 
133
        if (udev == NULL) {
 
134
                err = M210_ERR_SYS;
 
135
                goto out;
 
136
        }
 
137
 
 
138
        enumerate = udev_enumerate_new(udev);
 
139
        if (enumerate == NULL) {
 
140
                err = M210_ERR_SYS;
 
141
                goto out;
 
142
        }
 
143
 
 
144
        if (udev_enumerate_add_match_subsystem(enumerate, "hidraw")) {
 
145
                err = M210_ERR_SYS;
 
146
                goto out;
 
147
        }
 
148
 
 
149
        if (udev_enumerate_scan_devices(enumerate)) {
 
150
                err = M210_ERR_SYS;
 
151
                goto out;
 
152
        }
 
153
 
 
154
        list_entry = udev_enumerate_get_list_entry(enumerate);
 
155
 
 
156
        while (list_entry != NULL) {
 
157
                int ifn;
 
158
                uint16_t vendor;
 
159
                uint16_t product;
 
160
                char const *syspath;
 
161
                struct udev_device *device;
 
162
                char const *devnode;
 
163
                struct udev_device *parent;
 
164
 
 
165
                syspath =  udev_list_entry_get_name(list_entry);
 
166
                device = udev_device_new_from_syspath(udev, syspath);
 
167
                devnode = udev_device_get_devnode(device);
 
168
 
 
169
                /* Second parent: usb */
 
170
                parent = udev_device_get_parent(device);
 
171
                parent = udev_device_get_parent(parent);
 
172
 
 
173
                ifn = atoi(udev_device_get_sysattr_value(parent,
 
174
                                                         "bInterfaceNumber"));
 
175
                parent = udev_device_get_parent(parent);
 
176
                vendor = strtol(udev_device_get_sysattr_value(parent,
 
177
                                                              "idVendor"),
 
178
                                NULL, 16);
 
179
                product = strtol(udev_device_get_sysattr_value(parent,
 
180
                                                               "idProduct"),
 
181
                                 NULL, 16);
 
182
                if (vendor == DEVINFO_M210.vendor
 
183
                    && product == DEVINFO_M210.product
 
184
                    && iface == ifn) {
 
185
                        strncpy(path_ptr, devnode, path_size);
 
186
                        udev_device_unref(device);
 
187
                        goto out;
 
188
                }
 
189
                list_entry = udev_list_entry_get_next(list_entry);
 
190
                udev_device_unref(device);
 
191
        }
 
192
        err = M210_ERR_NO_DEV;
 
193
out:
 
194
        if (enumerate) {
 
195
                udev_enumerate_unref(enumerate);
 
196
        }
 
197
 
 
198
        if (udev) {
 
199
                udev_unref(udev);
 
200
        }
 
201
 
 
202
        return err;
 
203
}
 
204
 
 
205
static enum m210_err m210_dev_accept_download(struct m210_dev const *const dev_ptr)
 
206
{
 
207
        uint8_t const bytes[] = {0xb6};
 
208
        return m210_dev_write(dev_ptr, bytes, sizeof(bytes));
 
209
}
 
210
 
 
211
static enum m210_err m210_dev_reject_download(struct m210_dev const *const dev_ptr)
 
212
{
 
213
        uint8_t const bytes[] = {0xb7};
 
214
        return m210_dev_write(dev_ptr, bytes, sizeof(bytes));
 
215
}
 
216
 
 
217
static enum m210_err m210_dev_connect_hidraw(struct m210_dev *const dev_ptr,
 
218
                                             char *const *const hidraw_path_ptrs)
 
219
{
 
220
        enum m210_err err = M210_ERR_OK;
 
221
        int fds[M210_DEV_USB_INTERFACE_COUNT];
 
222
 
 
223
        for (size_t i = 0; i < M210_DEV_USB_INTERFACE_COUNT; ++i) {
 
224
                struct hidraw_devinfo devinfo;
 
225
                int fd = open(hidraw_path_ptrs[i], O_RDWR);
 
226
                if (fd == -1) {
 
227
                        err = M210_ERR_SYS;
 
228
                        goto out;
 
229
                }
 
230
 
 
231
                if (ioctl(fd, HIDIOCGRAWINFO, &devinfo)) {
 
232
                        err = M210_ERR_SYS;
 
233
                        goto out;
 
234
                }
 
235
 
 
236
                if (memcmp(&devinfo, &DEVINFO_M210,
 
237
                           sizeof(struct hidraw_devinfo)) != 0) {
 
238
                        err = M210_ERR_BAD_DEV;
 
239
                        goto out;
 
240
                }
 
241
 
 
242
                fds[i] = fd;
 
243
        }
 
244
 
 
245
out:
 
246
        if (!err) {
 
247
                memcpy(dev_ptr->fds, fds, sizeof(fds));
 
248
        }
 
249
        return err;
256
250
}
257
251
 
258
252
/*
260
254
 
261
255
  1: Request just packet count.
262
256
 
263
 
  HOST             DEVICE
 
257
  HOST             DEVICE
264
258
  =============================
265
259
  GET_PACKET_COUNT >
266
260
  < PACKET_COUNT
267
 
  REJECT           >
 
261
  REJECT           >
268
262
 
269
263
  2: Download packets.
270
264
 
271
 
  HOST              DEVICE
 
265
  HOST              DEVICE
272
266
  ==============================
273
267
  GET_PACKET_COUNT  >
274
268
  < PACKET_COUNT
275
 
  ACCEPT            >
 
269
  ACCEPT            >
276
270
  < PACKET #1
277
271
  < PACKET #2
278
272
  .
279
273
  .
280
274
  .
281
275
  < PACKET #N
282
 
  RESEND #X         >
 
276
  RESEND #X         >
283
277
  < PACKET #X
284
 
  RESEND #Y         >
 
278
  RESEND #Y         >
285
279
  < PACKET #Y
286
 
  ACCEPT            >
 
280
  ACCEPT            >
287
281
 
288
282
*/
289
 
static enum m210_err
290
 
m210_dev_begin_download(struct m210_dev const *const dev_ptr,
291
 
                        uint16_t *const packet_count_ptr)
292
 
{
293
 
        static uint8_t const bytes[] = {0xb5};
294
 
        uint8_t response[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
295
 
        enum m210_err err = M210_ERR_OK;
296
 
        int timeout_retries = 0;
297
 
 
298
 
        while (timeout_retries < M210_DEV_MAX_TIMEOUT_RETRIES) {
299
 
                err = m210_dev_write(dev_ptr, bytes, sizeof(bytes));
300
 
                if (err) {
301
 
                        goto exit;
302
 
                }
303
 
                ++timeout_retries;
304
 
 
305
 
                err = m210_dev_read(dev_ptr, 0, response, sizeof(response));
306
 
                if (err) {
307
 
                        if (err == M210_ERR_DEV_TIMEOUT) {
308
 
                                /* In addition to typical reasons for
309
 
                                 * timeout, M210 device timeouts if
310
 
                                 * queried the packet count but if it
311
 
                                 * does not have any notes. By
312
 
                                 * querying the packet count multiple
313
 
                                 * times, we ensure that the
314
 
                                 * timeouting is really due to lack of
315
 
                                 * notes.
316
 
                                 */
317
 
                                continue;
318
 
                        }
319
 
                        goto exit;
320
 
                }
321
 
 
322
 
                /* Check that the response is correct. */
323
 
                if (response[0] == 0xaa
324
 
                    && response[1] == 0xaa
325
 
                    && response[2] == 0xaa
326
 
                    && response[3] == 0xaa
327
 
                    && response[4] == 0xaa
328
 
                    && response[7] == 0x55
329
 
                    && response[8] == 0x55) {
330
 
                        break;
331
 
                }
332
 
 
333
 
        }
334
 
 
335
 
        memcpy(packet_count_ptr, response + 5, 2);
336
 
        *packet_count_ptr = be16toh(*packet_count_ptr);
337
 
 
338
 
exit:
339
 
        if (err) {
340
 
                if (err == M210_ERR_DEV_TIMEOUT) {
341
 
                        /* M210 has timeouted because it does not have
342
 
                         * any notes: its ok, the packet count is set
343
 
                         * to zero. */
344
 
                        err = M210_ERR_OK;
345
 
                } else {
346
 
                        /* Try to leave the device as it was before
347
 
                         * the error. */
348
 
                        m210_dev_reject_download(dev_ptr);
349
 
                }
350
 
        }
351
 
        return err;
352
 
}
353
 
 
354
 
static enum m210_err
355
 
m210_dev_read_packet(struct m210_dev const *const dev_ptr,
356
 
                     struct m210_dev_packet *const packet_ptr)
357
 
{
358
 
        enum m210_err err = m210_dev_read(dev_ptr, 0, packet_ptr,
359
 
                                          sizeof(struct m210_dev_packet));
360
 
        if (!err) {
361
 
                packet_ptr->num = be16toh(packet_ptr->num);
362
 
        }
363
 
        return err;
364
 
}
365
 
 
366
 
enum m210_err
367
 
m210_dev_connect(struct m210_dev **const dev_ptr_ptr)
368
 
{
369
 
        struct m210_dev *dev_ptr = NULL;
370
 
        enum m210_err err = M210_ERR_OK;
371
 
        char iface0_path[PATH_MAX];
372
 
        char iface1_path[PATH_MAX];
373
 
        char *paths[M210_DEV_USB_INTERFACE_COUNT] = {iface0_path, iface1_path};
374
 
 
375
 
        dev_ptr = malloc(sizeof(struct m210_dev));
376
 
        if (!dev_ptr) {
377
 
                err = M210_ERR_SYS;
378
 
                goto exit;
379
 
        }
380
 
 
381
 
        for (size_t i = 0; i < M210_DEV_USB_INTERFACE_COUNT; ++i) {
382
 
                memset(paths[i], 0, PATH_MAX);
383
 
        
384
 
                err = m210_dev_find_hidraw_devnode(i, paths[i], PATH_MAX);
385
 
                if (err) {
386
 
                        goto exit;
387
 
                }
388
 
        }
389
 
        err = m210_dev_connect_hidraw(dev_ptr, paths);
390
 
exit:
391
 
        if (err) {
392
 
                free(dev_ptr);
393
 
                dev_ptr = NULL;
394
 
        }
395
 
        *dev_ptr_ptr = dev_ptr;
396
 
        return err;
397
 
}
398
 
 
399
 
enum m210_err
400
 
m210_dev_disconnect(struct m210_dev **const dev_ptr_ptr)
401
 
{
402
 
        struct m210_dev *const dev_ptr = *dev_ptr_ptr;
403
 
        enum m210_err err = M210_ERR_OK;
404
 
 
405
 
        if (!dev_ptr) {
406
 
                goto exit;
407
 
        }
408
 
 
409
 
        for (int i = 0; i < M210_DEV_USB_INTERFACE_COUNT; ++i) {
410
 
                if (close(dev_ptr->fds[i]) == -1) {
411
 
                        err = M210_ERR_SYS;
412
 
                }
413
 
        }
414
 
        free(dev_ptr);
415
 
        *dev_ptr_ptr = NULL;
416
 
exit:
417
 
        return err;
 
283
static enum m210_err m210_dev_begin_download(struct m210_dev const *const dev_ptr,
 
284
                                             uint16_t *const packet_count_ptr)
 
285
{
 
286
        static uint8_t const bytes[] = {0xb5};
 
287
        uint8_t response[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
 
288
        enum m210_err err = M210_ERR_OK;
 
289
        int timeout_retries = 0;
 
290
 
 
291
        while (timeout_retries < M210_DEV_MAX_TIMEOUT_RETRIES) {
 
292
                err = m210_dev_write(dev_ptr, bytes, sizeof(bytes));
 
293
                if (err) {
 
294
                        goto out;
 
295
                }
 
296
                ++timeout_retries;
 
297
 
 
298
                err = m210_dev_read(dev_ptr, 0, response, sizeof(response));
 
299
                if (err) {
 
300
                        if (err == M210_ERR_DEV_TIMEOUT) {
 
301
                                /* In addition to typical reasons for
 
302
                                 * timeout, M210 device timeouts if
 
303
                                 * queried the packet count but if it
 
304
                                 * does not have any notes. By
 
305
                                 * querying the packet count multiple
 
306
                                 * times, we ensure that the
 
307
                                 * timeouting is really due to lack of
 
308
                                 * notes.
 
309
                                 */
 
310
                                continue;
 
311
                        }
 
312
                        goto out;
 
313
                }
 
314
 
 
315
                /* Check that the response is correct. */
 
316
                if (response[0] == 0xaa
 
317
                    && response[1] == 0xaa
 
318
                    && response[2] == 0xaa
 
319
                    && response[3] == 0xaa
 
320
                    && response[4] == 0xaa
 
321
                    && response[7] == 0x55
 
322
                    && response[8] == 0x55) {
 
323
                        break;
 
324
                }
 
325
 
 
326
        }
 
327
 
 
328
        memcpy(packet_count_ptr, response + 5, 2);
 
329
        *packet_count_ptr = be16toh(*packet_count_ptr);
 
330
 
 
331
out:
 
332
        if (err) {
 
333
                if (err == M210_ERR_DEV_TIMEOUT) {
 
334
                        /* M210 has timeouted because it does not have
 
335
                         * any notes: its ok, the packet count is set
 
336
                         * to zero. */
 
337
                        err = M210_ERR_OK;
 
338
                } else {
 
339
                        /* Try to leave the device as it was before
 
340
                         * the error. */
 
341
                        m210_dev_reject_download(dev_ptr);
 
342
                }
 
343
        }
 
344
        return err;
 
345
}
 
346
 
 
347
static enum m210_err m210_dev_read_packet(struct m210_dev const *const dev_ptr,
 
348
                                          struct m210_dev_packet *const packet_ptr)
 
349
{
 
350
        enum m210_err err = m210_dev_read(dev_ptr, 0, packet_ptr,
 
351
                                          sizeof(struct m210_dev_packet));
 
352
        if (!err) {
 
353
                packet_ptr->num = be16toh(packet_ptr->num);
 
354
        }
 
355
        return err;
 
356
}
 
357
 
 
358
enum m210_err m210_dev_connect(struct m210_dev **const dev_ptr_ptr)
 
359
{
 
360
        struct m210_dev *dev_ptr = NULL;
 
361
        enum m210_err err = M210_ERR_OK;
 
362
        char iface0_path[PATH_MAX];
 
363
        char iface1_path[PATH_MAX];
 
364
        char *paths[M210_DEV_USB_INTERFACE_COUNT] = {iface0_path, iface1_path};
 
365
 
 
366
        dev_ptr = malloc(sizeof(struct m210_dev));
 
367
        if (!dev_ptr) {
 
368
                err = M210_ERR_SYS;
 
369
                goto out;
 
370
        }
 
371
 
 
372
        for (size_t i = 0; i < M210_DEV_USB_INTERFACE_COUNT; ++i) {
 
373
                memset(paths[i], 0, PATH_MAX);
 
374
 
 
375
                err = m210_dev_find_hidraw_devnode(i, paths[i], PATH_MAX);
 
376
                if (err) {
 
377
                        goto out;
 
378
                }
 
379
        }
 
380
        err = m210_dev_connect_hidraw(dev_ptr, paths);
 
381
out:
 
382
        if (err) {
 
383
                free(dev_ptr);
 
384
                dev_ptr = NULL;
 
385
        }
 
386
        *dev_ptr_ptr = dev_ptr;
 
387
        return err;
 
388
}
 
389
 
 
390
enum m210_err m210_dev_disconnect(struct m210_dev **const dev_ptr_ptr)
 
391
{
 
392
        struct m210_dev *const dev_ptr = *dev_ptr_ptr;
 
393
        enum m210_err err = M210_ERR_OK;
 
394
 
 
395
        if (!dev_ptr) {
 
396
                goto out;
 
397
        }
 
398
 
 
399
        for (int i = 0; i < M210_DEV_USB_INTERFACE_COUNT; ++i) {
 
400
                if (close(dev_ptr->fds[i]) == -1) {
 
401
                        err = M210_ERR_SYS;
 
402
                }
 
403
        }
 
404
        free(dev_ptr);
 
405
        *dev_ptr_ptr = NULL;
 
406
out:
 
407
        return err;
418
408
}
419
409
 
420
410
/*
432
422
  more than the maximum number of bytes in devices memory.
433
423
 
434
424
*/
435
 
static enum m210_err
436
 
m210_dev_get_notes_size(struct m210_dev const *const dev_ptr,
437
 
                        uint32_t *const size_ptr)
438
 
{
439
 
        uint16_t packet_count = 0;
440
 
        enum m210_err err = M210_ERR_OK;
441
 
 
442
 
        err = m210_dev_begin_download(dev_ptr, &packet_count);
443
 
        if (err) {
444
 
                goto exit;
445
 
        }
446
 
 
447
 
        err = m210_dev_reject_download(dev_ptr);
448
 
exit:
449
 
        if (!err) {
450
 
                *size_ptr = packet_count * M210_DEV_PACKET_SIZE;
451
 
        }
452
 
        return err;
453
 
}
454
 
 
455
 
enum m210_err
456
 
m210_dev_get_info(struct m210_dev *const dev_ptr,
457
 
                  struct m210_dev_info *const info_ptr)
458
 
{
459
 
        enum m210_err err = M210_ERR_OK;
460
 
        static uint8_t const bytes[] = {0x95};
461
 
        uint8_t response[M210_DEV_RESPONSE_SIZE];
462
 
        uint32_t used_memory = 0;
463
 
  
464
 
        err = m210_dev_write(dev_ptr, bytes, sizeof(bytes));
465
 
        if (err) {
466
 
                goto exit;
467
 
        }
468
 
    
469
 
        while (1) {
470
 
                memset(response, 0, sizeof(response));
471
 
                err = m210_dev_read(dev_ptr, 0, response, sizeof(response));
472
 
                if (err) {
473
 
                        goto exit;
474
 
                }
475
 
        
476
 
                /* Check that the response is correct. */
477
 
                if (response[0] == 0x80
478
 
                    && response[1] == 0xa9
479
 
                    && response[2] == 0x28
480
 
                    && response[9] == 0x0e) {
481
 
                        break;
482
 
                }
483
 
        }
484
 
 
485
 
        err = m210_dev_get_notes_size(dev_ptr, &used_memory);
486
 
        if (err) {
487
 
                goto exit;
488
 
        }
489
 
 
490
 
        memcpy(&(info_ptr->firmware_version), response + 3, 2);
491
 
        memcpy(&(info_ptr->analog_version), response + 5, 2);
492
 
        memcpy(&(info_ptr->pad_version), response + 7, 2);
493
 
    
494
 
        info_ptr->firmware_version = be16toh(info_ptr->firmware_version);
495
 
        info_ptr->analog_version = be16toh(info_ptr->analog_version);
496
 
        info_ptr->pad_version = be16toh(info_ptr->pad_version);
497
 
        info_ptr->mode = response[10];
498
 
        info_ptr->used_memory = used_memory;
499
 
        
500
 
exit:
501
 
        return err;
502
 
}
503
 
 
504
 
enum m210_err
505
 
m210_dev_delete_notes(struct m210_dev *const dev_ptr)
506
 
{
507
 
        uint8_t const bytes[] = {0xb0};
508
 
        return m210_dev_write(dev_ptr, bytes, sizeof(bytes));
509
 
}
510
 
 
511
 
static enum m210_err
512
 
m210_dev_download(struct m210_dev const *const dev_ptr,
513
 
                  uint16_t packet_count,
514
 
                  uint16_t *const lost_nums,
515
 
                  FILE *const file)
516
 
{
517
 
        enum m210_err err = M210_ERR_OK;
518
 
        uint16_t lost_count = 0;
519
 
 
520
 
        for (int i = 0; i < packet_count; ++i) {
521
 
                struct m210_dev_packet packet;
522
 
                uint16_t const expected_packet_number = i + 1;
523
 
 
524
 
                err = m210_dev_read_packet(dev_ptr, &packet);
525
 
                if (err) {
526
 
                        goto exit;
527
 
                }
528
 
 
529
 
                if (packet.num != expected_packet_number) {
530
 
                        lost_nums[lost_count++] = expected_packet_number;
531
 
                }
532
 
 
533
 
                if (!lost_count) {
534
 
                        if (fwrite(packet.data, sizeof(packet.data), 1,
535
 
                                   file) != 1) {
536
 
                                err = M210_ERR_SYS;
537
 
                                goto exit;
538
 
                        }
539
 
                }
540
 
        }
541
 
 
542
 
        while (lost_count > 0) {
543
 
                struct m210_dev_packet packet;
544
 
 
545
 
                uint8_t resend_request[] = {0xb7, 0x00};
546
 
                resend_request[1] = htobe16(lost_nums[0]);
547
 
 
548
 
                err = m210_dev_write(dev_ptr, resend_request,
549
 
                                     sizeof(resend_request));
550
 
                if (err) {
551
 
                        goto exit;
552
 
                }
553
 
 
554
 
                err = m210_dev_read_packet(dev_ptr, &packet);
555
 
                if (err) {
556
 
                        goto exit;
557
 
                }
558
 
 
559
 
                if (packet.num == lost_nums[0]) {
560
 
                        lost_nums[0] = lost_nums[--lost_count];
561
 
                        if (fwrite(packet.data, sizeof(packet.data), 1,
562
 
                                   file) != 1) {
563
 
                                err = M210_ERR_SYS;
564
 
                                goto exit;
565
 
                        }
566
 
                }
567
 
        }
568
 
exit:
569
 
        return err;
570
 
}
571
 
 
572
 
enum m210_err
573
 
m210_dev_download_notes(struct m210_dev *const dev_ptr, FILE *file)
574
 
{
575
 
        enum m210_err err = M210_ERR_OK;
576
 
        uint16_t *lost_nums = NULL;
577
 
        uint16_t packet_count = 0;
578
 
 
579
 
        err = m210_dev_begin_download(dev_ptr, &packet_count);
580
 
        if (err) {
581
 
                goto exit;
582
 
        }
583
 
 
584
 
        if (packet_count == 0) {
585
 
                err = m210_dev_reject_download(dev_ptr);
586
 
                goto exit;
587
 
        }
588
 
 
589
 
        lost_nums = calloc(packet_count, sizeof(uint16_t));
590
 
        if (lost_nums == NULL) {
591
 
                int const original_errno = errno;
592
 
                m210_dev_reject_download(dev_ptr);
593
 
                errno = original_errno;
594
 
                err = M210_ERR_SYS;
595
 
                goto exit;
596
 
        }
597
 
 
598
 
        err = m210_dev_accept_download(dev_ptr);
599
 
        if (err) {
600
 
                goto exit;
601
 
        }
602
 
 
603
 
        err = m210_dev_download(dev_ptr, packet_count, lost_nums, file);
604
 
        if (err) {
605
 
                goto exit;
606
 
        }
607
 
 
608
 
        /*
609
 
          All packets have been received, time to thank the device for
610
 
          cooperation.
611
 
        */
612
 
        err = m210_dev_accept_download(dev_ptr);
613
 
exit:
614
 
        if (file) {
615
 
                fflush(file);
616
 
        }
617
 
        free(lost_nums);
618
 
        return err;
 
425
static enum m210_err m210_dev_get_notes_size(struct m210_dev const *const dev_ptr,
 
426
                                             uint32_t *const size_ptr)
 
427
{
 
428
        uint16_t packet_count = 0;
 
429
        enum m210_err err = M210_ERR_OK;
 
430
 
 
431
        err = m210_dev_begin_download(dev_ptr, &packet_count);
 
432
        if (err) {
 
433
                goto out;
 
434
        }
 
435
 
 
436
        err = m210_dev_reject_download(dev_ptr);
 
437
out:
 
438
        if (!err) {
 
439
                *size_ptr = packet_count * M210_DEV_PACKET_SIZE;
 
440
        }
 
441
        return err;
 
442
}
 
443
 
 
444
enum m210_err m210_dev_get_info(struct m210_dev *const dev_ptr,
 
445
                                struct m210_dev_info *const info_ptr)
 
446
{
 
447
        enum m210_err err = M210_ERR_OK;
 
448
        static uint8_t const bytes[] = {0x95};
 
449
        uint8_t response[M210_DEV_RESPONSE_SIZE];
 
450
        uint32_t used_memory = 0;
 
451
 
 
452
        err = m210_dev_write(dev_ptr, bytes, sizeof(bytes));
 
453
        if (err) {
 
454
                goto out;
 
455
        }
 
456
 
 
457
        while (1) {
 
458
                memset(response, 0, sizeof(response));
 
459
                err = m210_dev_read(dev_ptr, 0, response, sizeof(response));
 
460
                if (err) {
 
461
                        goto out;
 
462
                }
 
463
 
 
464
                /* Check that the response is correct. */
 
465
                if (response[0] == 0x80
 
466
                    && response[1] == 0xa9
 
467
                    && response[2] == 0x28
 
468
                    && response[9] == 0x0e) {
 
469
                        break;
 
470
                }
 
471
        }
 
472
 
 
473
        err = m210_dev_get_notes_size(dev_ptr, &used_memory);
 
474
        if (err) {
 
475
                goto out;
 
476
        }
 
477
 
 
478
        memcpy(&(info_ptr->firmware_version), response + 3, 2);
 
479
        memcpy(&(info_ptr->analog_version), response + 5, 2);
 
480
        memcpy(&(info_ptr->pad_version), response + 7, 2);
 
481
 
 
482
        info_ptr->firmware_version = be16toh(info_ptr->firmware_version);
 
483
        info_ptr->analog_version = be16toh(info_ptr->analog_version);
 
484
        info_ptr->pad_version = be16toh(info_ptr->pad_version);
 
485
        info_ptr->mode = response[10];
 
486
        info_ptr->used_memory = used_memory;
 
487
 
 
488
out:
 
489
        return err;
 
490
}
 
491
 
 
492
enum m210_err m210_dev_delete_notes(struct m210_dev *const dev_ptr)
 
493
{
 
494
        uint8_t const bytes[] = {0xb0};
 
495
        return m210_dev_write(dev_ptr, bytes, sizeof(bytes));
 
496
}
 
497
 
 
498
static enum m210_err m210_dev_download(struct m210_dev const *const dev_ptr,
 
499
                                       uint16_t packet_count,
 
500
                                       uint16_t *const lost_nums,
 
501
                                       FILE *const file)
 
502
{
 
503
        enum m210_err err = M210_ERR_OK;
 
504
        uint16_t lost_count = 0;
 
505
 
 
506
        for (int i = 0; i < packet_count; ++i) {
 
507
                struct m210_dev_packet packet;
 
508
                uint16_t const expected_packet_number = i + 1;
 
509
 
 
510
                err = m210_dev_read_packet(dev_ptr, &packet);
 
511
                if (err) {
 
512
                        goto out;
 
513
                }
 
514
 
 
515
                if (packet.num != expected_packet_number) {
 
516
                        lost_nums[lost_count++] = expected_packet_number;
 
517
                }
 
518
 
 
519
                if (!lost_count) {
 
520
                        if (fwrite(packet.data, sizeof(packet.data), 1,
 
521
                                   file) != 1) {
 
522
                                err = M210_ERR_SYS;
 
523
                                goto out;
 
524
                        }
 
525
                }
 
526
        }
 
527
 
 
528
        while (lost_count > 0) {
 
529
                struct m210_dev_packet packet;
 
530
 
 
531
                uint8_t resend_request[] = {0xb7, 0x00};
 
532
                resend_request[1] = htobe16(lost_nums[0]);
 
533
 
 
534
                err = m210_dev_write(dev_ptr, resend_request,
 
535
                                     sizeof(resend_request));
 
536
                if (err) {
 
537
                        goto out;
 
538
                }
 
539
 
 
540
                err = m210_dev_read_packet(dev_ptr, &packet);
 
541
                if (err) {
 
542
                        goto out;
 
543
                }
 
544
 
 
545
                if (packet.num == lost_nums[0]) {
 
546
                        lost_nums[0] = lost_nums[--lost_count];
 
547
                        if (fwrite(packet.data, sizeof(packet.data), 1,
 
548
                                   file) != 1) {
 
549
                                err = M210_ERR_SYS;
 
550
                                goto out;
 
551
                        }
 
552
                }
 
553
        }
 
554
out:
 
555
        return err;
 
556
}
 
557
 
 
558
enum m210_err m210_dev_download_notes(struct m210_dev *const dev_ptr, FILE *file)
 
559
{
 
560
        enum m210_err err = M210_ERR_OK;
 
561
        uint16_t *lost_nums = NULL;
 
562
        uint16_t packet_count = 0;
 
563
 
 
564
        err = m210_dev_begin_download(dev_ptr, &packet_count);
 
565
        if (err) {
 
566
                goto out;
 
567
        }
 
568
 
 
569
        if (packet_count == 0) {
 
570
                err = m210_dev_reject_download(dev_ptr);
 
571
                goto out;
 
572
        }
 
573
 
 
574
        lost_nums = calloc(packet_count, sizeof(uint16_t));
 
575
        if (lost_nums == NULL) {
 
576
                int const original_errno = errno;
 
577
                m210_dev_reject_download(dev_ptr);
 
578
                errno = original_errno;
 
579
                err = M210_ERR_SYS;
 
580
                goto out;
 
581
        }
 
582
 
 
583
        err = m210_dev_accept_download(dev_ptr);
 
584
        if (err) {
 
585
                goto out;
 
586
        }
 
587
 
 
588
        err = m210_dev_download(dev_ptr, packet_count, lost_nums, file);
 
589
        if (err) {
 
590
                goto out;
 
591
        }
 
592
 
 
593
        /*
 
594
          All packets have been received, time to thank the device for
 
595
          cooperation.
 
596
        */
 
597
        err = m210_dev_accept_download(dev_ptr);
 
598
out:
 
599
        if (file) {
 
600
                fflush(file);
 
601
        }
 
602
        free(lost_nums);
 
603
        return err;
619
604
}