]>
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 | ||
220 | return write_regs(sdi, regs, G_N_ELEMENTS(regs)); | |
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 | ||
533 | ret = SR_OK; | |
534 | ||
535 | sr_info("Bitstream upload done."); | |
536 | ||
537 | /* Check a scratch register? */ | |
538 | ret = write_reg(sdi, 0x7f, 0xaa); | |
539 | if (ret != SR_OK) | |
540 | goto out; | |
541 | ret = read_reg(sdi, 0x7f, ®_val); | |
542 | if (ret != SR_OK) | |
543 | goto out; | |
544 | if (reg_val != 0xaa) { | |
545 | sr_err("Failed FPGA register read-back (0x%02x != 0xaa).", rsp[0]); | |
546 | ret = SR_ERR; | |
547 | goto out; | |
548 | } | |
549 | ||
550 | out: | |
551 | g_free(bitstream); | |
552 | ||
553 | return ret; | |
554 | } | |
555 | ||
fbbafc69 | 556 | #if 0 |
ca7d19b5 JL |
557 | static int set_led(const struct sr_dev_inst *sdi, uint8_t r, uint8_t g, uint8_t b) |
558 | { | |
559 | uint8_t regs[][2] = { | |
560 | {REG_LED_RED, r}, | |
561 | {REG_LED_GREEN, g}, | |
562 | {REG_LED_BLUE, b}, | |
563 | }; | |
564 | ||
565 | authenticate(sdi); | |
566 | ||
567 | return write_regs(sdi, regs, G_N_ELEMENTS(regs)); | |
568 | } | |
fbbafc69 | 569 | #endif |
ca7d19b5 JL |
570 | |
571 | static int configure_channels(const struct sr_dev_inst *sdi) | |
572 | { | |
573 | struct dev_context *devc = sdi->priv; | |
574 | const struct sr_channel *c; | |
575 | const GSList *l; | |
576 | uint16_t mask; | |
577 | ||
578 | devc->dig_channel_cnt = 0; | |
579 | devc->dig_channel_mask = 0; | |
580 | for (l = sdi->channels; l; l = l->next) { | |
581 | c = l->data; | |
582 | if (!c->enabled) | |
583 | continue; | |
584 | ||
585 | mask = 1 << c->index; | |
586 | devc->dig_channel_masks[devc->dig_channel_cnt++] = mask; | |
587 | devc->dig_channel_mask |= mask; | |
588 | ||
589 | } | |
590 | sr_dbg("%d channels enabled (0x%04x)", | |
bb0c5271 | 591 | devc->dig_channel_cnt, devc->dig_channel_mask); |
ca7d19b5 JL |
592 | |
593 | return SR_OK; | |
594 | } | |
595 | ||
b6189f7c | 596 | SR_PRIV int saleae_logic_pro_init(const struct sr_dev_inst *sdi) |
ca7d19b5 | 597 | { |
da390890 JL |
598 | uint8_t reg_val; |
599 | uint8_t dummy[8]; | |
600 | uint8_t serial[8]; | |
601 | uint8_t magic[16]; | |
602 | int8_t temperature; | |
603 | int ret, i; | |
604 | ||
605 | ret = reseed(sdi); | |
606 | if (ret != SR_OK) | |
607 | return ret; | |
608 | ||
609 | ret = get_firmware_version(sdi); | |
610 | if (ret != SR_OK) | |
611 | return ret; | |
612 | ||
613 | sr_dbg("read serial"); | |
614 | ret = read_eeprom_serial(sdi, serial); | |
615 | if (ret != SR_OK) | |
616 | return ret; | |
617 | ||
618 | /* Check if we need to upload the bitstream. */ | |
619 | ret = read_reg(sdi, 0x7f, ®_val); | |
620 | if (ret != SR_OK) | |
621 | return ret; | |
622 | if (reg_val == 0xaa) { | |
623 | sr_info("Skipping bitstream upload."); | |
624 | } else { | |
625 | ret = upload_bitstream(sdi, "saleae-logicpro16-fpga.bitstream"); | |
626 | if (ret != SR_OK) | |
627 | return ret; | |
628 | } | |
629 | ||
630 | /* Reset the ADC? */ | |
631 | sr_dbg("reset ADC"); | |
632 | ret = write_reg(sdi, 0x00, 0x00); | |
633 | if (ret != SR_OK) | |
634 | return ret; | |
635 | ret = write_reg(sdi, 0x00, 0x80); | |
636 | if (ret != SR_OK) | |
637 | return ret; | |
638 | ||
639 | sr_dbg("init ADC"); | |
640 | ret = write_adc(sdi, 0x11, 0x0444); | |
641 | if (ret != SR_OK) | |
642 | return ret; | |
643 | ret = write_adc(sdi, 0x12, 0x0777); | |
644 | if (ret != SR_OK) | |
645 | return ret; | |
646 | ret = write_adc(sdi, 0x25, 0x0000); | |
647 | if (ret != SR_OK) | |
648 | return ret; | |
649 | ret = write_adc(sdi, 0x45, 0x0000); | |
650 | if (ret != SR_OK) | |
651 | return ret; | |
652 | ret = write_adc(sdi, 0x2a, 0x1111); | |
653 | if (ret != SR_OK) | |
654 | return ret; | |
655 | ret = write_adc(sdi, 0x2b, 0x1111); | |
656 | if (ret != SR_OK) | |
657 | return ret; | |
658 | ret = write_adc(sdi, 0x46, 0x0004); | |
659 | if (ret != SR_OK) | |
660 | return ret; | |
661 | ret = write_adc(sdi, 0x50, 0x0000); | |
662 | if (ret != SR_OK) | |
663 | return ret; | |
664 | ret = write_adc(sdi, 0x55, 0x0020); | |
665 | if (ret != SR_OK) | |
666 | return ret; | |
667 | ret = write_adc(sdi, 0x56, 0x0000); | |
668 | if (ret != SR_OK) | |
669 | return ret; | |
670 | ||
671 | ret = write_reg(sdi, 0x15, 0x00); | |
672 | if (ret != SR_OK) | |
673 | return ret; | |
674 | ||
675 | ret = write_adc(sdi, 0x0f, 0x0100); | |
676 | if (ret != SR_OK) | |
677 | return ret; | |
678 | ||
679 | /* Resets? */ | |
680 | sr_dbg("resets"); | |
681 | ret = write_reg(sdi, 0x00, 0x02); /* bit 1 */ | |
682 | if (ret != SR_OK) | |
683 | return ret; | |
684 | ret = write_reg(sdi, 0x00, 0x00); | |
685 | if (ret != SR_OK) | |
686 | return ret; | |
687 | ret = write_reg(sdi, 0x00, 0x04); /* bit 2 */ | |
688 | if (ret != SR_OK) | |
689 | return ret; | |
690 | ret = write_reg(sdi, 0x00, 0x00); | |
691 | if (ret != SR_OK) | |
692 | return ret; | |
693 | ret = write_reg(sdi, 0x00, 0x08); /* bit 3 */ | |
694 | if (ret != SR_OK) | |
695 | return ret; | |
696 | ret = write_reg(sdi, 0x00, 0x00); | |
697 | if (ret != SR_OK) | |
698 | return ret; | |
699 | ||
700 | sr_dbg("read dummy"); | |
701 | for (i = 0; i < 8; i++) { | |
702 | ret = read_reg(sdi, 0x41 + i, &dummy[i]); | |
703 | if (ret != SR_OK) | |
704 | return ret; | |
705 | } | |
706 | ||
707 | /* Read and write back magic EEPROM value. */ | |
708 | sr_dbg("read/write magic"); | |
709 | ret = read_eeprom_magic(sdi, magic); | |
710 | if (ret != SR_OK) | |
711 | return ret; | |
712 | for (i = 0; i < 16; i++) { | |
713 | ret = write_reg(sdi, 0x17, magic[i]); | |
714 | if (ret != SR_OK) | |
715 | return ret; | |
716 | } | |
717 | ||
718 | ret = read_temperature(sdi, &temperature); | |
719 | if (ret != SR_OK) | |
720 | return ret; | |
721 | sr_dbg("temperature = %d", temperature); | |
722 | ||
bb0c5271 | 723 | /* Setting the LED doesn't work yet. */ |
ca7d19b5 JL |
724 | /* set_led(sdi, 0x00, 0x00, 0xff); */ |
725 | ||
726 | return SR_OK; | |
727 | } | |
728 | ||
b6189f7c | 729 | SR_PRIV int saleae_logic_pro_prepare(const struct sr_dev_inst *sdi) |
ca7d19b5 JL |
730 | { |
731 | struct dev_context *devc = sdi->priv; | |
732 | uint8_t regs_unknown[][2] = { | |
733 | {0x03, 0x0f}, | |
734 | {0x04, 0x00}, | |
735 | {0x05, 0x00}, | |
736 | }; | |
737 | uint8_t regs_config[][2] = { | |
738 | {0x00, 0x00}, | |
bb0c5271 UH |
739 | {0x08, 0x00}, /* Analog channel mask (LSB) */ |
740 | {0x09, 0x00}, /* Analog channel mask (MSB) */ | |
741 | {0x06, 0x01}, /* Digital channel mask (LSB) */ | |
742 | {0x07, 0x00}, /* Digital channel mask (MSB) */ | |
743 | {0x0a, 0x00}, /* Analog sample rate? */ | |
744 | {0x0b, 0x64}, /* Digital sample rate? */ | |
ca7d19b5 | 745 | {0x0c, 0x00}, |
bb0c5271 UH |
746 | {0x0d, 0x00}, /* Analog mux rate? */ |
747 | {0x0e, 0x01}, /* Digital mux rate? */ | |
ca7d19b5 JL |
748 | {0x12, 0x04}, |
749 | {0x13, 0x00}, | |
bb0c5271 | 750 | {0x14, 0xff}, /* Pre-divider? */ |
ca7d19b5 JL |
751 | }; |
752 | uint8_t start_req[] = {0x00, 0x01}; | |
753 | uint8_t start_rsp[2] = {}; | |
754 | ||
755 | configure_channels(sdi); | |
756 | ||
bb0c5271 | 757 | /* Digital channel mask and muxing */ |
ca7d19b5 JL |
758 | regs_config[3][1] = devc->dig_channel_mask; |
759 | regs_config[4][1] = devc->dig_channel_mask >> 8; | |
760 | regs_config[9][1] = devc->dig_channel_cnt; | |
761 | ||
bb0c5271 | 762 | /* Samplerate */ |
ca7d19b5 JL |
763 | switch (devc->dig_samplerate) { |
764 | case SR_MHZ(1): | |
765 | regs_config[6][1] = 0x64; | |
766 | break; | |
767 | case SR_MHZ(2): | |
768 | regs_config[6][1] = 0x32; | |
769 | break; | |
770 | case SR_KHZ(2500): | |
771 | regs_config[6][1] = 0x28; | |
772 | break; | |
773 | case SR_MHZ(10): | |
774 | regs_config[6][1] = 0x0a; | |
775 | break; | |
776 | case SR_MHZ(25): | |
777 | regs_config[6][1] = 0x04; | |
778 | regs_config[12][1] = 0x80; | |
779 | break; | |
780 | case SR_MHZ(50): | |
781 | regs_config[6][1] = 0x02; | |
782 | regs_config[12][1] = 0x40; | |
783 | break; | |
784 | default: | |
785 | return SR_ERR_ARG; | |
786 | } | |
787 | ||
788 | authenticate(sdi); | |
789 | ||
790 | write_reg(sdi, 0x15, 0x03); | |
791 | write_regs(sdi, regs_unknown, G_N_ELEMENTS(regs_unknown)); | |
792 | write_regs(sdi, regs_config, G_N_ELEMENTS(regs_config)); | |
793 | ||
794 | transact(sdi, start_req, sizeof(start_req), start_rsp, sizeof(start_rsp)); | |
795 | ||
796 | return SR_OK; | |
797 | } | |
798 | ||
b6189f7c | 799 | SR_PRIV int saleae_logic_pro_start(const struct sr_dev_inst *sdi) |
ca7d19b5 JL |
800 | { |
801 | struct dev_context *devc = sdi->priv; | |
802 | ||
803 | devc->conv_size = 0; | |
804 | devc->batch_index = 0; | |
805 | ||
806 | write_reg(sdi, 0x00, 0x01); | |
807 | ||
808 | return SR_OK; | |
809 | } | |
810 | ||
b6189f7c | 811 | SR_PRIV int saleae_logic_pro_stop(const struct sr_dev_inst *sdi) |
ca7d19b5 JL |
812 | { |
813 | uint8_t stop_req[] = {0x00, 0x02}; | |
814 | uint8_t stop_rsp[2] = {}; | |
da390890 JL |
815 | uint8_t status; |
816 | int ret; | |
ca7d19b5 JL |
817 | |
818 | write_reg(sdi, 0x00, 0x00); | |
819 | transact(sdi, stop_req, sizeof(stop_req), stop_rsp, sizeof(stop_rsp)); | |
820 | ||
da390890 JL |
821 | ret = read_reg(sdi, 0x40, &status); |
822 | if (ret != SR_OK) | |
823 | return ret; | |
824 | if (status != 0x20) { | |
825 | sr_err("Capture error (status reg = 0x%02x).", status); | |
826 | return SR_ERR; | |
827 | } | |
828 | ||
ca7d19b5 JL |
829 | return SR_OK; |
830 | } | |
831 | ||
b6189f7c | 832 | static void saleae_logic_pro_send_data(const struct sr_dev_inst *sdi, |
ca7d19b5 JL |
833 | void *data, size_t length, size_t unitsize) |
834 | { | |
835 | const struct sr_datafeed_logic logic = { | |
836 | .length = length, | |
837 | .unitsize = unitsize, | |
838 | .data = data | |
839 | }; | |
840 | ||
841 | const struct sr_datafeed_packet packet = { | |
842 | .type = SR_DF_LOGIC, | |
843 | .payload = &logic | |
844 | }; | |
845 | ||
846 | sr_session_send(sdi, &packet); | |
847 | } | |
848 | ||
849 | /* | |
850 | * One batch from the device consists of 32 samples per active digital channel. | |
851 | * This stream of batches is packed into USB packets with 16384 bytes each. | |
852 | */ | |
b6189f7c | 853 | static void saleae_logic_pro_convert_data(const struct sr_dev_inst *sdi, |
ca7d19b5 JL |
854 | const uint32_t *src, size_t srccnt) |
855 | { | |
856 | struct dev_context *devc = sdi->priv; | |
857 | uint8_t *dst = devc->conv_buffer; | |
858 | uint32_t samples; | |
859 | uint16_t channel_mask; | |
860 | unsigned int sample_index, batch_index; | |
861 | uint16_t *dst_batch; | |
862 | ||
bb0c5271 UH |
863 | /* Copy partial batch to the beginning. */ |
864 | memcpy(dst, dst + devc->conv_size, CONV_BATCH_SIZE); | |
865 | /* Reset converted size. */ | |
ca7d19b5 JL |
866 | devc->conv_size = 0; |
867 | ||
868 | batch_index = devc->batch_index; | |
869 | while (srccnt--) { | |
870 | samples = *src++; | |
871 | dst_batch = (uint16_t*)dst; | |
872 | ||
bb0c5271 | 873 | /* First index of the batch. */ |
ca7d19b5 JL |
874 | if (batch_index == 0) |
875 | memset(dst, 0, CONV_BATCH_SIZE); | |
876 | ||
bb0c5271 | 877 | /* Convert one channel. */ |
ca7d19b5 JL |
878 | channel_mask = devc->dig_channel_masks[batch_index]; |
879 | for (sample_index = 0; sample_index <= 31; sample_index++) | |
bb0c5271 | 880 | if ((samples >> (31 - sample_index)) & 1) |
ca7d19b5 JL |
881 | dst_batch[sample_index] |= channel_mask; |
882 | ||
bb0c5271 | 883 | /* Last index of the batch. */ |
ca7d19b5 JL |
884 | if (++batch_index == devc->dig_channel_cnt) { |
885 | devc->conv_size += CONV_BATCH_SIZE; | |
886 | batch_index = 0; | |
887 | dst += CONV_BATCH_SIZE; | |
888 | } | |
889 | } | |
890 | devc->batch_index = batch_index; | |
891 | } | |
892 | ||
b6189f7c | 893 | SR_PRIV void LIBUSB_CALL saleae_logic_pro_receive_data(struct libusb_transfer *transfer) |
ca7d19b5 JL |
894 | { |
895 | const struct sr_dev_inst *sdi = transfer->user_data; | |
896 | struct dev_context *devc = sdi->priv; | |
897 | int ret; | |
898 | ||
899 | switch (transfer->status) { | |
900 | case LIBUSB_TRANSFER_NO_DEVICE: | |
901 | sr_dbg("FIXME no device"); | |
902 | return; | |
903 | case LIBUSB_TRANSFER_COMPLETED: | |
904 | case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */ | |
905 | break; | |
906 | default: | |
bb0c5271 | 907 | /* FIXME */ |
ca7d19b5 JL |
908 | return; |
909 | } | |
910 | ||
bb0c5271 | 911 | saleae_logic_pro_convert_data(sdi, (uint32_t*)transfer->buffer, 16 * 1024 / 4); |
b6189f7c | 912 | saleae_logic_pro_send_data(sdi, devc->conv_buffer, devc->conv_size, 2); |
ca7d19b5 JL |
913 | |
914 | if ((ret = libusb_submit_transfer(transfer)) != LIBUSB_SUCCESS) | |
915 | sr_dbg("FIXME resubmit failed"); | |
a8e913c4 | 916 | } |