- prepare OpenOCD for branching, created ./trunk/
[fw/openocd] / src / jtag / ftdi2232.c
1 /***************************************************************************
2  *   Copyright (C) 2004 by Dominic Rath                                    *
3  *   Dominic.Rath@gmx.de                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 /* project specific includes */
22 #include "log.h"
23 #include "types.h"
24 #include "jtag.h"
25 #include "configuration.h"
26 #include "command.h"
27
28 /* system includes */
29 #include <string.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <usb.h>
33 #include <ftdi.h>
34
35 #include <sys/time.h>
36 #include <time.h>
37
38 /* enable this to debug io latency
39  */
40 #if 0
41 #define _DEBUG_USB_IO_
42 #endif
43
44 int ftdi2232_execute_queue(void);
45
46 int ftdi2232_speed(int speed);
47 int ftdi2232_register_commands(struct command_context_s *cmd_ctx);
48 int ftdi2232_init(void);
49 int ftdi2232_quit(void);
50
51 enum { FTDI2232_TRST = 0x10, FTDI2232_SRST = 0x40 };
52 static u8 discrete_output = 0x0 | FTDI2232_TRST | FTDI2232_SRST;
53 static struct ftdi_context ftdic;
54
55 static u8 *ftdi2232_buffer = NULL;
56 static int ftdi2232_buffer_size = 0;
57 static int ftdi2232_read_pointer = 0;
58 static int ftdi2232_expect_read = 0;
59 #define FTDI2232_BUFFER_SIZE    131072
60 #define BUFFER_ADD ftdi2232_buffer[ftdi2232_buffer_size++]
61 #define BUFFER_READ ftdi2232_buffer[ftdi2232_read_pointer++]
62
63 #define FTDI2232_SAVE_SIZE      1024
64
65 int ftdi2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
66
67 static u16 ftdi2232_vid = 0x0403;
68 static u16 ftdi2232_pid = 0x6010;
69
70 jtag_interface_t ftdi2232_interface = 
71 {
72         
73         .name = "ftdi2232",
74         
75         .execute_queue = ftdi2232_execute_queue,
76         
77         .support_statemove = 1,
78         
79         .speed = ftdi2232_speed,
80         .register_commands = ftdi2232_register_commands,
81         .init = ftdi2232_init,
82         .quit = ftdi2232_quit,
83 };
84
85 int ftdi2232_speed(int speed)
86 {
87         u8 buf[3];
88
89         buf[0] = 0x86; /* command "set divisor" */
90         buf[1] = speed & 0xff; /* valueL (0=6MHz, 1=3MHz, 2=1.5MHz, ...*/
91         buf[2] = (speed >> 8) & 0xff; /* valueH */
92         
93         DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
94         ftdi_write_data(&ftdic, buf, 3);
95
96         return ERROR_OK;
97 }
98
99 int ftdi2232_register_commands(struct command_context_s *cmd_ctx)
100 {
101         register_command(cmd_ctx, NULL, "ftdi2232_vid_pid", ftdi2232_handle_vid_pid_command,
102                 COMMAND_CONFIG, NULL);
103         
104         return ERROR_OK;
105 }
106
107 void ftdi2232_end_state(state)
108 {
109         if (tap_move_map[state] != -1)
110                 end_state = state;
111         else
112         {
113                 ERROR("BUG: %i is not a valid end state", state);
114                 exit(-1);
115         }
116 }
117
118 void ftdi2232_read_scan(enum scan_type type, u8* buffer, int scan_size)
119 {
120         int num_bytes = ((scan_size + 7) / 8);
121         int bits_left = scan_size;
122         int cur_byte = 0;
123
124         while(num_bytes-- > 1)
125         {
126                 buffer[cur_byte] = BUFFER_READ;
127                 cur_byte++;
128                 bits_left -= 8;
129         }
130
131         buffer[cur_byte] = 0x0;
132
133         if (bits_left > 1)
134         {
135                 buffer[cur_byte] = BUFFER_READ >> 1;
136         }
137
138         buffer[cur_byte] = (buffer[cur_byte] | ((BUFFER_READ & 0x02) << 6)) >> (8 - bits_left);
139
140 }
141
142 void ftdi2232_debug_dump_buffer(void)
143 {
144         int i;
145         for (i = 0; i < ftdi2232_buffer_size; i++)
146         {
147                 printf("%2.2x ", ftdi2232_buffer[i]);
148                 if (i % 16 == 15)
149                         printf("\n");
150         }
151         printf("\n");
152         fflush(stdout);
153 }
154
155 int ftdi2232_send_and_recv(jtag_command_t *first, jtag_command_t *last)
156 {
157         jtag_command_t *cmd;
158         u8 *buffer;
159         int scan_size;
160         enum scan_type type;
161         int retval;
162
163         BUFFER_ADD = 0x87;      /* send immediate command */
164         
165         if (ftdi2232_buffer_size > FTDI2232_SAVE_SIZE)
166         {
167                 ERROR("BUG: ftdi2232_buffer grew beyond %i byte (%i) - this is going to fail", FTDI2232_SAVE_SIZE,  ftdi2232_buffer_size);
168         }
169
170 #ifdef _DEBUG_USB_IO_
171         DEBUG("write buffer (size %i):", ftdi2232_buffer_size);
172         ftdi2232_debug_dump_buffer();
173 #endif
174
175         if ((retval = ftdi_write_data(&ftdic, ftdi2232_buffer, ftdi2232_buffer_size)) < 0)
176         {
177                 ERROR("ftdi_write_data returned %i", retval);
178                 exit(-1);
179         }
180
181         if (ftdi2232_expect_read)
182         {
183                 int timeout = 100;
184                 ftdi2232_buffer_size = 0;
185                 
186                 while ((ftdi2232_buffer_size < ftdi2232_expect_read) && timeout)
187                 {
188                         ftdi2232_buffer_size += ftdi_read_data(&ftdic, ftdi2232_buffer + ftdi2232_buffer_size, FTDI2232_BUFFER_SIZE - ftdi2232_buffer_size);
189                         timeout--;
190                 }
191
192                 if (ftdi2232_expect_read != ftdi2232_buffer_size)
193                 {
194                         ERROR("ftdi2232_expect_read (%i) != ftdi2232_buffer_size (%i) (%i retries)", ftdi2232_expect_read, ftdi2232_buffer_size, 100 - timeout);
195                         ftdi2232_debug_dump_buffer();
196
197                         exit(-1);
198                 }
199
200 #ifdef _DEBUG_USB_IO_
201                 DEBUG("read buffer (%i retries): %i bytes", 100 - timeout, ftdi2232_buffer_size);
202                 ftdi2232_debug_dump_buffer();   
203 #endif
204         }
205
206         ftdi2232_expect_read = 0;
207         ftdi2232_read_pointer = 0;
208
209         cmd = first;
210         while (cmd != last)
211         {
212                 switch (cmd->type)
213                 {
214                         case JTAG_SCAN:
215                                 type = jtag_scan_type(cmd->cmd.scan);
216                                 if (type != SCAN_OUT)
217                                 {
218                                         scan_size = jtag_scan_size(cmd->cmd.scan);
219                                         buffer = calloc(CEIL(scan_size, 8), 1);
220                                         ftdi2232_read_scan(type, buffer, scan_size);
221                                         jtag_read_buffer(buffer, cmd->cmd.scan);
222                                         free(buffer);
223                                 }
224                                 break;
225                         default:
226                                 break;
227                 }
228                 cmd = cmd->next;
229         }
230         
231         ftdi2232_buffer_size = 0;
232
233         return ERROR_OK;
234 }
235
236 void ftdi2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
237 {
238         int num_bytes = (scan_size + 7) / 8;
239         int bits_left = scan_size;
240         int cur_byte = 0;
241         int last_bit;
242
243         /* command "Clock Data to TMS/CS Pin (no Read)" */
244         BUFFER_ADD = 0x4b;
245         /* scan 7 bit */
246         BUFFER_ADD = 0x6;
247         /* TMS data bits */
248         if (ir_scan)
249         {
250                 BUFFER_ADD = TAP_MOVE(cur_state, TAP_SI);
251                 cur_state = TAP_SI;
252         }
253         else
254         {
255                 BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD);
256                 cur_state = TAP_SD;
257         }
258         //DEBUG("added TMS scan (no read)");
259
260         /* add command for complete bytes */
261         if (num_bytes > 1)
262         {
263                 if (type == SCAN_IO)
264                 {
265                         /* Clock Data Bytes In and Out LSB First */
266                         BUFFER_ADD = 0x39;
267                         //DEBUG("added TDI bytes (io %i)", num_bytes);
268                 }
269                 else if (type == SCAN_OUT)
270                 {
271                         /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */
272                         BUFFER_ADD = 0x19;
273                         //DEBUG("added TDI bytes (o)");
274                 }
275                 else if (type == SCAN_IN)
276                 {
277                         /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */
278                         BUFFER_ADD = 0x28;
279                         //DEBUG("added TDI bytes (i %i)", num_bytes);
280                 }
281                 BUFFER_ADD = (num_bytes-2) & 0xff;
282                 BUFFER_ADD = ((num_bytes-2) >> 8) & 0xff;
283         }
284         if (type != SCAN_IN)
285         {
286                 /* add complete bytes */
287                 while(num_bytes-- > 1)
288                 {
289                         BUFFER_ADD = buffer[cur_byte];
290                         cur_byte++;
291                         bits_left -= 8;
292                 }
293         }
294         if (type == SCAN_IN)
295         {
296                 bits_left -= 8 * (num_bytes - 1);
297         }
298
299         /* the most signifcant bit is scanned during TAP movement */
300         if (type != SCAN_IN)
301                 last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1;
302         else
303                 last_bit = 0;
304
305         /* process remaining bits but the last one */
306         if (bits_left > 1)
307         {
308                 if (type == SCAN_IO)
309                 {
310                         /* Clock Data Bits In and Out LSB First */
311                         BUFFER_ADD = 0x3b;
312                         //DEBUG("added TDI bits (io) %i", bits_left - 1);
313                 }
314                 else if (type == SCAN_OUT)
315                 {
316                         /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */
317                         BUFFER_ADD = 0x1b;
318                         //DEBUG("added TDI bits (o)");
319                 }
320                 else if (type == SCAN_IN)
321                 {
322                         /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */
323                         BUFFER_ADD = 0x2a;
324                         //DEBUG("added TDI bits (i %i)", bits_left - 1);
325                 }
326                 BUFFER_ADD = bits_left - 2;
327                 if (type != SCAN_IN)
328                         BUFFER_ADD = buffer[cur_byte];
329         }
330
331         /* move from Shift-IR/DR to end state */
332         if (type != SCAN_OUT)
333         {
334                 /* Clock Data to TMS/CS Pin with Read */
335                 BUFFER_ADD = 0x6b;
336                 //DEBUG("added TMS scan (read)");
337         }
338         else
339         {
340                 /* Clock Data to TMS/CS Pin (no Read) */
341                 BUFFER_ADD = 0x4b;
342                 //DEBUG("added TMS scan (no read)");
343         }
344         BUFFER_ADD = 0x6;
345         BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7);
346         cur_state = end_state;
347
348 }
349
350 int ftdi2232_predict_scan_out(int scan_size, enum scan_type type)
351 {
352         int predicted_size = 6;
353         if (type == SCAN_IN)    /* only from device to host */
354         {
355                 predicted_size += (CEIL(scan_size, 8) > 1) ? 3 : 0;
356                 predicted_size += ((scan_size - 1) % 8) ? 2 : 0;
357         }
358         else                                    /* host to device, or bidirectional */
359         {
360                 predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) + 3 - 1) : 0;
361                 predicted_size += ((scan_size - 1) % 8) ? 3 : 0;
362         }
363
364         return predicted_size;
365 }
366
367 int ftdi2232_predict_scan_in(int scan_size, enum scan_type type)
368 {
369         int predicted_size = 0;
370         
371         if (type != SCAN_OUT)
372         {
373                 /* complete bytes */
374                 predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) - 1) : 0;
375                 /* remaining bits - 1 */
376                 predicted_size += ((scan_size - 1) % 8) ? 1 : 0;
377                 /* last bit (from TMS scan) */
378                 predicted_size += 1;
379         }
380         
381         //DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size);
382
383         return predicted_size;
384 }
385
386 int ftdi2232_execute_queue()
387 {
388         jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
389         jtag_command_t *first_unsent = cmd;     /* next command that has to be sent */
390         u8 *buffer;
391         int scan_size;  /* size of IR or DR scan */
392         enum scan_type type;
393         int i;
394         int predicted_size = 0;
395         int require_send = 0;
396
397         ftdi2232_buffer_size = 0;
398         ftdi2232_expect_read = 0;
399
400         while (cmd)
401         {
402                 switch(cmd->type)
403                 {
404                         case JTAG_END_STATE:
405                                 if (cmd->cmd.end_state->end_state != -1)
406                                         ftdi2232_end_state(cmd->cmd.end_state->end_state);
407                                 break;
408                         case JTAG_RESET:
409                                 /* only send the maximum buffer size that FT2232C can handle */
410                                 predicted_size = 3;
411                                 if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
412                                 {
413                                         ftdi2232_send_and_recv(first_unsent, cmd);
414                                         require_send = 0;
415                                         first_unsent = cmd;
416                                 }
417
418                                 if (cmd->cmd.reset->trst == 1)
419                                 {
420                                         cur_state = TAP_TLR;
421                                         discrete_output &= ~FTDI2232_TRST;
422                                 }
423                                 else if (cmd->cmd.reset->trst == 0)
424                                 {
425                                         discrete_output |= FTDI2232_TRST;
426                                 }
427
428                                 if (cmd->cmd.reset->srst == 1)
429                                         discrete_output &= ~FTDI2232_SRST;
430                                 else if (cmd->cmd.reset->srst == 0)
431                                         discrete_output |= FTDI2232_SRST;
432                                 /* command "set data bits low byte" */
433                                 BUFFER_ADD = 0x80;
434                                 /* value (TMS=1,TCK=0, TDI=0, TRST/SRST */
435                                 BUFFER_ADD = 0x08 | discrete_output;
436                                 /* dir (output=1), TCK/TDI/TMS=out, TDO=in, TRST/SRST=out */
437                                 BUFFER_ADD = 0x0b | FTDI2232_SRST | FTDI2232_TRST;
438                                 require_send = 1;
439                                 break;
440                         case JTAG_RUNTEST:
441                                 /* only send the maximum buffer size that FT2232C can handle */
442                                 predicted_size = 0;
443                                 if (cur_state != TAP_RTI)
444                                         predicted_size += 3;
445                                 predicted_size += 3 * CEIL(cmd->cmd.runtest->num_cycles, 7);
446                                 if ((cmd->cmd.runtest->end_state != -1) && (cmd->cmd.runtest->end_state != TAP_RTI))
447                                         predicted_size += 3;
448                                 if ((cmd->cmd.runtest->end_state == -1) && (end_state != TAP_RTI))
449                                         predicted_size += 3;
450                                 if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
451                                 {
452                                         ftdi2232_send_and_recv(first_unsent, cmd);
453                                         require_send = 0;
454                                         first_unsent = cmd;
455                                 }
456                                 if (cur_state != TAP_RTI)
457                                 {
458                                         /* command "Clock Data to TMS/CS Pin (no Read)" */
459                                         BUFFER_ADD = 0x4b;
460                                         /* scan 7 bit */
461                                         BUFFER_ADD = 0x6;
462                                         /* TMS data bits */
463                                         BUFFER_ADD = TAP_MOVE(cur_state, TAP_RTI);
464                                         cur_state = TAP_RTI;
465                                         require_send = 1;
466                                 }
467                                 i = cmd->cmd.runtest->num_cycles;
468                                 while (i > 0)
469                                 {
470                                         /* command "Clock Data to TMS/CS Pin (no Read)" */
471                                         BUFFER_ADD = 0x4b;
472                                         /* scan 7 bit */
473                                         BUFFER_ADD = (i > 7) ? 6 : (i - 1);
474                                         /* TMS data bits */
475                                         BUFFER_ADD = 0x0;
476                                         cur_state = TAP_RTI;
477                                         i -= (i > 7) ? 7 : i;
478                                         //DEBUG("added TMS scan (no read)");
479                                 }
480                                 if (cmd->cmd.runtest->end_state != -1)
481                                         ftdi2232_end_state(cmd->cmd.runtest->end_state);
482                                 if (cur_state != end_state)
483                                 {
484                                         /* command "Clock Data to TMS/CS Pin (no Read)" */
485                                         BUFFER_ADD = 0x4b;
486                                         /* scan 7 bit */
487                                         BUFFER_ADD = 0x6;
488                                         /* TMS data bits */
489                                         BUFFER_ADD = TAP_MOVE(cur_state, end_state);
490                                         cur_state = end_state;
491                                         //DEBUG("added TMS scan (no read)");
492                                 }
493                                 require_send = 1;
494                                 break;
495                         case JTAG_STATEMOVE:
496                                 /* only send the maximum buffer size that FT2232C can handle */
497                                 predicted_size = 3;
498                                 if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
499                                 {
500                                         ftdi2232_send_and_recv(first_unsent, cmd);
501                                         require_send = 0;
502                                         first_unsent = cmd;
503                                 }
504                                 if (cmd->cmd.statemove->end_state != -1)
505                                         ftdi2232_end_state(cmd->cmd.statemove->end_state);
506                                 /* command "Clock Data to TMS/CS Pin (no Read)" */
507                                 BUFFER_ADD = 0x4b;
508                                 /* scan 7 bit */
509                                 BUFFER_ADD = 0x6;
510                                 /* TMS data bits */
511                                 BUFFER_ADD = TAP_MOVE(cur_state, end_state);
512                                 //DEBUG("added TMS scan (no read)");
513                                 cur_state = end_state;
514                                 require_send = 1;
515                                 break;
516                         case JTAG_SCAN:
517                                 scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
518                                 type = jtag_scan_type(cmd->cmd.scan);
519                                 predicted_size = ftdi2232_predict_scan_out(scan_size, type);
520                                 if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
521                                 {
522                                         ftdi2232_send_and_recv(first_unsent, cmd);
523                                         require_send = 0;
524                                         first_unsent = cmd;
525                                 }
526                                 ftdi2232_expect_read += ftdi2232_predict_scan_in(scan_size, type);
527                                 //DEBUG("new read size: %i", ftdi2232_expect_read);
528                                 if (cmd->cmd.scan->end_state != -1)
529                                         ftdi2232_end_state(cmd->cmd.scan->end_state);
530                                 ftdi2232_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
531                                 require_send = 1;
532                                 if (buffer)
533                                         free(buffer);
534                                 break;
535                         case JTAG_SLEEP:
536                                 jtag_sleep(cmd->cmd.sleep->us);
537                                 break;
538                         default:
539                                 ERROR("BUG: unknown JTAG command type encountered");
540                                 exit(-1);
541                 }
542                 cmd = cmd->next;
543         }
544
545         if (require_send > 0)
546                 ftdi2232_send_and_recv(first_unsent, cmd);
547
548         return ERROR_OK;
549 }
550
551 int ftdi2232_init(void)
552 {
553         if (ftdi_init(&ftdic) < 0)
554                 return ERROR_JTAG_INIT_FAILED;
555
556         /* context, vendor id, product id */
557         if (ftdi_usb_open(&ftdic, ftdi2232_vid, ftdi2232_pid) < 0)
558         {
559                 ERROR("unable to open ftdi device: %s", ftdic.error_str);
560                 return ERROR_JTAG_INIT_FAILED;
561         }
562
563         if (ftdi_usb_reset(&ftdic) < 0)
564         {
565                 ERROR("unable to reset ftdi device");
566                 return ERROR_JTAG_INIT_FAILED;
567         }
568
569         if (ftdi_set_latency_timer(&ftdic, 1) < 0)
570         {
571                 ERROR("unable to set latency timer");
572                 return ERROR_JTAG_INIT_FAILED;
573         }
574
575         ftdi2232_buffer_size = 0;
576         ftdi2232_buffer = malloc(FTDI2232_BUFFER_SIZE);
577
578         ftdic.bitbang_mode = 0; /* Reset controller */
579         ftdi_enable_bitbang(&ftdic, 0x0b | FTDI2232_SRST | FTDI2232_TRST); /* ctx, i/o mask (out=1, in=0) */
580
581         ftdic.bitbang_mode = 2; /* MPSSE mode */
582         ftdi_enable_bitbang(&ftdic, 0x0b | FTDI2232_SRST | FTDI2232_TRST); /* ctx, i/o mask (out=1, in=0) */
583         
584         if (ftdi_usb_purge_buffers(&ftdic) < 0)
585         {
586                 ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
587                 return ERROR_JTAG_INIT_FAILED;
588         }
589
590         /* initialize low byte for jtag */
591         BUFFER_ADD = 0x80; /* command "set data bits low byte" */
592         BUFFER_ADD = 0x08 | FTDI2232_SRST | FTDI2232_TRST; /* value (TMS=1,TCK=0, TDI=0, xRST high) */
593         BUFFER_ADD = 0x0b | FTDI2232_SRST | FTDI2232_TRST; /* dir (output=1), TCK/TDI/TMS=out, TDO=in */
594         BUFFER_ADD = 0x85; /* command "Disconnect TDI/DO to TDO/DI for Loopback" */
595         ftdi2232_debug_dump_buffer();
596         if (ftdi_write_data(&ftdic, ftdi2232_buffer, ftdi2232_buffer_size) != 4)
597                 return ERROR_JTAG_INIT_FAILED;
598
599         ftdi2232_speed(jtag_speed);
600
601         return ERROR_OK;
602 }
603
604 int ftdi2232_quit(void)
605 {
606         ftdi_disable_bitbang(&ftdic);
607         
608         ftdi_usb_close(&ftdic);
609         
610         ftdi_deinit(&ftdic);
611
612         free(ftdi2232_buffer);
613
614         return ERROR_OK;
615 }
616
617 int ftdi2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
618 {
619         if (argc >= 2)
620         {
621                 ftdi2232_vid = strtol(args[0], NULL, 0);
622                 ftdi2232_pid = strtol(args[1], NULL, 0);
623         }
624         else
625         {
626                 WARNING("incomplete ftdi2232_vid_pid configuration directive");
627         }
628         
629         return ERROR_OK;
630 }