/* resetGemPC410 - try to debug the GBP comm Copyright (C) 2001 Ludovic Rousseau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * $Id: resetGemPC410.c,v 1.10 2004/07/03 21:42:45 rousseau Exp $ */ #include #include #include #include #include #include #define DEVICE "/dev/pcsc/2" #define BUFFER_SIZE 100 #define MAX_APDU_SIZE 16 void checksum(unsigned char cmd[], const int len); void debug(const unsigned char cmd[], const int len); void explain_gbp(const unsigned char buffer[], const int rv); int multi_read(int fd, unsigned char *buf, size_t count); int main(int argc, char *argv[]) { int fd; unsigned char cmd[MAX_APDU_SIZE], buffer[BUFFER_SIZE]; int rv; struct termios current_termios; printf("Using device: " DEVICE "\n"); if ((fd = open(DEVICE, O_RDWR | O_NOCTTY)) < 0) { printf("open error: %s\n", strerror(errno)); return 1; } if (tcgetattr(fd, ¤t_termios) == -1) { printf("tcgetattr() function error: %s\n", strerror(errno)); close(fd); fd = -1; return 1; } /* The serial port is not yet configured to 38400 bauds? */ if (cfgetospeed(¤t_termios) != B38400) { printf("actual baud rate: %d\n", cfgetospeed(¤t_termios)); current_termios.c_iflag = 0; current_termios.c_oflag = 0; /* Raw output modes */ current_termios.c_cflag = 0; /* Raw output modes */ /* Do not echo characters because if you connect * to a host it or your * modem will echo characters for you. * Don't generate signals. */ current_termios.c_lflag = 0; /* control flow - enable receiver - ignore modem * control lines */ current_termios.c_cflag = CREAD | CLOCAL; /* default speed is 38400 bauds */ cfsetospeed(¤t_termios, B38400); cfsetispeed(¤t_termios, 0); /* 0 corresponds to output speed */ current_termios.c_cflag |= CS8; /*case ODDPARITY: *current_termios.c_cflag |= PARENB + PARODD; *case EVENPARITY: *current_termios.c_cflag |= PARENB; * control caracteres * Minimum bytes to read * current_termios.c_cc[VMIN] = 0; * Time between two bytes read (VTIME x 0.10 s) * current_termios.c_cc[VTIME] = 0; * This is Non Canonical mode set. * by setting c_cc[VMIN]=0 and c_cc[VTIME] = 10 * each read operation will wait for 10/10 = 1 sec * If single byte is received, read function returns. * if timer expires, read() returns 0. * Minimum bytes to read */ current_termios.c_cc[VMIN] = 0; /* Time between two bytes read (VTIME x 0.10 s) */ current_termios.c_cc[VTIME] = 20; printf("Set serial port baudrate to 38400\n"); if (tcsetattr(fd, TCSANOW, ¤t_termios) == -1) { printf("tcsetattr error: %s\n", strerror(errno)); close(fd); fd = -1; return 1; } } else { printf("port " DEVICE " already at 38400 bauds\n"); } cmd[0] = 0x42; /* NAD */ cmd[1] = 0x00; /* PCB */ cmd[2] = 0x05; /* LEN */ cmd[3] = 0x22; /* Read Firmware Version */ cmd[4] = 0x05; cmd[5] = 0x3F; cmd[6] = 0xE0; cmd[7] = 0x10; cmd[8] = 0x00; /* EDC */ checksum(cmd, 9); printf("-> "); debug(cmd, 9); /* explain_gbp(cmd, 9); */ if (write(fd, cmd, 9) < 0) { printf("write error: %s\n", strerror(errno)); } if ((rv = multi_read(fd, buffer, BUFFER_SIZE)) < 0) { printf("read error: %s\n", strerror(errno)); } printf("%d bytes read\n<- ", rv); debug(buffer, rv); if (rv == 0) { if (tcgetattr(fd, ¤t_termios) == -1) { close(fd); fd = -1; printf("tcgetattr() function error\n"); return 1; } current_termios.c_cflag = CREAD | CLOCAL; /* default speed is 9600 bauds */ current_termios.c_cflag |= B9600; current_termios.c_cflag |= CS8; printf("Set serial port baudrate to 9600\n"); if (tcsetattr(fd, TCSANOW, ¤t_termios) == -1) { close(fd); fd = -1; printf("tcsetattr error"); return 1; } } explain_gbp(buffer, rv); cmd[1] = 0x40; checksum(cmd, 9); printf("-> "); debug(cmd, 9); /* explain_gbp(cmd, 9); */ if (write(fd, cmd, 9) < 0) { printf("write error: %s\n", strerror(errno)); } if ((rv = multi_read(fd, buffer, BUFFER_SIZE)) < 0) { printf("read error: %s\n", strerror(errno)); } printf("%d bytes read\n<- ", rv); debug(buffer, rv); explain_gbp(buffer, rv); /* reset GemCore */ cmd[0] = 0x42; /* NAD */ cmd[1] = 0x00; /* PCB */ cmd[2] = 0x04; /* LEN */ cmd[3] = 0x0C; /* Restart */ cmd[4] = 0x00; cmd[5] = 0x00; cmd[6] = 0x00; cmd[7] = 0x00; /* EDC */ checksum(cmd, 8); printf("-> "); debug(cmd, 8); if (write(fd, cmd, 8) < 0) { printf("write error: %s\n", strerror(errno)); } if ((rv = multi_read(fd, buffer, BUFFER_SIZE)) < 0) { printf("read error: %s\n", strerror(errno)); } printf("%d bytes read\n<- ", rv); debug(buffer, rv); explain_gbp(buffer, rv); close(fd); return 0; } /* main */ void checksum(unsigned char cmd[], const int len) { int edc, i; /* checksum */ edc = 0; for (i=0; i 31) printf("%c", cmd[i]); else printf("."); printf("\n"); } /* debug */ void explain_gbp(const unsigned char buffer[], const int rv) { if (rv < 4) { printf("GBP bloc too short: %d instead of min 5\n", rv); return; } switch (buffer[0]) { case 0x42: printf(" NAD: host to gemcore\n"); break; case 0x24: printf(" NAD: gemcore to host\n"); break; default: printf(" NAD: UNKNOWN value %02X\n", buffer[0]); } switch (buffer[1]) { case 0x00: printf(" PCB: I-block S=0\n"); break; case 0x40: printf(" PCB: I-block S=1\n"); break; case 0x80: printf(" PCB: R-block S=0, EDC error=0, another error=0\n"); break; case 0x90: printf(" PCB: R-block S=1, EDC error=0, another error=0\n"); break; case 0x81: printf(" PCB: R-block S=0, EDC error=1, another error=0\n"); break; case 0x91: printf(" PCB: R-block S=1, EDC error=1, another error=0\n"); break; case 0x82: printf(" PCB: R-block S=0, EDC error=0, another error=1\n"); break; case 0x92: printf(" PCB: R-block S=1, EDC error=0, another error=1\n"); break; case 0x83: printf(" PCB: R-block S=0, EDC error=1, another error=1\n"); break; case 0x93: printf(" PCB: R-block S=1, EDC error=1, another error=1\n"); break; case 0xB0: printf(" PCB: S-block resynch request\n"); break; case 0xE0: printf(" PCB: S-block resynch response\n"); break; default: printf(" PCB: UNKNOWN value %02X\n", buffer[1]); break; } printf(" LEN: %02X bytes\n", buffer[2]); switch (buffer[3]) { case 0x00: printf(" S: no error\n"); break; case 0x01: printf(" S: unknown driver\n"); break; case 0x02: printf(" S: operation impossible with this driver\n"); break; case 0x03: printf(" S: incorrect number of arguments\n"); break; case 0x04: printf(" S: reader command unknown\n"); break; case 0x05: printf(" S: response too long for the buffer\n"); break; case 0x10: printf(" S: resonse error at the card reset\n"); break; case 0x12: printf(" S: message too long\n"); break; case 0x13: printf(" S: byte reading error returned by an asynchronous cadr\n"); break; case 0x15: printf(" S: card powered down\n"); break; case 0x1B: printf(" S: a command has been sent with an incorrect number of parameters\n"); break; case 0x1C: printf(" S: overlap on writting flash memory\n"); break; case 0x1D: printf(" S: the TCK check byte is incorrect in a micropocessor card ATR\n"); break; case 0x1E: printf(" S: an attempt has been made to write a write-protected external memory\n"); break; case 0x1F: printf(" S: incorrect data has been send to external memory\n"); break; case 0xA0: printf(" S: error in the card reset response\n"); break; case 0xA1: printf(" S: card protocol error\n"); break; case 0xA2: printf(" S: card malfuntion\n"); break; case 0xA3: printf(" S: parity error\n"); break; case 0xA4: printf(" S: card has been chaining (T=1)\n"); break; case 0xA5: printf(" S: reader has aborted chaining (T=1)\n"); break; case 0xA6: printf(" S: resynch successfully performed by GemCore\n"); break; case 0xA7: printf(" S: protocol type selection (PTS) error\n"); break; case 0xB0: printf(" S: GemCP410 command not supported\n"); break; case 0xCF: printf(" S: other key already pressed\n"); break; case 0xE4: printf(" S: the card has just send an invalid procedure byte\n"); break; case 0xE5: printf(" S: the card has interrupted an exchange\n"); break; case 0xE7: printf(" S: error returned by the card\n"); break; case 0xF7: printf(" S: card removed\n"); break; case 0xF8: printf(" S: the cadr is consuming too much electricity\n"); break; case 0xFB: printf(" S: card missing\n"); break; default: printf(" S: UNKNOWN ERROR %02X\n", buffer[3]); break; } return; } /* explain_gbp */ int multi_read(int fd, unsigned char *buf, size_t count) { int rv, len, to_read, already_read; rv = read(fd, buf, count); if (rv < 0) return rv; /* too short */ if (rv < 3) { printf("ReadGBP: only %d byte(s) read\n", rv); return rv; } /* LEN byte (+4 bytes of protocol) */ to_read = buf[2]+4; /* Nb of bytes already read */ already_read = rv; /* Nb of bytes until the end of the buffer */ len = count - rv; while (already_read < to_read) { rv = read(fd, buf+already_read, len); if (rv < 0) { printf("ReadGBP: read error: %s\n", strerror(errno)); return rv; } already_read += rv; len -= rv; } return to_read; } /* multi_read */