]>
Commit | Line | Data |
---|---|---|
a8e913c4 JL |
1 | /* |
2 | * This file is part of the libsigrok project. | |
3 | * | |
4 | * Copyright (C) 2017 Jan Luebbe <jluebbe@lasnet.de> | |
5 | * | |
6 | * This program is free software: you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation, either version 3 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include <config.h> | |
ca7d19b5 | 21 | #include <string.h> |
a8e913c4 JL |
22 | #include "protocol.h" |
23 | ||
ca7d19b5 JL |
24 | #define COMMAND_START_CAPTURE 0x01 |
25 | #define COMMAND_STOP_CAPTURE 0x02 | |
26 | #define COMMAND_READ_EEPROM 0x07 | |
da390890 JL |
27 | #define COMMAND_INIT_BITSTREAM 0x7e |
28 | #define COMMAND_SEND_BITSTREAM 0x7f | |
ca7d19b5 JL |
29 | #define COMMAND_WRITE_REG 0x80 |
30 | #define COMMAND_READ_REG 0x81 | |
da390890 | 31 | #define COMMAND_READ_TEMP 0x86 |
ca7d19b5 JL |
32 | #define COMMAND_WRITE_I2C 0x87 |
33 | #define COMMAND_READ_I2C 0x88 | |
34 | #define COMMAND_WAKE_I2C 0x89 | |
35 | #define COMMAND_READ_FW_VER 0x8b | |
36 | ||
da390890 JL |
37 | #define REG_ADC_IDX 0x03 |
38 | #define REG_ADC_VAL_LSB 0x04 | |
39 | #define REG_ADC_VAL_MSB 0x05 | |
ca7d19b5 JL |
40 | #define REG_LED_RED 0x0f |
41 | #define REG_LED_GREEN 0x10 | |
42 | #define REG_LED_BLUE 0x11 | |
da390890 | 43 | #define REG_STATUS 0x40 |
ca7d19b5 JL |
44 | |
45 | static void iterate_lfsr(const struct sr_dev_inst *sdi) | |
46 | { | |
47 | struct dev_context *devc = sdi->priv; | |
48 | uint32_t lfsr = devc->lfsr; | |
49 | int i, max; | |
50 | ||
51 | max = (lfsr & 0x1f) + 34; | |
52 | for (i = 0; i <= max; i++) { | |
53 | lfsr = (lfsr >> 1) | \ | |
54 | ((lfsr ^ \ | |
55 | (lfsr >> 1) ^ \ | |
56 | (lfsr >> 21) ^ \ | |
57 | (lfsr >> 31) \ | |
58 | ) << 31); | |
59 | } | |
da390890 | 60 | sr_spew("Iterate 0x%08x -> 0x%08x", devc->lfsr, lfsr); |
ca7d19b5 JL |
61 | devc->lfsr = lfsr; |
62 | } | |
63 | ||
da390890 | 64 | static void encrypt(const struct sr_dev_inst *sdi, const uint8_t *in, uint8_t *out, uint16_t len) |
ca7d19b5 JL |
65 | { |
66 | struct dev_context *devc = sdi->priv; | |
67 | uint32_t lfsr = devc->lfsr; | |
68 | uint8_t value, mask; | |
69 | int i; | |
70 | ||
71 | for (i = 0; i < len; i++) { | |
72 | value = in[i]; | |
bb0c5271 | 73 | mask = lfsr >> (i % 4 * 8); |
ca7d19b5 JL |
74 | if (i == 0) |
75 | value = (value & 0x28) | ((value ^ mask) & ~0x28); | |
76 | else | |
77 | value = value ^ mask; | |
78 | out[i] = value; | |
79 | } | |
80 | iterate_lfsr(sdi); | |
81 | } | |
82 | ||
da390890 | 83 | static void decrypt(const struct sr_dev_inst *sdi, uint8_t *data, uint16_t len) |
ca7d19b5 JL |
84 | { |
85 | struct dev_context *devc = sdi->priv; | |
86 | uint32_t lfsr = devc->lfsr; | |
87 | int i; | |
88 | ||
bb0c5271 UH |
89 | for (i = 0; i < len; i++) |
90 | data[i] ^= (lfsr >> (i % 4 * 8)); | |
ca7d19b5 JL |
91 | iterate_lfsr(sdi); |
92 | } | |
93 | ||
94 | static int transact(const struct sr_dev_inst *sdi, | |
da390890 JL |
95 | const uint8_t *req, uint16_t req_len, |
96 | uint8_t *rsp, uint16_t rsp_len) | |
ca7d19b5 JL |
97 | { |
98 | struct sr_usb_dev_inst *usb = sdi->conn; | |
99 | uint8_t *req_enc; | |
100 | uint8_t rsp_dummy[1] = {}; | |
101 | int ret, xfer; | |
102 | ||
da390890 | 103 | if (req_len < 2 || req_len > 1024 || rsp_len > 128 || |
ca7d19b5 JL |
104 | !req || (rsp_len > 0 && !rsp)) |
105 | return SR_ERR_ARG; | |
106 | ||
107 | req_enc = g_malloc(req_len); | |
108 | encrypt(sdi, req, req_enc, req_len); | |
109 | ||
110 | ret = libusb_bulk_transfer(usb->devhdl, 1, req_enc, req_len, &xfer, 1000); | |
111 | if (ret != 0) { | |
112 | sr_dbg("Failed to send request 0x%02x: %s.", | |
113 | req[1], libusb_error_name(ret)); | |
114 | return SR_ERR; | |
115 | } | |
116 | if (xfer != req_len) { | |
117 | sr_dbg("Failed to send request 0x%02x: incorrect length " | |
118 | "%d != %d.", req[1], xfer, req_len); | |
119 | return SR_ERR; | |
120 | } | |
121 | ||
bb0c5271 | 122 | if (req[0] == 0x20) { /* Reseed. */ |
ca7d19b5 JL |
123 | return SR_OK; |
124 | } else if (rsp_len == 0) { | |
125 | rsp = rsp_dummy; | |
126 | rsp_len = sizeof(rsp_dummy); | |
127 | } | |
128 | ||
129 | ret = libusb_bulk_transfer(usb->devhdl, 0x80 | 1, rsp, rsp_len, | |
130 | &xfer, 1000); | |
131 | if (ret != 0) { | |
132 | sr_dbg("Failed to receive response to request 0x%02x: %s.", | |
133 | req[1], libusb_error_name(ret)); | |
134 | return SR_ERR; | |
135 | } | |
136 | if (xfer != rsp_len) { | |
137 | sr_dbg("Failed to receive response to request 0x%02x: " | |
138 | "incorrect length %d != %d.", req[1], xfer, rsp_len); | |
139 | return SR_ERR; | |
140 | } | |
141 | ||
142 | decrypt(sdi, rsp, rsp_len); | |
143 | ||
144 | return SR_OK; | |
145 | } | |
146 | ||
147 | static int reseed(const struct sr_dev_inst *sdi) | |
148 | { | |
149 | struct dev_context *devc = sdi->priv; | |
150 | uint8_t req[] = {0x20, 0x24, 0x4b, 0x35, 0x8e}; | |
151 | ||
152 | devc->lfsr = 0; | |
153 | return transact(sdi, req, sizeof(req), NULL, 0); | |
154 | } | |
155 | ||
156 | static int write_regs(const struct sr_dev_inst *sdi, uint8_t (*regs)[2], uint8_t cnt) | |
157 | { | |
158 | uint8_t req[64]; | |
159 | int i; | |
160 | ||
161 | if (cnt < 1 || cnt > 30) | |
162 | return SR_ERR_ARG; | |
163 | ||
164 | req[0] = 0x00; | |
165 | req[1] = COMMAND_WRITE_REG; | |
166 | req[2] = cnt; | |
167 | ||
168 | for (i = 0; i < cnt; i++) { | |
169 | req[3 + 2 * i] = regs[i][0]; | |
170 | req[4 + 2 * i] = regs[i][1]; | |
171 | } | |
172 | ||
bb0c5271 | 173 | return transact(sdi, req, 3 + (2 * cnt), NULL, 0); |
ca7d19b5 JL |
174 | } |
175 | ||
176 | static int write_reg(const struct sr_dev_inst *sdi, | |
177 | uint8_t address, uint8_t value) | |
178 | { | |
179 | uint8_t regs[2] = {address, value}; | |
180 | ||
181 | return write_regs(sdi, ®s, 1); | |
182 | } | |
183 | ||
da390890 JL |
184 | static int read_regs(const struct sr_dev_inst *sdi, |
185 | const uint8_t *regs, uint8_t *values, | |
186 | uint8_t cnt) | |
187 | { | |
188 | uint8_t req[33]; | |
189 | int i; | |
190 | ||
191 | if (cnt < 1 || cnt > 30) | |
192 | return SR_ERR_ARG; | |
193 | ||
194 | req[0] = 0x00; | |
195 | req[1] = COMMAND_READ_REG; | |
196 | req[2] = cnt; | |
197 | ||
198 | for (i = 0; i < cnt; i++) { | |
199 | req[3 + i] = regs[i]; | |
200 | } | |
201 | ||
202 | return transact(sdi, req, 3 + cnt, values, cnt); | |
203 | } | |
204 | ||
205 | static int read_reg(const struct sr_dev_inst *sdi, | |
206 | uint8_t address, uint8_t *value) | |
207 | { | |
208 | return read_regs(sdi, &address, value, 1); | |
209 | } | |
210 | ||
211 | static int write_adc(const struct sr_dev_inst *sdi, | |
212 | uint8_t address, uint16_t value) | |
213 | { | |
214 | uint8_t regs[][2] = { | |
215 | {REG_ADC_IDX, address}, | |
216 | {REG_ADC_VAL_LSB, value}, | |
217 | {REG_ADC_VAL_MSB, value >> 8}, | |
218 | }; | |
219 | ||
53012da6 | 220 | return write_regs(sdi, ARRAY_AND_SIZE(regs)); |
da390890 JL |
221 | } |
222 | ||
223 | static int read_eeprom(const struct sr_dev_inst *sdi, | |
224 | uint16_t address, uint8_t *data, uint16_t len) | |
225 | { | |
226 | uint8_t req[8] = { | |
227 | 0x00, COMMAND_READ_EEPROM, | |
228 | 0x33, 0x81, /* Unknown values */ | |
229 | address, address >> 8, | |
230 | len, len >> 8 | |
231 | }; | |
232 | ||
233 | return transact(sdi, req, sizeof(req), data, len); | |
234 | } | |
235 | ||
236 | static int read_eeprom_serial(const struct sr_dev_inst *sdi, | |
237 | uint8_t data[8]) | |
238 | { | |
239 | return read_eeprom(sdi, 0x08, data, 0x8); | |
240 | } | |
241 | ||
242 | static int read_eeprom_magic(const struct sr_dev_inst *sdi, | |
243 | uint8_t data[16]) | |
244 | { | |
245 | return read_eeprom(sdi, 0x10, data, 0x10); | |
246 | } | |
247 | ||
248 | static int read_temperature(const struct sr_dev_inst *sdi, int8_t *temp) | |
249 | { | |
250 | uint8_t req[2] = {0x00, COMMAND_READ_TEMP}; | |
251 | ||
252 | return transact(sdi, req, sizeof(req), (uint8_t*)temp, 1); | |
253 | } | |
254 | ||
ca7d19b5 | 255 | static int get_firmware_version(const struct sr_dev_inst *sdi) |
a8e913c4 | 256 | { |
ca7d19b5 JL |
257 | uint8_t req[2] = {0x00, COMMAND_READ_FW_VER}; |
258 | uint8_t rsp[128] = {}; | |
259 | int ret; | |
260 | ||
261 | ret = transact(sdi, req, sizeof(req), rsp, sizeof(rsp)); | |
262 | if (ret == SR_OK) { | |
263 | rsp[63] = 0; | |
264 | sr_dbg("fw-version: %s", rsp); | |
265 | } | |
266 | ||
267 | return ret; | |
268 | } | |
a8e913c4 | 269 | |
ca7d19b5 JL |
270 | static int read_i2c(const struct sr_dev_inst *sdi, uint8_t *data, uint8_t len) |
271 | { | |
272 | uint8_t req[5]; | |
bb0c5271 | 273 | uint8_t rsp[1 + 128]; |
ca7d19b5 | 274 | int ret; |
a8e913c4 | 275 | |
ca7d19b5 JL |
276 | if (len < 1 || len > 128 || !data) |
277 | return SR_ERR_ARG; | |
a8e913c4 | 278 | |
ca7d19b5 JL |
279 | req[0] = 0x00; |
280 | req[1] = COMMAND_READ_I2C; | |
bb0c5271 | 281 | req[2] = 0xc0; /* Fixed address */ |
ca7d19b5 | 282 | req[3] = len; |
bb0c5271 | 283 | req[4] = 0; /* Len MSB? */ |
a8e913c4 | 284 | |
ca7d19b5 | 285 | ret = transact(sdi, req, sizeof(req), rsp, 1 + len); |
bb0c5271 | 286 | if (ret != SR_OK) |
ca7d19b5 | 287 | return ret; |
ca7d19b5 JL |
288 | if (rsp[0] != 0x02) { |
289 | sr_dbg("Failed to do I2C read (0x%02x).", rsp[0]); | |
290 | return SR_ERR; | |
a8e913c4 JL |
291 | } |
292 | ||
bb0c5271 | 293 | memcpy(data, rsp + 1, len); |
ca7d19b5 JL |
294 | return SR_OK; |
295 | } | |
296 | ||
297 | static int write_i2c(const struct sr_dev_inst *sdi, const uint8_t *data, uint8_t len) | |
298 | { | |
299 | uint8_t req[5 + 128]; | |
300 | uint8_t rsp[1]; | |
301 | int ret; | |
302 | ||
303 | if (len < 1 || len > 128 || !data) | |
304 | return SR_ERR_ARG; | |
305 | ||
306 | req[0] = 0x00; | |
307 | req[1] = COMMAND_WRITE_I2C; | |
bb0c5271 | 308 | req[2] = 0xc0; /* Fixed address */ |
ca7d19b5 | 309 | req[3] = len; |
bb0c5271 | 310 | req[4] = 0; /* Len MSB? */ |
ca7d19b5 JL |
311 | memcpy(req + 5, data, len); |
312 | ||
313 | ret = transact(sdi, req, 5 + len, rsp, sizeof(rsp)); | |
bb0c5271 | 314 | if (ret != SR_OK) |
ca7d19b5 | 315 | return ret; |
ca7d19b5 JL |
316 | if (rsp[0] != 0x02) { |
317 | sr_dbg("Failed to do I2C write (0x%02x).", rsp[0]); | |
318 | return SR_ERR; | |
319 | } | |
320 | ||
321 | return SR_OK; | |
322 | } | |
323 | ||
324 | static int wake_i2c(const struct sr_dev_inst *sdi) | |
325 | { | |
326 | uint8_t req[] = {0x00, COMMAND_WAKE_I2C}; | |
327 | uint8_t rsp[1] = {}; | |
bb0c5271 | 328 | uint8_t i2c_rsp[1 + 1 + 2] = {}; |
ca7d19b5 JL |
329 | int ret; |
330 | ||
331 | ret = transact(sdi, req, sizeof(req), rsp, sizeof(rsp)); | |
bb0c5271 | 332 | if (ret != SR_OK) |
ca7d19b5 | 333 | return ret; |
ca7d19b5 JL |
334 | if (rsp[0] != 0x00) { |
335 | sr_dbg("Failed to do I2C wake trigger (0x%02x).", rsp[0]); | |
336 | return SR_ERR; | |
337 | } | |
338 | ||
339 | ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); | |
340 | if (ret != SR_OK) { | |
341 | return ret; | |
342 | } | |
343 | if (i2c_rsp[1] != 0x11) { | |
344 | sr_dbg("Failed to do I2C wake read (0x%02x).", i2c_rsp[0]); | |
345 | return SR_ERR; | |
346 | } | |
347 | ||
348 | return SR_OK; | |
349 | } | |
350 | ||
351 | static int crypto_random(const struct sr_dev_inst *sdi, uint8_t *data) | |
352 | { | |
353 | uint8_t i2c_req[8] = {0x03, 0x07, 0x1b, 0x00, 0x00, 0x00, 0x24, 0xcd}; | |
bb0c5271 | 354 | uint8_t i2c_rsp[1 + 32 + 2] = {}; |
ca7d19b5 JL |
355 | int ret; |
356 | ||
357 | ret = write_i2c(sdi, i2c_req, sizeof(i2c_req)); | |
bb0c5271 | 358 | if (ret != SR_OK) |
ca7d19b5 | 359 | return ret; |
ca7d19b5 | 360 | |
bb0c5271 | 361 | g_usleep(100000); /* TODO: Poll instead. */ |
ca7d19b5 JL |
362 | |
363 | ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); | |
bb0c5271 | 364 | if (ret != SR_OK) |
ca7d19b5 | 365 | return ret; |
ca7d19b5 | 366 | |
bb0c5271 UH |
367 | if (data) |
368 | memcpy(data, i2c_rsp + 1, 32); | |
ca7d19b5 JL |
369 | |
370 | return SR_OK; | |
371 | } | |
372 | ||
373 | static int crypto_nonce(const struct sr_dev_inst *sdi, uint8_t *data) | |
374 | { | |
bb0c5271 UH |
375 | uint8_t i2c_req[6 + 20 + 2] = {0x03, 0x1b, 0x16, 0x00, 0x00, 0x00}; |
376 | uint8_t i2c_rsp[1 + 32 + 2] = {}; | |
ca7d19b5 JL |
377 | int ret; |
378 | ||
bb0c5271 | 379 | /* CRC */ |
ca7d19b5 JL |
380 | i2c_req[26] = 0x7d; |
381 | i2c_req[27] = 0xe0; | |
382 | ||
383 | ret = write_i2c(sdi, i2c_req, sizeof(i2c_req)); | |
bb0c5271 | 384 | if (ret != SR_OK) |
ca7d19b5 | 385 | return ret; |
ca7d19b5 | 386 | |
bb0c5271 | 387 | g_usleep(100000); /* TODO: Poll instead. */ |
ca7d19b5 JL |
388 | |
389 | ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); | |
bb0c5271 | 390 | if (ret != SR_OK) |
ca7d19b5 | 391 | return ret; |
ca7d19b5 | 392 | |
bb0c5271 UH |
393 | if (data) |
394 | memcpy(data, i2c_rsp + 1, 32); | |
ca7d19b5 JL |
395 | |
396 | return SR_OK; | |
397 | } | |
398 | ||
399 | static int crypto_sign(const struct sr_dev_inst *sdi, uint8_t *data, uint8_t *crc) | |
400 | { | |
401 | uint8_t i2c_req[8] = {0x03, 0x07, 0x41, 0x80, 0x00, 0x00, 0x28, 0x05}; | |
bb0c5271 | 402 | uint8_t i2c_rsp[1 + 64 + 2] = {}; |
ca7d19b5 JL |
403 | int ret; |
404 | ||
405 | ret = write_i2c(sdi, i2c_req, sizeof(i2c_req)); | |
bb0c5271 | 406 | if (ret != SR_OK) |
ca7d19b5 | 407 | return ret; |
ca7d19b5 | 408 | |
bb0c5271 | 409 | g_usleep(100000); /* TODO: Poll instead. */ |
ca7d19b5 JL |
410 | |
411 | ret = read_i2c(sdi, i2c_rsp, sizeof(i2c_rsp)); | |
bb0c5271 | 412 | if (ret != SR_OK) |
ca7d19b5 | 413 | return ret; |
ca7d19b5 | 414 | |
bb0c5271 UH |
415 | memcpy(data, i2c_rsp + 1, 64); |
416 | memcpy(crc, i2c_rsp + 1 + 64, 2); | |
ca7d19b5 JL |
417 | |
418 | return SR_OK; | |
419 | } | |
420 | ||
421 | static int authenticate(const struct sr_dev_inst *sdi) | |
422 | { | |
423 | struct dev_context *devc = sdi->priv; | |
424 | uint8_t random[32] = {}; | |
425 | uint8_t nonce[32] = {}; | |
426 | uint8_t sig[64] = {}; | |
427 | uint8_t sig_crc[64] = {}; | |
428 | uint32_t lfsr; | |
429 | int i, ret; | |
430 | ||
431 | ret = wake_i2c(sdi); | |
432 | if (ret != SR_OK) | |
433 | return ret; | |
434 | ||
435 | ret = crypto_random(sdi, random); | |
436 | if (ret != SR_OK) | |
437 | return ret; | |
438 | sr_dbg("random: 0x%02x 0x%02x 0x%02x 0x%02x", random[0], random[1], random[2], random[3]); | |
439 | ||
440 | ret = crypto_nonce(sdi, nonce); | |
441 | if (ret != SR_OK) | |
442 | return ret; | |
443 | sr_dbg("nonce: 0x%02x 0x%02x 0x%02x 0x%02x", nonce[0], nonce[1], nonce[2], nonce[3]); | |
444 | ||
445 | ret = crypto_nonce(sdi, nonce); | |
446 | if (ret != SR_OK) | |
447 | return ret; | |
448 | sr_dbg("nonce: 0x%02x 0x%02x 0x%02x 0x%02x", nonce[0], nonce[1], nonce[2], nonce[3]); | |
449 | ||
450 | ret = crypto_sign(sdi, sig, sig_crc); | |
451 | if (ret != SR_OK) | |
452 | return ret; | |
453 | sr_dbg("sig: 0x%02x 0x%02x 0x%02x 0x%02x", sig[0], sig[1], sig[2], sig[3]); | |
454 | sr_dbg("sig crc: 0x%02x 0x%02x", sig_crc[0], sig_crc[1]); | |
455 | ||
456 | lfsr = 0; | |
457 | for (i = 0; i < 28; i++) | |
bb0c5271 | 458 | lfsr ^= nonce[i] << (8 * (i % 4)); |
ca7d19b5 JL |
459 | lfsr ^= sig_crc[0] | sig_crc[1] << 8; |
460 | ||
461 | sr_dbg("Authenticate 0x%08x -> 0x%08x", devc->lfsr, lfsr); | |
462 | devc->lfsr = lfsr; | |
463 | ||
464 | return SR_OK; | |
465 | } | |
466 | ||
da390890 JL |
467 | static int upload_bitstream_part(const struct sr_dev_inst *sdi, |
468 | const uint8_t *data, uint16_t len) | |
469 | { | |
470 | uint8_t req[4 + 1020]; | |
471 | uint8_t rsp[1]; | |
472 | int ret; | |
473 | ||
474 | if (len < 1 || len > 1020 || !data) | |
475 | return SR_ERR_ARG; | |
476 | ||
477 | req[0] = 0x00; | |
478 | req[1] = COMMAND_SEND_BITSTREAM; | |
479 | req[2] = len; | |
480 | req[3] = len >> 8; | |
481 | memcpy(req + 4, data, len); | |
482 | ||
483 | ret = transact(sdi, req, 4 + len, rsp, sizeof(rsp)); | |
484 | if (ret != SR_OK) | |
485 | return ret; | |
486 | if (rsp[0] != 0x00) { | |
487 | sr_dbg("Failed to do bitstream upload (0x%02x).", rsp[0]); | |
488 | return SR_ERR; | |
489 | } | |
490 | ||
491 | return SR_OK; | |
492 | } | |
493 | ||
494 | static int upload_bitstream(const struct sr_dev_inst *sdi, | |
495 | const char *name) | |
496 | { | |
497 | struct drv_context *drvc = sdi->driver->context; | |
498 | unsigned char *bitstream = NULL; | |
499 | uint8_t req[2]; | |
500 | uint8_t rsp[1]; | |
501 | uint8_t reg_val; | |
502 | int ret = SR_ERR; | |
503 | size_t bs_size, bs_offset = 0, bs_part_size; | |
504 | ||
505 | bitstream = sr_resource_load(drvc->sr_ctx, SR_RESOURCE_FIRMWARE, | |
506 | name, &bs_size, 512 * 1024); | |
507 | if (!bitstream) | |
508 | goto out; | |
509 | ||
510 | sr_info("Uploading bitstream '%s'.", name); | |
511 | ||
512 | req[0] = 0x00; | |
513 | req[1] = COMMAND_INIT_BITSTREAM; | |
514 | ||
515 | ret = transact(sdi, req, sizeof(req), rsp, sizeof(rsp)); | |
516 | if (ret != SR_OK) | |
517 | return ret; | |
518 | if (rsp[0] != 0x00) { | |
519 | sr_err("Failed to start bitstream upload (0x%02x).", rsp[0]); | |
520 | ret = SR_ERR; | |
521 | goto out; | |
522 | } | |
523 | ||
524 | while (bs_offset < bs_size) { | |
525 | bs_part_size = MIN(bs_size - bs_offset, 1020); | |
526 | sr_spew("Uploading %zd bytes.", bs_part_size); | |
527 | ret = upload_bitstream_part(sdi, bitstream + bs_offset, bs_part_size); | |
528 | if (ret != SR_OK) | |
529 | goto out; | |
530 | bs_offset += bs_part_size; | |
531 | } | |
532 | ||
da390890 JL |
533 | sr_info("Bitstream upload done."); |
534 | ||
535 | /* Check a scratch register? */ | |
536 | ret = write_reg(sdi, 0x7f, 0xaa); | |
537 | if (ret != SR_OK) | |
538 | goto out; | |
539 | ret = read_reg(sdi, 0x7f, ®_val); | |
540 | if (ret != SR_OK) | |
541 | goto out; | |
542 | if (reg_val != 0xaa) { | |
543 | sr_err("Failed FPGA register read-back (0x%02x != 0xaa).", rsp[0]); | |
544 | ret = SR_ERR; | |
545 | goto out; | |
546 | } | |
547 | ||
548 | out: | |
549 | g_free(bitstream); | |
550 | ||
551 | return ret; | |
552 | } | |
553 | ||
fbbafc69 | 554 | #if 0 |
ca7d19b5 JL |
555 | static int set_led(const struct sr_dev_inst *sdi, uint8_t r, uint8_t g, uint8_t b) |
556 | { | |
557 | uint8_t regs[][2] = { | |
558 | {REG_LED_RED, r}, | |
559 | {REG_LED_GREEN, g}, | |
560 | {REG_LED_BLUE, b}, | |
561 | }; | |
562 | ||
563 | authenticate(sdi); | |
564 | ||
53012da6 | 565 | return write_regs(sdi, ARRAY_AND_SIZE(regs)); |
ca7d19b5 | 566 | } |
fbbafc69 | 567 | #endif |
ca7d19b5 JL |
568 | |
569 | static int configure_channels(const struct sr_dev_inst *sdi) | |
570 | { | |
571 | struct dev_context *devc = sdi->priv; | |
572 | const struct sr_channel *c; | |
573 | const GSList *l; | |
574 | uint16_t mask; | |
575 | ||
576 | devc->dig_channel_cnt = 0; | |
577 | devc->dig_channel_mask = 0; | |
578 | for (l = sdi->channels; l; l = l->next) { | |
579 | c = l->data; | |
580 | if (!c->enabled) | |
581 | continue; | |
582 | ||
583 | mask = 1 << c->index; | |
584 | devc->dig_channel_masks[devc->dig_channel_cnt++] = mask; | |
585 | devc->dig_channel_mask |= mask; | |
586 | ||
587 | } | |
588 | sr_dbg("%d channels enabled (0x%04x)", | |
bb0c5271 | 589 | devc->dig_channel_cnt, devc->dig_channel_mask); |
ca7d19b5 JL |
590 | |
591 | return SR_OK; | |
592 | } | |
593 | ||
b6189f7c | 594 | SR_PRIV int saleae_logic_pro_init(const struct sr_dev_inst *sdi) |
ca7d19b5 | 595 | { |
da390890 JL |
596 | uint8_t reg_val; |
597 | uint8_t dummy[8]; | |
598 | uint8_t serial[8]; | |
599 | uint8_t magic[16]; | |
600 | int8_t temperature; | |
601 | int ret, i; | |
602 | ||
603 | ret = reseed(sdi); | |
604 | if (ret != SR_OK) | |
605 | return ret; | |
606 | ||
607 | ret = get_firmware_version(sdi); | |
608 | if (ret != SR_OK) | |
609 | return ret; | |
610 | ||
611 | sr_dbg("read serial"); | |
612 | ret = read_eeprom_serial(sdi, serial); | |
613 | if (ret != SR_OK) | |
614 | return ret; | |
615 | ||
616 | /* Check if we need to upload the bitstream. */ | |
617 | ret = read_reg(sdi, 0x7f, ®_val); | |
618 | if (ret != SR_OK) | |
619 | return ret; | |
620 | if (reg_val == 0xaa) { | |
621 | sr_info("Skipping bitstream upload."); | |
622 | } else { | |
623 | ret = upload_bitstream(sdi, "saleae-logicpro16-fpga.bitstream"); | |
624 | if (ret != SR_OK) | |
625 | return ret; | |
626 | } | |
627 | ||
628 | /* Reset the ADC? */ | |
629 | sr_dbg("reset ADC"); | |
630 | ret = write_reg(sdi, 0x00, 0x00); | |
631 | if (ret != SR_OK) | |
632 | return ret; | |
633 | ret = write_reg(sdi, 0x00, 0x80); | |
634 | if (ret != SR_OK) | |
635 | return ret; | |
636 | ||
637 | sr_dbg("init ADC"); | |
638 | ret = write_adc(sdi, 0x11, 0x0444); | |
639 | if (ret != SR_OK) | |
640 | return ret; | |
641 | ret = write_adc(sdi, 0x12, 0x0777); | |
642 | if (ret != SR_OK) | |
643 | return ret; | |
644 | ret = write_adc(sdi, 0x25, 0x0000); | |
645 | if (ret != SR_OK) | |
646 | return ret; | |
647 | ret = write_adc(sdi, 0x45, 0x0000); | |
648 | if (ret != SR_OK) | |
649 | return ret; | |
650 | ret = write_adc(sdi, 0x2a, 0x1111); | |
651 | if (ret != SR_OK) | |
652 | return ret; | |
653 | ret = write_adc(sdi, 0x2b, 0x1111); | |
654 | if (ret != SR_OK) | |
655 | return ret; | |
656 | ret = write_adc(sdi, 0x46, 0x0004); | |
657 | if (ret != SR_OK) | |
658 | return ret; | |
659 | ret = write_adc(sdi, 0x50, 0x0000); | |
660 | if (ret != SR_OK) | |
661 | return ret; | |
662 | ret = write_adc(sdi, 0x55, 0x0020); | |
663 | if (ret != SR_OK) | |
664 | return ret; | |
665 | ret = write_adc(sdi, 0x56, 0x0000); | |
666 | if (ret != SR_OK) | |
667 | return ret; | |
668 | ||
669 | ret = write_reg(sdi, 0x15, 0x00); | |
670 | if (ret != SR_OK) | |
671 | return ret; | |
672 | ||
673 | ret = write_adc(sdi, 0x0f, 0x0100); | |
674 | if (ret != SR_OK) | |
675 | return ret; | |
676 | ||
677 | /* Resets? */ | |
678 | sr_dbg("resets"); | |
679 | ret = write_reg(sdi, 0x00, 0x02); /* bit 1 */ | |
680 | if (ret != SR_OK) | |
681 | return ret; | |
682 | ret = write_reg(sdi, 0x00, 0x00); | |
683 | if (ret != SR_OK) | |
684 | return ret; | |
685 | ret = write_reg(sdi, 0x00, 0x04); /* bit 2 */ | |
686 | if (ret != SR_OK) | |
687 | return ret; | |
688 | ret = write_reg(sdi, 0x00, 0x00); | |
689 | if (ret != SR_OK) | |
690 | return ret; | |
691 | ret = write_reg(sdi, 0x00, 0x08); /* bit 3 */ | |
692 | if (ret != SR_OK) | |
693 | return ret; | |
694 | ret = write_reg(sdi, 0x00, 0x00); | |
695 | if (ret != SR_OK) | |
696 | return ret; | |
697 | ||
698 | sr_dbg("read dummy"); | |
699 | for (i = 0; i < 8; i++) { | |
700 | ret = read_reg(sdi, 0x41 + i, &dummy[i]); | |
701 | if (ret != SR_OK) | |
702 | return ret; | |
703 | } | |
704 | ||
705 | /* Read and write back magic EEPROM value. */ | |
706 | sr_dbg("read/write magic"); | |
707 | ret = read_eeprom_magic(sdi, magic); | |
708 | if (ret != SR_OK) | |
709 | return ret; | |
710 | for (i = 0; i < 16; i++) { | |
711 | ret = write_reg(sdi, 0x17, magic[i]); | |
712 | if (ret != SR_OK) | |
713 | return ret; | |
714 | } | |
715 | ||
716 | ret = read_temperature(sdi, &temperature); | |
717 | if (ret != SR_OK) | |
718 | return ret; | |
719 | sr_dbg("temperature = %d", temperature); | |
720 | ||
bb0c5271 | 721 | /* Setting the LED doesn't work yet. */ |
ca7d19b5 JL |
722 | /* set_led(sdi, 0x00, 0x00, 0xff); */ |
723 | ||
724 | return SR_OK; | |
725 | } | |
726 | ||
b6189f7c | 727 | SR_PRIV int saleae_logic_pro_prepare(const struct sr_dev_inst *sdi) |
ca7d19b5 JL |
728 | { |
729 | struct dev_context *devc = sdi->priv; | |
730 | uint8_t regs_unknown[][2] = { | |
731 | {0x03, 0x0f}, | |
732 | {0x04, 0x00}, | |
733 | {0x05, 0x00}, | |
734 | }; | |
735 | uint8_t regs_config[][2] = { | |
736 | {0x00, 0x00}, | |
bb0c5271 UH |
737 | {0x08, 0x00}, /* Analog channel mask (LSB) */ |
738 | {0x09, 0x00}, /* Analog channel mask (MSB) */ | |
739 | {0x06, 0x01}, /* Digital channel mask (LSB) */ | |
740 | {0x07, 0x00}, /* Digital channel mask (MSB) */ | |
741 | {0x0a, 0x00}, /* Analog sample rate? */ | |
742 | {0x0b, 0x64}, /* Digital sample rate? */ | |
ca7d19b5 | 743 | {0x0c, 0x00}, |
bb0c5271 UH |
744 | {0x0d, 0x00}, /* Analog mux rate? */ |
745 | {0x0e, 0x01}, /* Digital mux rate? */ | |
ca7d19b5 JL |
746 | {0x12, 0x04}, |
747 | {0x13, 0x00}, | |
bb0c5271 | 748 | {0x14, 0xff}, /* Pre-divider? */ |
ca7d19b5 JL |
749 | }; |
750 | uint8_t start_req[] = {0x00, 0x01}; | |
751 | uint8_t start_rsp[2] = {}; | |
752 | ||
753 | configure_channels(sdi); | |
754 | ||
bb0c5271 | 755 | /* Digital channel mask and muxing */ |
ca7d19b5 JL |
756 | regs_config[3][1] = devc->dig_channel_mask; |
757 | regs_config[4][1] = devc->dig_channel_mask >> 8; | |
758 | regs_config[9][1] = devc->dig_channel_cnt; | |
759 | ||
bb0c5271 | 760 | /* Samplerate */ |
ca7d19b5 JL |
761 | switch (devc->dig_samplerate) { |
762 | case SR_MHZ(1): | |
763 | regs_config[6][1] = 0x64; | |
764 | break; | |
765 | case SR_MHZ(2): | |
766 | regs_config[6][1] = 0x32; | |
767 | break; | |
768 | case SR_KHZ(2500): | |
769 | regs_config[6][1] = 0x28; | |
770 | break; | |
771 | case SR_MHZ(10): | |
772 | regs_config[6][1] = 0x0a; | |
773 | break; | |
774 | case SR_MHZ(25): | |
775 | regs_config[6][1] = 0x04; | |
776 | regs_config[12][1] = 0x80; | |
777 | break; | |
778 | case SR_MHZ(50): | |
779 | regs_config[6][1] = 0x02; | |
780 | regs_config[12][1] = 0x40; | |
781 | break; | |
782 | default: | |
783 | return SR_ERR_ARG; | |
784 | } | |
785 | ||
786 | authenticate(sdi); | |
787 | ||
788 | write_reg(sdi, 0x15, 0x03); | |
53012da6 UH |
789 | write_regs(sdi, ARRAY_AND_SIZE(regs_unknown)); |
790 | write_regs(sdi, ARRAY_AND_SIZE(regs_config)); | |
ca7d19b5 JL |
791 | |
792 | transact(sdi, start_req, sizeof(start_req), start_rsp, sizeof(start_rsp)); | |
793 | ||
794 | return SR_OK; | |
795 | } | |
796 | ||
b6189f7c | 797 | SR_PRIV int saleae_logic_pro_start(const struct sr_dev_inst *sdi) |
ca7d19b5 JL |
798 | { |
799 | struct dev_context *devc = sdi->priv; | |
800 | ||
801 | devc->conv_size = 0; | |
802 | devc->batch_index = 0; | |
803 | ||
804 | write_reg(sdi, 0x00, 0x01); | |
805 | ||
806 | return SR_OK; | |
807 | } | |
808 | ||
b6189f7c | 809 | SR_PRIV int saleae_logic_pro_stop(const struct sr_dev_inst *sdi) |
ca7d19b5 JL |
810 | { |
811 | uint8_t stop_req[] = {0x00, 0x02}; | |
812 | uint8_t stop_rsp[2] = {}; | |
da390890 JL |
813 | uint8_t status; |
814 | int ret; | |
ca7d19b5 JL |
815 | |
816 | write_reg(sdi, 0x00, 0x00); | |
817 | transact(sdi, stop_req, sizeof(stop_req), stop_rsp, sizeof(stop_rsp)); | |
818 | ||
da390890 JL |
819 | ret = read_reg(sdi, 0x40, &status); |
820 | if (ret != SR_OK) | |
821 | return ret; | |
822 | if (status != 0x20) { | |
823 | sr_err("Capture error (status reg = 0x%02x).", status); | |
824 | return SR_ERR; | |
825 | } | |
826 | ||
ca7d19b5 JL |
827 | return SR_OK; |
828 | } | |
829 | ||
b6189f7c | 830 | static void saleae_logic_pro_send_data(const struct sr_dev_inst *sdi, |
ca7d19b5 JL |
831 | void *data, size_t length, size_t unitsize) |
832 | { | |
833 | const struct sr_datafeed_logic logic = { | |
834 | .length = length, | |
835 | .unitsize = unitsize, | |
836 | .data = data | |
837 | }; | |
838 | ||
839 | const struct sr_datafeed_packet packet = { | |
840 | .type = SR_DF_LOGIC, | |
841 | .payload = &logic | |
842 | }; | |
843 | ||
844 | sr_session_send(sdi, &packet); | |
845 | } | |
846 | ||
847 | /* | |
848 | * One batch from the device consists of 32 samples per active digital channel. | |
849 | * This stream of batches is packed into USB packets with 16384 bytes each. | |
850 | */ | |
b6189f7c | 851 | static void saleae_logic_pro_convert_data(const struct sr_dev_inst *sdi, |
ca7d19b5 JL |
852 | const uint32_t *src, size_t srccnt) |
853 | { | |
854 | struct dev_context *devc = sdi->priv; | |
855 | uint8_t *dst = devc->conv_buffer; | |
856 | uint32_t samples; | |
857 | uint16_t channel_mask; | |
858 | unsigned int sample_index, batch_index; | |
859 | uint16_t *dst_batch; | |
860 | ||
bb0c5271 UH |
861 | /* Copy partial batch to the beginning. */ |
862 | memcpy(dst, dst + devc->conv_size, CONV_BATCH_SIZE); | |
863 | /* Reset converted size. */ | |
ca7d19b5 JL |
864 | devc->conv_size = 0; |
865 | ||
866 | batch_index = devc->batch_index; | |
867 | while (srccnt--) { | |
868 | samples = *src++; | |
869 | dst_batch = (uint16_t*)dst; | |
870 | ||
bb0c5271 | 871 | /* First index of the batch. */ |
ca7d19b5 JL |
872 | if (batch_index == 0) |
873 | memset(dst, 0, CONV_BATCH_SIZE); | |
874 | ||
bb0c5271 | 875 | /* Convert one channel. */ |
ca7d19b5 JL |
876 | channel_mask = devc->dig_channel_masks[batch_index]; |
877 | for (sample_index = 0; sample_index <= 31; sample_index++) | |
bb0c5271 | 878 | if ((samples >> (31 - sample_index)) & 1) |
ca7d19b5 JL |
879 | dst_batch[sample_index] |= channel_mask; |
880 | ||
bb0c5271 | 881 | /* Last index of the batch. */ |
ca7d19b5 JL |
882 | if (++batch_index == devc->dig_channel_cnt) { |
883 | devc->conv_size += CONV_BATCH_SIZE; | |
884 | batch_index = 0; | |
885 | dst += CONV_BATCH_SIZE; | |
886 | } | |
887 | } | |
888 | devc->batch_index = batch_index; | |
889 | } | |
890 | ||
b6189f7c | 891 | SR_PRIV void LIBUSB_CALL saleae_logic_pro_receive_data(struct libusb_transfer *transfer) |
ca7d19b5 JL |
892 | { |
893 | const struct sr_dev_inst *sdi = transfer->user_data; | |
894 | struct dev_context *devc = sdi->priv; | |
895 | int ret; | |
896 | ||
897 | switch (transfer->status) { | |
898 | case LIBUSB_TRANSFER_NO_DEVICE: | |
899 | sr_dbg("FIXME no device"); | |
900 | return; | |
901 | case LIBUSB_TRANSFER_COMPLETED: | |
902 | case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */ | |
903 | break; | |
904 | default: | |
bb0c5271 | 905 | /* FIXME */ |
ca7d19b5 JL |
906 | return; |
907 | } | |
908 | ||
bb0c5271 | 909 | saleae_logic_pro_convert_data(sdi, (uint32_t*)transfer->buffer, 16 * 1024 / 4); |
b6189f7c | 910 | saleae_logic_pro_send_data(sdi, devc->conv_buffer, devc->conv_size, 2); |
ca7d19b5 JL |
911 | |
912 | if ((ret = libusb_submit_transfer(transfer)) != LIBUSB_SUCCESS) | |
913 | sr_dbg("FIXME resubmit failed"); | |
a8e913c4 | 914 | } |