Update TODO part of readme
[lpctools] / isp_commands.c
1 /*********************************************************************
2  *
3  *   LPC ISP Commands
4  *
5  *
6  *  Copyright (C) 2012 Nathael Pajani <nathael.pajani@nathael.net>
7  *
8  *  This program is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  *********************************************************************/
24 #include <stdlib.h> /* strtoul */
25 #include <stdio.h>
26 #include <stdint.h>
27 #include <unistd.h>
28 #include <string.h> /* strncmp */
29 #include <ctype.h>
30 #include <errno.h>
32 #include <unistd.h> /* for open, close */
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
37 #include "isp_utils.h"
39 extern int trace_on;
42 /* Max should be 1270 for read memory, a little bit more for writes */
43 #define SERIAL_BUFSIZE  1300
44 #define REP_BUFSIZE 100
46 #define SYNCHRO_START "?"
47 #define SYNCHRO  "Synchronized\r\n"
48 #define SYNCHRO_OK "OK\r\n"
49 #define DATA_BLOCK_OK "OK\r\n"
50 #define DATA_BLOCK_RESEND "RESEND\r\n"
51 #define SYNCHRO_ECHO_OFF "A 0\r\n"
53 #define ISP_ABORT "\e"  /* Not handled */
55 #define UNLOCK "U 23130\r\n"
56 #define READ_UID "N\r\n"
57 #define READ_PART_ID "J\r\n"
58 #define READ_BOOT_VERSION "K\r\n"
60 #define LINE_DATA_LENGTH 45
61 #define LINES_PER_BLOCK 20
62 #define MAX_DATA_BLOCK_SIZE (LINES_PER_BLOCK * LINE_DATA_LENGTH) /* 900 */
63 #define MAX_BYTES_PER_LINE (1 + ((LINE_DATA_LENGTH / 3) * 4) + 2) /* "line length" (1) + 60 + \r\n */
65 #if (SERIAL_BUFSIZE < (MAX_BYTES_PER_LINE * LINES_PER_BLOCK + 10 + 2)) /* uuencoded data + checksum + \r\n */
66 #error "SERIAL_BUFSIZE too small"
67 #endif
69 /* Order in this table is important */
70 char* error_codes[] = {
71         "CMD_SUCCESS",
72         "INVALID_COMMAND",
73         "SRC_ADDR_ERROR",
74         "DST_ADDR_ERROR",
75         "SRC_ADDR_NOT_MAPPED",
76         "DST_ADDR_NOT_MAPPED",
77         "COUNT_ERROR",
78         "INVALID_SECTOR",
79         "SECTOR_NOT_BLANK",
80         "SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION",
81         "COMPARE_ERROR",
82         "BUSY",
83         "PARAM_ERROR",
84         "ADDR_ERROR",
85         "ADDR_NOT_MAPPED",
86         "CMD_LOCKED",
87         "INVALID_CODE",
88         "INVALID_BAUD_RATE",
89         "INVALID_STOP_BIT",
90         "CODE_READ_PROTECTION_ENABLED",
91 };
93 static int isp_ret_code(char* buf, char** endptr, int quiet)
94 {
95         unsigned int ret = 0;
96         ret = strtoul(buf, endptr, 10);
97         /* FIXME : Find how return code are sent (binary or ASCII) */
98         if (quiet != 1) {
99                 if (ret > (sizeof(error_codes)/sizeof(char*))) {
100                         printf("Received unknown error code '%u' !\n", ret);
101                 } else if ((ret != 0) || trace_on) {
102                         printf("Received error code '%u': %s\n", ret, error_codes[ret]);
103                 }
104         }
105         return ret;
109 /* Connect or reconnect to the target.
110  * crystal_freq is in KHz
111  * Return positive or NULL value when connection is OK, or negative value otherwise.
112  */
113 int isp_connect(unsigned int crystal_freq, int quiet)
115         char buf[REP_BUFSIZE];
116         char freq[10];
118         snprintf(freq, 8, "%d\r\n", crystal_freq);
120         /* Flush input (previously buffered garbage) */
121         isp_serial_flush_input();
123         /* Send synchronize request */
124         if (isp_serial_write(SYNCHRO_START, strlen(SYNCHRO_START)) != strlen(SYNCHRO_START)) {
125                 printf("Unable to send synchronize request.\n");
126                 return -5;
127         }
128         /* Wait for answer */
129         if (isp_serial_read(buf, REP_BUFSIZE, strlen(SYNCHRO)) < 0) {
130                 printf("Error reading synchronize answer.\n");
131                 return -4;
132         }
133         /* Check answer, and acknowledge if OK */
134         if (strncmp(SYNCHRO, buf, strlen(SYNCHRO)) == 0) {
135                 isp_serial_write(SYNCHRO, strlen(SYNCHRO));
136         } else {
137                 if (quiet != 1) {
138                         printf("Unable to synchronize, no synchro received.\n");
139                 }
140                 return -3;
141         }
142         /* Empty read buffer (echo is on) */
143         isp_serial_empty_buffer();
144         /* Read reply (OK) */
145         isp_serial_read(buf, REP_BUFSIZE, strlen(SYNCHRO_OK));
146         if (strncmp(SYNCHRO_OK, buf, strlen(SYNCHRO_OK)) != 0) {
147                 printf("Unable to synchronize, synchro not acknowledged.\n");
148                 return -2;
149         }
151         /* Documentation says we should send crystal frequency .. sending anything is OK */
152         isp_serial_write(freq, strlen(freq));
153         /* Empty read buffer (echo is on) */
154         isp_serial_empty_buffer();
155         /* Read reply (OK) */
156         isp_serial_read(buf, REP_BUFSIZE, strlen(SYNCHRO_OK));
157         if (strncmp(SYNCHRO_OK, buf, strlen(SYNCHRO_OK)) != 0) {
158                 printf("Unable to synchronize, crystal frequency not acknowledged.\n");
159                 return -2;
160         }
162         /* Turn off echo */
163         isp_serial_write(SYNCHRO_ECHO_OFF, strlen(SYNCHRO_ECHO_OFF));
164         /* Empty read buffer (echo still on) */
165         isp_serial_empty_buffer();
166         /* Read eror code for command */
167         isp_serial_read(buf, REP_BUFSIZE, 3);
169         /* Leave it even in quiet mode, so the user knows something is going on */
170         printf("Device session openned.\n");
172         return 1;
175 int isp_send_cmd_no_args(char* cmd_name, char* cmd, int quiet)
177         char buf[5];
178         int ret = 0, len = 0;
180         /* Send request */
181         if (isp_serial_write(cmd, strlen(cmd)) != (int)strlen(cmd)) {
182                 printf("Unable to send %s request.\n", cmd_name);
183                 return -5;
184         }
185         /* Wait for answer */
186         usleep( 5000 );
187         len = isp_serial_read(buf, 3, 3);
188         if (len <= 0) {
189                 printf("Error reading %s acknowledge.\n", cmd_name);
190                 return -4;
191         }
192         ret = isp_ret_code(buf, NULL, quiet);
193         return ret;
196 int isp_cmd_unlock(int quiet)
198         int ret = 0;
200         ret = isp_send_cmd_no_args("unlock", UNLOCK, quiet);
201         if (ret != 0) {
202                 printf("Unlock error.\n");
203                 return -1;
204         }
205         if (quiet == 0) {
206                 printf("Device memory protection unlocked.\n");
207         }
209         return 0;
212 int isp_cmd_read_uid(void)
214         char buf[REP_BUFSIZE];
215         char* tmp = NULL;
216         int i = 0, ret = 0, len = 0;
217         unsigned long int uid[4];
219         ret = isp_send_cmd_no_args("read-uid", READ_UID, 0);
220         if (ret != 0) {
221                 printf("Read UID error.\n");
222                 return ret;
223         }
224         len = isp_serial_read(buf, REP_BUFSIZE, 50);
225         if (len <= 0) {
226                 printf("Error reading uid.\n");
227                 return -2;
228         }
229         tmp = buf;
230         for (i=0; i<4; i++) {
231                 static char* endptr = NULL;
232                 uid[i] = strtoul(tmp, &endptr, 10);
233                 tmp = endptr;
234         }
235         printf("UID: 0x%08lx - 0x%08lx - 0x%08lx - 0x%08lx\n", uid[0], uid[1], uid[2], uid[3]);
237         return 0;
240 int isp_cmd_part_id(int quiet)
242         char buf[REP_BUFSIZE];
243         int ret = 0, len = 0;
244         unsigned long int part_id = 0;
246         ret = isp_send_cmd_no_args("read-part-id", READ_PART_ID, quiet);
247         if (ret != 0) {
248                 if (quiet != 1) {
249                         printf("Read part ID error.\n");
250                 }
251                 return ret;
252         }
253         len = isp_serial_read(buf, REP_BUFSIZE, 15);
254         if (len <= 0) {
255                 printf("Error reading part ID.\n");
256                 return -2;
257         }
258         /* FIXME : some part IDs are on two 32bits values */
259         part_id = strtoul(buf, NULL, 10);
260         if (quiet == 0) {
261                 printf("Part ID is 0x%08lx\n", part_id);
262         }
264         return part_id;
267 int isp_cmd_boot_version(void)
269         char buf[REP_BUFSIZE];
270         int ret = 0, len = 0;
271         char* tmp = NULL;
272         unsigned int ver[2];
274         ret = isp_send_cmd_no_args("read-boot-version", READ_BOOT_VERSION, 0);
275         if (ret != 0) {
276                 printf("Read boot version error.\n");
277                 return ret;
278         }
279         len = isp_serial_read(buf, REP_BUFSIZE, 20);
280         if (len <= 0) {
281                 printf("Error reading boot version.\n");
282                 return -2;
283         }
284         ver[0] = strtoul(buf, &tmp, 10);
285         ver[1] = strtoul(tmp, NULL, 10);
286         printf("Boot code version is %u.%u\n", ver[1], ver[0]);
288         return 0;
291 int isp_send_cmd_two_args(char* cmd_name, char cmd, unsigned int arg1, unsigned int arg2)
293         char buf[REP_BUFSIZE];
294         int ret = 0, len = 0;
296         /* Create read-memory request */
297         len = snprintf(buf, REP_BUFSIZE, "%c %u %u\r\n", cmd, arg1, arg2);
298         if (len > REP_BUFSIZE) {
299                 len = REP_BUFSIZE; /* This should not happen if REP_BUFSIZE is 32 or more ... */
300         }
302         /* Send request */
303         if (isp_serial_write(buf, len) != len) {
304                 printf("Unable to send %s request.\n", cmd_name);
305                 return -5;
306         }
307         /* Wait for answer */
308         usleep( 5000 );
309         len = isp_serial_read(buf, 3, 3);
310         if (len <= 0) {
311                 printf("Error reading %s acknowledge.\n", cmd_name);
312                 return -4;
313         }
314         ret = isp_ret_code(buf, NULL, 0);
315         return ret;
318 static int get_remaining_blocksize(unsigned int count, unsigned int actual_count, char* dir, unsigned int i)
320         unsigned int blocksize = 0;
321         unsigned int remain = count - actual_count;
323         if (remain >= MAX_DATA_BLOCK_SIZE) {
324                 blocksize = (MAX_BYTES_PER_LINE * LINES_PER_BLOCK);
325                 if (trace_on) {
326                         printf("%s block %d (%d line(s)).\n", dir, i, LINES_PER_BLOCK);
327                 }
328         } else {
329                 unsigned int nb_last_lines = (remain / LINE_DATA_LENGTH);
330                 if (remain % LINE_DATA_LENGTH) {
331                         nb_last_lines += 1;
332                 }
333                 /* 4 bytes transmitted for each 3 data bytes */
334                 blocksize = ((remain / 3) * 4);
335                 if (remain % 3) {
336                         blocksize += 4;
337                 }
338                 /* Add one byte per line for the starting "length character" and two bytes per
339                  * line for the ending "\r\n" */
340                 blocksize += (3 * nb_last_lines);
341                 if (trace_on) {
342                         printf("%s block %d of size %u (%d line(s)).\n", dir, i, blocksize, nb_last_lines);
343                 }
344         }
345         return blocksize;
348 /* Compute the number of blocks of the transmitted data. */
349 static int get_nb_blocks(unsigned int count, char* dir)
351         unsigned int lines = 0;
352         unsigned int blocks = 0;
354         /* See section 21.4.3 of LPC11xx user's manual (UM10398) */
355         lines = (count / LINE_DATA_LENGTH);
356         if (count % LINE_DATA_LENGTH) {
357                 lines += 1;
358         }
359         blocks = (lines / LINES_PER_BLOCK);
360         if (lines % LINES_PER_BLOCK) {
361                 blocks += 1;
362         }
363         if (trace_on) {
364                 printf("%s %d block(s) (%d line(s)).\n", dir, blocks, lines);
365         }
367         return blocks;
370 static unsigned int calc_checksum(unsigned char* data, unsigned int size)
372         unsigned int i = 0;
373         unsigned int checksum = 0;
375         for (i=0; i<size; i++) {
376                 checksum += data[i];
377         }
378         return checksum;
381 /*
382  * perform read-memory operation
383  * read 'count' bytes from 'addr' to 'data' buffer
384  */
385 int isp_read_memory(char* data, uint32_t addr, unsigned int count, unsigned int uuencoded)
387         /* Serial communication */
388         char buf[SERIAL_BUFSIZE];
389         int ret = 0, len = 0;
390         /* Reply handling */
391         unsigned int blocks = 0;
392         unsigned int total_bytes_received = 0; /* actual count of bytes received */
393         unsigned int i = 0;
395         /* Send command */
396         ret = isp_send_cmd_two_args("read-memory", 'R', addr, count);
397         if (ret != 0) {
398                 printf("Error when trying to read %u bytes of memory at address 0x%08x.\n", count, addr);
399                 return ret;
400         }
402         if (uuencoded == 0) {
403                 len = isp_serial_read(data, count, count);
404                 if (len <= 0) {
405                         printf("Error reading memory.\n");
406                         return -6;
407                 }
408                 if (len == (int)count) {
409                         return len;
410                 }
411                 /* Wait some time before reading possible remaining data */
412                 usleep( 1000 );
413                 len += isp_serial_read((data + len), (count - len), (count - len));
414                 if (len < 0) { /* Length may be null, as we may already have received everything */
415                         printf("Error reading memory.\n");
416                         return -5;
417                 }
418                 return len;
419         }
421         /* Now, find the number of blocks of the reply. */
422         blocks = get_nb_blocks(count, "Reading");
424         /* Receive and decode the data */
425         for (i=0; i<blocks; i++) {
426                 unsigned int blocksize = 0, decoded_size = 0;
427                 unsigned int received_checksum = 0, computed_checksum = 0;
428                 static int resend_request_for_block = 0;
430                 /* First compute the next block size */
431                 blocksize = get_remaining_blocksize(count, total_bytes_received, "Reading", i);
432                 /* Read the uuencoded data */
433                 len = isp_serial_read(buf, SERIAL_BUFSIZE, blocksize);
434                 if (len <= 0) {
435                         printf("Error reading memory.\n");
436                         ret = -6;
437                         break;
438                 }
439                 usleep( 1000 );
440                 /* Now read the checksum, maybe not yet received */
441                 len += isp_serial_read((buf + len), (SERIAL_BUFSIZE - len), ((len > (int)blocksize) ? 0 : 3));
442                 if (len < 0) { /* Length may be null, as we may already have received everything */
443                         printf("Error reading memory (checksum part).\n");
444                         ret = -5;
445                         break;
446                 }
447                 /* Decode. This must be done before sending acknowledge because we must
448                  * compute the checksum */
449                 decoded_size = isp_uu_decode((data + total_bytes_received), buf, blocksize);
450                 received_checksum = strtoul((buf + blocksize), NULL, 10);
451                 computed_checksum = calc_checksum((unsigned char*)(data + total_bytes_received), decoded_size);
452                 if (trace_on) {
453                         printf("Decoded Data :\n");
454                         isp_dump((unsigned char*)(data + total_bytes_received), decoded_size);
455                 }
456                 if (computed_checksum == received_checksum) {
457                         resend_request_for_block = 0; /* reset resend request counter */
458                         if (trace_on) {
459                                 printf("Reading of blocks %u OK, contained %u bytes\n", i, decoded_size);
460                         }
461                         /* Acknowledge data */
462                         if (isp_serial_write(DATA_BLOCK_OK, strlen(DATA_BLOCK_OK)) != strlen(DATA_BLOCK_OK)) {
463                                 printf("Unable to send acknowledge.\n");
464                                 ret = -4;
465                                 break;
466                         }
467                         /* Add data length to sum of received data */
468                         total_bytes_received += decoded_size;
469                 } else {
470                         resend_request_for_block++;
471                         if (trace_on) {
472                                 printf("Checksum error for block %u (received %u, computed %u) error number: %d.\n",
473                                                 i, received_checksum, computed_checksum, resend_request_for_block);
474                         }
475                         if (resend_request_for_block > 3) {
476                                 printf("Block %d still wrong after 3 attempts, aborting.\n", i);
477                                 ret = -2;
478                                 break;
479                         }
480                         /* Back to previous block */
481                         i--;
482                         /* Ask for resend */
483                         if (isp_serial_write(DATA_BLOCK_RESEND, strlen(DATA_BLOCK_RESEND)) != strlen(DATA_BLOCK_RESEND)) {
484                                 printf("Unable to send resend request.\n");
485                                 ret = -1;
486                                 break;
487                         }
488                 }
489         }
491         return total_bytes_received;
495 /*
496  * perform write-to-ram operation
497  * send 'count' bytes from 'data' to 'addr' in RAM
498  */
499 int isp_send_buf_to_ram(char* data, unsigned long int addr, unsigned int count, unsigned int perform_uuencode)
501         /* Serial communication */
502         int ret = 0, len = 0;
503         /* Reply handling */
504         unsigned int blocks = 0;
505         unsigned int total_bytes_sent = 0;
506         unsigned int i = 0;
508         /* Send write-to-ram request */
509         ret = isp_send_cmd_two_args("write-to-ram", 'W', addr, count);
510         if (ret != 0) {
511                 printf("Error when trying to start write procedure to address 0x%08lx.\n", addr);
512                 return -8;
513         }
515         /* First check if we must UU-encode data */
516         if (perform_uuencode == 0) {
517                 if (isp_serial_write(data, count) != (int)count) {
518                         printf("Error sending raw binary data.\n");
519                         return -7;
520                 }
521                 /* No checks required, we are done */
522                 return 0;
523         }
524         /* Now, find the number of blocks of data to send. */
525         blocks = get_nb_blocks(count, "Sending");
527         /* Encode and send the data */
528         for (i=0; i<blocks; i++) {
529                 char buf[SERIAL_BUFSIZE]; /* Store encoded data, to be sent to the microcontroller */
530                 char repbuf[REP_BUFSIZE];
531                 unsigned int datasize = 0, encoded_size = 0;
532                 unsigned int computed_checksum = 0;
533                 static int resend_requested_for_block = 0;
535                 /* First compute the next block size */
536                 datasize = (count - total_bytes_sent);
537                 if (datasize >= MAX_DATA_BLOCK_SIZE) {
538                         datasize = MAX_DATA_BLOCK_SIZE;
539                 }
541                 /* uuencode data */
542                 encoded_size = isp_uu_encode(buf, data + total_bytes_sent, datasize);
543                 /* Add checksum */
544                 computed_checksum = calc_checksum((unsigned char*)(data + total_bytes_sent), datasize);
545                 encoded_size += snprintf((buf + encoded_size), 12, "%u\r\n", computed_checksum);
546                 if (trace_on) {
547                         printf("Encoded Data :\n");
548                         isp_dump((unsigned char*)buf, encoded_size);
549                 }
550                 if (isp_serial_write(buf, encoded_size) != (int)encoded_size) {
551                         printf("Error sending uuencoded data.\n");
552                         ret = -6;
553                         break;
554                 }
556                 usleep( 20000 );
557                 len = isp_serial_read(repbuf, REP_BUFSIZE, 4);
558                 if (len <= 0) {
559                         printf("Error reading write acknowledge.\n");
560                         return -5;
561                 }
562                 if (strncmp(DATA_BLOCK_OK, repbuf, strlen(DATA_BLOCK_OK)) == 0) {
563                         total_bytes_sent += datasize;
564                         resend_requested_for_block = 0; /* reset resend request counter */
565                         if (trace_on) {
566                                 printf("Block %d sent.\n", i);
567                         }
568                 } else {
569                         resend_requested_for_block++;
570                         if (trace_on) {
571                                 printf("Checksum error for block %u, error number: %d.\n", i, resend_requested_for_block);
572                         }
573                         if (resend_requested_for_block >= 3) {
574                                 printf("Block %d still wrong after 3 attempts, aborting.\n", i);
575                                 ret = -2;
576                                 break;
577                         }
578                         /* Back to previous block */
579                         i--;
580                 }
581         }
583         return ret;
587 int isp_send_cmd_address(char cmd, uint32_t addr1, uint32_t addr2, uint32_t length, char* name)
589         char buf[SERIAL_BUFSIZE];
590         int ret = 0, len = 0;
591         char* tmp = NULL;
593         /* Create request */
594         len = snprintf(buf, SERIAL_BUFSIZE, "%c %u %u %u\r\n", cmd, addr1, addr2, length);
595         if (len > SERIAL_BUFSIZE) {
596                 len = SERIAL_BUFSIZE;
597         }
599         /* Send request */
600         if (isp_serial_write(buf, len) != len) {
601                 printf("Unable to send %s request.\n", name);
602                 return -5;
603         }
604         /* Wait for answer */
605         usleep( 5000 );
606         len = isp_serial_read(buf, 3, 3);
607         if (len <= 0) {
608                 printf("Error reading %s result.\n", name);
609                 return -4;
610         }
611         ret = isp_ret_code(buf, &tmp, 0);
612         return ret;
616 int isp_send_cmd_go(uint32_t addr, char mode)
618         char buf[SERIAL_BUFSIZE];
619         int ret = 0, len = 0;
621         if (addr < 0x200) {
622                 printf("Error: address must be 0x00000200 or greater for go command.\n");
623                 return -6;
624         }
625         if ((mode != 'T') && (mode != 'A')) {
626                 printf("Error: mode must be 'thumb' (T) or 'arm' (A) for go command.\n");
627                 return -5;
628         }
630         /* Create go request */
631         len = snprintf(buf, SERIAL_BUFSIZE, "G %u %c\r\n", addr, mode);
632         if (len > SERIAL_BUFSIZE) {
633                 len = SERIAL_BUFSIZE;
634         }
636         /* Send go request */
637         if (isp_serial_write(buf, len) != len) {
638                 printf("Unable to send go request.\n");
639                 return -4;
640         }
641         /* Wait for answer */
642         usleep( 5000 );
643         len = isp_serial_read(buf, SERIAL_BUFSIZE, 3);
644         if (len <= 0) {
645                 printf("Error reading go result.\n");
646                 return -3;
647         }
648         ret = isp_ret_code(buf, NULL, 0);
649         if (ret != 0) {
650                 printf("Error when trying to execute program at 0x%08x in '%c' mode.\n", addr, mode);
651                 return -1;
652         }
654         return 0;
657 int isp_send_cmd_sectors(char* name, char cmd, int first_sector, int last_sector, int quiet)
659         char buf[SERIAL_BUFSIZE];
660         int ret = 0, len = 0;
662         if (last_sector < first_sector) {
663                 printf("Last sector must be after (or equal to) first sector for %s command.\n", name);
664                 return -6;
665         }
667         /* Create request */
668         len = snprintf(buf, SERIAL_BUFSIZE, "%c %u %u\r\n", cmd, first_sector, last_sector);
669         if (len > SERIAL_BUFSIZE) {
670                 len = SERIAL_BUFSIZE;
671         }
672         /* Send request */
673         if (isp_serial_write(buf, len) != len) {
674                 printf("Unable to send %s request.\n", name);
675                 return -5;
676         }
677         /* Wait for answer */
678         usleep( 5000 );
679         len = isp_serial_read(buf, 3, 3); /* Read at exactly 3 bytes, so caller can retreive info */
680         if (len <= 0) {
681                 printf("Error reading %s result.\n", name);
682                 return -4;
683         }
684         ret = isp_ret_code(buf, NULL, quiet);
686         return ret;