/[pcsclite]/trunk/Drivers/ccid/src/ccid_serial.c
ViewVC logotype

Contents of /trunk/Drivers/ccid/src/ccid_serial.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1091 - (hide annotations) (download)
Wed Jul 21 08:59:28 2004 UTC (8 years, 11 months ago) by rousseau
File MIME type: text/plain
File size: 15038 byte(s)
initialise bMaxSlotIndex and ccid.bCurrentSlotIndex fields
1 rousseau 414 /*
2     * ccid_serial.c: communicate with a GemPC Twin smart card reader
3     * Copyright (C) 2001-2003 Ludovic Rousseau <ludovic.rousseau@free.fr>
4     *
5     * Thanks to Niki W. Waibel <niki.waibel@gmx.net> for a prototype version
6     *
7     * This program is free software; you can redistribute it and/or modify it
8     * under the terms of the GNU General Public License as published by the
9     * Free Software Foundation; either version 2 of the License, or (at your
10     * option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful, but
13     * WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15     * General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License along
18     * with this program; if not, write to the Free Software Foundation, Inc.,
19     * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     */
21    
22     /*
23     * $Id$
24     */
25    
26     #include <stdio.h>
27     #include <stdlib.h>
28     #include <fcntl.h>
29     #include <unistd.h>
30     #include <termios.h>
31     #include <string.h>
32     #include <errno.h>
33     #include <sys/time.h>
34     #include <sys/types.h>
35 rousseau 1022 #include <PCSC/ifdhandler.h>
36 rousseau 414
37 rousseau 877 #include "defs.h"
38     #include "ccid_ifdhandler.h"
39 rousseau 414 #include "config.h"
40     #include "debug.h"
41     #include "ccid.h"
42     #include "utils.h"
43 rousseau 1022 #include "commands.h"
44 rousseau 414
45     /* communication timeout in seconds */
46 rousseau 453 #define SERIAL_TIMEOUT 2
47 rousseau 414
48     #define SYNC 0x03
49     #define CTRL_ACK 0x06
50     #define CTRL_NAK 0x15
51     #define RDR_to_PC_NotifySlotChange 0x50
52     #define CARD_ABSENT 0x02
53     #define CARD_PRESENT 0x03
54    
55     /*
56     * normal command:
57     * 1 : SYNC
58     * 1 : CTRL
59     * 10 +data length : CCID command
60     * 1 : LRC
61     *
62     * SYNC : 0x03
63     * CTRL : ACK (0x06) or NAK (0x15)
64     * CCID command : see USB CCID specs
65     * LRC : xor of all the previous byes
66     *
67     * Error message:
68     * 1 : SYNC (0x03)
69     * 1 : CTRL (NAK: 0x15)
70     * 1 : LRC (0x16)
71     *
72     * Card insertion/withdrawal
73     * 1 : RDR_to_PC_NotifySlotChange (0x50)
74     * 1 : bmSlotIccState
75     * 0x02 if card absent
76     * 0x03 is card present
77     *
78     * Time request
79     * T=1 : normal CCID command
80     * T=0 : 1 byte (value between 0x80 and 0xFF)
81     *
82     */
83    
84 rousseau 453 /*
85     * You may get read timeout after a card movement.
86     * This is because you will get the echo of the CCID command
87     * but not the result of the command.
88     *
89     * This is not an applicative issue since the card is either removed (and
90     * powered off) or just inserted (and not yet powered on).
91     */
92    
93     /* 271 = max size for short APDU
94     * 2 bytes for header
95     * 1 byte checksum
96     * doubled for echo
97     */
98     #define GEMPCTWIN_MAXBUF (271 +2 +1) * 2
99    
100 rousseau 414 typedef struct
101     {
102     /*
103     * File handle on the serial port
104     */
105     int fd;
106    
107     /*
108 rousseau 649 * device used ("/dev/ttyS?" under Linux)
109 rousseau 414 */
110 rousseau 1054 /*@null@*/ char *device;
111 rousseau 414
112     /*
113 rousseau 453 * serial communication buffer
114     */
115     unsigned char buffer[GEMPCTWIN_MAXBUF];
116    
117     /*
118     * next available byte
119     */
120     int buffer_offset;
121    
122     /*
123     * number of available bytes
124     */
125     int buffer_offset_last;
126    
127     /*
128 rousseau 414 * CCID infos common to USB and serial
129     */
130     _ccid_descriptor ccid;
131    
132     } _serialDevice;
133    
134     /* The _serialDevice structure must be defined before including ccid_serial.h */
135     #include "ccid_serial.h"
136    
137 rousseau 892 /* no need to initialize to 0 since it is static */
138 rousseau 1077 static _serialDevice serialDevice[CCID_DRIVER_MAX_READERS];
139 rousseau 414
140 rousseau 1050 /* unexported functions */
141     static int ReadChunk(unsigned int lun, unsigned char *buffer, int buffer_length,
142     int min_length);
143    
144     static int get_bytes(unsigned int lun, unsigned char *buffer, int length);
145    
146    
147 rousseau 414 /*****************************************************************************
148     *
149     * WriteSerial: Send bytes to the card reader
150     *
151     *****************************************************************************/
152 rousseau 1043 status_t WriteSerial(unsigned int lun, unsigned int length, unsigned char *buffer)
153 rousseau 414 {
154     int i;
155     unsigned char lrc;
156     unsigned char low_level_buffer[GEMPCTWIN_MAXBUF];
157    
158     #ifdef DEBUG_LEVEL_COMM
159 rousseau 1047 char debug_header[] = "-> 123456 ";
160 rousseau 414
161 rousseau 1043 sprintf(debug_header, "-> %06X ", lun);
162 rousseau 414 #endif
163    
164     if (length > GEMPCTWIN_MAXBUF-3)
165     {
166 rousseau 608 DEBUG_CRITICAL3("command too long: %d for max %d",
167 rousseau 414 length, GEMPCTWIN_MAXBUF-3);
168     return STATUS_UNSUCCESSFUL;
169     }
170    
171     /* header */
172     low_level_buffer[0] = 0x03; /* SYNC */
173     low_level_buffer[1] = 0x06; /* ACK */
174    
175     /* CCID command */
176     memcpy(low_level_buffer+2, buffer, length);
177    
178     /* checksum */
179     lrc = 0;
180     for(i=0; i<length+2; i++)
181     lrc ^= low_level_buffer[i];
182     low_level_buffer[length+2] = lrc;
183    
184     #ifdef DEBUG_LEVEL_COMM
185     DEBUG_XXD(debug_header, low_level_buffer, length+3);
186     #endif
187    
188 rousseau 453 if (write(serialDevice[LunToReaderIndex(lun)].fd, low_level_buffer,
189     length+3) != length+3)
190 rousseau 414 {
191 rousseau 608 DEBUG_CRITICAL2("write error: %s", strerror(errno));
192 rousseau 414 return STATUS_UNSUCCESSFUL;
193     }
194    
195     return STATUS_SUCCESS;
196     } /* WriteSerial */
197    
198    
199     /*****************************************************************************
200     *
201     * ReadSerial: Receive bytes from the card reader
202     *
203     *****************************************************************************/
204 rousseau 1053 status_t ReadSerial(unsigned int lun, /*@unused@*/ unsigned int *length,
205     unsigned char *buffer)
206 rousseau 414 {
207 rousseau 453 unsigned char c;
208     int rv;
209     int echo;
210     int to_read;
211     int i;
212 rousseau 414
213 rousseau 453 /* we get the echo first */
214     echo = TRUE;
215 rousseau 414
216 rousseau 453 start:
217 rousseau 462 DEBUG_COMM("start");
218 rousseau 453 if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
219     return rv;
220 rousseau 414
221 rousseau 453 if (c == RDR_to_PC_NotifySlotChange)
222     goto slot_change;
223 rousseau 414
224 rousseau 453 if (c == SYNC)
225     goto sync;
226 rousseau 414
227 rousseau 453 if (c >= 0x80)
228 rousseau 462 {
229     DEBUG_COMM2("time request: 0x%02X", c);
230 rousseau 453 goto start;
231 rousseau 462 }
232 rousseau 414
233 rousseau 453 DEBUG_CRITICAL2("Got 0x%02X", c);
234     return STATUS_COMM_ERROR;
235 rousseau 414
236 rousseau 453 slot_change:
237 rousseau 462 DEBUG_COMM("slot change");
238 rousseau 453 if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
239     return rv;
240 rousseau 414
241 rousseau 453 if (c == CARD_ABSENT)
242 rousseau 774 {
243 rousseau 453 DEBUG_COMM("Card removed");
244 rousseau 774 }
245 rousseau 453 else
246     if (c == CARD_PRESENT)
247 rousseau 774 {
248 rousseau 453 DEBUG_COMM("Card inserted");
249 rousseau 774 }
250 rousseau 453 else
251 rousseau 774 {
252 rousseau 1044 DEBUG_COMM2("Unknown card movement: %d", c);
253 rousseau 774 }
254 rousseau 453 goto start;
255 rousseau 414
256 rousseau 453 sync:
257 rousseau 462 DEBUG_COMM("sync");
258 rousseau 453 if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
259     return rv;
260 rousseau 414
261 rousseau 453 if (c == CTRL_ACK)
262     goto ack;
263 rousseau 414
264 rousseau 453 if (c == CTRL_NAK)
265     goto nak;
266 rousseau 414
267 rousseau 453 DEBUG_CRITICAL2("Got 0x%02X instead of ACK/NAK", c);
268     return STATUS_COMM_ERROR;
269 rousseau 414
270 rousseau 453 nak:
271 rousseau 462 DEBUG_COMM("nak");
272 rousseau 453 if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
273     return rv;
274 rousseau 414
275 rousseau 453 if (c != (SYNC ^ CTRL_NAK))
276 rousseau 414 {
277 rousseau 453 DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
278     return STATUS_COMM_ERROR;
279 rousseau 414 }
280 rousseau 453 else
281     goto start;
282 rousseau 414
283 rousseau 453 ack:
284 rousseau 462 DEBUG_COMM("ack");
285 rousseau 453 /* normal CCID frame */
286     if ((rv = get_bytes(lun, buffer, 5)) != STATUS_SUCCESS)
287     return rv;
288 rousseau 414
289 rousseau 453 /* total frame size */
290     to_read = 10+dw2i(buffer, 1);
291 rousseau 414
292 rousseau 462 DEBUG_COMM2("frame size: %d", to_read);
293 rousseau 453 if ((rv = get_bytes(lun, buffer+5, to_read-5)) != STATUS_SUCCESS)
294     return rv;
295 rousseau 414
296 rousseau 462 #ifdef DEBUG_LEVEL_COMM
297     DEBUG_XXD("frame: ", buffer, to_read);
298     #endif
299    
300 rousseau 453 /* lrc */
301 rousseau 462 DEBUG_COMM("lrc");
302 rousseau 453 if ((rv = get_bytes(lun, &c, 1)) != STATUS_SUCCESS)
303     return rv;
304    
305 rousseau 462 DEBUG_COMM2("lrc: 0x%02X", c);
306 rousseau 414 for (i=0; i<to_read; i++)
307 rousseau 453 c ^= buffer[i];
308 rousseau 414
309 rousseau 453 if (c != (SYNC ^ CTRL_ACK))
310     DEBUG_CRITICAL2("Wrong LRC: 0x%02X", c);
311 rousseau 414
312 rousseau 453 if (echo)
313     {
314     echo = FALSE;
315     goto start;
316     }
317 rousseau 414
318     return STATUS_SUCCESS;
319     } /* ReadSerial */
320    
321    
322     /*****************************************************************************
323     *
324 rousseau 453 * get_bytes: get n bytes
325 rousseau 414 *
326     *****************************************************************************/
327 rousseau 1043 int get_bytes(unsigned int lun, unsigned char *buffer, int length)
328 rousseau 414 {
329 rousseau 453 int offset = serialDevice[LunToReaderIndex(lun)].buffer_offset;
330     int offset_last = serialDevice[LunToReaderIndex(lun)].buffer_offset_last;
331 rousseau 414
332 rousseau 608 DEBUG_COMM3("available: %d, needed: %d", offset_last-offset,
333 rousseau 462 length);
334 rousseau 453 /* enough data are available */
335     if (offset + length <= offset_last)
336 rousseau 414 {
337 rousseau 608 DEBUG_COMM("data available");
338 rousseau 453 memcpy(buffer, serialDevice[LunToReaderIndex(lun)].buffer + offset, length);
339     serialDevice[LunToReaderIndex(lun)].buffer_offset += length;
340 rousseau 414 }
341 rousseau 453 else
342 rousseau 414 {
343 rousseau 453 int present, rv;
344 rousseau 414
345 rousseau 453 /* copy available data */
346     present = offset_last - offset;
347 rousseau 414
348 rousseau 453 if (present > 0)
349 rousseau 462 {
350 rousseau 608 DEBUG_COMM2("some data available: %d", present);
351 rousseau 462 memcpy(buffer, serialDevice[LunToReaderIndex(lun)].buffer + offset,
352     present);
353     }
354 rousseau 414
355 rousseau 453 /* get fresh data */
356 rousseau 608 DEBUG_COMM2("get more data: %d", length - present);
357 rousseau 453 rv = ReadChunk(lun, serialDevice[LunToReaderIndex(lun)].buffer, sizeof(serialDevice[LunToReaderIndex(lun)].buffer), length - present);
358     if (rv < 0)
359     return STATUS_COMM_ERROR;
360 rousseau 414
361 rousseau 453 /* fill the buffer */
362     memcpy(buffer + present, serialDevice[LunToReaderIndex(lun)].buffer,
363     length - present);
364     serialDevice[LunToReaderIndex(lun)].buffer_offset = length - present;
365     serialDevice[LunToReaderIndex(lun)].buffer_offset_last = rv;
366 rousseau 608 DEBUG_COMM3("offset: %d, last_offset: %d",
367 rousseau 462 serialDevice[LunToReaderIndex(lun)].buffer_offset,
368     serialDevice[LunToReaderIndex(lun)].buffer_offset_last);
369 rousseau 414 }
370    
371 rousseau 453 return STATUS_SUCCESS;
372     } /* get_bytes */
373 rousseau 414
374 rousseau 453
375 rousseau 414 /*****************************************************************************
376     *
377     * ReadChunk: read a minimum number of bytes
378     *
379     *****************************************************************************/
380 rousseau 1050 static int ReadChunk(unsigned int lun, unsigned char *buffer,
381     int buffer_length, int min_length)
382 rousseau 414 {
383 rousseau 453 int fd = serialDevice[LunToReaderIndex(lun)].fd;
384 rousseau 1045 # ifndef S_SPLINT_S
385 rousseau 414 fd_set fdset;
386 rousseau 1045 # endif
387 rousseau 414 struct timeval t;
388 rousseau 462 int i, rv = 0;
389     int already_read;
390 rousseau 414 #ifdef DEBUG_LEVEL_COMM
391 rousseau 1047 char debug_header[] = "<- 123456 ";
392 rousseau 414
393 rousseau 1046 sprintf(debug_header, "<- %06X ", lun);
394 rousseau 414 #endif
395    
396 rousseau 462 already_read = 0;
397     while (already_read < min_length)
398     {
399     /* use select() to, eventually, timeout */
400     FD_ZERO(&fdset);
401     FD_SET(fd, &fdset);
402     t.tv_sec = SERIAL_TIMEOUT;
403     t.tv_usec = 0;
404 rousseau 414
405 rousseau 462 i = select(fd+1, &fdset, NULL, NULL, &t);
406     if (i == -1)
407 rousseau 414 {
408 rousseau 462 DEBUG_CRITICAL2("select: %s", strerror(errno));
409 rousseau 414 return -1;
410     }
411 rousseau 462 else
412     if (i == 0)
413     {
414     DEBUG_COMM2("Timeout! (%d sec)", SERIAL_TIMEOUT);
415     return -1;
416     }
417 rousseau 414
418 rousseau 462 rv = read(fd, buffer + already_read, buffer_length - already_read);
419     if (rv < 0)
420     {
421     DEBUG_COMM2("read error: %s", strerror(errno));
422     return -1;
423     }
424 rousseau 414
425 rousseau 453 #ifdef DEBUG_LEVEL_COMM
426 rousseau 462 DEBUG_XXD(debug_header, buffer + already_read, rv);
427 rousseau 453 #endif
428 rousseau 414
429 rousseau 462 already_read += rv;
430 rousseau 608 DEBUG_COMM3("read: %d, to read: %d", already_read,
431 rousseau 414 min_length);
432     }
433    
434 rousseau 462 return already_read;
435 rousseau 414 } /* ReadChunk */
436    
437    
438     /*****************************************************************************
439     *
440     * OpenSerial: open the port
441     *
442     *****************************************************************************/
443 rousseau 1043 status_t OpenSerial(unsigned int lun, int channel)
444 rousseau 414 {
445     char dev_name[FILENAME_MAX];
446    
447 rousseau 608 DEBUG_COMM3("Lun: %X, Channel: %d", lun, channel);
448 rousseau 414
449     /*
450     * Conversion of old-style ifd-hanler 1.0 CHANNELID
451     */
452     if (channel == 0x0103F8)
453     channel = 1;
454     else
455     if (channel == 0x0102F8)
456     channel = 2;
457     else
458     if (channel == 0x0103E8)
459     channel = 3;
460     else
461     if (channel == 0x0102E8)
462     channel = 4;
463    
464     if (channel < 0)
465     {
466     DEBUG_CRITICAL2("wrong port number: %d", (int) channel);
467     return STATUS_UNSUCCESSFUL;
468     }
469    
470     sprintf(dev_name, "/dev/pcsc/%d", (int) channel);
471    
472 rousseau 649 return OpenSerialByName(lun, dev_name);
473     } /* OpenSerial */
474    
475     /*****************************************************************************
476     *
477     * OpenSerialByName: open the port
478     *
479     *****************************************************************************/
480 rousseau 1043 status_t OpenSerialByName(unsigned int lun, char *dev_name)
481 rousseau 649 {
482     struct termios current_termios;
483     int i;
484 rousseau 1049 unsigned int reader = LunToReaderIndex(lun);
485 rousseau 649
486     DEBUG_COMM3("Lun: %X, Device: %d", lun, dev_name);
487    
488 rousseau 414 /* check if the same channel is not already used */
489 rousseau 1077 for (i=0; i<CCID_DRIVER_MAX_READERS; i++)
490 rousseau 414 {
491 rousseau 649 if (serialDevice[i].device &&
492     strcmp(serialDevice[i].device, dev_name) == 0)
493 rousseau 414 {
494 rousseau 649 DEBUG_CRITICAL2("Device %s already in use", dev_name);
495 rousseau 414 return STATUS_UNSUCCESSFUL;
496     }
497     }
498    
499     serialDevice[reader].fd = open(dev_name, O_RDWR | O_NOCTTY);
500    
501 rousseau 892 if (-1 == serialDevice[reader].fd)
502 rousseau 414 {
503     DEBUG_CRITICAL3("open %s: %s", dev_name, strerror(errno));
504     return STATUS_UNSUCCESSFUL;
505     }
506    
507     /* set channel used */
508 rousseau 649 serialDevice[reader].device = strdup(dev_name);
509 rousseau 414
510     /* empty in and out serial buffers */
511     if (tcflush(serialDevice[reader].fd, TCIOFLUSH))
512     DEBUG_INFO2("tcflush() function error: %s", strerror(errno));
513    
514     /* get config attributes */
515     if (tcgetattr(serialDevice[reader].fd, &current_termios) == -1)
516     {
517     DEBUG_INFO2("tcgetattr() function error: %s", strerror(errno));
518     close(serialDevice[reader].fd);
519     serialDevice[reader].fd = -1;
520    
521     return STATUS_UNSUCCESSFUL;
522     }
523    
524     /* IGNBRK: ignore BREAK condition on input
525     * IGNPAR: ignore framing errors and parity errors. */
526     current_termios.c_iflag = IGNBRK | IGNPAR;
527     current_termios.c_oflag = 0; /* Raw output modes */
528     /* CS8: 8-bits character size
529     * CSTOPB: set two stop bits
530     * CREAD: enable receiver
531     * CLOCAL: ignore modem control lines */
532     current_termios.c_cflag = CS8 | CSTOPB | CREAD | CLOCAL;
533    
534     /* Do not echo characters because if you connect to a host it or your modem
535     * will echo characters for you. Don't generate signals. */
536     current_termios.c_lflag = 0;
537    
538     /* set serial port speed to 115200 bauds */
539     cfsetspeed(&current_termios, B115200);
540    
541     DEBUG_INFO("Set serial port baudrate to 115200 and correct configuration");
542     if (tcsetattr(serialDevice[reader].fd, TCSANOW, &current_termios) == -1)
543     {
544     close(serialDevice[reader].fd);
545     serialDevice[reader].fd = -1;
546     DEBUG_INFO2("tcsetattr error: %s", strerror(errno));
547    
548     return STATUS_UNSUCCESSFUL;
549     }
550    
551     serialDevice[reader].ccid.bSeq = 0;
552     serialDevice[reader].ccid.readerID = GEMPCTWIN;
553     serialDevice[reader].ccid.dwMaxCCIDMessageLength = 271;
554 rousseau 672 serialDevice[reader].ccid.dwMaxIFSD = 254;
555 rousseau 414 serialDevice[reader].ccid.dwFeatures = 0x00010230;
556 rousseau 900 serialDevice[reader].ccid.bPINSupport = 0x0;
557 rousseau 694 serialDevice[reader].ccid.dwDefaultClock = 4000;
558     serialDevice[reader].ccid.dwMaxDataRate = 344086;
559 rousseau 1091 serialDevice[reader].ccid.bMaxSlotIndex = 0;
560     serialDevice[reader].ccid.bCurrentSlotIndex = 0;
561 rousseau 414
562 rousseau 453 serialDevice[reader].buffer_offset = 0;
563     serialDevice[reader].buffer_offset_last = 0;
564    
565 rousseau 1022 /* perform a command to be sure a GemPC Twin reader is connected
566     * get the reader firmware */
567     {
568 rousseau 1048 unsigned char tx_buffer[] = "\x02";
569     unsigned char rx_buffer[50];
570     unsigned int rx_length = sizeof(rx_buffer);
571 rousseau 1022
572     if (IFD_SUCCESS != CmdEscape(lun, tx_buffer, sizeof(tx_buffer),
573     rx_buffer, &rx_length))
574     {
575     DEBUG_CRITICAL("Get firmware failed. Maybe the reader is not co,,ected");
576     return STATUS_UNSUCCESSFUL;
577     }
578    
579     rx_buffer[rx_length] = '\0';
580     DEBUG_INFO2("Firmware: %s", rx_buffer);
581     }
582    
583 rousseau 414 return STATUS_SUCCESS;
584 rousseau 649 } /* OpenSerialByName */
585 rousseau 414
586    
587     /*****************************************************************************
588     *
589     * CloseSerial: close the port
590     *
591     *****************************************************************************/
592 rousseau 1043 status_t CloseSerial(unsigned int lun)
593 rousseau 414 {
594 rousseau 1049 unsigned int reader = LunToReaderIndex(lun);
595 rousseau 414
596     close(serialDevice[reader].fd);
597     serialDevice[reader].fd = -1;
598    
599 rousseau 649 free(serialDevice[reader].device);
600     serialDevice[reader].device = NULL;
601    
602 rousseau 414 return STATUS_SUCCESS;
603     } /* CloseSerial */
604    
605    
606     /*****************************************************************************
607     *
608     * get_ccid_descriptor
609     *
610     ****************************************************************************/
611 rousseau 1043 _ccid_descriptor *get_ccid_descriptor(unsigned int lun)
612 rousseau 414 {
613     return &serialDevice[LunToReaderIndex(lun)].ccid;
614     } /* get_ccid_descriptor */
615    
616    

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.5