]> git.zerfleddert.de Git - usb-driver/blame - jtagkey.c
typo
[usb-driver] / jtagkey.c
CommitLineData
8121bc50 1#include <stdio.h>
2#include <ftdi.h>
9640dec9 3#include <unistd.h>
3cc5a0bc 4#include <pthread.h>
8121bc50 5#include "usb-driver.h"
5e3d963b 6#include "config.h"
8121bc50 7#include "jtagkey.h"
8
3cc5a0bc 9#define USBBUFSIZE 1048576
66c1fd53 10#define JTAG_SPEED 100000
f9318fa1 11#define BULK_LATENCY 2
12#define OTHER_LATENCY 1
d0e2002d 13
8121bc50 14static struct ftdi_context ftdic;
f9318fa1 15
16static int jtagkey_latency(int latency) {
17 static int current = 0;
18 int ret;
19
20 if (current != latency) {
21 DPRINTF("switching latency\n");
22 if ((ret = ftdi_set_latency_timer(&ftdic, latency)) != 0) {
23 fprintf(stderr, "unable to set latency timer: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
24 return ret;
25 }
26
27 current = latency;
28 }
29
30 return ret;
31}
8121bc50 32
5e3d963b 33static int jtagkey_init(unsigned short vid, unsigned short pid) {
8121bc50 34 int ret = 0;
d0e2002d 35 unsigned char c;
8121bc50 36
37 if ((ret = ftdi_init(&ftdic)) != 0) {
38 fprintf(stderr, "unable to initialise libftdi: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
39 return ret;
40 }
41
42 if ((ret = ftdi_usb_open(&ftdic, vid, pid)) != 0) {
43 fprintf(stderr, "unable to open ftdi device: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
44 return ret;
45 }
46
47 if ((ret = ftdi_usb_reset(&ftdic)) != 0) {
48 fprintf(stderr, "unable reset device: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
49 return ret;
50 }
51
52 if ((ret = ftdi_set_interface(&ftdic, INTERFACE_A)) != 0) {
53 fprintf(stderr, "unable to set interface: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
54 return ret;
55 }
56
3cc5a0bc 57 if ((ret = ftdi_write_data_set_chunksize(&ftdic, USBBUFSIZE)) != 0) {
58 fprintf(stderr, "unable to set write chunksize: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
59 return ret;
60 }
4af4753d 61
3cc5a0bc 62 if ((ret = ftdi_read_data_set_chunksize(&ftdic, USBBUFSIZE)) != 0) {
63 fprintf(stderr, "unable to set read chunksize: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
8121bc50 64 return ret;
65 }
66
f9318fa1 67 if ((ret = jtagkey_latency(OTHER_LATENCY)) != 0)
8121bc50 68 return ret;
8121bc50 69
d0e2002d 70 c = 0x00;
71 ftdi_write_data(&ftdic, &c, 1);
72
75417531 73 if ((ret = ftdi_set_bitmode(&ftdic, JTAGKEY_TCK|JTAGKEY_TDI|JTAGKEY_TMS|JTAGKEY_OEn, BITMODE_SYNCBB)) != 0) {
8121bc50 74 fprintf(stderr, "unable to enable bitbang mode: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
75 return ret;
76 }
77
66c1fd53 78 if ((ret = ftdi_set_baudrate(&ftdic, JTAG_SPEED)) != 0) {
79 fprintf(stderr, "unable to set baudrate: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
80 return ret;
81 }
82
8121bc50 83 if ((ret = ftdi_usb_purge_buffers(&ftdic)) != 0) {
84 fprintf(stderr, "unable to purge buffers: %d (%s)\n", ret, ftdi_get_error_string(&ftdic));
85 return ret;
86 }
87
88 return ret;
89}
90
5e3d963b 91int jtagkey_open(int num) {
92 int ret;
93
94 ret = jtagkey_init(config_usb_vid(num), config_usb_pid(num));
95
96 if (ret >= 0)
97 ret = 0xff;
98
99 return ret;
100}
101
102void jtagkey_close(int handle) {
103 if (handle == 0xff) {
104 ftdi_disable_bitbang(&ftdic);
105 ftdi_usb_close(&ftdic);
106 ftdi_deinit(&ftdic);
107 }
8121bc50 108}
109
110void jtagkey_state(unsigned char data) {
111 fprintf(stderr,"Pins high: ");
112
113 if (data & JTAGKEY_TCK)
114 fprintf(stderr,"TCK ");
115
116 if (data & JTAGKEY_TDI)
117 fprintf(stderr,"TDI ");
118
119 if (data & JTAGKEY_TDO)
120 fprintf(stderr,"TDO ");
121
122 if (data & JTAGKEY_TMS)
123 fprintf(stderr,"TMS ");
124
125 if (data & JTAGKEY_VREF)
126 fprintf(stderr,"VREF ");
127
128 fprintf(stderr,"\n");
129}
130
3cc5a0bc 131struct jtagkey_reader_arg {
132 int num;
133 unsigned char *buf;
134};
135
136static void *jtagkey_reader(void *thread_arg) {
137 struct jtagkey_reader_arg *arg = (struct jtagkey_reader_arg*)thread_arg;
3cc5a0bc 138 int i;
139
140 i = 0;
141 DPRINTF("reader for %d bytes\n", arg->num);
142 while (i < arg->num) {
143 i += ftdi_read_data(&ftdic, arg->buf + i, arg->num - i);
144 }
145
146 pthread_exit(NULL);
147}
148
617583d0 149/* TODO: Interpret JTAG commands and transfer in MPSSE mode */
8121bc50 150int jtagkey_transfer(WD_TRANSFER *tr, int fd, unsigned int request, int ppbase, int ecpbase, int num) {
151 int ret = 0;
152 int i;
d0e2002d 153 int nread = 0;
8121bc50 154 unsigned long port;
155 unsigned char val;
d0e2002d 156 static unsigned char last_data = 0;
e81047b8 157 static unsigned char last_write = 0x00;
d0e2002d 158 static unsigned char writebuf[USBBUFSIZE], *writepos = writebuf;
159 static unsigned char readbuf[USBBUFSIZE], *readpos;
617583d0 160 unsigned char data, prev_data, last_cyc_write;
3cc5a0bc 161 struct jtagkey_reader_arg targ;
162 pthread_t reader_thread;
d0e2002d 163
e81047b8 164 /* Count reads */
d0e2002d 165 for (i = 0; i < num; i++)
e81047b8 166 if (tr[i].cmdTrans == PP_READ)
d0e2002d 167 nread++;
168
169 /* Write combining */
170 if ((writepos-writebuf > sizeof(writebuf)-num) || (nread && writepos-writebuf)) {
4af4753d 171 unsigned char *pos = writebuf;
172 int len;
3cc5a0bc 173
d0e2002d 174 DPRINTF("writing %d bytes due to %d following reads in %d chunks or full buffer\n", writepos-writebuf, nread, num);
f9318fa1 175 jtagkey_latency(BULK_LATENCY);
d0e2002d 176
3cc5a0bc 177 targ.num = writepos-pos;
178 targ.buf = readbuf;
179 pthread_create(&reader_thread, NULL, &jtagkey_reader, &targ);
f9318fa1 180
4af4753d 181 while (pos < writepos) {
85690a3f 182 len = writepos-pos;
183
3cc5a0bc 184 if (len > USBBUFSIZE)
185 len = USBBUFSIZE;
d0e2002d 186
4af4753d 187 DPRINTF("combined write of %d/%d\n",len,writepos-pos);
188 ftdi_write_data(&ftdic, pos, len);
189 pos += len;
e81047b8 190 }
3cc5a0bc 191 pthread_join(reader_thread, NULL);
4af4753d 192
d0e2002d 193 writepos = writebuf;
194 }
8121bc50 195
617583d0 196 last_cyc_write = last_write;
197
8121bc50 198 for (i = 0; i < num; i++) {
199 DPRINTF("dwPort: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n",
200 (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes,
201 tr[i].fAutoinc, tr[i].dwOptions);
202
203 port = (unsigned long)tr[i].dwPort;
204 val = tr[i].Data.Byte;
205
206#ifdef DEBUG
207 if (tr[i].cmdTrans == 13)
208 DPRINTF("write byte: %d\n", val);
209#endif
210
b122ac4b 211 /* Pad writebuf for read-commands in stream */
d0e2002d 212 *writepos = last_data;
e81047b8 213 prev_data = last_data;
b122ac4b 214
8121bc50 215 if (port == ppbase + PP_DATA) {
216 DPRINTF("data port\n");
217
218 data = 0x00;
219 switch(tr[i].cmdTrans) {
220 case PP_READ:
221 ret = 0; /* We don't support reading of the data port */
222 break;
223
224 case PP_WRITE:
225 if (val & PP_TDI) {
226 data |= JTAGKEY_TDI;
227 DPRINTF("TDI\n");
228 } else {
229 DPRINTF("!TDI\n");
230 }
231 if (val & PP_TCK) {
232 data |= JTAGKEY_TCK;
233 DPRINTF("TCK\n");
234 } else {
235 DPRINTF("!TCK\n");
236 }
237 if (val & PP_TMS) {
238 data |= JTAGKEY_TMS;
239 DPRINTF("TMS\n");
240 } else {
241 DPRINTF("!TMS\n");
242 }
243 if (val & PP_CTRL) {
d0e2002d 244 data = JTAGKEY_OEn;
8121bc50 245 DPRINTF("CTRL\n");
246 } else {
247 DPRINTF("!CTRL\n");
248 }
8121bc50 249
d0e2002d 250 if (val & PP_PROG) {
251 DPRINTF("PROG\n");
252 } else {
253 DPRINTF("!PROG\n");
254 }
255
256 *writepos = data;
257
b122ac4b 258 last_data = data;
d0e2002d 259 last_write = val;
8121bc50 260 break;
261
262 default:
263 fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr[i].cmdTrans);
264 ret = -1;
265 break;
266 }
b122ac4b 267 }
e81047b8 268
617583d0 269 if ((tr[i].cmdTrans == PP_READ) || (*writepos != prev_data) || (i == num-1))
e81047b8 270 writepos++;
b122ac4b 271 }
272
d0e2002d 273 if (nread)
274 {
275 DPRINTF("writing %d bytes\n", writepos-writebuf);
59b06a85 276
277 *writepos = last_data;
278 writepos++;
279
f9318fa1 280 jtagkey_latency(OTHER_LATENCY);
281
3cc5a0bc 282 targ.num = writepos-writebuf;
283 targ.buf = readbuf;
284 pthread_create(&reader_thread, NULL, &jtagkey_reader, &targ);
9640dec9 285 ftdi_write_data(&ftdic, writebuf, writepos-writebuf);
3cc5a0bc 286 pthread_join(reader_thread, NULL);
b122ac4b 287
288#ifdef DEBUG
d0e2002d 289 DPRINTF("write: ");
290 hexdump(writebuf, writepos-writebuf);
291 DPRINTF("read: ");
292 hexdump(readbuf, i);
b122ac4b 293#endif
294
d0e2002d 295 writepos = writebuf;
296 } else {
297 return ret;
298 }
299
300 readpos = readbuf;
617583d0 301 last_write = last_cyc_write;
b122ac4b 302
303 for (i = 0; i < num; i++) {
304 DPRINTF("dwPort: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n",
305 (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes,
306 tr[i].fAutoinc, tr[i].dwOptions);
307
308 port = (unsigned long)tr[i].dwPort;
309 val = tr[i].Data.Byte;
617583d0 310
311 if ((tr[i].cmdTrans != PP_READ) && (val == last_write) && (i != num-1))
312 continue;
313
d0e2002d 314 readpos++;
b122ac4b 315
d0e2002d 316 if (port == ppbase + PP_DATA) {
317 if (tr[i].cmdTrans == PP_WRITE) {
318 last_write = val;
319 }
320 } else if (port == ppbase + PP_STATUS) {
321 DPRINTF("status port (last write: 0x%x)\n", last_write);
8121bc50 322 switch(tr[i].cmdTrans) {
323 case PP_READ:
d0e2002d 324 data = *readpos;
59b06a85 325
8121bc50 326#ifdef DEBUG
327 DPRINTF("READ: 0x%x\n", data);
328 jtagkey_state(data);
329#endif
330
331 val = 0x00;
d0e2002d 332 if ((data & JTAGKEY_TDO) && (last_write & PP_PROG))
8121bc50 333 val |= PP_TDO;
334
617583d0 335 if (~last_write & PP_PROG)
d0e2002d 336 val |= 0x08;
337
8121bc50 338 if (last_write & 0x40)
339 val |= 0x20;
340 else
341 val |= 0x80;
342 break;
343
344 case PP_WRITE:
345 ret = 0; /* Status Port is readonly */
346 break;
347
348 default:
349 fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr[i].cmdTrans);
350 ret = -1;
351 break;
352 }
8121bc50 353 } else {
8121bc50 354 ret = 0;
355 }
356
357 tr[i].Data.Byte = val;
358
359 DPRINTF("dwPortReturn: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n",
360 (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes,
361 tr[i].fAutoinc, tr[i].dwOptions);
362#ifdef DEBUG
363 if (tr[i].cmdTrans == 10)
364 DPRINTF("read byte: %d\n", tr[i].Data.Byte);
365#endif
366 }
367
368 return ret;
369}
Impressum, Datenschutz