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