2 * ccid_serial.c: communicate with a GemPC Twin smart card reader
3 * Copyright (C) 2001-2010 Ludovic Rousseau <ludovic.rousseau@free.fr>
5 * Thanks to Niki W. Waibel <niki.waibel@gmx.net> for a prototype version
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with this library; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <sys/types.h>
31 #include <sys/ioctl.h>
32 #include <ifdhandler.h>
36 #include "ccid_ifdhandler.h"
42 #include "strlcpycat.h"
47 #define RDR_to_PC_NotifySlotChange 0x50
48 #define CARD_ABSENT 0x02
49 #define CARD_PRESENT 0x03
55 * 10 +data length : CCID command
59 * CTRL : ACK (0x06) or NAK (0x15)
60 * CCID command : see USB CCID specs
61 * LRC : xor of all the previous byes
65 * 1 : CTRL (NAK: 0x15)
68 * Card insertion/withdrawal
69 * 1 : RDR_to_PC_NotifySlotChange (0x50)
72 * 0x03 is card present
75 * T=1 : normal CCID command
76 * T=0 : 1 byte (value between 0x80 and 0xFF)
81 * You may get read timeout after a card movement.
82 * This is because you will get the echo of the CCID command
83 * but not the result of the command.
85 * This is not an applicative issue since the card is either removed (and
86 * powered off) or just inserted (and not yet powered on).
89 /* 271 = max size for short APDU
94 #define GEMPCTWIN_MAXBUF (271 +2 +1) * 2
99 * File handle on the serial port
104 * device used ("/dev/ttyS?" under Linux)
106 /*@null@*/ char *device;
109 * Number of slots using the same device
111 int real_nb_opened_slots;
112 int *nb_opened_slots;
115 * does the reader echoes the serial communication bytes?
120 * serial communication buffer
122 unsigned char buffer[GEMPCTWIN_MAXBUF];
125 * next available byte
130 * number of available bytes
132 int buffer_offset_last;
135 * CCID infos common to USB and serial
137 _ccid_descriptor ccid;
141 /* The _serialDevice structure must be defined before including ccid_serial.h */
142 #include "ccid_serial.h"
144 /* data rates supported by the GemPC Twin (serial and PCMCIA) */
145 unsigned int SerialTwinDataRates[] = { ISO_DATA_RATES, 0 };
147 /* data rates supported by the GemPC PinPad, GemCore Pos Pro & SIM Pro */
148 unsigned int SerialExtendedDataRates[] = { ISO_DATA_RATES, 500000, 0 };
150 /* data rates supported by the secondary slots on the GemCore Pos Pro & SIM Pro */
151 unsigned int SerialCustomDataRates[] = { GEMPLUS_CUSTOM_DATA_RATES, 0 };
153 /* data rates supported by the GemCore SIM Pro 2 */
154 unsigned int SIMPro2DataRates[] = { SIMPRO2_ISO_DATA_RATES, 0 };
156 /* no need to initialize to 0 since it is static */
157 static _serialDevice serialDevice[CCID_DRIVER_MAX_READERS];
159 /* unexported functions */
160 static int ReadChunk(unsigned int reader_index, unsigned char *buffer,
161 int buffer_length, int min_length);
163 static int get_bytes(unsigned int reader_index, /*@out@*/ unsigned char *buffer,
167 /*****************************************************************************
169 * WriteSerial: Send bytes to the card reader
171 *****************************************************************************/
172 status_t WriteSerial(unsigned int reader_index, unsigned int length,
173 unsigned char *buffer)
177 unsigned char low_level_buffer[GEMPCTWIN_MAXBUF];
179 char debug_header[] = "-> 123456 ";
181 (void)snprintf(debug_header, sizeof(debug_header), "-> %06X ",
184 if (length > GEMPCTWIN_MAXBUF-3)
186 DEBUG_CRITICAL3("command too long: %d for max %d",
187 length, GEMPCTWIN_MAXBUF-3);
188 return STATUS_UNSUCCESSFUL;
192 low_level_buffer[0] = 0x03; /* SYNC */
193 low_level_buffer[1] = 0x06; /* ACK */
196 memcpy(low_level_buffer+2, buffer, length);
200 for(i=0; i<length+2; i++)
201 lrc ^= low_level_buffer[i];
202 low_level_buffer[length+2] = lrc;
204 DEBUG_XXD(debug_header, low_level_buffer, length+3);
206 if (write(serialDevice[reader_index].fd, low_level_buffer,
207 length+3) != length+3)
209 DEBUG_CRITICAL2("write error: %s", strerror(errno));
210 return STATUS_UNSUCCESSFUL;
213 return STATUS_SUCCESS;
217 /*****************************************************************************
219 * ReadSerial: Receive bytes from the card reader
221 *****************************************************************************/
222 status_t ReadSerial(unsigned int reader_index,
223 unsigned int *length, unsigned char *buffer)
231 /* we get the echo first */
232 echo = serialDevice[reader_index].echo;
236 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
239 if (c == RDR_to_PC_NotifySlotChange)
247 DEBUG_COMM2("time request: 0x%02X", c);
251 DEBUG_CRITICAL2("Got 0x%02X", c);
252 return STATUS_COMM_ERROR;
255 DEBUG_COMM("slot change");
256 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
259 if (c == CARD_ABSENT)
261 DEBUG_COMM("Card removed");
264 if (c == CARD_PRESENT)
266 DEBUG_COMM("Card inserted");
270 DEBUG_COMM2("Unknown card movement: %d", c);
276 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
285 DEBUG_CRITICAL2("Got 0x%02X instead of ACK/NAK", c);
286 return STATUS_COMM_ERROR;
290 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
293 if (c != (SYNC ^ CTRL_NAK))
295 DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
296 return STATUS_COMM_ERROR;
300 DEBUG_COMM("NAK requested");
301 return STATUS_COMM_NAK;
306 /* normal CCID frame */
307 if ((rv = get_bytes(reader_index, buffer, 5)) != STATUS_SUCCESS)
310 /* total frame size */
311 to_read = 10+dw2i(buffer, 1);
313 if ((to_read < 10) || (to_read > (int)*length))
315 DEBUG_CRITICAL2("Wrong value for frame size: %d", to_read);
316 return STATUS_COMM_ERROR;
319 DEBUG_COMM2("frame size: %d", to_read);
320 if ((rv = get_bytes(reader_index, buffer+5, to_read-5)) != STATUS_SUCCESS)
323 DEBUG_XXD("frame: ", buffer, to_read);
327 if ((rv = get_bytes(reader_index, &c, 1)) != STATUS_SUCCESS)
330 DEBUG_COMM2("lrc: 0x%02X", c);
331 for (i=0; i<to_read; i++)
334 if (c != (SYNC ^ CTRL_ACK))
335 DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
343 /* length of data read */
346 return STATUS_SUCCESS;
350 /*****************************************************************************
352 * get_bytes: get n bytes
354 *****************************************************************************/
355 int get_bytes(unsigned int reader_index, unsigned char *buffer, int length)
357 int offset = serialDevice[reader_index].buffer_offset;
358 int offset_last = serialDevice[reader_index].buffer_offset_last;
360 DEBUG_COMM3("available: %d, needed: %d", offset_last-offset,
362 /* enough data are available */
363 if (offset + length <= offset_last)
365 DEBUG_COMM("data available");
366 memcpy(buffer, serialDevice[reader_index].buffer + offset, length);
367 serialDevice[reader_index].buffer_offset += length;
373 /* copy available data */
374 present = offset_last - offset;
378 DEBUG_COMM2("some data available: %d", present);
379 memcpy(buffer, serialDevice[reader_index].buffer + offset,
384 DEBUG_COMM2("get more data: %d", length - present);
385 rv = ReadChunk(reader_index, serialDevice[reader_index].buffer,
386 sizeof(serialDevice[reader_index].buffer), length - present);
388 return STATUS_COMM_ERROR;
390 /* fill the buffer */
391 memcpy(buffer + present, serialDevice[reader_index].buffer,
393 serialDevice[reader_index].buffer_offset = length - present;
394 serialDevice[reader_index].buffer_offset_last = rv;
395 DEBUG_COMM3("offset: %d, last_offset: %d",
396 serialDevice[reader_index].buffer_offset,
397 serialDevice[reader_index].buffer_offset_last);
400 return STATUS_SUCCESS;
404 /*****************************************************************************
406 * ReadChunk: read a minimum number of bytes
408 *****************************************************************************/
409 static int ReadChunk(unsigned int reader_index, unsigned char *buffer,
410 int buffer_length, int min_length)
412 int fd = serialDevice[reader_index].fd;
419 char debug_header[] = "<- 123456 ";
421 (void)snprintf(debug_header, sizeof(debug_header), "<- %06X ",
425 while (already_read < min_length)
427 /* use select() to, eventually, timeout */
430 t.tv_sec = serialDevice[reader_index].ccid.readTimeout / 1000;
431 t.tv_usec = (serialDevice[reader_index].ccid.readTimeout - t.tv_sec*1000)*1000;
433 i = select(fd+1, &fdset, NULL, NULL, &t);
436 DEBUG_CRITICAL2("select: %s", strerror(errno));
442 DEBUG_COMM2("Timeout! (%d ms)", serialDevice[reader_index].ccid.readTimeout);
446 rv = read(fd, buffer + already_read, buffer_length - already_read);
449 DEBUG_COMM2("read error: %s", strerror(errno));
453 DEBUG_XXD(debug_header, buffer + already_read, rv);
456 DEBUG_COMM3("read: %d, to read: %d", already_read,
464 /*****************************************************************************
466 * OpenSerial: open the port
468 *****************************************************************************/
469 status_t OpenSerial(unsigned int reader_index, int channel)
471 char dev_name[FILENAME_MAX];
473 DEBUG_COMM3("Reader index: %X, Channel: %d", reader_index, channel);
476 * Conversion of old-style ifd-hanler 1.0 CHANNELID
478 if (channel == 0x0103F8)
481 if (channel == 0x0102F8)
484 if (channel == 0x0103E8)
487 if (channel == 0x0102E8)
492 DEBUG_CRITICAL2("wrong port number: %d", channel);
493 return STATUS_UNSUCCESSFUL;
496 (void)snprintf(dev_name, sizeof(dev_name), "/dev/pcsc/%d", channel);
498 return OpenSerialByName(reader_index, dev_name);
501 /*****************************************************************************
503 * set_ccid_descriptor: init ccid descriptor
504 * depending on reader type specified in device.
506 * return: STATUS_UNSUCCESSFUL,
508 * -1 (Reader already used)
510 *****************************************************************************/
511 static status_t set_ccid_descriptor(unsigned int reader_index,
512 const char *reader_name, const char *dev_name)
516 int already_used = FALSE;
517 static int previous_reader_index = -1;
519 readerID = GEMPCTWIN;
520 if (0 == strcasecmp(reader_name,"GemCorePOSPro"))
521 readerID = GEMCOREPOSPRO;
522 else if (0 == strcasecmp(reader_name,"GemCoreSIMPro"))
523 readerID = GEMCORESIMPRO;
524 else if (0 == strcasecmp(reader_name,"GemCoreSIMPro2"))
525 readerID = GEMCORESIMPRO2;
526 else if (0 == strcasecmp(reader_name,"GemPCPinPad"))
527 readerID = GEMPCPINPAD;
528 else if (0 == strcasecmp(reader_name,"SEC1210"))
531 /* check if the same channel is not already used to manage multi-slots readers*/
532 for (i = 0; i < CCID_DRIVER_MAX_READERS; i++)
534 if (serialDevice[i].device
535 && strcmp(serialDevice[i].device, dev_name) == 0)
539 DEBUG_COMM2("%s already used. Multi-slot reader?", dev_name);
544 /* this reader is already managed by us */
547 if ((previous_reader_index != -1)
548 && serialDevice[previous_reader_index].device
549 && (strcmp(serialDevice[previous_reader_index].device, dev_name) == 0)
550 && serialDevice[previous_reader_index].ccid.bCurrentSlotIndex < serialDevice[previous_reader_index].ccid.bMaxSlotIndex)
552 /* we reuse the same device and the reader is multi-slot */
553 serialDevice[reader_index] = serialDevice[previous_reader_index];
555 *serialDevice[reader_index].nb_opened_slots += 1;
556 serialDevice[reader_index].ccid.bCurrentSlotIndex++;
557 serialDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT;
558 DEBUG_INFO2("Opening slot: %d",
559 serialDevice[reader_index].ccid.bCurrentSlotIndex);
565 /* Allocate a memory buffer that will be
566 * released in CloseUSB() */
567 void *ptr = malloc(sizeof SerialCustomDataRates);
570 memcpy(ptr, SerialCustomDataRates,
571 sizeof SerialCustomDataRates);
574 serialDevice[reader_index].ccid.arrayOfSupportedDataRates = ptr;
576 serialDevice[reader_index].ccid.dwMaxDataRate = 125000;
580 serialDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL;
581 serialDevice[reader_index].ccid.dwMaxDataRate = 826000;
584 /* GemPC Twin or GemPC Card */
586 serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialTwinDataRates;
587 serialDevice[reader_index].ccid.dwMaxDataRate = 344086;
594 DEBUG_CRITICAL2("Trying to open too many slots on %s", dev_name);
595 return STATUS_UNSUCCESSFUL;
600 /* Common to all readers */
601 serialDevice[reader_index].ccid.real_bSeq = 0;
602 serialDevice[reader_index].ccid.pbSeq = &serialDevice[reader_index].ccid.real_bSeq;
603 serialDevice[reader_index].real_nb_opened_slots = 1;
604 serialDevice[reader_index].nb_opened_slots = &serialDevice[reader_index].real_nb_opened_slots;
605 serialDevice[reader_index].ccid.bCurrentSlotIndex = 0;
607 serialDevice[reader_index].ccid.dwMaxCCIDMessageLength = 271;
608 serialDevice[reader_index].ccid.dwMaxIFSD = 254;
609 serialDevice[reader_index].ccid.dwFeatures = 0x00010230;
610 serialDevice[reader_index].ccid.dwDefaultClock = 4000;
612 serialDevice[reader_index].buffer_offset = 0;
613 serialDevice[reader_index].buffer_offset_last = 0;
615 serialDevice[reader_index].ccid.readerID = readerID;
616 serialDevice[reader_index].ccid.bPINSupport = 0x0;
617 serialDevice[reader_index].ccid.dwMaxDataRate = 344086;
618 serialDevice[reader_index].ccid.bMaxSlotIndex = 0;
619 serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialTwinDataRates;
620 serialDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT;
621 serialDevice[reader_index].ccid.dwSlotStatus = IFD_ICC_PRESENT;
622 serialDevice[reader_index].ccid.bVoltageSupport = 0x07; /* 1.8V, 3V and 5V */
623 serialDevice[reader_index].ccid.gemalto_firmware_features = NULL;
625 serialDevice[reader_index].ccid.zlp = FALSE;
627 serialDevice[reader_index].echo = TRUE;
629 /* change some values depending on the reader */
633 serialDevice[reader_index].ccid.bMaxSlotIndex = 4; /* 5 slots */
634 serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialExtendedDataRates;
635 serialDevice[reader_index].echo = FALSE;
636 serialDevice[reader_index].ccid.dwMaxDataRate = 500000;
640 serialDevice[reader_index].ccid.bMaxSlotIndex = 1; /* 2 slots */
641 serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialExtendedDataRates;
642 serialDevice[reader_index].echo = FALSE;
643 serialDevice[reader_index].ccid.dwMaxDataRate = 500000;
647 serialDevice[reader_index].ccid.dwDefaultClock = 4800;
648 serialDevice[reader_index].ccid.bMaxSlotIndex = 1; /* 2 slots */
649 serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SIMPro2DataRates;
650 serialDevice[reader_index].echo = FALSE;
651 serialDevice[reader_index].ccid.dwMaxDataRate = 825806;
655 serialDevice[reader_index].ccid.bPINSupport = 0x03;
656 serialDevice[reader_index].ccid.arrayOfSupportedDataRates = SerialExtendedDataRates;
657 serialDevice[reader_index].ccid.dwMaxDataRate = 500000;
661 serialDevice[reader_index].ccid.dwFeatures = 0x000100B2;
662 serialDevice[reader_index].ccid.dwDefaultClock = 4800;
663 serialDevice[reader_index].ccid.dwMaxDataRate = 826000;
664 serialDevice[reader_index].ccid.arrayOfSupportedDataRates = NULL;
665 serialDevice[reader_index].ccid.bMaxSlotIndex = 1; /* 2 slots */
666 serialDevice[reader_index].echo = FALSE;
672 /* memorise the current reader_index so we can detect
673 * a new OpenSerialByName on a multi slot reader */
674 previous_reader_index = reader_index;
676 /* we just created a secondary slot on a multi-slot reader */
678 return STATUS_SECONDARY_SLOT;
680 return STATUS_SUCCESS;
681 } /* set_ccid_descriptor */
684 /*****************************************************************************
686 * OpenSerialByName: open the port
688 *****************************************************************************/
689 status_t OpenSerialByName(unsigned int reader_index, char *dev_name)
691 struct termios current_termios;
692 unsigned int reader = reader_index;
693 /* 255 is MAX_DEVICENAME in pcscd.h */
694 char reader_name[255] = "GemPCTwin";
698 DEBUG_COMM3("Reader index: %X, Device: %s", reader_index, dev_name);
700 /* parse dev_name using the pattern "device:name" */
701 p = strchr(dev_name, ':');
704 /* copy the second part of the string */
705 strlcpy(reader_name, p+1, sizeof(reader_name));
707 /* replace ':' by '\0' so that dev_name only contains the device name */
711 ret = set_ccid_descriptor(reader_index, reader_name, dev_name);
712 if (STATUS_UNSUCCESSFUL == ret)
713 return STATUS_UNSUCCESSFUL;
715 /* secondary slot so do not physically open the device */
716 if (STATUS_SECONDARY_SLOT == ret)
717 return STATUS_SUCCESS;
719 serialDevice[reader].fd = open(dev_name, O_RDWR | O_NOCTTY);
721 if (-1 == serialDevice[reader].fd)
723 DEBUG_CRITICAL3("open %s: %s", dev_name, strerror(errno));
724 return STATUS_UNSUCCESSFUL;
727 /* Set RTS signal to low to prevent the smart card reader
728 * from sending its plug and play string. */
732 if (ioctl(serialDevice[reader].fd, TIOCMGET, &flags) < 0)
734 DEBUG_CRITICAL2("Get RS232 signals state failed: %s",
740 if (ioctl(serialDevice[reader].fd, TIOCMSET, &flags) < 0)
742 DEBUG_CRITICAL2("Set RTS to low failed: %s", strerror(errno));
746 DEBUG_COMM("Plug-n-Play inhibition successful");
751 /* set channel used */
752 serialDevice[reader].device = strdup(dev_name);
754 /* empty in and out serial buffers */
755 if (tcflush(serialDevice[reader].fd, TCIOFLUSH))
756 DEBUG_INFO2("tcflush() function error: %s", strerror(errno));
758 /* get config attributes */
759 if (tcgetattr(serialDevice[reader].fd, ¤t_termios) == -1)
761 DEBUG_INFO2("tcgetattr() function error: %s", strerror(errno));
762 (void)close(serialDevice[reader].fd);
763 serialDevice[reader].fd = -1;
765 return STATUS_UNSUCCESSFUL;
768 /* IGNBRK: ignore BREAK condition on input
769 * IGNPAR: ignore framing errors and parity errors. */
770 current_termios.c_iflag = IGNBRK | IGNPAR;
771 current_termios.c_oflag = 0; /* Raw output modes */
772 /* CS8: 8-bits character size
773 * CSTOPB: set two stop bits
774 * CREAD: enable receiver
775 * CLOCAL: ignore modem control lines */
776 current_termios.c_cflag = CS8 | CSTOPB | CREAD | CLOCAL;
778 /* Do not echo characters because if you connect to a host it or your modem
779 * will echo characters for you. Don't generate signals. */
780 current_termios.c_lflag = 0;
782 if (0 == strcasecmp(reader_name,"GemCoreSIMPro2"))
784 unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
785 unsigned int old_timeout;
788 /* Unless we resume from a stand-by condition, GemCoreSIMPro2
789 * starts at 9600 bauds, so let's first try this speed */
790 /* set serial port speed to 9600 bauds */
791 (void)cfsetspeed(¤t_termios, B9600);
792 DEBUG_INFO1("Set serial port baudrate to 9600 and correct configuration");
793 if (tcsetattr(serialDevice[reader_index].fd, TCSANOW, ¤t_termios) == -1)
795 (void)close(serialDevice[reader_index].fd);
796 serialDevice[reader_index].fd = -1;
797 DEBUG_CRITICAL2("tcsetattr error: %s", strerror(errno));
799 return STATUS_UNSUCCESSFUL;
802 /* Test current speed issuing a CmdGetSlotStatus with a very
803 * short time out of 1 seconds */
804 old_timeout = serialDevice[reader_index].ccid.readTimeout;
806 serialDevice[reader_index].ccid.readTimeout = 1*1000;
807 r = CmdGetSlotStatus(reader_index, pcbuffer);
809 /* Restore default time out value */
810 serialDevice[reader_index].ccid.readTimeout = old_timeout;
812 if (IFD_SUCCESS == r)
814 /* We are at 9600 bauds, let's move to 115200 */
815 unsigned char tx_buffer[] = { 0x01, 0x10, 0x20 };
816 unsigned char rx_buffer[50];
817 unsigned int rx_length = sizeof(rx_buffer);
819 if (IFD_SUCCESS == CmdEscape(reader_index, tx_buffer,
820 sizeof(tx_buffer), rx_buffer, &rx_length, 0))
822 /* Let the reader setup its new communication speed */
823 (void)usleep(250*1000);
827 DEBUG_INFO1("CmdEscape to configure 115200 bauds failed");
830 /* In case of a failure, reader is probably already at 115200
831 * bauds as code below assumes */
834 /* set serial port speed to 115200 bauds */
835 (void)cfsetspeed(¤t_termios, B115200);
837 DEBUG_INFO1("Set serial port baudrate to 115200 and correct configuration");
838 if (tcsetattr(serialDevice[reader].fd, TCSANOW, ¤t_termios) == -1)
840 (void)close(serialDevice[reader].fd);
841 serialDevice[reader].fd = -1;
842 DEBUG_INFO2("tcsetattr error: %s", strerror(errno));
844 return STATUS_UNSUCCESSFUL;
847 /* perform a command to be sure a Gemalto reader is connected
848 * get the reader firmware */
850 unsigned char tx_buffer[1];
851 unsigned char rx_buffer[50];
852 unsigned int rx_length = sizeof(rx_buffer);
854 if (0 == strcasecmp(reader_name,"SEC1210"))
855 tx_buffer[0] = 0x06; // unknown but supported command
857 tx_buffer[0] = 0x02; // get reader firmware
859 /* 2 seconds timeout to not wait too long if no reader is connected */
860 if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer),
861 rx_buffer, &rx_length, 2*1000))
863 DEBUG_CRITICAL("Get firmware failed. Maybe the reader is not connected");
864 (void)CloseSerial(reader_index);
865 return STATUS_UNSUCCESSFUL;
868 rx_buffer[rx_length] = '\0';
869 DEBUG_INFO2("Firmware: %s", rx_buffer);
872 /* perform a command to configure GemPC Twin reader card movement
873 * notification to synchronous mode: the card movement is notified _after_
874 * the host command and _before_ the reader anwser */
875 if (0 != strcasecmp(reader_name,"SEC1210"))
877 unsigned char tx_buffer[] = { 0x01, 0x01, 0x01};
878 unsigned char rx_buffer[50];
879 unsigned int rx_length = sizeof(rx_buffer);
881 if (IFD_SUCCESS != CmdEscape(reader_index, tx_buffer, sizeof(tx_buffer),
882 rx_buffer, &rx_length, 0))
884 DEBUG_CRITICAL("Change card movement notification failed.");
885 (void)CloseSerial(reader_index);
886 return STATUS_UNSUCCESSFUL;
890 serialDevice[reader_index].ccid.sIFD_serial_number = NULL;
891 serialDevice[reader_index].ccid.sIFD_iManufacturer = NULL;
892 serialDevice[reader_index].ccid.IFD_bcdDevice = 0;
894 return STATUS_SUCCESS;
895 } /* OpenSerialByName */
898 /*****************************************************************************
900 * CloseSerial: close the port
902 *****************************************************************************/
903 status_t CloseSerial(unsigned int reader_index)
905 unsigned int reader = reader_index;
907 /* device not opened */
908 if (NULL == serialDevice[reader_index].device)
909 return STATUS_UNSUCCESSFUL;
911 DEBUG_COMM2("Closing serial device: %s", serialDevice[reader_index].device);
913 /* Decrement number of opened slot */
914 (*serialDevice[reader_index].nb_opened_slots)--;
916 /* release the allocated ressources for the last slot only */
917 if (0 == *serialDevice[reader_index].nb_opened_slots)
919 DEBUG_COMM("Last slot closed. Release resources");
921 (void)close(serialDevice[reader].fd);
922 serialDevice[reader].fd = -1;
924 free(serialDevice[reader].device);
925 serialDevice[reader].device = NULL;
928 return STATUS_SUCCESS;
932 /*****************************************************************************
934 * get_ccid_descriptor
936 ****************************************************************************/
937 _ccid_descriptor *get_ccid_descriptor(unsigned int reader_index)
939 return &serialDevice[reader_index].ccid;
940 } /* get_ccid_descriptor */